From 872c08148ea75805897592414592ea4fe31d0503 Mon Sep 17 00:00:00 2001 From: yoff Date: Tue, 2 Jun 2026 14:09:28 +0000 Subject: [PATCH 001/188] Python: add shared-CFG AstSig adapter (AstNodeImpl) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Preparatory refactor for the shared-CFG dataflow migration. Adds the adapter that mediates between the Python AST and the shared codeql.controlflow.ControlFlowGraph signature, plus the test suites that validate the new CFG directly against this adapter. The public facade is added in the following commit. Library additions: - semmle.python.controlflow.internal.AstNodeImpl — wraps Python's Stmt/Expr/Scope/Pattern and adds two synthetic kinds of node (BlockStmt for body slots, intermediate nodes for multi-operand boolean expressions) to satisfy the shared CFG signature. - lib/ide-contextual-queries/printCfg.ql — the IDE "Print CFG" query, retargeted to the new CFG. - consistency-queries/CfgConsistency.ql — consistency query running the shared CFG's standard checks against Python. Test additions (all driven directly off AstNodeImpl): - ControlFlow/bindings/* — annotation-driven SSA-binding tests (annassign, compound, comprehension, decorated, except_handler, imports, match_pattern, parameters, simple, type_params, walrus_starred, with_stmt, dead_under_no_raise). - ControlFlow/evaluation-order/NewCfg*.ql — mirrors of the existing OldCfg evaluation-order self-validation suite, run against the new CFG via NewCfgImpl.qll. - Minor extensions to existing test_if.py / test_boolean.py + cosmetic .expected churn on a handful of OldCfg tests. No dataflow, SSA, or production query is migrated yet. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../ql/consistency-queries/CfgConsistency.ql | 2 + .../ql/lib/ide-contextual-queries/printCfg.ql | 42 + .../controlflow/internal/AstNodeImpl.qll | 1628 +++++++++++++++++ .../CONSISTENCY/CfgConsistency.expected | 4 + .../bindings/BindingsTest.expected | 0 .../ControlFlow/bindings/BindingsTest.ql | 32 + .../ControlFlow/bindings/annassign.py | 13 + .../ControlFlow/bindings/compound.py | 14 + .../ControlFlow/bindings/comprehension.py | 21 + .../bindings/dead_under_no_raise.py | 52 + .../ControlFlow/bindings/decorated.py | 30 + .../ControlFlow/bindings/except_handler.py | 19 + .../ControlFlow/bindings/imports.py | 14 + .../ControlFlow/bindings/match_pattern.py | 24 + .../ControlFlow/bindings/parameters.py | 42 + .../ControlFlow/bindings/simple.py | 14 + .../ControlFlow/bindings/type_params.py | 21 + .../ControlFlow/bindings/walrus_starred.py | 14 + .../ControlFlow/bindings/with_stmt.py | 21 + .../NewCfgAllLiveReachable.expected | 0 .../NewCfgAllLiveReachable.ql | 14 + .../NewCfgAnnotationHasCfgNode.expected | 1 + .../NewCfgAnnotationHasCfgNode.ql | 18 + .../NewCfgBasicBlockAnnotationGap.expected | 0 .../NewCfgBasicBlockAnnotationGap.ql | 26 + .../NewCfgBasicBlockOrdering.expected | 0 .../NewCfgBasicBlockOrdering.ql | 21 + .../NewCfgBranchTimestamps.expected | 0 .../NewCfgBranchTimestamps.ql | 80 + ...gConsecutivePredecessorTimestamps.expected | 1 + .../NewCfgConsecutivePredecessorTimestamps.ql | 22 + .../NewCfgConsecutiveTimestamps.expected | 0 .../NewCfgConsecutiveTimestamps.ql | 29 + .../evaluation-order/NewCfgImpl.qll | 120 ++ .../NewCfgNeverReachable.expected | 0 .../evaluation-order/NewCfgNeverReachable.ql | 21 + .../NewCfgNoBackwardFlow.expected | 0 .../evaluation-order/NewCfgNoBackwardFlow.ql | 22 + .../NewCfgNoBasicBlock.expected | 1 + .../evaluation-order/NewCfgNoBasicBlock.ql | 18 + .../NewCfgNoSharedReachable.expected | 0 .../NewCfgNoSharedReachable.ql | 21 + .../NewCfgStrictForward.expected | 0 .../evaluation-order/NewCfgStrictForward.ql | 22 + .../evaluation-order/OldCfgImpl.qll | 8 +- .../ControlFlow/evaluation-order/test_if.py | 2 +- 46 files changed, 2449 insertions(+), 5 deletions(-) create mode 100644 python/ql/consistency-queries/CfgConsistency.ql create mode 100644 python/ql/lib/ide-contextual-queries/printCfg.ql create mode 100644 python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll create mode 100644 python/ql/test/extractor-tests/syntax_error/CONSISTENCY/CfgConsistency.expected create mode 100644 python/ql/test/library-tests/ControlFlow/bindings/BindingsTest.expected create mode 100644 python/ql/test/library-tests/ControlFlow/bindings/BindingsTest.ql create mode 100644 python/ql/test/library-tests/ControlFlow/bindings/annassign.py create mode 100644 python/ql/test/library-tests/ControlFlow/bindings/compound.py create mode 100644 python/ql/test/library-tests/ControlFlow/bindings/comprehension.py create mode 100644 python/ql/test/library-tests/ControlFlow/bindings/dead_under_no_raise.py create mode 100644 python/ql/test/library-tests/ControlFlow/bindings/decorated.py create mode 100644 python/ql/test/library-tests/ControlFlow/bindings/except_handler.py create mode 100644 python/ql/test/library-tests/ControlFlow/bindings/imports.py create mode 100644 python/ql/test/library-tests/ControlFlow/bindings/match_pattern.py create mode 100644 python/ql/test/library-tests/ControlFlow/bindings/parameters.py create mode 100644 python/ql/test/library-tests/ControlFlow/bindings/simple.py create mode 100644 python/ql/test/library-tests/ControlFlow/bindings/type_params.py create mode 100644 python/ql/test/library-tests/ControlFlow/bindings/walrus_starred.py create mode 100644 python/ql/test/library-tests/ControlFlow/bindings/with_stmt.py create mode 100644 python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAllLiveReachable.expected create mode 100644 python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAllLiveReachable.ql create mode 100644 python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAnnotationHasCfgNode.expected create mode 100644 python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAnnotationHasCfgNode.ql create mode 100644 python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockAnnotationGap.expected create mode 100644 python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockAnnotationGap.ql create mode 100644 python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockOrdering.expected create mode 100644 python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockOrdering.ql create mode 100644 python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBranchTimestamps.expected create mode 100644 python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBranchTimestamps.ql create mode 100644 python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutivePredecessorTimestamps.expected create mode 100644 python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutivePredecessorTimestamps.ql create mode 100644 python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutiveTimestamps.expected create mode 100644 python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutiveTimestamps.ql create mode 100644 python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgImpl.qll create mode 100644 python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNeverReachable.expected create mode 100644 python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNeverReachable.ql create mode 100644 python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBackwardFlow.expected create mode 100644 python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBackwardFlow.ql create mode 100644 python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBasicBlock.expected create mode 100644 python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBasicBlock.ql create mode 100644 python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoSharedReachable.expected create mode 100644 python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoSharedReachable.ql create mode 100644 python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgStrictForward.expected create mode 100644 python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgStrictForward.ql diff --git a/python/ql/consistency-queries/CfgConsistency.ql b/python/ql/consistency-queries/CfgConsistency.ql new file mode 100644 index 000000000000..ab13eddf190c --- /dev/null +++ b/python/ql/consistency-queries/CfgConsistency.ql @@ -0,0 +1,2 @@ +import semmle.python.controlflow.internal.AstNodeImpl +import ControlFlow::Consistency diff --git a/python/ql/lib/ide-contextual-queries/printCfg.ql b/python/ql/lib/ide-contextual-queries/printCfg.ql new file mode 100644 index 000000000000..6e325e84bb7b --- /dev/null +++ b/python/ql/lib/ide-contextual-queries/printCfg.ql @@ -0,0 +1,42 @@ +/** + * @name Print CFG + * @description Produces a representation of a file's Control Flow Graph. + * This query is used by the VS Code extension. + * @id py/print-cfg + * @kind graph + * @tags ide-contextual-queries/print-cfg + */ + +import semmle.python.Files as Files +// import semmle.python.Scope +import semmle.python.controlflow.internal.AstNodeImpl + +external string selectedSourceFile(); + +private predicate selectedSourceFileAlias = selectedSourceFile/0; + +external int selectedSourceLine(); + +private predicate selectedSourceLineAlias = selectedSourceLine/0; + +external int selectedSourceColumn(); + +private predicate selectedSourceColumnAlias = selectedSourceColumn/0; + +module ViewCfgQueryInput implements ControlFlow::ViewCfgQueryInputSig { + predicate selectedSourceFile = selectedSourceFileAlias/0; + + predicate selectedSourceLine = selectedSourceLineAlias/0; + + predicate selectedSourceColumn = selectedSourceColumnAlias/0; + + predicate cfgScopeSpan( + Ast::Callable scope, Files::File file, int startLine, int startColumn, int endLine, + int endColumn + ) { + file = scope.getLocation().getFile() and + scope.getLocation().hasLocationInfo(_, startLine, startColumn, endLine, endColumn) + } +} + +import ControlFlow::ViewCfgQuery diff --git a/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll b/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll new file mode 100644 index 000000000000..5d87b16f3511 --- /dev/null +++ b/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll @@ -0,0 +1,1628 @@ +/** + * Provides classes for the shared control-flow library, mediating between + * the Python AST and `AstSig`. + * + * The `Ast` module wraps Python's `Stmt`, `Expr`, `Scope`, and `Pattern`, + * and adds two synthetic kinds of node: + * - `BlockStmt`, identifying a body slot of a parent AST node (e.g. an + * `if`'s then or else branch). `Py::StmtList` itself is not directly + * wrapped. + * - Intermediate nodes for multi-operand boolean expressions. + */ +overlay[local?] +module; + +private import python as Py +private import codeql.controlflow.ControlFlowGraph +private import codeql.controlflow.SuccessorType +private import codeql.util.Void + +/** + * Gets the bound `Name` of a PEP 695 type parameter (`TypeVar`, + * `ParamSpec`, or `TypeVarTuple`). The base `TypeParameter` class does + * not expose `getName()`; this helper dispatches over the subtypes. + */ +private Py::Name typeParameterName(Py::TypeParameter tp) { + result = tp.(Py::TypeVar).getName() + or + result = tp.(Py::ParamSpec).getName() + or + result = tp.(Py::TypeVarTuple).getName() +} + +/** Provides the Python implementation of the shared CFG `AstSig`. */ +module Ast implements AstSig { + private newtype TAstNode = + TPyStmt(Py::Stmt s) or + TPyExpr(Py::Expr e) { not e instanceof Py::BoolExpr } or + TScope(Py::Scope sc) or + TPattern(Py::Pattern p) or + /** + * A synthetic node representing an operand pair of an `and`/`or` + * expression. For `a and b and c` (operands 0, 1, 2) we model the + * operation as a right-nested tree: pair 0 represents the whole + * expression with left=a and right=pair 1; pair 1 represents + * `b and c` with left=b and right=c. Each Python `Py::BoolExpr` + * with `n` operands has `n - 1` such pairs (indices `0 .. n - 2`). + */ + TBoolExprPair(Py::BoolExpr be, int index) { index = [0 .. count(be.getAValue()) - 2] } or + /** + * A synthetic block statement, wrapping a `Py::StmtList`. Each list of + * statements that represents an imperative block (a function/class/module + * body, an `if`/`while`/`for` branch, a `try`/`except`/`finally` body, + * etc.) becomes one `BlockStmt` node in the CFG. `Py::StmtList`s used + * in other roles - `Try.getHandlers()` (iterated via `getCatch`) and + * `MatchStmt.getCases()` (iterated via `getCase`) - are excluded, as + * the shared library's `Try`/`Switch` logic walks their items + * individually. + */ + TBlockStmt(Py::StmtList sl) { + not sl = any(Py::Try t).getHandlers() and + not sl = any(Py::MatchStmt m).getCases() + } + + /** + * The union of `TPyStmt` (wrapping `Py::Stmt`) and `TBlockStmt` (wrapping + * `Py::StmtList`). Both represent the kinds of node that can appear in + * a `Stmt` position in the CFG. + */ + private class TStmt = TPyStmt or TBlockStmt; + + /** + * The union of `TPyExpr` (wrapping non-boolean `Py::Expr`) and + * `TBoolExprPair` (synthetic operand pairs of `and`/`or` expressions). + * Both represent the kinds of node that can appear in an `Expr` + * position in the CFG. + */ + private class TExpr = TPyExpr or TBoolExprPair; + + /** + * An AST node visible to the shared CFG. + * + * This is the abstract implementation class. It enforces that each + * concrete subclass provides `toString`, `getLocation`, and + * `getEnclosingCallable` (one subclass per `TAstNode` newtype branch). + * The public alias `AstNode` is what users (and the `AstSig` signature) + * see; subclasses inside this module extend `AstNodeImpl` directly. + */ + abstract private class AstNodeImpl extends TAstNode { + /** Gets a textual representation of this AST node. */ + abstract string toString(); + + /** Gets the location of this AST node. */ + abstract Py::Location getLocation(); + + /** Gets the enclosing callable that contains this node, if any. */ + abstract Callable getEnclosingCallable(); + + /** Gets the underlying Python `Stmt`, if this node wraps one. */ + Py::Stmt asStmt() { this = TPyStmt(result) } + + /** + * Gets the underlying Python `Expr`, if this node wraps one. Boolean + * expressions are represented by `TBoolExprPair(_, 0)`; this + * predicate also recovers the underlying `Py::BoolExpr` from such a + * representation. + */ + Py::Expr asExpr() { + this = TPyExpr(result) + or + this = TBoolExprPair(result, 0) + } + + /** Gets the underlying Python `Scope`, if this node wraps one. */ + Py::Scope asScope() { this = TScope(result) } + + /** Gets the underlying Python `Pattern`, if this node wraps one. */ + Py::Pattern asPattern() { this = TPattern(result) } + + /** Gets the underlying Python `StmtList`, if this node is a `BlockStmt`. */ + Py::StmtList asStmtList() { this = TBlockStmt(result) } + + /** + * Gets the child of this AST node at the specified (zero-based) + * index, in evaluation order. Subclasses with children override + * this method. + */ + AstNode getChild(int index) { none() } + } + + /** An AST node visible to the shared CFG. */ + final class AstNode = AstNodeImpl; + + /** Gets the immediately enclosing callable that contains `node`. */ + Callable getEnclosingCallable(AstNode node) { result = node.getEnclosingCallable() } + + /** + * A callable: a function, class, or module scope. + * + * In Python, all three are executable scopes with statement bodies. + */ + class Callable extends AstNodeImpl, TScope { + private Py::Scope sc; + + Callable() { this = TScope(sc) } + + override string toString() { result = sc.toString() } + + override Py::Location getLocation() { result = sc.getLocation() } + + override Callable getEnclosingCallable() { result.asScope() = sc.getEnclosingScope() } + } + + /** Gets the body of callable `c`. */ + AstNode callableGetBody(Callable c) { result.asStmtList() = c.asScope().getBody() } + + /** + * A parameter of a callable. + * + * Modelled per the C# template (`csharp/.../ControlFlowGraph.qll:147-156`): + * each Python parameter (the `Py::Parameter` AST node, which is a `Name` + * or — Python 2 only — a `Tuple` in store context) becomes a CFG node + * at a stable position in the enclosing callable's entry sequence. + * + * Default-value expressions for positional and keyword-only parameters + * are wired separately on the `FunctionDefExpr` / `LambdaExpr` wrappers + * (they evaluate at function-definition time, not at call time). + * `Parameter::getDefaultValue()` returns `none()` here, signalling to + * the shared library that the parameter never falls back to a default + * during call binding. This mirrors C# for non-optional parameters. + */ + class Parameter extends Expr { + private Py::Parameter param; + + Parameter() { this = TPyExpr(param) } + + /** Gets the underlying Python parameter. */ + Py::Parameter asParameter() { result = param } + + /** + * Gets the default-value expression of this parameter, if any. + * + * Returns `none()`: defaults evaluate at function-definition time and + * are wired into the CFG via `FunctionDefExpr.getDefault` / + * `LambdaExpr.getDefault`. The shared library calls this predicate + * to model the "missing argument → evaluate default" fallback during + * call binding, which Python does not model at the CFG level. + */ + Expr getDefaultValue() { none() } + + /** + * Gets the pattern for this parameter. In Python, there is no destructuring + * pattern syntax for parameters, so the pattern is the parameter itself. + */ + AstNode getPattern() { result = this } + } + + /** + * Gets the `index`th parameter of callable `c`, ordered as Python binds + * them at call time: positional, then vararg (`*args`), then + * keyword-only, then kwarg (`**kwargs`). + */ + Parameter callableGetParameter(Callable c, int index) { + exists(Py::Function f | f = c.asScope() | + result.asParameter() = + rank[index + 1](Py::Parameter p, int subOrder, int subIndex | + // positional parameters first + p = f.getArg(subIndex) and subOrder = 0 + or + // then *args + p = f.getVararg() and subOrder = 1 and subIndex = 0 + or + // then keyword-only parameters + p = f.getKeywordOnlyArg(subIndex) and subOrder = 2 + or + // finally **kwargs + p = f.getKwarg() and subOrder = 3 and subIndex = 0 + | + p order by subOrder, subIndex + ) + ) + } + + /** A statement. */ + class Stmt extends AstNodeImpl, TStmt { + // For `TPyStmt` instances, delegate to the wrapped Python statement. + // `BlockStmt` (the only `TBlockStmt` subclass) provides its own overrides. + override string toString() { result = this.asStmt().toString() } + + override Py::Location getLocation() { result = this.asStmt().getLocation() } + + override Callable getEnclosingCallable() { result.asScope() = this.asStmt().getScope() } + } + + /** An expression. */ + class Expr extends AstNodeImpl, TExpr { + // For `TPyExpr` instances, delegate to the wrapped Python expression. + // `BinaryExpr` (the only `TBoolExprPair` subclass) provides its own overrides. + override string toString() { result = this.asExpr().toString() } + + override Py::Location getLocation() { result = this.asExpr().getLocation() } + + override Callable getEnclosingCallable() { result.asScope() = this.asExpr().getScope() } + } + + /** A pattern in a `match` statement. */ + additional class Pattern extends AstNodeImpl, TPattern { + private Py::Pattern p; + + Pattern() { this = TPattern(p) } + + override string toString() { result = p.toString() } + + override Py::Location getLocation() { result = p.getLocation() } + + override Callable getEnclosingCallable() { result.asScope() = p.getScope() } + } + + /** + * A `case x` pattern that binds `x` to the matched value. + */ + additional class MatchCapturePattern extends Pattern { + private Py::MatchCapturePattern cap; + + MatchCapturePattern() { this = TPattern(cap) } + + /** Gets the bound Name expression. */ + Expr getVariable() { result.asExpr() = cap.getVariable() } + + override AstNode getChild(int index) { index = 0 and result = this.getVariable() } + } + + /** + * A `case pattern as name` pattern. + */ + additional class MatchAsPattern extends Pattern { + private Py::MatchAsPattern asp; + + MatchAsPattern() { this = TPattern(asp) } + + /** Gets the inner pattern. */ + AstNode getPattern() { result.asPattern() = asp.getPattern() } + + /** Gets the bound Name expression. */ + Expr getAlias() { result.asExpr() = asp.getAlias() } + + override AstNode getChild(int index) { + index = 0 and result = this.getPattern() + or + index = 1 and result = this.getAlias() + } + } + + /** + * A `case [a, b, *rest]` star pattern. Binds `rest` to the remaining + * elements of the sequence. + */ + additional class MatchStarPattern extends Pattern { + private Py::MatchStarPattern starp; + + MatchStarPattern() { this = TPattern(starp) } + + /** Gets the target Pattern (a `MatchCapturePattern` if `*rest`). */ + AstNode getTarget() { result.asPattern() = starp.getTarget() } + + override AstNode getChild(int index) { index = 0 and result = this.getTarget() } + } + + /** + * A `case [a, b, ...]` sequence pattern. Recurses into the sub-patterns. + */ + additional class MatchSequencePattern extends Pattern { + private Py::MatchSequencePattern seqp; + + MatchSequencePattern() { this = TPattern(seqp) } + + /** Gets the `n`th sub-pattern. */ + AstNode getPattern(int n) { result.asPattern() = seqp.getPattern(n) } + + override AstNode getChild(int index) { result = this.getPattern(index) } + } + + /** + * A `case Cls(a, b, x=y)` class pattern. + */ + additional class MatchClassPattern extends Pattern { + private Py::MatchClassPattern clsp; + + MatchClassPattern() { this = TPattern(clsp) } + + /** Gets the class expression of this class pattern. */ + Expr getClass() { result.asExpr() = clsp.getClass() } + + /** Gets the `n`th positional sub-pattern. */ + AstNode getPositional(int n) { result.asPattern() = clsp.getPositional(n) } + + /** Gets the `n`th keyword sub-pattern. */ + AstNode getKeyword(int n) { result.asPattern() = clsp.getKeyword(n) } + + private int numPositional() { result = count(int i | exists(clsp.getPositional(i))) } + + override AstNode getChild(int index) { + index = 0 and result = this.getClass() + or + result = this.getPositional(index - 1) and index >= 1 + or + result = this.getKeyword(index - 1 - this.numPositional()) and + index >= 1 + this.numPositional() + } + } + + /** + * A `case {k: v}` mapping pattern. + */ + additional class MatchMappingPattern extends Pattern { + private Py::MatchMappingPattern mapp; + + MatchMappingPattern() { this = TPattern(mapp) } + + AstNode getMapping(int n) { result.asPattern() = mapp.getMapping(n) } + + override AstNode getChild(int index) { result = this.getMapping(index) } + } + + /** + * A key-value pair inside a `case {k: v}` mapping pattern. + */ + additional class MatchKeyValuePattern extends Pattern { + private Py::MatchKeyValuePattern kvp; + + MatchKeyValuePattern() { this = TPattern(kvp) } + + AstNode getKey() { result.asPattern() = kvp.getKey() } + + AstNode getValue() { result.asPattern() = kvp.getValue() } + + override AstNode getChild(int index) { + index = 0 and result = this.getKey() + or + index = 1 and result = this.getValue() + } + } + + /** + * A `case Cls(name=value)` keyword sub-pattern. + */ + additional class MatchKeywordPattern extends Pattern { + private Py::MatchKeywordPattern kwp; + + MatchKeywordPattern() { this = TPattern(kwp) } + + Expr getAttribute() { result.asExpr() = kwp.getAttribute() } + + AstNode getValue() { result.asPattern() = kwp.getValue() } + + override AstNode getChild(int index) { + index = 0 and result = this.getAttribute() + or + index = 1 and result = this.getValue() + } + } + + /** A `case **rest` double-star mapping sub-pattern. */ + additional class MatchDoubleStarPattern extends Pattern { + private Py::MatchDoubleStarPattern dsp; + + MatchDoubleStarPattern() { this = TPattern(dsp) } + + AstNode getTarget() { result.asPattern() = dsp.getTarget() } + + override AstNode getChild(int index) { index = 0 and result = this.getTarget() } + } + + /** A `case p1 | p2 | …` or-pattern. */ + additional class MatchOrPattern extends Pattern { + private Py::MatchOrPattern orp; + + MatchOrPattern() { this = TPattern(orp) } + + AstNode getPattern(int n) { result.asPattern() = orp.getPattern(n) } + + override AstNode getChild(int index) { result = this.getPattern(index) } + } + + /** A `case 1` literal pattern. */ + additional class MatchLiteralPattern extends Pattern { + private Py::MatchLiteralPattern litp; + + MatchLiteralPattern() { this = TPattern(litp) } + + Expr getLiteral() { result.asExpr() = litp.getLiteral() } + + override AstNode getChild(int index) { index = 0 and result = this.getLiteral() } + } + + /** A `case Cls.NAME` value pattern. */ + additional class MatchValuePattern extends Pattern { + private Py::MatchValuePattern vp; + + MatchValuePattern() { this = TPattern(vp) } + + Expr getValue() { result.asExpr() = vp.getValue() } + + override AstNode getChild(int index) { index = 0 and result = this.getValue() } + } + + /** + * A block statement, modeling the body of a parent AST node as a + * sequence of statements. + */ + class BlockStmt extends Stmt, TBlockStmt { + private Py::StmtList sl; + + BlockStmt() { this = TBlockStmt(sl) } + + /** Gets the `n`th (zero-based) statement in this block. */ + Stmt getStmt(int n) { result.asStmt() = sl.getItem(n) } + + /** Gets the last statement in this block. */ + Stmt getLastStmt() { result.asStmt() = sl.getLastItem() } + + override string toString() { result = sl.toString() } + + // `Py::StmtList` has no native location; approximate with the first + // item's location. + override Py::Location getLocation() { result = sl.getItem(0).getLocation() } + + override Callable getEnclosingCallable() { + result.asScope() = sl.getParent().(Py::Scope) + or + result.asScope() = sl.getParent().(Py::Stmt).getScope() + } + + override AstNode getChild(int index) { result = this.getStmt(index) } + } + + /** An expression statement. */ + class ExprStmt extends Stmt { + private Py::ExprStmt exprStmt; + + ExprStmt() { this = TPyStmt(exprStmt) } + + /** Gets the expression in this expression statement. */ + Expr getExpr() { result.asExpr() = exprStmt.getValue() } + + override AstNode getChild(int index) { index = 0 and result = this.getExpr() } + } + + /** An assignment statement (`x = y = expr`). */ + additional class AssignStmt extends Stmt { + private Py::Assign assign; + + AssignStmt() { this = TPyStmt(assign) } + + Expr getValue() { result.asExpr() = assign.getValue() } + + Expr getTarget(int n) { result.asExpr() = assign.getTarget(n) } + + int getNumberOfTargets() { result = count(assign.getATarget()) } + + override AstNode getChild(int index) { + index = 0 and result = this.getValue() + or + result = this.getTarget(index - 1) and index >= 1 + } + } + + /** An augmented assignment statement (`x += expr`). */ + additional class AugAssignStmt extends Stmt { + private Py::AugAssign augAssign; + + AugAssignStmt() { this = TPyStmt(augAssign) } + + Expr getOperation() { result.asExpr() = augAssign.getOperation() } + + override AstNode getChild(int index) { index = 0 and result = this.getOperation() } + } + + /** + * An annotated assignment statement (`x: T = expr`, or `x: T` without + * value). The evaluation order follows CPython: annotation first, then + * the optional value, then the target binding. + */ + additional class AnnAssignStmt extends Stmt { + private Py::AnnAssign annAssign; + + AnnAssignStmt() { this = TPyStmt(annAssign) } + + Expr getAnnotation() { result.asExpr() = annAssign.getAnnotation() } + + Expr getValue() { result.asExpr() = annAssign.getValue() } + + Expr getTarget() { result.asExpr() = annAssign.getTarget() } + + override AstNode getChild(int index) { + index = 0 and result = this.getAnnotation() + or + index = 1 and result = this.getValue() + or + index = 2 and result = this.getTarget() + } + } + + /** An assignment expression / walrus operator (`x := expr`). */ + additional class NamedExpr extends Expr { + private Py::AssignExpr assignExpr; + + NamedExpr() { this = TPyExpr(assignExpr) } + + Expr getValue() { result.asExpr() = assignExpr.getValue() } + + Expr getTarget() { result.asExpr() = assignExpr.getTarget() } + + override AstNode getChild(int index) { + index = 0 and result = this.getValue() + or + index = 1 and result = this.getTarget() + } + } + + /** + * An `if` statement. + * + * Python's `elif` chains are represented as nested `If` nodes in the + * else branch's `StmtList`. The shared CFG library handles this + * naturally: `getElse()` returns the `BlockStmt` wrapping the else + * branch, and if that block contains a single `If`, the result is + * a chained conditional. + */ + class IfStmt extends Stmt { + private Py::If ifStmt; + + IfStmt() { this = TPyStmt(ifStmt) } + + /** Gets the underlying Python `If` statement. */ + Py::If asIf() { result = ifStmt } + + /** Gets the condition of this `if` statement. */ + Expr getCondition() { result.asExpr() = ifStmt.getTest() } + + /** Gets the `then` (true) branch of this `if` statement. */ + Stmt getThen() { result.asStmtList() = ifStmt.getBody() } + + /** Gets the `else` (false) branch, if any. */ + Stmt getElse() { result.asStmtList() = ifStmt.getOrelse() } + + override AstNode getChild(int index) { + index = 0 and result = this.getCondition() + or + index = 1 and result = this.getThen() + or + index = 2 and result = this.getElse() + } + } + + /** A loop statement. */ + class LoopStmt extends Stmt { + LoopStmt() { + this = TPyStmt(any(Py::While w)) + or + this = TPyStmt(any(Py::For f)) + } + + /** Gets the body of this loop statement. */ + Stmt getBody() { none() } + } + + /** A `while` loop statement. */ + class WhileStmt extends LoopStmt { + private Py::While whileStmt; + + WhileStmt() { this = TPyStmt(whileStmt) } + + /** Gets the boolean condition of this `while` loop. */ + Expr getCondition() { result.asExpr() = whileStmt.getTest() } + + override Stmt getBody() { result.asStmtList() = whileStmt.getBody() } + + /** Gets the `else` branch of this `while` loop, if any. */ + Stmt getElse() { result.asStmtList() = whileStmt.getOrelse() } + + override AstNode getChild(int index) { + index = 0 and result = this.getCondition() + or + index = 1 and result = this.getBody() + or + index = 2 and result = this.getElse() + } + } + + /** + * A `do-while` loop statement. Python has no do-while construct. + */ + class DoStmt extends LoopStmt { + DoStmt() { none() } + + Expr getCondition() { none() } + } + + /** An `until` loop. Python has no `until` loop. */ + class UntilStmt extends LoopStmt { + UntilStmt() { none() } + + Expr getCondition() { none() } + } + + /** A C-style `for` loop. Python has no C-style for loop. */ + class ForStmt extends LoopStmt { + ForStmt() { none() } + + AstNode getInit(int index) { none() } + + Expr getCondition() { none() } + + AstNode getUpdate(int index) { none() } + } + + /** A for-each loop (`for x in iterable:`). */ + class ForeachStmt extends LoopStmt { + private Py::For forStmt; + + ForeachStmt() { this = TPyStmt(forStmt) } + + /** Gets the loop variable. */ + Expr getVariable() { result.asExpr() = forStmt.getTarget() } + + /** Gets the collection being iterated. */ + Expr getCollection() { result.asExpr() = forStmt.getIter() } + + override Stmt getBody() { result.asStmtList() = forStmt.getBody() } + + /** Gets the `else` branch of this `for` loop, if any. */ + Stmt getElse() { result.asStmtList() = forStmt.getOrelse() } + + override AstNode getChild(int index) { + index = 0 and result = this.getCollection() + or + index = 1 and result = this.getVariable() + or + index = 2 and result = this.getBody() + or + index = 3 and result = this.getElse() + } + } + + /** A `break` statement. */ + class BreakStmt extends Stmt { + BreakStmt() { this = TPyStmt(any(Py::Break b)) } + } + + /** A `continue` statement. */ + class ContinueStmt extends Stmt { + ContinueStmt() { this = TPyStmt(any(Py::Continue c)) } + } + + /** A `goto` statement. Python has no goto. */ + class GotoStmt extends Stmt { + GotoStmt() { none() } + } + + /** A `return` statement. */ + class ReturnStmt extends Stmt { + private Py::Return ret; + + ReturnStmt() { this = TPyStmt(ret) } + + /** Gets the expression being returned, if any. */ + Expr getExpr() { result.asExpr() = ret.getValue() } + + override AstNode getChild(int index) { index = 0 and result = this.getExpr() } + } + + /** A `raise` statement (mapped to `Throw`). */ + class Throw extends Stmt { + private Py::Raise raise; + + Throw() { this = TPyStmt(raise) } + + /** Gets the expression being raised. */ + Expr getExpr() { result.asExpr() = raise.getException() } + + /** Gets the cause of this `raise`, if any. */ + Expr getCause() { result.asExpr() = raise.getCause() } + + override AstNode getChild(int index) { + index = 0 and result = this.getExpr() + or + index = 1 and result = this.getCause() + } + } + + /** + * An `import` statement (`import a, b` or `from m import a, b`). + * + * Each alias contributes two children in evaluation order: first the + * value expression (which performs the import side-effect), then the + * bound `asname` Name (the in-scope binding). This makes both reachable + * from the CFG and allows `Name.defines(v)` for `asname` Names to have + * corresponding CFG nodes — which is essential for SSA to see import + * bindings. + */ + additional class ImportStmt extends Stmt { + private Py::Import imp; + + ImportStmt() { this = TPyStmt(imp) } + + /** Gets the value (module/member expression) of the `n`th alias. */ + Expr getValue(int n) { result.asExpr() = imp.getName(n).getValue() } + + /** Gets the bound `asname` of the `n`th alias. */ + Expr getAsname(int n) { result.asExpr() = imp.getName(n).getAsname() } + + /** Gets the number of aliases in this import statement. */ + int getNumberOfAliases() { result = count(int i | exists(imp.getName(i))) } + + override AstNode getChild(int index) { + exists(int i | + index = 2 * i and result = this.getValue(i) + or + index = 2 * i + 1 and result = this.getAsname(i) + ) + } + } + + /** + * A `from m import *` statement. Evaluates the module expression but + * binds no name (the bindings happen by side-effect at runtime, which + * is not modelled at the CFG level). + */ + additional class ImportStarStmt extends Stmt { + private Py::ImportStar imp; + + ImportStarStmt() { this = TPyStmt(imp) } + + Expr getModule() { result.asExpr() = imp.getModule() } + + override AstNode getChild(int index) { index = 0 and result = this.getModule() } + } + + /** A `with` statement. */ + additional class WithStmt extends Stmt { + private Py::With withStmt; + + WithStmt() { this = TPyStmt(withStmt) } + + Expr getContextExpr() { result.asExpr() = withStmt.getContextExpr() } + + Expr getOptionalVars() { result.asExpr() = withStmt.getOptionalVars() } + + Stmt getBody() { result.asStmtList() = withStmt.getBody() } + + override AstNode getChild(int index) { + index = 0 and result = this.getContextExpr() + or + index = 1 and result = this.getOptionalVars() + or + index = 2 and result = this.getBody() + } + } + + /** An `assert` statement. */ + additional class AssertStmt extends Stmt { + private Py::Assert assertStmt; + + AssertStmt() { this = TPyStmt(assertStmt) } + + Expr getTest() { result.asExpr() = assertStmt.getTest() } + + Expr getMsg() { result.asExpr() = assertStmt.getMsg() } + + override AstNode getChild(int index) { + index = 0 and result = this.getTest() + or + index = 1 and result = this.getMsg() + } + } + + /** A `delete` statement. */ + additional class DeleteStmt extends Stmt { + private Py::Delete del; + + DeleteStmt() { this = TPyStmt(del) } + + Expr getTarget(int n) { result.asExpr() = del.getTarget(n) } + + override AstNode getChild(int index) { result = this.getTarget(index) } + } + + /** + * A PEP 695 `type` statement (`type Alias[T1, T2] = value`). + * + * The type parameters bind at statement-evaluation time. The value + * expression is captured for lazy evaluation but the alias `Name` + * itself binds the resulting `TypeAliasType` object — so the CFG must + * visit at minimum the type-parameter names and the alias name. + */ + additional class TypeAliasStmt extends Stmt { + private Py::TypeAlias ta; + + TypeAliasStmt() { this = TPyStmt(ta) } + + /** Gets the alias `Name` bound by this statement. */ + Expr getName() { result.asExpr() = ta.getName() } + + /** + * Gets the `n`th PEP 695 type-parameter name (a `Name` in store + * context), in declaration order. + */ + Expr getTypeParamName(int n) { result.asExpr() = typeParameterName(ta.getTypeParameter(n)) } + + int getNumberOfTypeParams() { result = count(ta.getATypeParameter()) } + + override AstNode getChild(int index) { + result = this.getTypeParamName(index) + or + index = this.getNumberOfTypeParams() and result = this.getName() + } + } + + /** A `try` statement. */ + class TryStmt extends Stmt { + private Py::Try tryStmt; + + TryStmt() { this = TPyStmt(tryStmt) } + + AstNode getBody(int index) { index = 0 and result.asStmtList() = tryStmt.getBody() } + + /** Gets the `else` branch of this `try` statement, if any. */ + Stmt getElse() { result.asStmtList() = tryStmt.getOrelse() } + + Stmt getFinally() { result.asStmtList() = tryStmt.getFinalbody() } + + CatchClause getCatch(int index) { result.asStmt() = tryStmt.getHandler(index) } + + override AstNode getChild(int index) { + index = 0 and result = this.getBody(0) + or + result = this.getCatch(index - 1) and index >= 1 + or + index = -1 and result = this.getFinally() + or + index = -2 and result = this.getElse() + } + } + + /** + * Gets the `else` branch of `try` statement `try`, if any. + */ + AstNode getTryElse(TryStmt try) { result = try.getElse() } + + /** + * Gets the `else` branch of loop `loop`, if any. + * + * Python's `while`/`for` loops may have an `else` block that runs when the + * loop completes without `break`. + */ + AstNode getLoopElse(LoopStmt loop) { + result = loop.(WhileStmt).getElse() + or + result = loop.(ForeachStmt).getElse() + } + + /** An exception handler (`except` or `except*`). */ + class CatchClause extends Stmt { + private Py::ExceptionHandler handler; + + CatchClause() { this = TPyStmt(handler) } + + /** + * Gets the type-test pattern of this exception handler, if any. + * + * This is the single syntactic type expression (`except TypeError:` → + * `TypeError`; `except (A, B):` → the `(A, B)` tuple). A bare `except:` + * has no pattern and is therefore a catch-all that matches any + * exception. The type test and the variable binding are independent + * child nodes in Python, matching the shared CFG model. + * + * We read the raw type child directly (extractor relation `py_exprs` + * at child index 1) rather than the public `getType()` accessor: the + * latter flattens a tuple of exception types (`except (A, B):`) into + * its individual elements, which would yield several patterns for one + * handler and violate the shared CFG's single-pattern-per-catch + * contract. The raw child is the one tuple node, modelling the + * runtime's single `isinstance(exc, (A, B))` test. + */ + AstNode getPattern() { + exists(Py::Expr rawType | py_exprs(rawType, _, handler, 1) | result.asExpr() = rawType) + } + + /** Gets the variable name of this exception handler, if any. */ + AstNode getVariable() { result.asExpr() = handler.getName() } + + /** Holds: catch clauses do not have a `Condition` in Python's model. */ + Expr getCondition() { none() } + + /** Gets the body of this exception handler. */ + Stmt getBody() { + result.asStmtList() = handler.(Py::ExceptStmt).getBody() + or + result.asStmtList() = handler.(Py::ExceptGroupStmt).getBody() + } + + override AstNode getChild(int index) { + index = 0 and result = this.getPattern() + or + index = 1 and result = this.getVariable() + or + index = 2 and result = this.getBody() + } + } + + /** A `match` statement, mapped to the shared CFG's `Switch`. */ + class Switch extends Stmt { + private Py::MatchStmt matchStmt; + + Switch() { this = TPyStmt(matchStmt) } + + Expr getExpr() { result.asExpr() = matchStmt.getSubject() } + + Case getCase(int index) { result.asStmt() = matchStmt.getCase(index) } + + Stmt getStmt(int index) { none() } + + override AstNode getChild(int index) { + index = 0 and result = this.getExpr() + or + result = this.getCase(index - 1) and index >= 1 + } + } + + /** A `case` clause in a match statement. */ + class Case extends Stmt { + private Py::Case caseStmt; + + Case() { this = TPyStmt(caseStmt) } + + AstNode getPattern(int index) { index = 0 and result.asPattern() = caseStmt.getPattern() } + + Expr getGuard() { result.asExpr() = caseStmt.getGuard().(Py::Guard).getTest() } + + AstNode getBody() { result.asStmtList() = caseStmt.getBody() } + + /** Holds if this case is a wildcard pattern (`case _:`). */ + predicate isWildcard() { caseStmt.getPattern() instanceof Py::MatchWildcardPattern } + + override AstNode getChild(int index) { + index = 0 and result = this.getPattern(0) + or + index = 1 and result = this.getGuard() + or + index = 2 and result = this.getBody() + } + } + + /** A wildcard case (`case _:`). */ + class DefaultCase extends Case { + DefaultCase() { this.isWildcard() } + } + + /** A conditional expression (`x if cond else y`). */ + class ConditionalExpr extends Expr { + private Py::IfExp ifExp; + + ConditionalExpr() { this = TPyExpr(ifExp) } + + /** Gets the condition of this expression. */ + Expr getCondition() { result.asExpr() = ifExp.getTest() } + + /** Gets the true branch of this expression. */ + Expr getThen() { result.asExpr() = ifExp.getBody() } + + /** Gets the false branch of this expression. */ + Expr getElse() { result.asExpr() = ifExp.getOrelse() } + + override AstNode getChild(int index) { + index = 0 and result = this.getCondition() + or + index = 1 and result = this.getThen() + or + index = 2 and result = this.getElse() + } + } + + /** + * A binary expression for the shared CFG. In Python, this covers all + * `and`/`or` expression operand pairs. + */ + class BinaryExpr extends Expr, TBoolExprPair { + private Py::BoolExpr be; + private int index; + + BinaryExpr() { this = TBoolExprPair(be, index) } + + /** Gets the underlying Python `BoolExpr`. */ + Py::BoolExpr getBoolExpr() { result = be } + + /** Gets the (zero-based) index of this pair within its `BoolExpr`. */ + int getIndex() { result = index } + + override string toString() { result = be.getOperator() } + + override Py::Location getLocation() { result = be.getValue(index).getLocation() } + + override Callable getEnclosingCallable() { result.asScope() = be.getScope() } + + /** Gets the left operand of this binary expression. */ + Expr getLeftOperand() { result.asExpr() = be.getValue(index) } + + /** Gets the right operand of this binary expression. */ + Expr getRightOperand() { + // Last pair: right operand is the final value. + index = count(be.getAValue()) - 2 and result.asExpr() = be.getValue(index + 1) + or + // Non-last pair: right operand is the next synthetic pair. + index < count(be.getAValue()) - 2 and + exists(BinaryExpr next | + next.getBoolExpr() = be and next.getIndex() = index + 1 and result = next + ) + } + + override AstNode getChild(int childIndex) { + childIndex = 0 and result = this.getLeftOperand() + or + childIndex = 1 and result = this.getRightOperand() + } + } + + /** A short-circuiting logical `and` expression. */ + class LogicalAndExpr extends BinaryExpr { + LogicalAndExpr() { this.getBoolExpr().getOp() instanceof Py::And } + } + + /** A short-circuiting logical `or` expression. */ + class LogicalOrExpr extends BinaryExpr { + LogicalOrExpr() { this.getBoolExpr().getOp() instanceof Py::Or } + } + + /** A null-coalescing expression. Python has no null-coalescing operator. */ + class NullCoalescingExpr extends BinaryExpr { + NullCoalescingExpr() { none() } + } + + /** + * A unary expression. Currently only used for the `not` subclass. + */ + class UnaryExpr extends Expr { + UnaryExpr() { exists(Py::UnaryExpr u | this = TPyExpr(u) and u.getOp() instanceof Py::Not) } + + /** Gets the operand of this unary expression. */ + Expr getOperand() { result.asExpr() = this.asExpr().(Py::UnaryExpr).getOperand() } + + override AstNode getChild(int index) { index = 0 and result = this.getOperand() } + } + + /** A logical `not` expression. */ + class LogicalNotExpr extends UnaryExpr { } + + /** + * An assignment expression. + * + * Empty in Python: `x = y` and `x += y` are statements (`AssignStmt` and + * `AugAssignStmt`), not expressions, and the walrus `x := y` is modeled + * separately as `NamedExpr`. The shared library's `Assignment` extends + * `BinaryExpr`, so it cannot share instances with our `Stmt`-based + * assignment forms. + */ + class Assignment extends BinaryExpr { + Assignment() { none() } + } + + /** A simple assignment expression. Empty in Python (see `Assignment`). */ + class AssignExpr extends Assignment { } + + /** A compound assignment expression. Empty in Python (see `Assignment`). */ + class CompoundAssignment extends Assignment { } + + /** + * A short-circuiting logical AND compound assignment expression (`&&=`). + * Python has no such operator. + */ + class AssignLogicalAndExpr extends CompoundAssignment { } + + /** + * A short-circuiting logical OR compound assignment expression (`||=`). + * Python has no such operator. + */ + class AssignLogicalOrExpr extends CompoundAssignment { } + + /** + * A short-circuiting null-coalescing compound assignment expression + * (`??=`). Python has no such operator. + */ + class AssignNullCoalescingExpr extends CompoundAssignment { } + + /** A boolean literal expression (`True` or `False`). */ + class BooleanLiteral extends Expr { + BooleanLiteral() { this = TPyExpr(any(Py::True t)) or this = TPyExpr(any(Py::False f)) } + + /** Gets the boolean value of this literal. */ + boolean getValue() { + this.asExpr() instanceof Py::True and result = true + or + this.asExpr() instanceof Py::False and result = false + } + } + + /** A pattern match expression. Python has no `instanceof`-style pattern match expression. */ + class PatternMatchExpr extends Expr { + PatternMatchExpr() { none() } + + Expr getExpr() { none() } + + AstNode getPattern() { none() } + } + + // ===== Python-specific expression classes (used by `getChild`) ===== + /** A Python binary expression (arithmetic, bitwise, matmul, etc.). */ + additional class ArithBinaryExpr extends Expr { + private Py::BinaryExpr binExpr; + + ArithBinaryExpr() { this = TPyExpr(binExpr) } + + Expr getLeft() { result.asExpr() = binExpr.getLeft() } + + Expr getRight() { result.asExpr() = binExpr.getRight() } + + override AstNode getChild(int index) { + index = 0 and result = this.getLeft() + or + index = 1 and result = this.getRight() + } + } + + /** A call expression (`func(args...)`). */ + additional class CallExpr extends Expr { + private Py::Call call; + + CallExpr() { this = TPyExpr(call) } + + Expr getFunc() { result.asExpr() = call.getFunc() } + + Expr getPositionalArg(int n) { result.asExpr() = call.getPositionalArg(n) } + + int getNumberOfPositionalArgs() { result = count(call.getAPositionalArg()) } + + Expr getKeywordValue(int n) { + result.asExpr() = call.getNamedArg(n).(Py::Keyword).getValue() + or + result.asExpr() = call.getNamedArg(n).(Py::DictUnpacking).getValue() + } + + int getNumberOfNamedArgs() { result = count(call.getANamedArg()) } + + override AstNode getChild(int index) { + index = 0 and result = this.getFunc() + or + result = this.getPositionalArg(index - 1) and index >= 1 + or + result = this.getKeywordValue(index - 1 - this.getNumberOfPositionalArgs()) and + index >= 1 + this.getNumberOfPositionalArgs() + } + } + + /** A subscript expression (`obj[index]`). */ + additional class SubscriptExpr extends Expr { + private Py::Subscript sub; + + SubscriptExpr() { this = TPyExpr(sub) } + + Expr getObject() { result.asExpr() = sub.getObject() } + + Expr getIndex() { result.asExpr() = sub.getIndex() } + + override AstNode getChild(int index) { + index = 0 and result = this.getObject() + or + index = 1 and result = this.getIndex() + } + } + + /** An attribute access (`obj.name`). */ + additional class AttributeExpr extends Expr { + private Py::Attribute attr; + + AttributeExpr() { this = TPyExpr(attr) } + + Expr getObject() { result.asExpr() = attr.getObject() } + + override AstNode getChild(int index) { index = 0 and result = this.getObject() } + } + + /** + * An `import x.y` module expression. Modelled as a leaf — the dotted + * name is just a string. + */ + additional class ImportExpression extends Expr { + ImportExpression() { this.asExpr() instanceof Py::ImportExpr } + } + + /** + * A `from m import x` member access. The module sub-expression is a + * child so that the CFG visits both the module load and this + * attribute selection. + */ + additional class ImportMemberExpr extends Expr { + private Py::ImportMember im; + + ImportMemberExpr() { this = TPyExpr(im) } + + /** Gets the module expression `m` in `from m import x`. */ + Expr getModule() { result.asExpr() = im.getModule() } + + override AstNode getChild(int index) { index = 0 and result = this.getModule() } + } + + /** A tuple literal. */ + additional class TupleExpr extends Expr { + private Py::Tuple tuple; + + TupleExpr() { this = TPyExpr(tuple) } + + Expr getElt(int n) { result.asExpr() = tuple.getElt(n) } + + override AstNode getChild(int index) { result = this.getElt(index) } + } + + /** A list literal. */ + additional class ListExpr extends Expr { + private Py::List list; + + ListExpr() { this = TPyExpr(list) } + + Expr getElt(int n) { result.asExpr() = list.getElt(n) } + + override AstNode getChild(int index) { result = this.getElt(index) } + } + + /** A set literal. */ + additional class SetExpr extends Expr { + private Py::Set set; + + SetExpr() { this = TPyExpr(set) } + + Expr getElt(int n) { result.asExpr() = set.getElt(n) } + + override AstNode getChild(int index) { result = this.getElt(index) } + } + + /** A dict literal. */ + additional class DictExpr extends Expr { + private Py::Dict dict; + + DictExpr() { this = TPyExpr(dict) } + + /** + * Gets the key of the `n`th item (at child index `2*n`); the value is + * at child index `2*n + 1`. + */ + Expr getKey(int n) { result.asExpr() = dict.getItem(n).(Py::KeyValuePair).getKey() } + + Expr getValue(int n) { result.asExpr() = dict.getItem(n).(Py::KeyValuePair).getValue() } + + int getNumberOfItems() { result = count(dict.getAnItem()) } + + override AstNode getChild(int index) { + exists(int item | + index = 2 * item and result = this.getKey(item) + or + index = 2 * item + 1 and result = this.getValue(item) + ) + } + } + + /** A unary expression other than `not` (e.g., `-x`, `+x`, `~x`). */ + additional class ArithUnaryExpr extends Expr { + private Py::UnaryExpr unaryExpr; + + ArithUnaryExpr() { this = TPyExpr(unaryExpr) and not unaryExpr.getOp() instanceof Py::Not } + + Expr getOperand() { result.asExpr() = unaryExpr.getOperand() } + + override AstNode getChild(int index) { index = 0 and result = this.getOperand() } + } + + /** + * A comprehension or generator expression. The iterable is evaluated in + * the enclosing scope; the body runs in a nested synthetic function + * scope handled by its own CFG. + */ + additional class Comprehension extends Expr { + private Py::Expr iterable; + + Comprehension() { + exists(Py::Expr c | this = TPyExpr(c) | + iterable = c.(Py::ListComp).getIterable() + or + iterable = c.(Py::SetComp).getIterable() + or + iterable = c.(Py::DictComp).getIterable() + or + iterable = c.(Py::GeneratorExp).getIterable() + ) + } + + Expr getIterable() { result.asExpr() = iterable } + + override AstNode getChild(int index) { index = 0 and result = this.getIterable() } + } + + /** A comparison expression (`a < b`, `a < b < c`, etc.). */ + additional class CompareExpr extends Expr { + private Py::Compare cmp; + + CompareExpr() { this = TPyExpr(cmp) } + + Expr getLeft() { result.asExpr() = cmp.getLeft() } + + Expr getComparator(int n) { result.asExpr() = cmp.getComparator(n) } + + override AstNode getChild(int index) { + index = 0 and result = this.getLeft() + or + result = this.getComparator(index - 1) and index >= 1 + } + } + + /** A slice expression (`start:stop:step`). */ + additional class SliceExpr extends Expr { + private Py::Slice slice; + + SliceExpr() { this = TPyExpr(slice) } + + Expr getStart() { result.asExpr() = slice.getStart() } + + Expr getStop() { result.asExpr() = slice.getStop() } + + Expr getStep() { result.asExpr() = slice.getStep() } + + override AstNode getChild(int index) { + index = 0 and result = this.getStart() + or + index = 1 and result = this.getStop() + or + index = 2 and result = this.getStep() + } + } + + /** A starred expression (`*x`). */ + additional class StarredExpr extends Expr { + private Py::Starred starred; + + StarredExpr() { this = TPyExpr(starred) } + + Expr getValue() { result.asExpr() = starred.getValue() } + + override AstNode getChild(int index) { index = 0 and result = this.getValue() } + } + + /** A formatted string literal (`f"...{expr}..."`). */ + additional class FstringExpr extends Expr { + private Py::Fstring fstring; + + FstringExpr() { this = TPyExpr(fstring) } + + Expr getValue(int n) { result.asExpr() = fstring.getValue(n) } + + override AstNode getChild(int index) { result = this.getValue(index) } + } + + /** A formatted value inside an f-string (`{expr}` or `{expr:spec}`). */ + additional class FormattedValueExpr extends Expr { + private Py::FormattedValue fv; + + FormattedValueExpr() { this = TPyExpr(fv) } + + Expr getValue() { result.asExpr() = fv.getValue() } + + Expr getFormatSpec() { result.asExpr() = fv.getFormatSpec() } + + override AstNode getChild(int index) { + index = 0 and result = this.getValue() + or + index = 1 and result = this.getFormatSpec() + } + } + + /** A `yield` expression. */ + additional class YieldExpr extends Expr { + private Py::Yield yield; + + YieldExpr() { this = TPyExpr(yield) } + + Expr getValue() { result.asExpr() = yield.getValue() } + + override AstNode getChild(int index) { index = 0 and result = this.getValue() } + } + + /** A `yield from` expression. */ + additional class YieldFromExpr extends Expr { + private Py::YieldFrom yieldFrom; + + YieldFromExpr() { this = TPyExpr(yieldFrom) } + + Expr getValue() { result.asExpr() = yieldFrom.getValue() } + + override AstNode getChild(int index) { index = 0 and result = this.getValue() } + } + + /** An `await` expression. */ + additional class AwaitExpr extends Expr { + private Py::Await await; + + AwaitExpr() { this = TPyExpr(await) } + + Expr getValue() { result.asExpr() = await.getValue() } + + override AstNode getChild(int index) { index = 0 and result = this.getValue() } + } + + /** + * A class definition expression (visits bases, but NOT PEP 695 type + * parameters — those bind in an annotation scope that nests the class + * body, so they belong to the inner scope's CFG, not the enclosing + * scope's; the legacy CFG also omitted them). + */ + additional class ClassDefExpr extends Expr { + private Py::ClassExpr classExpr; + + ClassDefExpr() { this = TPyExpr(classExpr) } + + Expr getBase(int n) { result.asExpr() = classExpr.getBase(n) } + + override AstNode getChild(int index) { result = this.getBase(index) } + } + + /** + * A function definition expression (visits positional and keyword + * defaults, but NOT PEP 695 type parameters — those bind in an + * annotation scope that nests the function body, so they belong to + * the inner scope's CFG, not the enclosing scope's; the legacy CFG + * also omitted them). + */ + additional class FunctionDefExpr extends Expr { + private Py::FunctionExpr funcExpr; + + FunctionDefExpr() { this = TPyExpr(funcExpr) } + + /** + * Gets the `n`th default for a positional argument, in evaluation + * order. Note that `Args.getDefault(int)` is indexed by argument + * position (with gaps for arguments without defaults), so we must + * renumber here to obtain contiguous indices. + */ + Expr getDefault(int n) { + result.asExpr() = + rank[n + 1](Py::Expr d, int i | d = funcExpr.getArgs().getDefault(i) | d order by i) + } + + /** Gets the `n`th default for a keyword-only argument, in evaluation order. */ + Expr getKwDefault(int n) { + result.asExpr() = + rank[n + 1](Py::Expr d, int i | d = funcExpr.getArgs().getKwDefault(i) | d order by i) + } + + int getNumberOfDefaults() { result = count(funcExpr.getArgs().getADefault()) } + + override AstNode getChild(int index) { + result = this.getDefault(index) + or + result = this.getKwDefault(index - this.getNumberOfDefaults()) + } + } + + /** A lambda expression (has default args evaluated at definition time). */ + additional class LambdaExpr extends Expr { + private Py::Lambda lambda; + + LambdaExpr() { this = TPyExpr(lambda) } + + /** Gets the `n`th default for a positional argument, in evaluation order. */ + Expr getDefault(int n) { + result.asExpr() = + rank[n + 1](Py::Expr d, int i | d = lambda.getArgs().getDefault(i) | d order by i) + } + + /** Gets the `n`th default for a keyword-only argument, in evaluation order. */ + Expr getKwDefault(int n) { + result.asExpr() = + rank[n + 1](Py::Expr d, int i | d = lambda.getArgs().getKwDefault(i) | d order by i) + } + + int getNumberOfDefaults() { result = count(lambda.getArgs().getADefault()) } + + override AstNode getChild(int index) { + result = this.getDefault(index) + or + result = this.getKwDefault(index - this.getNumberOfDefaults()) + } + } + + /** Gets the child of `n` at the specified (zero-based) index. */ + AstNode getChild(AstNode n, int index) { result = n.getChild(index) } +} + +private module Cfg0 = Make0; + +private import Cfg0 + +private module Cfg1 = Make1; + +private import Cfg1 + +private module Cfg2 = Make2; + +private import Cfg2 + +private module Input implements InputSig1, InputSig2 { + predicate cfgCachedStageRef() { CfgCachedStage::ref() } + + private newtype TLabel = TNone() + + class Label extends TLabel { + string toString() { result = "label" } + } + + class CallableContext = Void; + + predicate inConditionalContext(Ast::AstNode n, ConditionKind kind) { + kind.isBoolean() and + n = any(Ast::AssertStmt a).getTest() + } + + private string assertThrowTag() { result = "[assert-throw]" } + + predicate additionalNode(Ast::AstNode n, string tag, NormalSuccessor t) { + n instanceof Ast::AssertStmt and tag = assertThrowTag() and t instanceof DirectSuccessor + } + + predicate beginAbruptCompletion( + Ast::AstNode ast, PreControlFlowNode n, AbruptCompletion c, boolean always + ) { + ast instanceof Ast::AssertStmt and + n.isAdditional(ast, assertThrowTag()) and + c.asSimpleAbruptCompletion() instanceof ExceptionSuccessor and + always = true + } + + predicate endAbruptCompletion(Ast::AstNode ast, PreControlFlowNode n, AbruptCompletion c) { + none() + } + + predicate step(PreControlFlowNode n1, PreControlFlowNode n2) { + exists(Ast::AssertStmt assertStmt | + n1.isBefore(assertStmt) and + n2.isBefore(assertStmt.getTest()) + or + n1.isAfterTrue(assertStmt.getTest()) and + n2.isAfter(assertStmt) + or + n1.isAfterFalse(assertStmt.getTest()) and + ( + n2.isBefore(assertStmt.getMsg()) + or + not exists(assertStmt.getMsg()) and + n2.isAdditional(assertStmt, assertThrowTag()) + ) + or + n1.isAfter(assertStmt.getMsg()) and + n2.isAdditional(assertStmt, assertThrowTag()) + ) + } +} + +import CfgCachedStage +import Public + +/** + * Maps a CFG AST wrapper node to the corresponding Python AST node, if any. + * Entry, exit, and synthetic nodes have no corresponding Python AST node. + */ +Py::AstNode astNodeToPyNode(Ast::AstNode n) { + result = n.asExpr() + or + result = n.asStmt() + or + result = n.asScope() + or + result = n.asPattern() +} diff --git a/python/ql/test/extractor-tests/syntax_error/CONSISTENCY/CfgConsistency.expected b/python/ql/test/extractor-tests/syntax_error/CONSISTENCY/CfgConsistency.expected new file mode 100644 index 000000000000..91a01a3a3d93 --- /dev/null +++ b/python/ql/test/extractor-tests/syntax_error/CONSISTENCY/CfgConsistency.expected @@ -0,0 +1,4 @@ +consistencyOverview +| deadEnd | 1 | +deadEnd +| without_loop.py:7:5:7:9 | Break | diff --git a/python/ql/test/library-tests/ControlFlow/bindings/BindingsTest.expected b/python/ql/test/library-tests/ControlFlow/bindings/BindingsTest.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/ql/test/library-tests/ControlFlow/bindings/BindingsTest.ql b/python/ql/test/library-tests/ControlFlow/bindings/BindingsTest.ql new file mode 100644 index 000000000000..a507878911b1 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/BindingsTest.ql @@ -0,0 +1,32 @@ +/** + * Phase -1 of the dataflow CFG migration: verifies that every variable + * binding visible to the AST (`Name.defines(v)`) corresponds to a CFG node + * in the new CFG (`semmle.python.controlflow.internal.AstNodeImpl`). + * + * The expected tag is `cfgdefines=`. Each binding annotation in the + * test sources looks like `# $ cfgdefines=x` for a binding currently + * covered by the new CFG, or `# $ MISSING: cfgdefines=x` for a binding + * that is known to be uncovered (a "red" test case that should be + * green-flipped once the corresponding `cfg-ext-*` extension lands). + */ + +import python +import semmle.python.controlflow.internal.AstNodeImpl as CfgImpl +import utils.test.InlineExpectationsTest + +module CfgBindingsTest implements TestSig { + string getARelevantTag() { result = "cfgdefines" } + + predicate hasActualResult(Location location, string element, string tag, string value) { + exists(Name n, Variable v, CfgImpl::ControlFlowNode cfg | + n.defines(v) and + cfg.getAstNode().asExpr() = n and + location = n.getLocation() and + element = n.toString() and + tag = "cfgdefines" and + value = v.getId() + ) + } +} + +import MakeTest diff --git a/python/ql/test/library-tests/ControlFlow/bindings/annassign.py b/python/ql/test/library-tests/ControlFlow/bindings/annassign.py new file mode 100644 index 000000000000..7a9ae3ab6c79 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/annassign.py @@ -0,0 +1,13 @@ +# Annotated assignment (PEP 526). Both with and without an initializer. + +a: int = 1 # $ cfgdefines=a +b: str = "hi" # $ cfgdefines=b + +# Annotation without value: the AST records `c` as defined, +# and the new CFG now visits it via the AnnAssignStmt wrapper. +c: int # $ cfgdefines=c + +class K: # $ cfgdefines=K + field: int = 0 # $ cfgdefines=field + + diff --git a/python/ql/test/library-tests/ControlFlow/bindings/compound.py b/python/ql/test/library-tests/ControlFlow/bindings/compound.py new file mode 100644 index 000000000000..cb2f36f12ffe --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/compound.py @@ -0,0 +1,14 @@ +# Compound (tuple/list) assignment targets — actually wired in the new CFG. + +a, b = (1, 2) # $ cfgdefines=a cfgdefines=b +[c, d] = [3, 4] # $ cfgdefines=c cfgdefines=d + +# Nested unpacking. +(e, (f, g)) = (1, (2, 3)) # $ cfgdefines=e cfgdefines=f cfgdefines=g + +# Star unpacking. +h, *i = [1, 2, 3] # $ cfgdefines=h cfgdefines=i + +# Chained assignment with compound target. +j = k, l = (5, 6) # $ cfgdefines=j cfgdefines=k cfgdefines=l + diff --git a/python/ql/test/library-tests/ControlFlow/bindings/comprehension.py b/python/ql/test/library-tests/ControlFlow/bindings/comprehension.py new file mode 100644 index 000000000000..6b5f722c1f7e --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/comprehension.py @@ -0,0 +1,21 @@ +# Comprehension and `for` loop targets — wired in the new CFG. +# Comprehensions are nested function scopes with a synthetic `.0` parameter +# bound to the iterable. + +# Bare-name `for` target. +for i in range(3): # $ cfgdefines=i + pass + +# Compound `for` target. +for k, v in [(1, 2)]: # $ cfgdefines=k cfgdefines=v + pass + +# Comprehension targets. +_ = [x for x in range(3)] # $ cfgdefines=_ cfgdefines=x cfgdefines=.0 +_ = {y: z for y, z in []} # $ cfgdefines=_ cfgdefines=y cfgdefines=z cfgdefines=.0 +_ = (a for a in []) # $ cfgdefines=_ cfgdefines=a cfgdefines=.0 + +# Nested comprehensions. +_ = [b for c in [] for b in c] # $ cfgdefines=_ cfgdefines=c cfgdefines=b cfgdefines=.0 + + diff --git a/python/ql/test/library-tests/ControlFlow/bindings/dead_under_no_raise.py b/python/ql/test/library-tests/ControlFlow/bindings/dead_under_no_raise.py new file mode 100644 index 000000000000..dbfb857b5360 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/dead_under_no_raise.py @@ -0,0 +1,52 @@ +# Dead bindings under the "no expressions raise" CFG abstraction. +# +# The new CFG does not currently model raise edges from arbitrary +# expressions. As a consequence, code that is only reachable through +# exception flow is (correctly) classified as dead and has no CFG node. +# Variable bindings in dead code do not need CFG nodes - SSA / dataflow +# over dead code is moot. +# +# These tests act as a regression guard: the bindings below intentionally +# have no `cfgdefines=` annotations. If raise modelling is later added, +# the BindingsTest infrastructure will surface the new CFG nodes as +# unexpected results, and this file will need to be revisited. + + +def f(obj): # $ cfgdefines=f cfgdefines=obj + try: + return len(obj) + except TypeError: + pass + + # The first try's body always returns; its except handler does not + # raise or otherwise transfer control, so under "no expressions + # raise" the only paths out of the try-statement are dead. Everything + # below is unreachable. + try: + hint = type(obj).__length_hint__ + except AttributeError: + return None + return hint + + +def g(): # $ cfgdefines=g + try: + raise Exception("inner") + except: + raise Exception("outer") + else: + # Unreachable: the inner try body always raises, so the `else:` + # clause never runs. + hit_inner_else = True + + +def h(cache, key): # $ cfgdefines=h cfgdefines=cache cfgdefines=key + try: + return cache[key] + except KeyError: + pass + + # Same pattern as `f`: dead under "no expressions raise". + value = compute(key) + cache[key] = value + return value diff --git a/python/ql/test/library-tests/ControlFlow/bindings/decorated.py b/python/ql/test/library-tests/ControlFlow/bindings/decorated.py new file mode 100644 index 000000000000..9b93c166acec --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/decorated.py @@ -0,0 +1,30 @@ +# Decorated `def`/`class` — wired in the new CFG. + + +def deco(f): # $ cfgdefines=deco cfgdefines=f + return f + + +@deco +def decorated_func(): # $ cfgdefines=decorated_func + pass + + +@deco +class DecoratedClass: # $ cfgdefines=DecoratedClass + pass + + +# Stacked decorators. +@deco +@deco +def doubly(): # $ cfgdefines=doubly + pass + + +# Inside a class body. +class Outer: # $ cfgdefines=Outer + @staticmethod + def inner(): # $ cfgdefines=inner + pass + diff --git a/python/ql/test/library-tests/ControlFlow/bindings/except_handler.py b/python/ql/test/library-tests/ControlFlow/bindings/except_handler.py new file mode 100644 index 000000000000..57b6c99fe9b6 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/except_handler.py @@ -0,0 +1,19 @@ +# Exception-handler name bindings. These are already wired in the new +# CFG provided the try body can raise; `raise` statements are reliably +# treated as exception sources. + +try: + raise ValueError("oops") +except ValueError as e: # $ cfgdefines=e + pass + +try: + raise TypeError("oops") +except (TypeError, KeyError) as err: # $ cfgdefines=err + pass + +# Exception groups (Python 3.11+). +try: + raise ValueError("oops") +except* ValueError as eg: # $ cfgdefines=eg + pass diff --git a/python/ql/test/library-tests/ControlFlow/bindings/imports.py b/python/ql/test/library-tests/ControlFlow/bindings/imports.py new file mode 100644 index 000000000000..c8834b5332a0 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/imports.py @@ -0,0 +1,14 @@ +# Import aliases — all bound names below are now reachable via the new +# CFG's `ImportStmt` wrapper. + +import os # $ cfgdefines=os +import os.path # $ cfgdefines=os +import os as o # $ cfgdefines=o +from os import path # $ cfgdefines=path +from os import path as p # $ cfgdefines=p +from os import sep, linesep # $ cfgdefines=sep cfgdefines=linesep +from os import ( + getcwd, # $ cfgdefines=getcwd + getcwdb, # $ cfgdefines=getcwdb +) + diff --git a/python/ql/test/library-tests/ControlFlow/bindings/match_pattern.py b/python/ql/test/library-tests/ControlFlow/bindings/match_pattern.py new file mode 100644 index 000000000000..0868a2680d0a --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/match_pattern.py @@ -0,0 +1,24 @@ +# Match-statement pattern bindings — wired in the new CFG. + +def f(subject): # $ cfgdefines=f cfgdefines=subject + match subject: + case x: # $ cfgdefines=x + pass + case [a, b]: # $ cfgdefines=a cfgdefines=b + pass + case {"k": v}: # $ cfgdefines=v + pass + case Point(p, q): # $ cfgdefines=p cfgdefines=q + pass + case [_, *rest]: # $ cfgdefines=rest + pass + case (1 | 2) as n: # $ cfgdefines=n + pass + + +class Point: # $ cfgdefines=Point + __match_args__ = ("x", "y") # $ cfgdefines=__match_args__ + x: int # $ cfgdefines=x + y: int # $ cfgdefines=y + + diff --git a/python/ql/test/library-tests/ControlFlow/bindings/parameters.py b/python/ql/test/library-tests/ControlFlow/bindings/parameters.py new file mode 100644 index 000000000000..7fe5e01e4c4b --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/parameters.py @@ -0,0 +1,42 @@ +# Function parameters. + +def positional(a, b): # $ cfgdefines=positional cfgdefines=a cfgdefines=b + pass + + +def with_default(x=1, y=2): # $ cfgdefines=with_default cfgdefines=x cfgdefines=y + pass + + +def with_vararg(*args): # $ cfgdefines=with_vararg cfgdefines=args + pass + + +def with_kwarg(**kwargs): # $ cfgdefines=with_kwarg cfgdefines=kwargs + pass + + +def with_kwonly(*, k1, k2=5): # $ cfgdefines=with_kwonly cfgdefines=k1 cfgdefines=k2 + pass + + +def kitchen_sink(a, b=2, *args, k1, k2=5, **kw): # $ cfgdefines=kitchen_sink cfgdefines=a cfgdefines=b cfgdefines=args cfgdefines=k1 cfgdefines=k2 cfgdefines=kw + pass + + +# Methods get `self` / `cls`. +class C: # $ cfgdefines=C + def method(self, x): # $ cfgdefines=method cfgdefines=self cfgdefines=x + pass + + @classmethod + def cmethod(cls, x): # $ cfgdefines=cmethod cfgdefines=cls cfgdefines=x + pass + + +# Lambda parameter. +_ = lambda p: p + 1 # $ cfgdefines=_ cfgdefines=p + +# PEP 570 positional-only. +def pos_only(a, b, /, c): # $ cfgdefines=pos_only cfgdefines=a cfgdefines=b cfgdefines=c + pass diff --git a/python/ql/test/library-tests/ControlFlow/bindings/simple.py b/python/ql/test/library-tests/ControlFlow/bindings/simple.py new file mode 100644 index 000000000000..51cb7d828c91 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/simple.py @@ -0,0 +1,14 @@ +# Simple bindings that should already work in the new CFG. +# No MISSING annotations expected. + +x = 1 # $ cfgdefines=x +y = x + 1 # $ cfgdefines=y + +def f(): # $ cfgdefines=f + pass + +class C: # $ cfgdefines=C + pass + +# Re-assignment. +x = 2 # $ cfgdefines=x diff --git a/python/ql/test/library-tests/ControlFlow/bindings/type_params.py b/python/ql/test/library-tests/ControlFlow/bindings/type_params.py new file mode 100644 index 000000000000..2bd34dc3f0ee --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/type_params.py @@ -0,0 +1,21 @@ +# PEP 695 type parameters (Python 3.12+). + +# PEP 695 type-param names on `def`/`class` bind in an annotation scope +# that nests the function/class body — they have no CFG node in the +# enclosing scope (matching the legacy CFG). +def func[T](x: T) -> T: # $ cfgdefines=func cfgdefines=x + return x + + +class Box[T]: # $ cfgdefines=Box + item: T # $ cfgdefines=item + + +# Multi-parameter, with bound and variadics. +def multi[T: int, *Ts, **P](x: T, *args: *Ts, **kwargs: P.kwargs) -> T: # $ cfgdefines=multi cfgdefines=x cfgdefines=args cfgdefines=kwargs + return x + + +# `type` statement (PEP 695). +type Alias[T] = list[T] # $ cfgdefines=Alias cfgdefines=T + diff --git a/python/ql/test/library-tests/ControlFlow/bindings/walrus_starred.py b/python/ql/test/library-tests/ControlFlow/bindings/walrus_starred.py new file mode 100644 index 000000000000..5c0c1bd83191 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/walrus_starred.py @@ -0,0 +1,14 @@ +# Walrus and starred-target edge cases — wired in the new CFG. + +# Walrus in expression context. +if (y := 5) > 0: # $ cfgdefines=y + pass + +# Walrus in a comprehension. The comprehension introduces a synthetic +# `.0` parameter bound to the iterable. +_ = [w for _ in range(3) if (w := 1)] # $ cfgdefines=_ cfgdefines=w cfgdefines=.0 + +# Starred target in a Tuple LHS. +*head, tail = [1, 2, 3] # $ cfgdefines=head cfgdefines=tail + + diff --git a/python/ql/test/library-tests/ControlFlow/bindings/with_stmt.py b/python/ql/test/library-tests/ControlFlow/bindings/with_stmt.py new file mode 100644 index 000000000000..5fffe46c5d40 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/with_stmt.py @@ -0,0 +1,21 @@ +# `with cm() as x:` bindings — wired in the new CFG. + +class CM: # $ cfgdefines=CM + def __enter__(self): return self # $ cfgdefines=__enter__ cfgdefines=self + def __exit__(self, *a): pass # $ cfgdefines=__exit__ cfgdefines=self cfgdefines=a + +with CM() as x: # $ cfgdefines=x + pass + +# Multiple items. +with CM() as a, CM() as b: # $ cfgdefines=a cfgdefines=b + pass + +# Parenthesised form (Python 3.10+). +with (CM() as p, CM() as q): # $ cfgdefines=p cfgdefines=q + pass + +# Compound target in `with`. +with CM() as (m, n): # $ cfgdefines=m cfgdefines=n + pass + diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAllLiveReachable.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAllLiveReachable.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAllLiveReachable.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAllLiveReachable.ql new file mode 100644 index 000000000000..75f02d14a9cb --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAllLiveReachable.ql @@ -0,0 +1,14 @@ +/** New-CFG version of AllLiveReachable. */ + +import python +import TimerUtils +import NewCfgImpl + +private module Utils = EvalOrderCfgUtils; + +private import Utils +private import Utils::CfgTests + +from TimerCfgNode a, TestFunction f +where allLiveReachable(a, f) +select a, "Unreachable live annotation; entry of $@ does not reach this node", f, f.getName() diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAnnotationHasCfgNode.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAnnotationHasCfgNode.expected new file mode 100644 index 000000000000..8b137891791f --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAnnotationHasCfgNode.expected @@ -0,0 +1 @@ + diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAnnotationHasCfgNode.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAnnotationHasCfgNode.ql new file mode 100644 index 000000000000..4b1d82e27e67 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAnnotationHasCfgNode.ql @@ -0,0 +1,18 @@ +/** + * New-CFG version of AnnotationHasCfgNode. + * + * Checks that every timer annotation has a corresponding CFG node. + */ + +import python +import TimerUtils +import NewCfgImpl + +private module Utils = EvalOrderCfgUtils; + +private import Utils::CfgTests + +from TimerAnnotation ann +where annotationWithoutCfgNode(ann) +select ann, "Annotation in $@ has no CFG node", ann.getTestFunction(), + ann.getTestFunction().getName() diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockAnnotationGap.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockAnnotationGap.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockAnnotationGap.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockAnnotationGap.ql new file mode 100644 index 000000000000..80dd759a3651 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockAnnotationGap.ql @@ -0,0 +1,26 @@ +/** + * New-CFG version of BasicBlockAnnotationGap. + * + * Original: + * Checks that within a basic block, if a node is annotated then its + * successor is also annotated (or excluded). A gap in annotations + * within a basic block indicates a missing annotation, since there + * are no branches to justify the gap. + * + * Nodes with exceptional successors are excluded, as the exception + * edge leaves the basic block and the normal successor may be dead. + */ + +import python +import TimerUtils +import NewCfgImpl + +private module Utils = EvalOrderCfgUtils; + +private import Utils +private import Utils::CfgTests + +from TimerCfgNode a, CfgNode succ +where basicBlockAnnotationGap(a, succ) +select a, "Annotated node followed by unannotated $@ in the same basic block", succ, + succ.getNode().toString() diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockOrdering.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockOrdering.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockOrdering.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockOrdering.ql new file mode 100644 index 000000000000..f06d08d937e3 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockOrdering.ql @@ -0,0 +1,21 @@ +/** + * New-CFG version of BasicBlockOrdering. + * + * Original: + * Checks that within a single basic block, annotations appear in + * increasing minimum-timestamp order. + */ + +import python +import TimerUtils +import NewCfgImpl + +private module Utils = EvalOrderCfgUtils; + +private import Utils +private import Utils::CfgTests + +from TimerCfgNode a, TimerCfgNode b, int minA, int minB +where basicBlockOrdering(a, b, minA, minB) +select a, "Basic block ordering: $@ appears before $@", a.getTimestampExpr(minA), + "timestamp " + minA, b.getTimestampExpr(minB), "timestamp " + minB diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBranchTimestamps.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBranchTimestamps.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBranchTimestamps.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBranchTimestamps.ql new file mode 100644 index 000000000000..cfd8ffb4e4bd --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBranchTimestamps.ql @@ -0,0 +1,80 @@ +/** + * New-CFG version of BranchTimestamps. + * + * Checks that when a node has both a true and false successor, the + * live timestamps on one branch are marked as dead on the other. + * This ensures that boolean branches are fully annotated with dead() + * markers for the paths not taken. + * + * Limitation: the `@ t[ts, ...]` / `dead(ts)` annotation scheme can only + * model branch-dead-ness for plain boolean control flow that reconverges + * linearly after the split — i.e. `if`-with-else and `if`-expression. + * It cannot model: + * + * * loops (`while` / `for`): body timestamps repeat across iterations, + * so the loop-exit annotation can't list them as dead; + * * `match` statements: each `case` body is a syntactically distinct + * sub-tree, and the branches don't reconverge through a common + * annotation point in the timeline; + * * `try` / `with` and `raise` / `assert`: exception edges are modelled + * as true/false but flow to syntactically distinct handlers, with no + * reconvergence in the linear annotation order; + * * short-circuit `and` / `or` (`BoolExpr`): the branches reconverge at + * the BoolExpr's after-node, so timestamps on one branch are live + * downstream of the other rather than dead; + * * `if` without an `else` clause, and `if`/`elif` chains: the false + * branch reconverges with the true branch at the post-if statement + * (no-else) or fans out across multiple elif-test annotations, + * neither of which fit the binary annotation scheme. + * + * Branch nodes inside those constructs are therefore whitelisted out + * below. The check still fires (and is useful) for plain `if`/`else` + * and conditional-expression branching. + */ + +import python +import TimerUtils +import NewCfgImpl + +private module Utils = EvalOrderCfgUtils; + +private import Utils +private import Utils::CfgTests + +/** + * Holds if `f` contains a construct whose branches the linear-timestamp + * annotation scheme cannot describe (see file-level comment). + */ +private predicate hasUnmodellableBranching(Function f) { + exists(AstNode bad | + bad.getScope() = f and + ( + bad instanceof While + or + bad instanceof For + or + bad instanceof MatchStmt + or + bad instanceof Try + or + bad instanceof With + or + bad instanceof Raise + or + bad instanceof Assert + or + bad instanceof BoolExpr + or + bad instanceof If and + (not exists(bad.(If).getAnOrelse()) or bad.(If).isElif()) + ) + ) +} + +from TimerCfgNode node, int ts, string branch +where + missingBranchTimestamp(node, ts, branch) and + not hasUnmodellableBranching(node.getTestFunction()) +select node, + "Timestamp " + ts + " on true/false branch is missing a dead() annotation on the " + branch + + " successor in $@", node.getTestFunction(), node.getTestFunction().getName() diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutivePredecessorTimestamps.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutivePredecessorTimestamps.expected new file mode 100644 index 000000000000..8b137891791f --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutivePredecessorTimestamps.expected @@ -0,0 +1 @@ + diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutivePredecessorTimestamps.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutivePredecessorTimestamps.ql new file mode 100644 index 000000000000..3feacae264e5 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutivePredecessorTimestamps.ql @@ -0,0 +1,22 @@ +/** + * New-CFG version of ConsecutivePredecessorTimestamps. + * + * Checks that each annotated node (except the minimum timestamp) has + * a predecessor annotation with timestamp `a - 1`. This is the reverse + * of ConsecutiveTimestamps: it catches nodes that are reachable but + * arrived at from the wrong place (skipping an intermediate node). + */ + +import python +import TimerUtils +import NewCfgImpl + +private module Utils = EvalOrderCfgUtils; + +private import Utils +private import Utils::CfgTests + +from TimerAnnotation ann, int a +where consecutivePredecessorTimestamps(ann, a) +select ann, "$@ in $@ has no consecutive predecessor (expected " + (a - 1) + ")", + ann.getTimestampExpr(a), "Timestamp " + a, ann.getTestFunction(), ann.getTestFunction().getName() diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutiveTimestamps.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutiveTimestamps.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutiveTimestamps.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutiveTimestamps.ql new file mode 100644 index 000000000000..8e52663d6eaf --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutiveTimestamps.ql @@ -0,0 +1,29 @@ +/** + * New-CFG version of ConsecutiveTimestamps. + * + * Original: + * Checks that consecutive annotated nodes have consecutive timestamps: + * for each annotation with timestamp `a`, some CFG node for that annotation + * must have a next annotation containing `a + 1`. + * + * Handles CFG splitting (e.g., finally blocks duplicated for normal/exceptional + * flow) by checking that at least one split has the required successor. + * + * Only applies to functions where all annotations are in the function's + * own scope (excludes tests with generators, async, comprehensions, or + * lambdas that have annotations in nested scopes). + */ + +import python +import TimerUtils +import NewCfgImpl + +private module Utils = EvalOrderCfgUtils; + +private import Utils +private import Utils::CfgTests + +from TimerAnnotation ann, int a +where consecutiveTimestamps(ann, a) +select ann, "$@ in $@ has no consecutive successor (expected " + (a + 1) + ")", + ann.getTimestampExpr(a), "Timestamp " + a, ann.getTestFunction(), ann.getTestFunction().getName() diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgImpl.qll b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgImpl.qll new file mode 100644 index 000000000000..cbecb2da19d9 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgImpl.qll @@ -0,0 +1,120 @@ +/** + * Implementation of the evaluation-order CFG signature using the new + * shared control flow graph from AstNodeImpl. + */ + +private import python as Py +import TimerUtils +private import semmle.python.controlflow.internal.AstNodeImpl as CfgImpl +private import codeql.controlflow.SuccessorType + +private class NewControlFlowNode = CfgImpl::ControlFlowNode; + +private class NewBasicBlock = CfgImpl::BasicBlock; + +/** New (shared) CFG implementation of the evaluation-order signature. */ +module NewCfg implements EvalOrderCfgSig { + class CfgNode instanceof NewControlFlowNode { + // We must pick a *unique* representative CFG node for each AST node. The + // shared CFG has several nodes per AST node (before / in-post-order / after + // / after-value splits), but the timer test framework keys annotations on + // `getNode()` and assumes one CFG node per annotated AST node. Without a + // filter, an annotated `f()` would map to both `f()` and `After f()`, which + // breaks two framework invariants: (1) the "no shared reachable" check + // requires that two distinct nodes sharing a timestamp be mutually + // unreachable (true/false branches of a condition), but `Before f()`, + // `f()` and `After f()` share the annotation's timestamp *and* lie on one + // linear path; and (2) the annotation walk (`nextTimerAnnotation`) halts at + // the first reachable representative, so a second node for the same AST + // node would stall the walk on the same timestamp instead of advancing to + // the next evaluation event. + // + // We use the "after" node (`isAfter`) rather than the canonical `injects` + // node, because `injects` represents short-circuit / conditional + // expressions (`and`/`or`/`not`/ternary) by their *before* node, placing + // them ahead of their operands — wrong for evaluation order. `isAfter` + // instead picks the post-evaluation node: the merged before/after node for + // simple leaves, the `TAfterNode` for post-order expressions, and the + // `AfterValueNode`(s) for pre-order conditionals, all positioned after the + // operands. The two value-split nodes of a conditional are genuinely + // distinct evaluation outcomes (handled by `getATrueSuccessor` / + // `getAFalseSuccessor`), so they do not violate the uniqueness assumption. + CfgNode() { NewControlFlowNode.super.isAfter(_) } + + string toString() { result = NewControlFlowNode.super.toString() } + + Py::Location getLocation() { result = NewControlFlowNode.super.getLocation() } + + Py::AstNode getNode() { + result = CfgImpl::astNodeToPyNode(NewControlFlowNode.super.getAstNode()) + } + + CfgNode getASuccessor() { nextCfgNode(this, result) } + + CfgNode getATrueSuccessor() { + NewControlFlowNode.super.isAfterTrue(_) and + // Only where there's also a false branch (true boolean split) + exists(NewControlFlowNode other | other.isAfterFalse(NewControlFlowNode.super.getAstNode())) and + nextCfgNodeFrom(this, result) + } + + CfgNode getAFalseSuccessor() { + NewControlFlowNode.super.isAfterFalse(_) and + // Only where there's also a true branch (true boolean split) + exists(NewControlFlowNode other | other.isAfterTrue(NewControlFlowNode.super.getAstNode())) and + nextCfgNodeFrom(this, result) + } + + CfgNode getAnExceptionalSuccessor() { + exists(NewControlFlowNode mid | + mid = NewControlFlowNode.super.getAnExceptionSuccessor() and + nextCfgNodeFrom(mid, result) + ) + } + + Py::Scope getScope() { result = NewControlFlowNode.super.getEnclosingCallable().asScope() } + + BasicBlock getBasicBlock() { + exists(NewBasicBlock bb, int i | bb.getNode(i) = this and result = bb) + } + } + + /** + * Holds if `next` is the nearest CfgNode reachable from `n` via + * one or more raw CFG successor edges, skipping non-CfgNode intermediaries. + */ + private predicate nextCfgNodeFrom(NewControlFlowNode n, CfgNode next) { + next = n.getASuccessor() + or + exists(NewControlFlowNode mid | + mid = n.getASuccessor() and + not mid instanceof CfgNode and + nextCfgNodeFrom(mid, next) + ) + } + + /** + * Holds if `next` is the nearest CfgNode successor of `n`, + * skipping synthetic intermediate nodes. + */ + private predicate nextCfgNode(CfgNode n, CfgNode next) { nextCfgNodeFrom(n, next) } + + class BasicBlock instanceof NewBasicBlock { + string toString() { result = NewBasicBlock.super.toString() } + + CfgNode getNode(int n) { result = NewBasicBlock.super.getNode(n) } + + predicate reaches(BasicBlock bb) { this = bb or this.strictlyReaches(bb) } + + predicate strictlyReaches(BasicBlock bb) { NewBasicBlock.super.getASuccessor+() = bb } + + predicate strictlyDominates(BasicBlock bb) { NewBasicBlock.super.strictlyDominates(bb) } + } + + CfgNode scopeGetEntryNode(Py::Scope s) { + exists(CfgImpl::ControlFlow::EntryNode entry | + entry.getEnclosingCallable().asScope() = s and + nextCfgNodeFrom(entry, result) + ) + } +} diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNeverReachable.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNeverReachable.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNeverReachable.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNeverReachable.ql new file mode 100644 index 000000000000..6949b2cc6e9b --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNeverReachable.ql @@ -0,0 +1,21 @@ +/** + * New-CFG version of NeverReachable. + * + * Original: + * Checks that expressions annotated with `t.never` either have no CFG + * node, or if they do, that the node is not reachable from its scope's + * entry (including within the same basic block). + */ + +import python +import TimerUtils +import NewCfgImpl + +private module Utils = EvalOrderCfgUtils; + +private import Utils::CfgTests + +from TimerAnnotation ann +where neverReachable(ann) +select ann, "Node annotated with t.never is reachable in $@", ann.getTestFunction(), + ann.getTestFunction().getName() diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBackwardFlow.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBackwardFlow.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBackwardFlow.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBackwardFlow.ql new file mode 100644 index 000000000000..442ca5f5456c --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBackwardFlow.ql @@ -0,0 +1,22 @@ +/** + * New-CFG version of NoBackwardFlow. + * + * Original: + * Checks that time never flows backward between consecutive timer annotations + * in the CFG. For each pair of consecutive annotated nodes (A -> B), there must + * exist timestamps a in A and b in B with a < b. + */ + +import python +import TimerUtils +import NewCfgImpl + +private module Utils = EvalOrderCfgUtils; + +private import Utils +private import Utils::CfgTests + +from TimerCfgNode a, TimerCfgNode b, int minA, int maxB +where noBackwardFlow(a, b, minA, maxB) +select a, "Backward flow: $@ flows to $@ (max timestamp $@)", a.getTimestampExpr(minA), + minA.toString(), b, b.getNode().toString(), b.getTimestampExpr(maxB), maxB.toString() diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBasicBlock.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBasicBlock.expected new file mode 100644 index 000000000000..8b137891791f --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBasicBlock.expected @@ -0,0 +1 @@ + diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBasicBlock.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBasicBlock.ql new file mode 100644 index 000000000000..e07890f72502 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBasicBlock.ql @@ -0,0 +1,18 @@ +/** + * New-CFG version of NoBasicBlock. + * + * Checks that every annotated CFG node belongs to a basic block. + */ + +import python +import TimerUtils +import NewCfgImpl + +private module Utils = EvalOrderCfgUtils; + +private import Utils +private import Utils::CfgTests + +from CfgNode n, TestFunction f +where noBasicBlock(n, f) +select n, "CFG node in $@ does not belong to any basic block", f, f.getName() diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoSharedReachable.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoSharedReachable.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoSharedReachable.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoSharedReachable.ql new file mode 100644 index 000000000000..5a1a1aba2a7a --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoSharedReachable.ql @@ -0,0 +1,21 @@ +/** + * New-CFG version of NoSharedReachable. + * + * Original: + * Checks that two annotations sharing a timestamp value are on + * mutually exclusive CFG paths (neither can reach the other). + */ + +import python +import TimerUtils +import NewCfgImpl + +private module Utils = EvalOrderCfgUtils; + +private import Utils +private import Utils::CfgTests + +from TimerCfgNode a, TimerCfgNode b, int ts +where noSharedReachable(a, b, ts) +select a, "Shared timestamp $@ but this node reaches $@", a.getTimestampExpr(ts), ts.toString(), b, + b.getNode().toString() diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgStrictForward.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgStrictForward.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgStrictForward.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgStrictForward.ql new file mode 100644 index 000000000000..ebbc60346db0 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgStrictForward.ql @@ -0,0 +1,22 @@ +/** + * New-CFG version of StrictForward. + * + * Original: + * Stronger version of NoBackwardFlow: for consecutive annotated nodes + * A -> B that both have a single timestamp (non-loop code) and B does + * NOT dominate A (forward edge), requires max(A) < min(B). + */ + +import python +import TimerUtils +import NewCfgImpl + +private module Utils = EvalOrderCfgUtils; + +private import Utils +private import Utils::CfgTests + +from TimerCfgNode a, TimerCfgNode b, int maxA, int minB +where strictForward(a, b, maxA, minB) +select a, "Strict forward violation: $@ flows to $@", a.getTimestampExpr(maxA), "timestamp " + maxA, + b.getTimestampExpr(minB), "timestamp " + minB diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/OldCfgImpl.qll b/python/ql/test/library-tests/ControlFlow/evaluation-order/OldCfgImpl.qll index cb7bbb495b87..fc52c8dd3ed1 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/OldCfgImpl.qll +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/OldCfgImpl.qll @@ -3,14 +3,14 @@ * Python control flow graph. */ -private import python as PY +private import python as Py import TimerUtils /** Existing Python CFG implementation of the evaluation-order signature. */ module OldCfg implements EvalOrderCfgSig { - class CfgNode = PY::ControlFlowNode; + class CfgNode = Py::ControlFlowNode; - class BasicBlock = PY::BasicBlock; + class BasicBlock = Py::BasicBlock; - CfgNode scopeGetEntryNode(PY::Scope s) { result = s.getEntryNode() } + CfgNode scopeGetEntryNode(Py::Scope s) { result = s.getEntryNode() } } diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/test_if.py b/python/ql/test/library-tests/ControlFlow/evaluation-order/test_if.py index 8880aaaef348..a6eb6c7d5cac 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/test_if.py +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/test_if.py @@ -85,7 +85,7 @@ def test_nested_if_else(t): else: z = 2 @ t[dead(4)] else: - z = 3 @ t[dead(4)] + z = 3 @ t[dead(3), dead(4)] w = 0 @ t[5] From fbfbbd342a0120beb0db6e4280f3d2e7d624df4f Mon Sep 17 00:00:00 2001 From: yoff Date: Tue, 2 Jun 2026 14:09:28 +0000 Subject: [PATCH 002/188] Python: add new shared-CFG-backed control flow graph facade (Cfg) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds the public facade on top of the AstNodeImpl adapter from the previous commit. Re-exposes the same API surface as semmle/python/Flow.qll (ControlFlowNode, CallNode, BasicBlock, NameNode, DefinitionNode, CompareNode, ...), backed by the shared codeql.controlflow.ControlFlowGraph library. - semmle.python.controlflow.internal.Cfg — public facade. - ControlFlow/store-load/* — basic store/load coverage via the facade. The new CFG library is added additively: it has zero callers in lib/ and src/, and the legacy CFG in semmle/python/Flow.qll remains the default. Dataflow, SSA, and production query migration land in follow-up PRs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../change-notes/2026-05-19-add-shared-cfg.md | 4 + .../python/controlflow/internal/Cfg.qll | 1025 +++++++++++++++++ .../store-load/StoreLoadTest.expected | 0 .../ControlFlow/store-load/StoreLoadTest.ql | 41 + .../ControlFlow/store-load/test.py | 56 + 5 files changed, 1126 insertions(+) create mode 100644 python/ql/lib/change-notes/2026-05-19-add-shared-cfg.md create mode 100644 python/ql/lib/semmle/python/controlflow/internal/Cfg.qll create mode 100644 python/ql/test/library-tests/ControlFlow/store-load/StoreLoadTest.expected create mode 100644 python/ql/test/library-tests/ControlFlow/store-load/StoreLoadTest.ql create mode 100644 python/ql/test/library-tests/ControlFlow/store-load/test.py diff --git a/python/ql/lib/change-notes/2026-05-19-add-shared-cfg.md b/python/ql/lib/change-notes/2026-05-19-add-shared-cfg.md new file mode 100644 index 000000000000..913f95320d87 --- /dev/null +++ b/python/ql/lib/change-notes/2026-05-19-add-shared-cfg.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* A new Python control flow graph implementation has been added under `semmle.python.controlflow.internal.Cfg` (backed by `AstNodeImpl.qll`), built on the shared `codeql.controlflow.ControlFlowGraph` library. It is not yet used by the dataflow library or any production query; the legacy CFG in `semmle/python/Flow.qll` remains the default. The new library is exposed for tests and for upcoming migrations. diff --git a/python/ql/lib/semmle/python/controlflow/internal/Cfg.qll b/python/ql/lib/semmle/python/controlflow/internal/Cfg.qll new file mode 100644 index 000000000000..2d39ae8450ed --- /dev/null +++ b/python/ql/lib/semmle/python/controlflow/internal/Cfg.qll @@ -0,0 +1,1025 @@ +/** + * Provides a Python control flow graph facade backed by the shared + * `codeql.controlflow.ControlFlowGraph` library (via `AstNodeImpl.qll`). + * + * This module re-exposes the same API surface as `semmle/python/Flow.qll` + * (the legacy CFG), but is implemented on the new shared CFG. It is + * intended as a drop-in replacement for use by the Python dataflow library + * and other downstream code. + * + * Layering follows the Java pattern (`java/ql/lib/semmle/code/java/Expr.qll` + * and `SsaImpl.qll`): variable identity and similar AST-level semantics + * live on the Python AST classes (`Name.defines(v)`, `Name.uses(v)`, ...); + * the CFG layer is purely positional, with `toAst` / `getNode` bridging + * back to the AST. The shared SSA library can then be parameterized on + * (`BasicBlock`, `int`) directly, with no CFG-level variable predicates. + */ +overlay[local?] +module; + +private import python as Py +private import semmle.python.controlflow.internal.AstNodeImpl as CfgImpl +private import codeql.controlflow.SuccessorType +private import codeql.controlflow.BasicBlock as BB + +/** + * A nested sub-module that explicitly implements `BB::CfgSig`, so this + * `Cfg` facade can be passed to parameterised shared modules such as + * `codeql.dataflow.VariableCapture::Flow`. The sub-module + * exposes the *raw* shared-CFG types from `AstNodeImpl.qll` (where the + * signature is satisfied natively), not the facade's wrapped types. + */ +module CfgForBb implements BB::CfgSig { + class ControlFlowNode = CfgImpl::ControlFlowNode; + + class BasicBlock = CfgImpl::BasicBlock; + + class EntryBasicBlock = CfgImpl::Cfg::EntryBasicBlock; + + predicate dominatingEdge = CfgImpl::Cfg::dominatingEdge/2; +} + +/** + * Gets the Python AST node corresponding to CFG node `n`, if any. + * + * Multiple CFG nodes may map to the same AST node (e.g. `TBeforeNode(Call)` + * and `TAstNode(Call)` both map to `Py::Call`). This is a pure translation; + * uniqueness constraints are enforced at the dataflow layer where needed. + */ +private Py::AstNode toAst(CfgImpl::ControlFlowNode n) { + result = CfgImpl::astNodeToPyNode(n.getAstNode()) +} + +/** + * A control flow node. + * + * This is the full set of CFG nodes from the shared library — it includes + * before-nodes, in-order/post-order nodes, after-value-split nodes, and + * entry/exit nodes. This enables full control-flow-level reasoning and + * compatibility with the shared control-flow reachability library. + * + * AST-level semantics (`getNode()`, `isLoad()`, typed wrappers, etc.) + * are available only on the `injects` (canonical) node for each AST node. + * Non-injects nodes are purely positional CFG nodes with no AST mapping. + */ +class ControlFlowNode extends CfgImpl::ControlFlowNode { + /** Gets the syntactic element corresponding to this flow node, if any. */ + Py::AstNode getNode() { result = toAst(this) } + + /** Gets a predecessor of this flow node. */ + ControlFlowNode getAPredecessor() { this = result.getASuccessor() } + + /** Gets a successor of this flow node. */ + ControlFlowNode getASuccessor() { result = super.getASuccessor() } + + /** Gets a successor for this node if the relevant condition is True. */ + ControlFlowNode getATrueSuccessor() { + result = super.getASuccessor(any(BooleanSuccessor t | t.getValue() = true)) + } + + /** Gets a successor for this node if the relevant condition is False. */ + ControlFlowNode getAFalseSuccessor() { + result = super.getASuccessor(any(BooleanSuccessor t | t.getValue() = false)) + } + + /** Gets a successor for this node if an exception is raised. */ + ControlFlowNode getAnExceptionalSuccessor() { result = super.getAnExceptionSuccessor() } + + /** Gets a successor for this node if no exception is raised. */ + ControlFlowNode getANormalSuccessor() { result = super.getANormalSuccessor() } + + /** Gets the basic block containing this flow node. */ + BasicBlock getBasicBlock() { result = super.getBasicBlock() } + + /** Gets the scope containing this flow node. */ + Py::Scope getScope() { result = super.getEnclosingCallable().asScope() } + + /** Gets the enclosing module. */ + Py::Module getEnclosingModule() { result = this.getScope().getEnclosingModule() } + + /** Gets the immediate dominator of this flow node. */ + ControlFlowNode getImmediateDominator() { + // Defined positionally via the basic-block dominance tree. + exists(BasicBlock bb, int i | bb.getNode(i) = this | + // Predecessor within the same basic block. + i > 0 and result = bb.getNode(i - 1) + or + // First node of `bb`: dominator is the last node of the immediate dominator block. + i = 0 and result = bb.getImmediateDominator().getLastNode() + ) + } + + /** Holds if this strictly dominates `other`. */ + pragma[inline] + predicate strictlyDominates(ControlFlowNode other) { super.strictlyDominates(other) } + + /** Holds if this dominates `other` (reflexively). */ + pragma[inline] + predicate dominates(ControlFlowNode other) { super.dominates(other) } + + /** Holds if this is the first node in its enclosing scope. */ + predicate isEntryNode() { this instanceof CfgImpl::ControlFlow::EntryNode } + + /** Holds if this is the first node of a module. */ + predicate isModuleEntry() { + this.isEntryNode() and super.getAstNode().asScope() instanceof Py::Module + } + + /** Holds if this node may exit its scope by raising an exception. */ + predicate isExceptionalExit(Py::Scope s) { + this instanceof CfgImpl::ControlFlow::ExceptionalExitNode and + super.getEnclosingCallable().asScope() = s + } + + /** Holds if this node is a normal (non-exceptional) exit. */ + predicate isNormalExit() { this instanceof CfgImpl::ControlFlow::NormalExitNode } + + // ===== AST-shape predicates (bridges to the wrapped Python AST) ===== + /** + * Holds if this flow node is a load (including those in augmented + * assignments). + * + * Note: an augmented-assignment target (`x[i]` in `x[i] += 1`) is + * both a load and a store — `isLoad` and `isStore` both hold on the + * canonical CFG node. This mirrors Java's `VarAccess.isVarRead`, + * which holds on the destination of compound and unary assignments + * even though the destination is also a write. + */ + predicate isLoad() { exists(Py::Expr e | e = toAst(this) | py_expr_contexts(_, 3, e)) } + + /** Holds if this flow node is a store (including those in augmented assignments). */ + predicate isStore() { + exists(Py::Expr e | e = toAst(this) | py_expr_contexts(_, 5, e) or augstore(_, this)) + } + + /** Holds if this flow node is a delete. */ + predicate isDelete() { exists(Py::Expr e | e = toAst(this) | py_expr_contexts(_, 2, e)) } + + /** Holds if this flow node is a parameter. */ + predicate isParameter() { exists(Py::Expr e | e = toAst(this) | py_expr_contexts(_, 4, e)) } + + /** Holds if this flow node is a store in an augmented assignment. */ + predicate isAugStore() { augstore(_, this) } + + /** Holds if this flow node is a load in an augmented assignment. */ + predicate isAugLoad() { augstore(this, _) } + + /** Holds if this flow node corresponds to a literal. */ + predicate isLiteral() { + toAst(this) instanceof Py::Bytes or + toAst(this) instanceof Py::Dict or + toAst(this) instanceof Py::DictComp or + toAst(this) instanceof Py::Set or + toAst(this) instanceof Py::SetComp or + toAst(this) instanceof Py::Ellipsis or + toAst(this) instanceof Py::GeneratorExp or + toAst(this) instanceof Py::Lambda or + toAst(this) instanceof Py::ListComp or + toAst(this) instanceof Py::List or + toAst(this) instanceof Py::Num or + toAst(this) instanceof Py::Tuple or + toAst(this) instanceof Py::Unicode or + toAst(this) instanceof Py::NameConstant + } + + /** Holds if this flow node corresponds to an attribute expression. */ + predicate isAttribute() { toAst(this) instanceof Py::Attribute } + + /** Holds if this flow node corresponds to a subscript expression. */ + predicate isSubscript() { toAst(this) instanceof Py::Subscript } + + /** Holds if this flow node corresponds to an import member. */ + predicate isImportMember() { toAst(this) instanceof Py::ImportMember } + + /** Holds if this flow node corresponds to a call. */ + predicate isCall() { toAst(this) instanceof Py::Call } + + /** Holds if this flow node corresponds to an import. */ + predicate isImport() { toAst(this) instanceof Py::ImportExpr } + + /** Holds if this flow node corresponds to a conditional expression. */ + predicate isIfExp() { toAst(this) instanceof Py::IfExp } + + /** Holds if this flow node corresponds to a function definition expression. */ + predicate isFunction() { toAst(this) instanceof Py::FunctionExpr } + + /** Holds if this flow node corresponds to a class definition expression. */ + predicate isClass() { toAst(this) instanceof Py::ClassExpr } + + /** + * Holds if this flow node is a branch (i.e. has both a true and a + * false successor). + */ + predicate isBranch() { exists(this.getATrueSuccessor()) or exists(this.getAFalseSuccessor()) } + + /** + * Gets a CFG child of this node, defined as a CFG node whose AST node + * is a child of this CFG node's AST node, restricted to nodes that + * dominate this one (so the child has been evaluated by the time we + * reach this node). + * + * Mirrors `Flow.qll`'s `getAChild`. UnaryExprNode is excluded because + * its operand is its CFG predecessor (handled separately). + */ + pragma[nomagic] + ControlFlowNode getAChild() { + toAst(this).(Py::Expr).getAChildNode() = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) and + not this instanceof UnaryExprNode + } + + /** Holds if this flow node strictly reaches `other`. */ + predicate strictlyReaches(ControlFlowNode other) { this.getASuccessor+() = other } +} + +/** + * Holds if `load` is the load half of an augmented-assignment target, + * and `store` is the corresponding store half. + * + * In the legacy CFG (`Flow.qll`) the same Python `Name` had two + * distinct CFG nodes — a load node (context 3) earlier in the BB, and + * a store node (context 5) later. The legacy `augstore` related the + * pair via dominance. + * + * In the new (shared) CFG, the canonical node for an AST expression is + * unique, so `load` and `store` collapse onto the same CFG node. The + * predicate is therefore reflexive on the augmented-assignment + * target's canonical node. + */ +private predicate augstore(ControlFlowNode load, ControlFlowNode store) { + exists(Py::AugAssign aa | aa.getTarget() = toAst(load)) and + load = store +} + +/** + * A basic block — a maximal-length sequence of control flow nodes such + * that no node except the first has a predecessor outside the sequence, + * and no node except the last has a successor outside the sequence. + */ +class BasicBlock extends CfgImpl::BasicBlock { + /** Gets the `n`th node in this basic block. */ + ControlFlowNode getNode(int n) { result = super.getNode(n) } + + /** Gets a node in this basic block. */ + ControlFlowNode getANode() { result = super.getNode(_) } + + /** Gets the first node in this basic block. */ + ControlFlowNode firstNode() { result = this.getNode(0) } + + /** Gets the last node in this basic block. */ + ControlFlowNode getLastNode() { result = super.getLastNode() } + + /** Holds if this basic block contains `node`. */ + predicate contains(ControlFlowNode node) { node = this.getANode() } + + // Inherited from the shared library's `BasicBlock`: + // getASuccessor(), getASuccessor(SuccessorType), getAPredecessor(), + // strictlyDominates(), dominates(), getImmediateDominator(), + // length(), inLoop(). + // We shadow `getNode(int)` etc. to return `ControlFlowNode` (this + // facade's type) and add Python-style helpers below. + /** Gets a true successor to this basic block. */ + BasicBlock getATrueSuccessor() { + result = super.getASuccessor(any(BooleanSuccessor t | t.getValue() = true)) + } + + /** Gets a false successor to this basic block. */ + BasicBlock getAFalseSuccessor() { + result = super.getASuccessor(any(BooleanSuccessor t | t.getValue() = false)) + } + + /** Gets an unconditional successor to this basic block. */ + BasicBlock getAnUnconditionalSuccessor() { + result = super.getASuccessor() and + not result = this.getATrueSuccessor() and + not result = this.getAFalseSuccessor() + } + + /** Gets an exceptional successor to this basic block. */ + BasicBlock getAnExceptionalSuccessor() { result = super.getASuccessor(any(ExceptionSuccessor t)) } + + /** + * Holds if this basic block is in the dominance frontier of `df`. + * + * Note: implemented locally rather than via the shared lib, which + * doesn't currently expose a `dominanceFrontier` predicate at this + * level. + */ + predicate inDominanceFrontier(BasicBlock df) { + this = df.getAPredecessor() and not this = df.getImmediateDominator() + or + exists(BasicBlock prev | prev.inDominanceFrontier(df) | + this = prev.getImmediateDominator() and + not this = df.getImmediateDominator() + ) + } + + /** Holds if this basic block strictly reaches `other`. */ + predicate strictlyReaches(BasicBlock other) { super.getASuccessor+() = other } + + /** Holds if this basic block reaches `other` (reflexively). */ + predicate reaches(BasicBlock other) { this = other or this.strictlyReaches(other) } + + /** Holds if flow from this basic block reaches a normal exit from its scope. */ + predicate reachesExit() { + this.getANode() instanceof CfgImpl::ControlFlow::NormalExitNode + or + exists(BasicBlock succ | succ = super.getASuccessor() and succ.reachesExit()) + } + + /** Gets the scope of this basic block. */ + Py::Scope getScope() { exists(ControlFlowNode n | n = this.getANode() | result = n.getScope()) } + + /** Holds if flow from this BasicBlock always reaches `succ`. */ + predicate alwaysReaches(BasicBlock succ) { + succ = this + or + strictcount(BasicBlock s | s = super.getASuccessor()) = 1 and + succ = super.getASuccessor() + or + forex(BasicBlock immsucc | immsucc = super.getASuccessor() | immsucc.alwaysReaches(succ)) + } + + /** + * Holds if this basic block ends in a node that branches on a boolean + * outcome, and `other` is dominated by the corresponding successor + * for `branch` while not being reachable from the other branch + * without going through this BB. + * + * In other words: any execution that reaches `other` must have just + * evaluated the last node of this BB and taken the `branch` outcome. + * This mirrors the legacy `ConditionBlock.controls(BB, branch)`. + */ + predicate controls(BasicBlock other, boolean branch) { + exists(BasicBlock succ | + branch = true and succ = this.getATrueSuccessor() + or + branch = false and succ = this.getAFalseSuccessor() + | + succ.dominates(other) and + // The other branch must not also reach `other` — otherwise + // `other` is not actually controlled by `branch`. + not exists(BasicBlock otherSucc | + branch = true and otherSucc = this.getAFalseSuccessor() + or + branch = false and otherSucc = this.getATrueSuccessor() + | + otherSucc.reaches(other) + ) + ) + } +} + +// =========================================================================== +// Re-exports for SSA / dominance consumers +// +// The shared `BB::CfgSig` requires `EntryBasicBlock` and `dominatingEdge` in +// addition to the BasicBlock class we already expose. They are provided by +// the shared CFG library on the `BB::Make` instantiation produced by +// `AstNodeImpl.qll`. +// =========================================================================== +/** An entry basic block, that is, a basic block whose first node is an entry node. */ +class EntryBasicBlock = CfgImpl::Cfg::EntryBasicBlock; + +/** + * Holds if `bb1` has `bb2` as a direct successor and the edge between `bb1` + * and `bb2` is a dominating edge. + */ +predicate dominatingEdge = CfgImpl::Cfg::dominatingEdge/2; + +// =========================================================================== +// AST-shape subclasses of ControlFlowNode +// +// Each class is a thin wrapper around the canonical CFG node for a given +// kind of Python AST node. Methods that take/return CFG nodes look up +// related CFG nodes by AST identity (via `getNode()`), and the dominance +// constraint from the old CFG (`result.getBasicBlock().dominates(this.getBasicBlock())`) +// is preserved. +// =========================================================================== +/** Gets the canonical `ControlFlowNode` for AST expression `e`. */ +ControlFlowNode astExprToCfg(Py::Expr e) { result.getNode() = e } + +/** A control flow node corresponding to a `Name` or `PlaceHolder` expression. */ +class NameNode extends ControlFlowNode { + NameNode() { + toAst(this) instanceof Py::Name + or + toAst(this) instanceof Py::PlaceHolder + } + + /** + * Holds if this flow node defines the variable `v`. + * + * This includes augmented-assignment targets — `n += 1` is both a + * read and a write of `n`, so `defines(n)` and `uses(n)` both hold + * on the same canonical CFG node. Mirrors Java's `VariableUpdate` + * semantics where compound assignments register both a write + * (`VarWrite`) and a read (`VarRead`) on the destination. + */ + predicate defines(Py::Variable v) { exists(Py::Name n | n = toAst(this) and n.defines(v)) } + + /** Holds if this flow node deletes the variable `v`. */ + predicate deletes(Py::Variable v) { exists(Py::Name n | n = toAst(this) and n.deletes(v)) } + + /** Holds if this flow node uses the variable `v`. */ + predicate uses(Py::Variable v) { + this.isLoad() and + exists(Py::Name u | u = toAst(this) and u.uses(v)) + or + exists(Py::PlaceHolder u | + u = toAst(this) and u.getVariable() = v and u.getCtx() instanceof Py::Load + ) + } + + /** Gets the identifier of this name node. */ + string getId() { + result = toAst(this).(Py::Name).getId() + or + result = toAst(this).(Py::PlaceHolder).getId() + } + + /** Holds if this is a use of a local variable. */ + predicate isLocal() { exists(Py::Variable v | this.uses(v) and v instanceof Py::LocalVariable) } + + /** Holds if this is a use of a non-local variable. */ + predicate isNonLocal() { + exists(Py::Variable v | this.uses(v) and v.getScope() != this.getScope()) + } + + /** Holds if this is a use of a global (including builtin) variable. */ + predicate isGlobal() { exists(Py::Variable v | this.uses(v) and v instanceof Py::GlobalVariable) } + + /** + * Holds if this is a use of `self` — the first parameter of an + * enclosing method. + * + * AST-level approximation: matches when the Name uses a `Variable` + * that is the first parameter of an enclosing `Function` defined + * inside a `Class`. + */ + predicate isSelf() { + exists(Py::Variable v, Py::Function f, Py::Class c | + this.uses(v) and + f = c.getAMethod() and + v.getScope() = f and + v = f.getArg(0).(Py::Name).getVariable() + ) + } +} + +/** A control flow node corresponding to a named constant (`None`, `True`, `False`). */ +class NameConstantNode extends NameNode { + NameConstantNode() { toAst(this) instanceof Py::NameConstant } +} + +/** A control flow node corresponding to a call. */ +class CallNode extends ControlFlowNode { + CallNode() { toAst(this) instanceof Py::Call } + + override Py::Call getNode() { result = super.getNode() } + + /** Gets the underlying Python `Call`. */ + Py::Call getCall() { result = toAst(this) } + + /** Gets the flow node for the function component of this call. */ + ControlFlowNode getFunction() { + exists(Py::Call c | + c = toAst(this) and + c.getFunc() = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } + + /** Gets the flow node for the `n`th positional argument. */ + ControlFlowNode getArg(int n) { + exists(Py::Call c | + c = toAst(this) and + c.getArg(n) = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } + + /** Gets the flow node for the named argument with name `name`. */ + ControlFlowNode getArgByName(string name) { + exists(Py::Call c, Py::Keyword k | + c = toAst(this) and + k = c.getANamedArg() and + k.getValue() = toAst(result) and + k.getArg() = name and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } + + /** Gets a flow node corresponding to any argument. */ + ControlFlowNode getAnArg() { result = this.getArg(_) or result = this.getArgByName(_) } + + /** Gets the first tuple (`*args`) argument, if any. */ + ControlFlowNode getStarArg() { + exists(Py::Call c | + c = toAst(this) and + c.getStarArg() = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } + + /** Gets a dictionary (`**kwargs`) argument, if any. */ + ControlFlowNode getKwargs() { + exists(Py::Call c | + c = toAst(this) and + c.getKwargs() = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } + + /** Holds if this call is a decorator call applied to a class or a function. */ + predicate isDecoratorCall() { this.isClassDecoratorCall() or this.isFunctionDecoratorCall() } + + /** Holds if this call is a decorator call applied to a class. */ + predicate isClassDecoratorCall() { + exists(Py::ClassExpr cls | toAst(this) = cls.getADecoratorCall()) + } + + /** Holds if this call is a decorator call applied to a function. */ + predicate isFunctionDecoratorCall() { + exists(Py::FunctionExpr func | toAst(this) = func.getADecoratorCall()) + } +} + +/** A control flow node corresponding to an attribute expression. */ +class AttrNode extends ControlFlowNode { + AttrNode() { toAst(this) instanceof Py::Attribute } + + override Py::Attribute getNode() { result = super.getNode() } + + /** Gets the flow node for the object of the attribute expression. */ + ControlFlowNode getObject() { + exists(Py::Attribute a | + a = toAst(this) and + a.getObject() = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } + + /** Gets the flow node for the object of this attribute expression, with the matching name. */ + ControlFlowNode getObject(string name) { + exists(Py::Attribute a | + a = toAst(this) and + a.getObject() = toAst(result) and + a.getName() = name and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } + + /** Gets the attribute name. */ + string getName() { exists(Py::Attribute a | a = toAst(this) and a.getName() = result) } +} + +/** A control flow node corresponding to an import statement (`import x`). */ +class ImportExprNode extends ControlFlowNode { + ImportExprNode() { toAst(this) instanceof Py::ImportExpr } + + override Py::ImportExpr getNode() { result = super.getNode() } +} + +/** A control flow node corresponding to a `from ... import name` expression. */ +class ImportMemberNode extends ControlFlowNode { + ImportMemberNode() { toAst(this) instanceof Py::ImportMember } + + override Py::ImportMember getNode() { result = super.getNode() } + + /** Gets the flow node for the module being imported from, with the matching name. */ + ControlFlowNode getModule(string name) { + exists(Py::ImportMember i | + i = toAst(this) and + i.getModule() = toAst(result) and + i.getName() = name and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } +} + +/** A control flow node corresponding to a `from ... import *` statement. */ +class ImportStarNode extends ControlFlowNode { + ImportStarNode() { toAst(this) instanceof Py::ImportStar } + + override Py::ImportStar getNode() { result = super.getNode() } + + /** Gets the flow node for the module being imported from. */ + ControlFlowNode getModule() { + exists(Py::ImportStar i | + i = toAst(this) and + i.getModuleExpr() = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } +} + +/** A control flow node corresponding to a subscript expression. */ +class SubscriptNode extends ControlFlowNode { + SubscriptNode() { toAst(this) instanceof Py::Subscript } + + override Py::Subscript getNode() { result = super.getNode() } + + /** Gets the flow node for the value being subscripted. */ + ControlFlowNode getObject() { + exists(Py::Subscript s | + s = toAst(this) and + s.getObject() = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } + + /** Gets the flow node for the index expression. */ + ControlFlowNode getIndex() { + exists(Py::Subscript s | + s = toAst(this) and + s.getIndex() = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } +} + +/** A control flow node corresponding to a comparison operation. */ +class CompareNode extends ControlFlowNode { + CompareNode() { toAst(this) instanceof Py::Compare } + + override Py::Compare getNode() { result = super.getNode() } + + /** Holds if `left` and `right` are a pair of operands for this comparison. */ + predicate operands(ControlFlowNode left, Py::Cmpop op, ControlFlowNode right) { + exists(Py::Compare c, Py::Expr eleft, Py::Expr eright | + c = toAst(this) and eleft = toAst(left) and eright = toAst(right) + | + eleft = c.getLeft() and eright = c.getComparator(0) and op = c.getOp(0) + or + exists(int i | + eleft = c.getComparator(i - 1) and eright = c.getComparator(i) and op = c.getOp(i) + ) + ) and + left.getBasicBlock().dominates(this.getBasicBlock()) and + right.getBasicBlock().dominates(this.getBasicBlock()) + } +} + +/** A control flow node corresponding to a conditional expression (`x if c else y`). */ +class IfExprNode extends ControlFlowNode { + IfExprNode() { toAst(this) instanceof Py::IfExp } + + override Py::IfExp getNode() { result = super.getNode() } + + /** Gets the flow node for one of the value operands (true-branch or false-branch). */ + ControlFlowNode getAnOperand() { + exists(Py::IfExp ie | + ie = toAst(this) and + (toAst(result) = ie.getBody() or toAst(result) = ie.getOrelse()) + ) + } +} + +/** A control flow node corresponding to an assignment expression (walrus `:=`). */ +class AssignmentExprNode extends ControlFlowNode { + AssignmentExprNode() { toAst(this) instanceof Py::AssignExpr } + + override Py::AssignExpr getNode() { result = super.getNode() } + + /** Gets the flow node for the left-hand side. */ + ControlFlowNode getTarget() { + exists(Py::AssignExpr a | + a = toAst(this) and + a.getTarget() = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } + + /** Gets the flow node for the right-hand side. */ + ControlFlowNode getValue() { + exists(Py::AssignExpr a | + a = toAst(this) and + a.getValue() = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } +} + +/** A control flow node corresponding to a binary expression (`a + b` etc.). */ +class BinaryExprNode extends ControlFlowNode { + BinaryExprNode() { toAst(this) instanceof Py::BinaryExpr } + + override Py::BinaryExpr getNode() { result = super.getNode() } + + ControlFlowNode getLeft() { + exists(Py::BinaryExpr be | + be = toAst(this) and + be.getLeft() = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } + + ControlFlowNode getRight() { + exists(Py::BinaryExpr be | + be = toAst(this) and + be.getRight() = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } + + Py::Operator getOp() { result = toAst(this).(Py::BinaryExpr).getOp() } + + /** Holds if `left` and `right` are the operands and `op` is the operator. */ + predicate operands(ControlFlowNode left, Py::Operator op, ControlFlowNode right) { + left = this.getLeft() and right = this.getRight() and op = this.getOp() + } + + /** Gets either operand. */ + ControlFlowNode getAnOperand() { result = this.getLeft() or result = this.getRight() } +} + +/** A control flow node corresponding to a boolean expression (`a and b`, `a or b`). */ +class BoolExprNode extends ControlFlowNode { + BoolExprNode() { toAst(this) instanceof Py::BoolExpr } + + override Py::BoolExpr getNode() { result = super.getNode() } + + Py::Boolop getOp() { result = toAst(this).(Py::BoolExpr).getOp() } + + /** Gets any operand of this boolean expression. */ + ControlFlowNode getAnOperand() { + exists(Py::BoolExpr be | + be = toAst(this) and + be.getAValue() = toAst(result) + ) + } +} + +/** A control flow node corresponding to a unary expression (`-x`, `not x`, etc.). */ +class UnaryExprNode extends ControlFlowNode { + UnaryExprNode() { toAst(this) instanceof Py::UnaryExpr } + + override Py::UnaryExpr getNode() { result = super.getNode() } + + ControlFlowNode getOperand() { + exists(Py::UnaryExpr u | + u = toAst(this) and + u.getOperand() = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } + + Py::Unaryop getOp() { result = toAst(this).(Py::UnaryExpr).getOp() } +} + +/** + * A control flow node that is a definition: it appears in a context that + * binds a variable (assignment target, parameter, etc.). + */ +class DefinitionNode extends ControlFlowNode { + DefinitionNode() { this.isStore() or this.isParameter() } + + /** Gets the value assigned, if any. */ + ControlFlowNode getValue() { + // For-target: the value is the for-loop's iter expression (which + // is also where `Cfg::ForNode` lives — its `getNode()` returns the + // enclosing `Py::For` statement). Treated specially because there + // is no AST node holding the result of `iter(next(seq))`; we use + // the iter expression's CFG node as the stand-in. + exists(Py::For f | + f.getTarget() = toAst(this) and + toAst(result) = f.getIter() + ) + or + exists(Py::AstNode value | value = assignedValue(toAst(this)) | + toAst(result) = value and + ( + result.getBasicBlock().dominates(this.getBasicBlock()) + or + result.isImport() + or + // The default value for a parameter is evaluated in the same basic block as + // the function definition, but the parameter belongs to the basic block of the + // function, so there is no dominance relationship between the two. + exists(Py::Parameter param | toAst(this) = param.asName()) + ) + ) + } +} + +/** + * Gets the AST node that holds the value assigned to `lhs` in a binding + * context. Mirrors `Flow.qll::assigned_value`. + */ +private Py::AstNode assignedValue(Py::Expr lhs) { + // lhs = result + exists(Py::Assign a | a.getATarget() = lhs and result = a.getValue()) + or + // lhs := result + exists(Py::AssignExpr a | a.getTarget() = lhs and result = a.getValue()) + or + // lhs: annotation = result + exists(Py::AnnAssign a | a.getTarget() = lhs and result = a.getValue()) + or + // import result as lhs (also covers plain `import lhs`, where alias.getAsname() = lhs) + exists(Py::Alias a | a.getAsname() = lhs and result = a.getValue()) + or + // lhs += x -> result is the (lhs + x) binary expression + exists(Py::AugAssign a, Py::BinaryExpr b | + b = a.getOperation() and result = b and lhs = b.getLeft() + ) + or + // Nested sequence assign: ..., lhs, ... = ..., result, ... + exists(Py::Assign a | nestedSequenceAssign(a.getATarget(), a.getValue(), lhs, result)) + or + // Parameter default + exists(Py::Parameter param | lhs = param.asName() and result = param.getDefault()) +} + +/** + * Helper for nested sequence assignments such as `(a, b), c = (1, 2), 3`. + */ +private predicate nestedSequenceAssign( + Py::Expr leftParent, Py::Expr rightParent, Py::Expr left, Py::Expr right +) { + exists(int i | + leftParent.(Py::Tuple).getElt(i) = left and rightParent.(Py::Tuple).getElt(i) = right + or + leftParent.(Py::List).getElt(i) = left and rightParent.(Py::List).getElt(i) = right + ) + or + exists(Py::Expr leftMid, Py::Expr rightMid | + nestedSequenceAssign(leftParent, rightParent, leftMid, rightMid) and + nestedSequenceAssign(leftMid, rightMid, left, right) + ) +} + +/** A control flow node corresponding to a deletion (`del x`). */ +class DeletionNode extends ControlFlowNode { + DeletionNode() { this.isDelete() } +} + +/** A control flow node corresponding to a `for` loop target. */ +class ForNode extends ControlFlowNode { + ForNode() { exists(Py::For f | toAst(this) = f.getIter()) } + + /** Gets the iterable expression. */ + ControlFlowNode getIter() { + result = this and result = result // canonical "after" of the iterable + } + + /** Gets the sequence expression (alias for `getIter()`, matches legacy Flow naming). */ + ControlFlowNode getSequence() { result = this.getIter() } + + /** Gets the target (loop variable) of the `for` loop. */ + ControlFlowNode getTarget() { + exists(Py::For f | + f.getIter() = toAst(this) and + f.getTarget() = toAst(result) + ) + } + + /** Holds if `target` is the loop variable and `sequence` is the iterable. */ + predicate iterates(ControlFlowNode target, ControlFlowNode sequence) { + target = this.getTarget() and sequence = this.getSequence() + } +} + +/** A control flow node corresponding to a `raise` statement. */ +class RaiseStmtNode extends ControlFlowNode { + RaiseStmtNode() { toAst(this) instanceof Py::Raise } + + override Py::Raise getNode() { result = super.getNode() } + + /** Gets the exception expression, if any. */ + ControlFlowNode getException() { + exists(Py::Raise r | + r = toAst(this) and + r.getException() = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } +} + +/** A control flow node corresponding to a starred expression (`*x`). */ +class StarredNode extends ControlFlowNode { + StarredNode() { toAst(this) instanceof Py::Starred } + + /** Gets the value being starred. */ + ControlFlowNode getValue() { + exists(Py::Starred s | + s = toAst(this) and + s.getValue() = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } +} + +/** A control flow node corresponding to an `except` clause's name binding. */ +class ExceptFlowNode extends ControlFlowNode { + ExceptFlowNode() { exists(Py::ExceptStmt e | toAst(this) = e.getName()) } + + /** Gets the CFG node for the bound `as`-name itself. */ + ControlFlowNode getName() { result = this } + + /** Gets the type expression of this exception handler. */ + ControlFlowNode getType() { + exists(Py::ExceptStmt e | + e.getName() = toAst(this) and + e.getType() = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } +} + +/** A control flow node corresponding to an `except*` clause's name binding. */ +class ExceptGroupFlowNode extends ControlFlowNode { + ExceptGroupFlowNode() { exists(Py::ExceptGroupStmt e | toAst(this) = e.getName()) } + + /** Gets the CFG node for the bound `as`-name itself. */ + ControlFlowNode getName() { result = this } +} + +/** Abstract base class for sequence nodes (tuple, list). */ +abstract class SequenceNode extends ControlFlowNode { + /** Gets the `n`th element of this sequence. */ + abstract ControlFlowNode getElement(int n); + + /** Gets any element of this sequence. */ + ControlFlowNode getAnElement() { result = this.getElement(_) } +} + +/** A control flow node corresponding to a tuple literal. */ +class TupleNode extends SequenceNode { + TupleNode() { toAst(this) instanceof Py::Tuple } + + override ControlFlowNode getElement(int n) { + exists(Py::Tuple t | + t = toAst(this) and + t.getElt(n) = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } +} + +/** A control flow node corresponding to a list literal. */ +class ListNode extends SequenceNode { + ListNode() { toAst(this) instanceof Py::List } + + override ControlFlowNode getElement(int n) { + exists(Py::List l | + l = toAst(this) and + l.getElt(n) = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } +} + +/** A control flow node corresponding to a set literal. */ +class SetNode extends ControlFlowNode { + SetNode() { toAst(this) instanceof Py::Set } + + /** Gets the flow node for an element of the set. */ + ControlFlowNode getAnElement() { + exists(Py::Set s | + s = toAst(this) and + s.getAnElt() = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } +} + +/** A control flow node corresponding to a dict literal. */ +class DictNode extends ControlFlowNode { + DictNode() { toAst(this) instanceof Py::Dict } + + /** Gets the flow node for a key of the dict. */ + ControlFlowNode getAKey() { + exists(Py::Dict d | + d = toAst(this) and + d.getAKey() = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } + + /** Gets the flow node for a value of the dict. */ + ControlFlowNode getAValue() { + exists(Py::Dict d | + d = toAst(this) and + d.getAValue() = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } +} + +/** A control flow node corresponding to an iterable in a `for` loop. */ +class IterableNode extends ControlFlowNode { + IterableNode() { + this instanceof SequenceNode + or + this instanceof SetNode + } + + /** Gets the control flow node for an element of this iterable. */ + ControlFlowNode getAnElement() { + result = this.(SequenceNode).getAnElement() + or + result = this.(SetNode).getAnElement() + } +} diff --git a/python/ql/test/library-tests/ControlFlow/store-load/StoreLoadTest.expected b/python/ql/test/library-tests/ControlFlow/store-load/StoreLoadTest.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/ql/test/library-tests/ControlFlow/store-load/StoreLoadTest.ql b/python/ql/test/library-tests/ControlFlow/store-load/StoreLoadTest.ql new file mode 100644 index 000000000000..4ab2ef5be8fb --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/store-load/StoreLoadTest.ql @@ -0,0 +1,41 @@ +/** + * Inline-expectations test for the store/load/delete/parameter + * classification predicates on the new-CFG facade. + * + * Each tag fires when the corresponding predicate (`isLoad`, + * `isStore`, `isDelete`, `isParameter`, `isAugLoad`, `isAugStore`) + * holds on the canonical CFG node wrapping a `Py::Name` with the + * given identifier. Subscript and attribute stores are not covered + * by these tags — only the `Name`-typed targets/loads they involve. + */ + +import python +import semmle.python.controlflow.internal.Cfg as Cfg +import utils.test.InlineExpectationsTest + +module StoreLoadTest implements TestSig { + string getARelevantTag() { result = ["load", "store", "delete", "param", "augload", "augstore"] } + + predicate hasActualResult(Location location, string element, string tag, string value) { + exists(Cfg::NameNode n | + location = n.getLocation() and + element = n.toString() and + value = n.getId() and + ( + n.isLoad() and not n.isAugLoad() and tag = "load" + or + n.isStore() and not n.isAugStore() and tag = "store" + or + n.isDelete() and tag = "delete" + or + n.isParameter() and tag = "param" + or + n.isAugLoad() and tag = "augload" + or + n.isAugStore() and tag = "augstore" + ) + ) + } +} + +import MakeTest diff --git a/python/ql/test/library-tests/ControlFlow/store-load/test.py b/python/ql/test/library-tests/ControlFlow/store-load/test.py new file mode 100644 index 000000000000..dfca45a0b47b --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/store-load/test.py @@ -0,0 +1,56 @@ +# Store/load/delete/parameter classification on the new-CFG facade. +# +# Each annotated location carries the (sorted, deduplicated) set of +# kinds the CFG facade reports there. Comparing against the legacy +# 'semmle.python.Flow' classification is done by the comparison query +# 'StoreLoadParity.ql' — annotations here are only the positive +# assertions for the new facade. +# +# Tags: +# load= -- isLoad() fires on the Name +# store= -- isStore() fires +# delete= -- isDelete() fires +# param= -- isParameter() fires +# augload= -- isAugLoad() fires (the LHS of x += ... when read) +# augstore= -- isAugStore() fires (the LHS of x += ... when written) + + +# --- plain load / store / delete --- + +x = 1 # $ store=x +y = x + 1 # $ store=y load=x +print(y) # $ load=print load=y +del x # $ delete=x + + +# --- function definitions (parameters) --- + +def f(a, b=2, *args, c, **kwargs): # $ store=f param=a param=b param=args param=c param=kwargs + return a + b + c # $ load=a load=b load=c + + +# --- augmented assignment splits one Name into load + store halves --- + +def aug(): # $ store=aug + n = 0 # $ store=n + n += 1 # $ augload=n augstore=n + return n # $ load=n + + +# --- subscript / attribute stores --- + +class C: # $ store=C + pass + + +def stores(obj, container, idx): # $ store=stores param=obj param=container param=idx + obj.attr = 1 # $ load=obj + container[idx] = 2 # $ load=container load=idx + return obj # $ load=obj + + +# --- tuple unpacking --- + +def unpack(pair): # $ store=unpack param=pair + a, b = pair # $ store=a store=b load=pair + return a + b # $ load=a load=b From 41c9d8b80a9b930ab81a712db9cd04d2b7a4b000 Mon Sep 17 00:00:00 2001 From: yoff Date: Wed, 3 Jun 2026 09:46:03 +0000 Subject: [PATCH 003/188] Python: model exception edges for raise-prone expressions inside try/with MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The new CFG previously only emitted exception edges for explicit `raise` and `assert` statements. As a result, code that became reachable only via the exception path of an arbitrary expression (e.g., the body of an `except` handler following a try-body whose `call()` could raise) was classified as dead, breaking analyses like StackTraceExposure, FileNotAlwaysClosed, ExceptionInfo, UseOfExit, and CatchingBaseException. This commit adds a `mayThrow` predicate over expressions that are known sources of implicit exceptions in Python (calls, attribute access, subscripts, arithmetic/comparison operators, imports, await/yield/yield from) plus `from m import *` at the statement level, and routes them through the shared CFG's `beginAbruptCompletion(_, _, ExceptionSuccessor, always=false)` hook. The set of exception sources is restricted to nodes that are syntactically inside a `try`/`with` statement in the same scope. This mirrors Java's `ControlFlowGraph::mayThrow`, which only emits exception edges where local handling can observe them — outside such contexts, the edges add CFG complexity (weakening BarrierGuard precision and breaking SSA continuity around augmented assignments and subscript stores) without analysis benefit, since exceptions just propagate to the function exit anyway. Net effect on the test suite: ~100 alerts restored across the exception- related query tests (StackTraceExposure +29, ExceptionInfo +17, FileNotAlwaysClosed +52, UseOfExit +1, CatchingBaseException restored) with no precision regressions. Affected `.expected` files and the regression-guard `dead_under_no_raise.py` are updated accordingly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../controlflow/internal/AstNodeImpl.qll | 88 +++++++++++++++++++ .../bindings/dead_under_no_raise.py | 37 ++++---- 2 files changed, 107 insertions(+), 18 deletions(-) diff --git a/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll b/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll index 5d87b16f3511..803d3ca6e279 100644 --- a/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll +++ b/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll @@ -1571,6 +1571,89 @@ private module Input implements InputSig1, InputSig2 { private string assertThrowTag() { result = "[assert-throw]" } + /** + * Holds if the AST node `n` may raise an exception at runtime as part of + * its normal evaluation (not via an explicit `raise`/`assert`, which are + * modelled separately). + * + * The set mirrors what the legacy CFG used to flag implicitly: function + * calls (anything can raise), attribute access (`AttributeError`), + * subscript access (`IndexError`/`KeyError`/`TypeError`), arithmetic and + * comparison operators (`TypeError`/`ZeroDivisionError`), imports + * (`ImportError`/`ModuleNotFoundError`), and generator/coroutine + * suspension points (`await`/`yield`/`yield from`). + * + * Bare `Name` reads are intentionally excluded — modelling every name + * read as `mayThrow` would explode CFG edge count for negligible + * analysis value. `BoolExpr`/`IfExp` containers are also excluded; the + * operands they evaluate contribute their own exception edges. + */ + private predicate exprMayThrow(Py::Expr e) { + e instanceof Py::Call + or + e instanceof Py::Attribute + or + e instanceof Py::Subscript + or + e instanceof Py::BinaryExpr + or + e instanceof Py::UnaryExpr + or + e instanceof Py::Compare + or + e instanceof Py::ImportExpr + or + e instanceof Py::ImportMember + or + e instanceof Py::Await + or + e instanceof Py::Yield + or + e instanceof Py::YieldFrom + } + + /** + * Holds if the statement `s` may raise an exception at runtime as part + * of its normal evaluation. Currently restricted to `from m import *` + * (which performs the import as a statement-level side effect). + */ + private predicate stmtMayThrow(Py::Stmt s) { s instanceof Py::ImportStar } + + /** + * Holds if `n` is syntactically inside the body, handlers, `else`, or + * `finally` of a `try` statement (or the body of a `with` statement, + * which compiles to an implicit try/finally for `__exit__`) in the + * same scope. + * + * This mirrors Java's `ControlFlowGraph::mayThrow`, which only emits + * exception edges when there is local exception handling that would + * observe them. Outside such contexts, exception edges would add CFG + * complexity (weakening BarrierGuard precision and breaking SSA + * continuity around augmented assignments and subscript stores) + * without any analysis benefit, since exceptions just propagate to + * the function exit anyway. + */ + private predicate inExceptionContext(Py::AstNode py) { + exists(Py::Try t | t.containsInScope(py)) + or + exists(Py::With w | w.containsInScope(py)) + } + + /** + * Holds if `n` may raise an exception during normal evaluation. See + * `exprMayThrow` and `stmtMayThrow` for the included AST classes. + * + * Restricted to nodes inside a `try`/`with` statement: matches Java's + * approach of only modelling exception flow where it can be observed + * by local handling. + */ + private predicate mayThrow(Ast::AstNode n) { + exists(Py::AstNode py | py = n.asExpr() or py = n.asStmt() | + (exprMayThrow(py) or stmtMayThrow(py)) and + inExceptionContext(py) + ) + } + predicate additionalNode(Ast::AstNode n, string tag, NormalSuccessor t) { n instanceof Ast::AssertStmt and tag = assertThrowTag() and t instanceof DirectSuccessor } @@ -1582,6 +1665,11 @@ private module Input implements InputSig1, InputSig2 { n.isAdditional(ast, assertThrowTag()) and c.asSimpleAbruptCompletion() instanceof ExceptionSuccessor and always = true + or + mayThrow(ast) and + n.isIn(ast) and + c.asSimpleAbruptCompletion() instanceof ExceptionSuccessor and + always = false } predicate endAbruptCompletion(Ast::AstNode ast, PreControlFlowNode n, AbruptCompletion c) { diff --git a/python/ql/test/library-tests/ControlFlow/bindings/dead_under_no_raise.py b/python/ql/test/library-tests/ControlFlow/bindings/dead_under_no_raise.py index dbfb857b5360..9058f2b71165 100644 --- a/python/ql/test/library-tests/ControlFlow/bindings/dead_under_no_raise.py +++ b/python/ql/test/library-tests/ControlFlow/bindings/dead_under_no_raise.py @@ -1,15 +1,15 @@ -# Dead bindings under the "no expressions raise" CFG abstraction. +# Reachability of code following a try whose body always returns. # -# The new CFG does not currently model raise edges from arbitrary -# expressions. As a consequence, code that is only reachable through -# exception flow is (correctly) classified as dead and has no CFG node. -# Variable bindings in dead code do not need CFG nodes - SSA / dataflow -# over dead code is moot. +# The new CFG models exception edges for raise-prone expressions when +# they appear inside a `try` (or `with`) statement, mirroring Java's +# `mayThrow`. This means the body of a `try` has both a normal +# completion edge and an exception edge to its handlers, so code +# following the try-statement is reachable via the except-handler path +# even when the try-body would otherwise always return. # -# These tests act as a regression guard: the bindings below intentionally -# have no `cfgdefines=` annotations. If raise modelling is later added, -# the BindingsTest infrastructure will surface the new CFG nodes as -# unexpected results, and this file will need to be revisited. +# Code that is not reachable under either normal or exception flow +# (for example, the `else` clause of a try whose body unconditionally +# raises) remains correctly classified as dead. def f(obj): # $ cfgdefines=f cfgdefines=obj @@ -18,12 +18,12 @@ def f(obj): # $ cfgdefines=f cfgdefines=obj except TypeError: pass - # The first try's body always returns; its except handler does not - # raise or otherwise transfer control, so under "no expressions - # raise" the only paths out of the try-statement are dead. Everything - # below is unreachable. + # The try-body always returns, but `len(obj)` can raise (it is + # inside the try, so we model its exception edge). The + # `except TypeError: pass` handler falls through to here, making + # the code below reachable. try: - hint = type(obj).__length_hint__ + hint = type(obj).__length_hint__ # $ cfgdefines=hint except AttributeError: return None return hint @@ -35,7 +35,8 @@ def g(): # $ cfgdefines=g except: raise Exception("outer") else: - # Unreachable: the inner try body always raises, so the `else:` + # Unreachable: the inner try body always raises (via an explicit + # `raise`, which is modelled unconditionally), so the `else:` # clause never runs. hit_inner_else = True @@ -46,7 +47,7 @@ def h(cache, key): # $ cfgdefines=h cfgdefines=cache cfgdefines=key except KeyError: pass - # Same pattern as `f`: dead under "no expressions raise". - value = compute(key) + # Same pattern as `f`: reachable via the except-handler fall-through. + value = compute(key) # $ cfgdefines=value cache[key] = value return value From 47d2b05bc53191129311e00502debfc521b30508 Mon Sep 17 00:00:00 2001 From: yoff Date: Mon, 29 Jun 2026 13:17:31 +0000 Subject: [PATCH 004/188] Python: visit function parameter and return annotations in new CFG The new (shared-CFG-based) Python control flow graph in `semmle.python.controlflow.internal.Cfg` previously did not emit CFG nodes for parameter type annotations (`def f(x: T): ...`) or for the return type annotation (`-> T`). The legacy CFG emitted both, and a small number of framework models rely on this: `LocalSources.qll`'s `annotatedInstance` walks the parameter annotation expression by way of its CFG node to track that a parameter receives an instance of the annotated class. After the dataflow flip to the new CFG/SSA this regression manifested as lost flows in any test exercising annotation-based parameter tracking: FastAPI `Depends()` receivers, Pydantic request bodies, Starlette `WebSocket`, the call-graph type-annotation test, and so on. Extend `FunctionDefExpr` to visit each annotation as a child of the function-def expression, in CPython evaluation order: positional parameter annotations, `*args` annotation, keyword-only parameter annotations, `**kwargs` annotation, then the return annotation. (Lambda expressions have no annotations in Python syntax, so `LambdaExpr` is unchanged.) PEP 695 type parameters remain out of scope; they belong to the inner annotation scope, not the enclosing CFG. Restored test results across `framework/aiohttp`, `framework/fastapi`, `framework/lxml`, the `CallGraph-type-annotations` test, and `CWE-022-PathInjection`. Two FastAPI list-comprehension MISSING markers become positive (`taint_test.py:41,55`). CPython CFG consistency remains clean. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../2026-06-04-cfg-parameter-annotations.md | 4 ++ .../controlflow/internal/AstNodeImpl.qll | 63 +++++++++++++++++-- 2 files changed, 63 insertions(+), 4 deletions(-) create mode 100644 python/ql/lib/change-notes/2026-06-04-cfg-parameter-annotations.md diff --git a/python/ql/lib/change-notes/2026-06-04-cfg-parameter-annotations.md b/python/ql/lib/change-notes/2026-06-04-cfg-parameter-annotations.md new file mode 100644 index 000000000000..96ba81e1610e --- /dev/null +++ b/python/ql/lib/change-notes/2026-06-04-cfg-parameter-annotations.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* The new (shared-CFG-based) Python control flow graph now visits parameter and return type annotations as CFG nodes for function definitions, matching the legacy CFG. This restores annotation-based type tracking through framework models such as FastAPI's `Depends()`, Pydantic request models, Starlette `WebSocket` handlers, and any other models that flow a class reference through `Parameter.getAnnotation()` to identify instances of the annotated class. diff --git a/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll b/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll index 803d3ca6e279..8199008e88c9 100644 --- a/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll +++ b/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll @@ -1474,10 +1474,19 @@ module Ast implements AstSig { /** * A function definition expression (visits positional and keyword - * defaults, but NOT PEP 695 type parameters — those bind in an - * annotation scope that nests the function body, so they belong to - * the inner scope's CFG, not the enclosing scope's; the legacy CFG - * also omitted them). + * defaults followed by parameter and return type annotations, but NOT + * PEP 695 type parameters — those bind in an annotation scope that + * nests the function body, so they belong to the inner scope's CFG, + * not the enclosing scope's; the legacy CFG also omitted them). + * + * Evaluation order follows CPython: defaults are pushed first, then + * keyword-only defaults, then annotations (the `__annotations__` dict + * is built last, before `MAKE_FUNCTION`). Annotations are emitted as + * CFG nodes so that flows from a class reference into a parameter's + * type annotation are visible to dataflow (e.g. so that framework + * models like FastAPI's `Depends()` can use a parameter's type hint + * to track that the parameter receives an instance of the annotated + * class — see `LocalSources::annotatedInstance`). */ additional class FunctionDefExpr extends Expr { private Py::FunctionExpr funcExpr; @@ -1501,15 +1510,61 @@ module Ast implements AstSig { rank[n + 1](Py::Expr d, int i | d = funcExpr.getArgs().getKwDefault(i) | d order by i) } + /** + * Gets the `n`th annotation expression, in CPython evaluation + * order: positional parameter annotations (by argument position), + * `*args` annotation, keyword-only parameter annotations (by + * argument position), `**kwargs` annotation, then the return + * annotation. Each annotation appears at most once. + */ + Expr getAnnotation(int n) { + result.asExpr() = + rank[n + 1](Py::Expr a, int subOrder, int subIndex | + functionAnnotation(funcExpr, a, subOrder, subIndex) + | + a order by subOrder, subIndex + ) + } + int getNumberOfDefaults() { result = count(funcExpr.getArgs().getADefault()) } + int getNumberOfKwDefaults() { result = count(funcExpr.getArgs().getAKwDefault()) } + + int getNumberOfAnnotations() { + result = count(Py::Expr a | functionAnnotation(funcExpr, a, _, _)) + } + override AstNode getChild(int index) { result = this.getDefault(index) or result = this.getKwDefault(index - this.getNumberOfDefaults()) + or + result = this.getAnnotation(index - this.getNumberOfDefaults() - this.getNumberOfKwDefaults()) } } + /** + * Holds if `a` is an annotation of `funcExpr` in slot + * `(subOrder, subIndex)`. Slots are CPython evaluation order: + * positional param annotations (subOrder 0, subIndex = argument + * position), `*args` annotation (1, 0), keyword-only annotations + * (2, position), `**kwargs` annotation (3, 0), return annotation + * (4, 0). + */ + private predicate functionAnnotation( + Py::FunctionExpr funcExpr, Py::Expr a, int subOrder, int subIndex + ) { + a = funcExpr.getArgs().getAnnotation(subIndex) and subOrder = 0 + or + a = funcExpr.getArgs().getVarargannotation() and subOrder = 1 and subIndex = 0 + or + a = funcExpr.getArgs().getKwAnnotation(subIndex) and subOrder = 2 + or + a = funcExpr.getArgs().getKwargannotation() and subOrder = 3 and subIndex = 0 + or + a = funcExpr.getReturns() and subOrder = 4 and subIndex = 0 + } + /** A lambda expression (has default args evaluated at definition time). */ additional class LambdaExpr extends Expr { private Py::Lambda lambda; From a06a72c3080f92a4b8ad9834822a1a8d6d5f60cb Mon Sep 17 00:00:00 2001 From: Keshav Malik Date: Thu, 9 Jul 2026 10:54:19 +0530 Subject: [PATCH 005/188] JS: Model Sails Action2 inputs as remote sources --- .../codeql/reusables/supported-frameworks.rst | 1 + .../2026-07-07-sails-action2-inputs.md | 4 + .../javascript/frameworks/HttpFrameworks.qll | 1 + .../semmle/javascript/frameworks/Sails.qll | 85 +++++++++++++++++++ .../attachments/assigned-action.js | 11 +++ .../attachments/destructured-action.js | 9 ++ .../attachments/download-thumbnail.js | 14 +++ .../Sails/src/api/helpers/read-thumbnail.js | 9 ++ .../frameworks/Sails/src/lib/machine.js | 9 ++ .../frameworks/Sails/tests.expected | 9 ++ .../library-tests/frameworks/Sails/tests.ql | 8 ++ .../CWE-022/TaintedPath/TaintedPath.expected | 8 ++ .../attachments/download-thumbnail.js | 25 ++++++ 13 files changed, 193 insertions(+) create mode 100644 javascript/ql/lib/change-notes/2026-07-07-sails-action2-inputs.md create mode 100644 javascript/ql/lib/semmle/javascript/frameworks/Sails.qll create mode 100644 javascript/ql/test/library-tests/frameworks/Sails/src/api/controllers/attachments/assigned-action.js create mode 100644 javascript/ql/test/library-tests/frameworks/Sails/src/api/controllers/attachments/destructured-action.js create mode 100644 javascript/ql/test/library-tests/frameworks/Sails/src/api/controllers/attachments/download-thumbnail.js create mode 100644 javascript/ql/test/library-tests/frameworks/Sails/src/api/helpers/read-thumbnail.js create mode 100644 javascript/ql/test/library-tests/frameworks/Sails/src/lib/machine.js create mode 100644 javascript/ql/test/library-tests/frameworks/Sails/tests.expected create mode 100644 javascript/ql/test/library-tests/frameworks/Sails/tests.ql create mode 100644 javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/api/controllers/attachments/download-thumbnail.js diff --git a/docs/codeql/reusables/supported-frameworks.rst b/docs/codeql/reusables/supported-frameworks.rst index 930cdc6b629a..0552a3495175 100644 --- a/docs/codeql/reusables/supported-frameworks.rst +++ b/docs/codeql/reusables/supported-frameworks.rst @@ -191,6 +191,7 @@ and the CodeQL library pack ``codeql/javascript-all`` (`changelog Date: Thu, 16 Jul 2026 15:48:53 +0000 Subject: [PATCH 006/188] Model Vue Router useRoute sources --- javascript/ql/lib/semmle/javascript/frameworks/Vue.qll | 2 ++ 1 file changed, 2 insertions(+) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Vue.qll b/javascript/ql/lib/semmle/javascript/frameworks/Vue.qll index 59490a2d5c65..193571b3b773 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Vue.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Vue.qll @@ -652,6 +652,8 @@ module Vue { t.start() and ( exists(API::Node router | router = API::moduleImport("vue-router") | + result = router.getMember("useRoute").getACall() + or result = router.getInstance().getMember("currentRoute").asSource() or result = From 74496589f0be3e1f6785a039743f809e52190558 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 16 Jul 2026 15:51:49 +0000 Subject: [PATCH 007/188] Test Vue useRoute query source --- javascript/ql/test/library-tests/frameworks/Vue/router.js | 4 +++- .../ql/test/library-tests/frameworks/Vue/tests.expected | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/javascript/ql/test/library-tests/frameworks/Vue/router.js b/javascript/ql/test/library-tests/frameworks/Vue/router.js index 65dc4d13e99e..efae87483443 100644 --- a/javascript/ql/test/library-tests/frameworks/Vue/router.js +++ b/javascript/ql/test/library-tests/frameworks/Vue/router.js @@ -1,4 +1,4 @@ -import Router from 'vue-router'; +import Router, { useRoute } from 'vue-router'; export const router = new Router({ routes: [ @@ -43,3 +43,5 @@ router.afterEach((to, from) => { to.query.x; from.query.x; }); + +useRoute().query; diff --git a/javascript/ql/test/library-tests/frameworks/Vue/tests.expected b/javascript/ql/test/library-tests/frameworks/Vue/tests.expected index 633a8f9924db..9379678a8bd3 100644 --- a/javascript/ql/test/library-tests/frameworks/Vue/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/Vue/tests.expected @@ -191,6 +191,7 @@ remoteFlowSource | router.js:39:5:39:14 | from.query | | router.js:43:5:43:12 | to.query | | router.js:44:5:44:14 | from.query | +| router.js:47:1:47:16 | useRoute().query | parseErrors attribute | compont-with-route.vue:2:8:2:21 | v-html=dataA | v-html | @@ -239,6 +240,7 @@ threatModelSource | router.js:39:5:39:14 | from.query | remote | | router.js:43:5:43:12 | to.query | remote | | router.js:44:5:44:14 | from.query | remote | +| router.js:47:1:47:16 | useRoute().query | remote | | single-component-file-1.vue:7:45:7:54 | this.input | view-component-input | | single-file-component-3-script.js:5:42:5:51 | this.input | view-component-input | | single-file-component-4.vue:21:14:21:23 | this.input | view-component-input | From 9aaa1492544426fbd302b641cd87f7e1b22bf6cd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 16 Jul 2026 16:04:19 +0000 Subject: [PATCH 008/188] Add change note for Vue Router useRoute query support --- change-notes/1.26/analysis-javascript.md | 1 + 1 file changed, 1 insertion(+) diff --git a/change-notes/1.26/analysis-javascript.md b/change-notes/1.26/analysis-javascript.md index 15edb607c70a..ef3a8e23ffd0 100644 --- a/change-notes/1.26/analysis-javascript.md +++ b/change-notes/1.26/analysis-javascript.md @@ -42,6 +42,7 @@ - [styled-components](https://www.npmjs.com/package/styled-components) - [throttle-debounce](https://www.npmjs.com/package/throttle-debounce) - [underscore](https://www.npmjs.com/package/underscore) + - [vue-router](https://www.npmjs.com/package/vue-router) * Analyzing files with the ".cjs" extension is now supported. * ES2021 features are now supported. From 03d2ad50e7f15f9ad3072bf007906e6a6931ddeb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 16 Jul 2026 16:08:50 +0000 Subject: [PATCH 009/188] Add YYYY-MM-DD format change note for Vue Router useRoute query --- .../lib/change-notes/2026-07-16-vue-router-useRoute-query.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 javascript/ql/lib/change-notes/2026-07-16-vue-router-useRoute-query.md diff --git a/javascript/ql/lib/change-notes/2026-07-16-vue-router-useRoute-query.md b/javascript/ql/lib/change-notes/2026-07-16-vue-router-useRoute-query.md new file mode 100644 index 000000000000..eeec2232f3e9 --- /dev/null +++ b/javascript/ql/lib/change-notes/2026-07-16-vue-router-useRoute-query.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* The query parameter of Vue Router's `useRoute()` Composition API is now recognized as a client-side remote flow source. From 7e08178d63828c4b9a23db2583d28a8be4614c05 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 16 Jul 2026 17:12:55 +0000 Subject: [PATCH 010/188] Add Vue summary models for ref, shallowRef, toRef, reactive, and computed --- javascript/ql/lib/ext/vue.model.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 javascript/ql/lib/ext/vue.model.yml diff --git a/javascript/ql/lib/ext/vue.model.yml b/javascript/ql/lib/ext/vue.model.yml new file mode 100644 index 000000000000..20af3b1f1acb --- /dev/null +++ b/javascript/ql/lib/ext/vue.model.yml @@ -0,0 +1,15 @@ +extensions: + - addsTo: + pack: codeql/javascript-all + extensible: summaryModel + data: + # ref(x).value === x + - ["vue", "Member[ref]", "Argument[0]", "ReturnValue.Member[value]", "value"] + # shallowRef(x).value === x + - ["vue", "Member[shallowRef]", "Argument[0]", "ReturnValue.Member[value]", "value"] + # customRef / toRef keep the wrapped value reachable via .value + - ["vue", "Member[toRef]", "Argument[0]", "ReturnValue.Member[value]", "taint"] + # reactive(x) returns a proxy that preserves the members of x + - ["vue", "Member[reactive]", "Argument[0]", "ReturnValue", "taint"] + # computed(() => expr).value === return value of the getter + - ["vue", "Member[computed]", "Argument[0].ReturnValue", "ReturnValue.Member[value]", "value"] From dc15554a1ed5f86315ebbbbdc9c359e97e8f38eb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 16 Jul 2026 17:38:30 +0000 Subject: [PATCH 011/188] Move Vue flow models into QL --- .../2026-07-16-vue-composition-api-flow.md | 4 +++ javascript/ql/lib/ext/vue.model.yml | 15 -------- .../lib/semmle/javascript/frameworks/Vue.qll | 36 +++++++++++++++++++ .../library-tests/frameworks/Vue/tests.ql | 18 ++++++++++ .../test/library-tests/frameworks/Vue/tst.js | 6 ++++ 5 files changed, 64 insertions(+), 15 deletions(-) create mode 100644 javascript/ql/lib/change-notes/2026-07-16-vue-composition-api-flow.md delete mode 100644 javascript/ql/lib/ext/vue.model.yml diff --git a/javascript/ql/lib/change-notes/2026-07-16-vue-composition-api-flow.md b/javascript/ql/lib/change-notes/2026-07-16-vue-composition-api-flow.md new file mode 100644 index 000000000000..d03bebdb129d --- /dev/null +++ b/javascript/ql/lib/change-notes/2026-07-16-vue-composition-api-flow.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Added flow models for Vue's `ref`, `shallowRef`, `toRef`, `reactive`, and `computed` Composition API helpers. diff --git a/javascript/ql/lib/ext/vue.model.yml b/javascript/ql/lib/ext/vue.model.yml deleted file mode 100644 index 20af3b1f1acb..000000000000 --- a/javascript/ql/lib/ext/vue.model.yml +++ /dev/null @@ -1,15 +0,0 @@ -extensions: - - addsTo: - pack: codeql/javascript-all - extensible: summaryModel - data: - # ref(x).value === x - - ["vue", "Member[ref]", "Argument[0]", "ReturnValue.Member[value]", "value"] - # shallowRef(x).value === x - - ["vue", "Member[shallowRef]", "Argument[0]", "ReturnValue.Member[value]", "value"] - # customRef / toRef keep the wrapped value reachable via .value - - ["vue", "Member[toRef]", "Argument[0]", "ReturnValue.Member[value]", "taint"] - # reactive(x) returns a proxy that preserves the members of x - - ["vue", "Member[reactive]", "Argument[0]", "ReturnValue", "taint"] - # computed(() => expr).value === return value of the getter - - ["vue", "Member[computed]", "Argument[0].ReturnValue", "ReturnValue.Member[value]", "value"] diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Vue.qll b/javascript/ql/lib/semmle/javascript/frameworks/Vue.qll index 193571b3b773..0e8f48de49bc 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Vue.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Vue.qll @@ -35,6 +35,42 @@ module Vue { result = any(GlobalVueEntryPoint e).getANode() } + /** Models data flow through Vue Composition API helpers. */ + private class VueCompositionApiSummary extends DataFlow::SummarizedCallable::Range { + string name; + + VueCompositionApiSummary() { + name = ["ref", "shallowRef", "toRef", "reactive", "computed"] and + this = "vue." + name + } + + override predicate propagatesFlow(string input, string output, boolean preservesValue) { + name = ["ref", "shallowRef"] and + input = "Argument[0]" and + output = "ReturnValue.Member[value]" and + preservesValue = true + or + name = "toRef" and + input = "Argument[0]" and + output = "ReturnValue.Member[value]" and + preservesValue = false + or + name = "reactive" and + input = "Argument[0]" and + output = "ReturnValue" and + preservesValue = false + or + name = "computed" and + input = "Argument[0].ReturnValue" and + output = "ReturnValue.Member[value]" and + preservesValue = true + } + + override DataFlow::InvokeNode getACall() { + result = API::moduleImport("vue").getMember(name).getACall() + } + } + /** * Gets a reference to the 'Vue' object. */ diff --git a/javascript/ql/test/library-tests/frameworks/Vue/tests.ql b/javascript/ql/test/library-tests/frameworks/Vue/tests.ql index c631f46d3293..6121a7f9a46b 100644 --- a/javascript/ql/test/library-tests/frameworks/Vue/tests.ql +++ b/javascript/ql/test/library-tests/frameworks/Vue/tests.ql @@ -1,6 +1,24 @@ import javascript import semmle.javascript.security.dataflow.DomBasedXssCustomizations +module TestConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { + source.(DataFlow::CallNode).getCalleeName() = "source" + } + + predicate isSink(DataFlow::Node sink) { + sink = any(DataFlow::CallNode call | call.getCalleeName() = "sink").getAnArgument() + } +} + +module TestDataFlow = DataFlow::Global; + +module TestTaintFlow = TaintTracking::Global; + +query predicate compositionApiDataFlow = TestDataFlow::flow/2; + +query predicate compositionApiTaintFlow = TestTaintFlow::flow/2; + query predicate component_getAPropertyValue(Vue::Component c, string name, DataFlow::Node prop) { c.getAPropertyValue(name) = prop } diff --git a/javascript/ql/test/library-tests/frameworks/Vue/tst.js b/javascript/ql/test/library-tests/frameworks/Vue/tst.js index 6ee0954063a9..64c14a291194 100644 --- a/javascript/ql/test/library-tests/frameworks/Vue/tst.js +++ b/javascript/ql/test/library-tests/frameworks/Vue/tst.js @@ -115,3 +115,9 @@ let subclass2 = base.extend({ fromSubclass2: 100 } }); + +sink(Vue.ref(source("ref")).value); +sink(Vue.shallowRef(source("shallowRef")).value); +sink(Vue.toRef(source("toRef")).value); +sink(Vue.reactive(source("reactive"))); +sink(Vue.computed(() => source("computed")).value); From d99bb542b70cf994535bf4c102350e1200facc5b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 16 Jul 2026 17:42:19 +0000 Subject: [PATCH 012/188] Fix and verify Vue flow summaries --- javascript/ql/lib/semmle/javascript/frameworks/Vue.qll | 1 + .../test/library-tests/frameworks/Vue/tests.expected | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Vue.qll b/javascript/ql/lib/semmle/javascript/frameworks/Vue.qll index 0e8f48de49bc..1edb53e814c5 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Vue.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Vue.qll @@ -36,6 +36,7 @@ module Vue { } /** Models data flow through Vue Composition API helpers. */ + overlay[local?] private class VueCompositionApiSummary extends DataFlow::SummarizedCallable::Range { string name; diff --git a/javascript/ql/test/library-tests/frameworks/Vue/tests.expected b/javascript/ql/test/library-tests/frameworks/Vue/tests.expected index 9379678a8bd3..ffa220d5dc8e 100644 --- a/javascript/ql/test/library-tests/frameworks/Vue/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/Vue/tests.expected @@ -248,3 +248,13 @@ threatModelSource | single-file-component-6.vue:5:11:5:15 | input | view-component-input | | single-file-component-7.vue:5:11:5:15 | input | view-component-input | | single-file-component-8.vue:5:11:5:15 | input | view-component-input | +compositionApiDataFlow +| tst.js:119:14:119:26 | source("ref") | tst.js:119:6:119:33 | Vue.ref ... ).value | +| tst.js:120:21:120:40 | source("shallowRef") | tst.js:120:6:120:47 | Vue.sha ... ).value | +| tst.js:123:25:123:42 | source("computed") | tst.js:123:6:123:49 | Vue.com ... ).value | +compositionApiTaintFlow +| tst.js:119:14:119:26 | source("ref") | tst.js:119:6:119:33 | Vue.ref ... ).value | +| tst.js:120:21:120:40 | source("shallowRef") | tst.js:120:6:120:47 | Vue.sha ... ).value | +| tst.js:121:16:121:30 | source("toRef") | tst.js:121:6:121:37 | Vue.toR ... ).value | +| tst.js:122:19:122:36 | source("reactive") | tst.js:122:6:122:37 | Vue.rea ... tive")) | +| tst.js:123:25:123:42 | source("computed") | tst.js:123:6:123:49 | Vue.com ... ).value | From c5b3ca0e98841a515218c7e504d88cc637b1e63a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 16 Jul 2026 17:47:12 +0000 Subject: [PATCH 013/188] Merge Vue change notes --- .../lib/change-notes/2026-07-16-vue-composition-api-flow.md | 4 ---- .../lib/change-notes/2026-07-16-vue-router-useRoute-query.md | 1 + 2 files changed, 1 insertion(+), 4 deletions(-) delete mode 100644 javascript/ql/lib/change-notes/2026-07-16-vue-composition-api-flow.md diff --git a/javascript/ql/lib/change-notes/2026-07-16-vue-composition-api-flow.md b/javascript/ql/lib/change-notes/2026-07-16-vue-composition-api-flow.md deleted file mode 100644 index d03bebdb129d..000000000000 --- a/javascript/ql/lib/change-notes/2026-07-16-vue-composition-api-flow.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* Added flow models for Vue's `ref`, `shallowRef`, `toRef`, `reactive`, and `computed` Composition API helpers. diff --git a/javascript/ql/lib/change-notes/2026-07-16-vue-router-useRoute-query.md b/javascript/ql/lib/change-notes/2026-07-16-vue-router-useRoute-query.md index eeec2232f3e9..91f8d0a204d4 100644 --- a/javascript/ql/lib/change-notes/2026-07-16-vue-router-useRoute-query.md +++ b/javascript/ql/lib/change-notes/2026-07-16-vue-router-useRoute-query.md @@ -2,3 +2,4 @@ category: minorAnalysis --- * The query parameter of Vue Router's `useRoute()` Composition API is now recognized as a client-side remote flow source. +* Added flow models for Vue's `ref`, `shallowRef`, `toRef`, `reactive`, and `computed` Composition API helpers. From 0f8f88484778ebf96529826846f14cb968a07926 Mon Sep 17 00:00:00 2001 From: Adrien Pessu <7055334+adrienpessu@users.noreply.github.com> Date: Fri, 17 Jul 2026 15:27:48 +0200 Subject: [PATCH 014/188] Add Vue toRef value-flow and computed object-overload tests Make `toRef` value-preserving and model the `computed` object overload so `.value` flow is exercised for both `computed` API shapes. `computed` is moved into the `vue.model.yml` data extension because the object overload requires callback flow synthesis that a hand-written `SummarizedCallable` cannot provide. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5c95b651-1e79-499e-9e11-e09065b14aa9 --- javascript/ql/lib/ext/vue.model.yml | 9 ++++++++ .../lib/semmle/javascript/frameworks/Vue.qll | 23 ++++++++----------- .../frameworks/Vue/tests.expected | 3 +++ .../test/library-tests/frameworks/Vue/tst.js | 1 + 4 files changed, 23 insertions(+), 13 deletions(-) create mode 100644 javascript/ql/lib/ext/vue.model.yml diff --git a/javascript/ql/lib/ext/vue.model.yml b/javascript/ql/lib/ext/vue.model.yml new file mode 100644 index 000000000000..9ff24265a8d4 --- /dev/null +++ b/javascript/ql/lib/ext/vue.model.yml @@ -0,0 +1,9 @@ +extensions: + - addsTo: + pack: codeql/javascript-all + extensible: summaryModel + data: + # `computed(() => ...)` — function overload: the getter's return value flows to `.value`. + - ["vue", "Member[computed]", "Argument[0].ReturnValue", "ReturnValue.Member[value]", "value"] + # `computed({ get() { ... } })` — object overload: the `get` getter's return value flows to `.value`. + - ["vue", "Member[computed]", "Argument[0].Member[get].ReturnValue", "ReturnValue.Member[value]", "value"] diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Vue.qll b/javascript/ql/lib/semmle/javascript/frameworks/Vue.qll index 1edb53e814c5..35a66debf4f1 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Vue.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Vue.qll @@ -35,36 +35,33 @@ module Vue { result = any(GlobalVueEntryPoint e).getANode() } - /** Models data flow through Vue Composition API helpers. */ + /** + * Models data flow through Vue Composition API helpers. + * + * Note that `computed` is not modeled here but in the `vue.model.yml` data + * extension, because its object overload (`computed({ get() { ... } })`) + * requires callback flow synthesis that data extensions support but a + * hand-written `SummarizedCallable` does not. + */ overlay[local?] private class VueCompositionApiSummary extends DataFlow::SummarizedCallable::Range { string name; VueCompositionApiSummary() { - name = ["ref", "shallowRef", "toRef", "reactive", "computed"] and + name = ["ref", "shallowRef", "toRef", "reactive"] and this = "vue." + name } override predicate propagatesFlow(string input, string output, boolean preservesValue) { - name = ["ref", "shallowRef"] and + name = ["ref", "shallowRef", "toRef"] and input = "Argument[0]" and output = "ReturnValue.Member[value]" and preservesValue = true or - name = "toRef" and - input = "Argument[0]" and - output = "ReturnValue.Member[value]" and - preservesValue = false - or name = "reactive" and input = "Argument[0]" and output = "ReturnValue" and preservesValue = false - or - name = "computed" and - input = "Argument[0].ReturnValue" and - output = "ReturnValue.Member[value]" and - preservesValue = true } override DataFlow::InvokeNode getACall() { diff --git a/javascript/ql/test/library-tests/frameworks/Vue/tests.expected b/javascript/ql/test/library-tests/frameworks/Vue/tests.expected index ffa220d5dc8e..01ff68751781 100644 --- a/javascript/ql/test/library-tests/frameworks/Vue/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/Vue/tests.expected @@ -251,10 +251,13 @@ threatModelSource compositionApiDataFlow | tst.js:119:14:119:26 | source("ref") | tst.js:119:6:119:33 | Vue.ref ... ).value | | tst.js:120:21:120:40 | source("shallowRef") | tst.js:120:6:120:47 | Vue.sha ... ).value | +| tst.js:121:16:121:30 | source("toRef") | tst.js:121:6:121:37 | Vue.toR ... ).value | | tst.js:123:25:123:42 | source("computed") | tst.js:123:6:123:49 | Vue.com ... ).value | +| tst.js:124:36:124:59 | source( ... bject") | tst.js:124:6:124:82 | Vue.com ... ).value | compositionApiTaintFlow | tst.js:119:14:119:26 | source("ref") | tst.js:119:6:119:33 | Vue.ref ... ).value | | tst.js:120:21:120:40 | source("shallowRef") | tst.js:120:6:120:47 | Vue.sha ... ).value | | tst.js:121:16:121:30 | source("toRef") | tst.js:121:6:121:37 | Vue.toR ... ).value | | tst.js:122:19:122:36 | source("reactive") | tst.js:122:6:122:37 | Vue.rea ... tive")) | | tst.js:123:25:123:42 | source("computed") | tst.js:123:6:123:49 | Vue.com ... ).value | +| tst.js:124:36:124:59 | source( ... bject") | tst.js:124:6:124:82 | Vue.com ... ).value | diff --git a/javascript/ql/test/library-tests/frameworks/Vue/tst.js b/javascript/ql/test/library-tests/frameworks/Vue/tst.js index 64c14a291194..d402668c2e1d 100644 --- a/javascript/ql/test/library-tests/frameworks/Vue/tst.js +++ b/javascript/ql/test/library-tests/frameworks/Vue/tst.js @@ -121,3 +121,4 @@ sink(Vue.shallowRef(source("shallowRef")).value); sink(Vue.toRef(source("toRef")).value); sink(Vue.reactive(source("reactive"))); sink(Vue.computed(() => source("computed")).value); +sink(Vue.computed({ get() { return source("computedObject"); }, set(v) {} }).value); From bebb9f5a67f8d4a92e968c9802c277347acac671 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 21 Jul 2026 09:02:28 +0100 Subject: [PATCH 015/188] Rust: Test spacing. --- .../strings/inline-taint-flow.expected | 254 +++++++++--------- .../library-tests/dataflow/strings/main.rs | 7 + 2 files changed, 134 insertions(+), 127 deletions(-) diff --git a/rust/ql/test/library-tests/dataflow/strings/inline-taint-flow.expected b/rust/ql/test/library-tests/dataflow/strings/inline-taint-flow.expected index 859ab8e116e8..638ac1bb9737 100644 --- a/rust/ql/test/library-tests/dataflow/strings/inline-taint-flow.expected +++ b/rust/ql/test/library-tests/dataflow/strings/inline-taint-flow.expected @@ -8,134 +8,134 @@ models | 7 | Summary: alloc::fmt::format; Argument[0]; ReturnValue; taint | | 8 | Summary: core::hint::must_use; Argument[0]; ReturnValue; value | edges -| main.rs:26:9:26:9 | s | main.rs:27:19:27:19 | s | provenance | | -| main.rs:26:9:26:9 | s | main.rs:27:19:27:25 | s[...] | provenance | | -| main.rs:26:13:26:22 | source(...) | main.rs:26:9:26:9 | s | provenance | | -| main.rs:27:9:27:14 | sliced [&ref] | main.rs:28:16:28:21 | sliced | provenance | | -| main.rs:27:18:27:25 | &... [&ref] | main.rs:27:9:27:14 | sliced [&ref] | provenance | | -| main.rs:27:19:27:19 | s | main.rs:27:19:27:25 | s[...] | provenance | MaD:2 | -| main.rs:27:19:27:25 | s[...] | main.rs:27:18:27:25 | &... [&ref] | provenance | | -| main.rs:32:9:32:10 | s1 | main.rs:35:14:35:15 | s1 | provenance | | -| main.rs:32:14:32:23 | source(...) | main.rs:32:9:32:10 | s1 | provenance | | -| main.rs:35:9:35:10 | s4 | main.rs:38:10:38:11 | s4 | provenance | | -| main.rs:35:14:35:15 | s1 | main.rs:35:14:35:20 | ... + ... | provenance | MaD:5 | -| main.rs:35:14:35:20 | ... + ... | main.rs:35:9:35:10 | s4 | provenance | | -| main.rs:43:9:43:10 | s1 | main.rs:46:34:46:35 | s1 | provenance | | -| main.rs:43:14:43:23 | source(...) | main.rs:43:9:43:10 | s1 | provenance | | -| main.rs:46:33:46:35 | &s1 [&ref] | main.rs:46:10:46:35 | ... + ... | provenance | MaD:4 | -| main.rs:46:34:46:35 | s1 | main.rs:46:33:46:35 | &s1 [&ref] | provenance | | -| main.rs:51:9:51:10 | s1 | main.rs:52:27:52:28 | s1 | provenance | | -| main.rs:51:14:51:29 | source_slice(...) | main.rs:51:9:51:10 | s1 | provenance | | -| main.rs:52:9:52:10 | s2 | main.rs:53:10:53:11 | s2 | provenance | | -| main.rs:52:14:52:29 | ...::from(...) | main.rs:52:9:52:10 | s2 | provenance | | -| main.rs:52:27:52:28 | s1 | main.rs:52:14:52:29 | ...::from(...) | provenance | MaD:3 | -| main.rs:57:9:57:10 | s1 | main.rs:58:14:58:15 | s1 | provenance | | -| main.rs:57:14:57:29 | source_slice(...) | main.rs:57:9:57:10 | s1 | provenance | | -| main.rs:58:9:58:10 | s2 | main.rs:59:10:59:11 | s2 | provenance | | -| main.rs:58:14:58:15 | s1 | main.rs:58:14:58:27 | s1.to_string() | provenance | MaD:1 | -| main.rs:58:14:58:27 | s1.to_string() | main.rs:58:9:58:10 | s2 | provenance | | -| main.rs:63:9:63:9 | s | main.rs:64:16:64:16 | s | provenance | | -| main.rs:63:13:63:22 | source(...) | main.rs:63:9:63:9 | s | provenance | | -| main.rs:64:16:64:16 | s | main.rs:64:16:64:25 | s.as_str() | provenance | MaD:6 | -| main.rs:68:9:68:9 | s | main.rs:70:34:70:61 | MacroExpr | provenance | | -| main.rs:68:9:68:9 | s | main.rs:73:34:73:59 | MacroExpr | provenance | | -| main.rs:68:13:68:22 | source(...) | main.rs:68:9:68:9 | s | provenance | | -| main.rs:70:9:70:18 | formatted1 | main.rs:71:10:71:19 | formatted1 | provenance | | -| main.rs:70:22:70:62 | ...::format(...) | main.rs:70:9:70:18 | formatted1 | provenance | | -| main.rs:70:34:70:61 | MacroExpr | main.rs:70:22:70:62 | ...::format(...) | provenance | MaD:7 | -| main.rs:73:9:73:18 | formatted2 | main.rs:74:10:74:19 | formatted2 | provenance | | -| main.rs:73:22:73:60 | ...::format(...) | main.rs:73:9:73:18 | formatted2 | provenance | | -| main.rs:73:34:73:59 | MacroExpr | main.rs:73:22:73:60 | ...::format(...) | provenance | MaD:7 | -| main.rs:76:9:76:13 | width | main.rs:77:34:77:74 | MacroExpr | provenance | | -| main.rs:76:17:76:32 | source_usize(...) | main.rs:76:9:76:13 | width | provenance | | -| main.rs:77:9:77:18 | formatted3 | main.rs:78:10:78:19 | formatted3 | provenance | | -| main.rs:77:22:77:75 | ...::format(...) | main.rs:77:9:77:18 | formatted3 | provenance | | -| main.rs:77:34:77:74 | MacroExpr | main.rs:77:22:77:75 | ...::format(...) | provenance | MaD:7 | -| main.rs:82:9:82:10 | s1 | main.rs:86:18:86:25 | MacroExpr | provenance | | -| main.rs:82:9:82:10 | s1 | main.rs:87:18:87:32 | MacroExpr | provenance | | -| main.rs:82:14:82:23 | source(...) | main.rs:82:9:82:10 | s1 | provenance | | -| main.rs:86:18:86:25 | ...::format(...) | main.rs:86:18:86:25 | { ... } | provenance | | -| main.rs:86:18:86:25 | ...::must_use(...) | main.rs:86:10:86:26 | MacroExpr | provenance | | -| main.rs:86:18:86:25 | MacroExpr | main.rs:86:18:86:25 | ...::format(...) | provenance | MaD:7 | -| main.rs:86:18:86:25 | { ... } | main.rs:86:18:86:25 | ...::must_use(...) | provenance | MaD:8 | -| main.rs:87:18:87:32 | ...::format(...) | main.rs:87:18:87:32 | { ... } | provenance | | -| main.rs:87:18:87:32 | ...::must_use(...) | main.rs:87:10:87:33 | MacroExpr | provenance | | -| main.rs:87:18:87:32 | MacroExpr | main.rs:87:18:87:32 | ...::format(...) | provenance | MaD:7 | -| main.rs:87:18:87:32 | { ... } | main.rs:87:18:87:32 | ...::must_use(...) | provenance | MaD:8 | +| main.rs:27:9:27:9 | s | main.rs:28:19:28:19 | s | provenance | | +| main.rs:27:9:27:9 | s | main.rs:28:19:28:25 | s[...] | provenance | | +| main.rs:27:13:27:22 | source(...) | main.rs:27:9:27:9 | s | provenance | | +| main.rs:28:9:28:14 | sliced [&ref] | main.rs:29:16:29:21 | sliced | provenance | | +| main.rs:28:18:28:25 | &... [&ref] | main.rs:28:9:28:14 | sliced [&ref] | provenance | | +| main.rs:28:19:28:19 | s | main.rs:28:19:28:25 | s[...] | provenance | MaD:2 | +| main.rs:28:19:28:25 | s[...] | main.rs:28:18:28:25 | &... [&ref] | provenance | | +| main.rs:33:9:33:10 | s1 | main.rs:36:14:36:15 | s1 | provenance | | +| main.rs:33:14:33:23 | source(...) | main.rs:33:9:33:10 | s1 | provenance | | +| main.rs:36:9:36:10 | s4 | main.rs:39:10:39:11 | s4 | provenance | | +| main.rs:36:14:36:15 | s1 | main.rs:36:14:36:20 | ... + ... | provenance | MaD:5 | +| main.rs:36:14:36:20 | ... + ... | main.rs:36:9:36:10 | s4 | provenance | | +| main.rs:44:9:44:10 | s1 | main.rs:47:34:47:35 | s1 | provenance | | +| main.rs:44:14:44:23 | source(...) | main.rs:44:9:44:10 | s1 | provenance | | +| main.rs:47:33:47:35 | &s1 [&ref] | main.rs:47:10:47:35 | ... + ... | provenance | MaD:4 | +| main.rs:47:34:47:35 | s1 | main.rs:47:33:47:35 | &s1 [&ref] | provenance | | +| main.rs:52:9:52:10 | s1 | main.rs:53:27:53:28 | s1 | provenance | | +| main.rs:52:14:52:29 | source_slice(...) | main.rs:52:9:52:10 | s1 | provenance | | +| main.rs:53:9:53:10 | s2 | main.rs:54:10:54:11 | s2 | provenance | | +| main.rs:53:14:53:29 | ...::from(...) | main.rs:53:9:53:10 | s2 | provenance | | +| main.rs:53:27:53:28 | s1 | main.rs:53:14:53:29 | ...::from(...) | provenance | MaD:3 | +| main.rs:58:9:58:10 | s1 | main.rs:59:14:59:15 | s1 | provenance | | +| main.rs:58:14:58:29 | source_slice(...) | main.rs:58:9:58:10 | s1 | provenance | | +| main.rs:59:9:59:10 | s2 | main.rs:60:10:60:11 | s2 | provenance | | +| main.rs:59:14:59:15 | s1 | main.rs:59:14:59:27 | s1.to_string() | provenance | MaD:1 | +| main.rs:59:14:59:27 | s1.to_string() | main.rs:59:9:59:10 | s2 | provenance | | +| main.rs:64:9:64:9 | s | main.rs:65:16:65:16 | s | provenance | | +| main.rs:64:13:64:22 | source(...) | main.rs:64:9:64:9 | s | provenance | | +| main.rs:65:16:65:16 | s | main.rs:65:16:65:25 | s.as_str() | provenance | MaD:6 | +| main.rs:69:9:69:9 | s | main.rs:71:34:71:61 | MacroExpr | provenance | | +| main.rs:69:9:69:9 | s | main.rs:74:34:74:59 | MacroExpr | provenance | | +| main.rs:69:13:69:22 | source(...) | main.rs:69:9:69:9 | s | provenance | | +| main.rs:71:9:71:18 | formatted1 | main.rs:72:10:72:19 | formatted1 | provenance | | +| main.rs:71:22:71:62 | ...::format(...) | main.rs:71:9:71:18 | formatted1 | provenance | | +| main.rs:71:34:71:61 | MacroExpr | main.rs:71:22:71:62 | ...::format(...) | provenance | MaD:7 | +| main.rs:74:9:74:18 | formatted2 | main.rs:75:10:75:19 | formatted2 | provenance | | +| main.rs:74:22:74:60 | ...::format(...) | main.rs:74:9:74:18 | formatted2 | provenance | | +| main.rs:74:34:74:59 | MacroExpr | main.rs:74:22:74:60 | ...::format(...) | provenance | MaD:7 | +| main.rs:77:9:77:13 | width | main.rs:78:34:78:74 | MacroExpr | provenance | | +| main.rs:77:17:77:32 | source_usize(...) | main.rs:77:9:77:13 | width | provenance | | +| main.rs:78:9:78:18 | formatted3 | main.rs:79:10:79:19 | formatted3 | provenance | | +| main.rs:78:22:78:75 | ...::format(...) | main.rs:78:9:78:18 | formatted3 | provenance | | +| main.rs:78:34:78:74 | MacroExpr | main.rs:78:22:78:75 | ...::format(...) | provenance | MaD:7 | +| main.rs:89:9:89:10 | s1 | main.rs:93:18:93:25 | MacroExpr | provenance | | +| main.rs:89:9:89:10 | s1 | main.rs:94:18:94:32 | MacroExpr | provenance | | +| main.rs:89:14:89:23 | source(...) | main.rs:89:9:89:10 | s1 | provenance | | +| main.rs:93:18:93:25 | ...::format(...) | main.rs:93:18:93:25 | { ... } | provenance | | +| main.rs:93:18:93:25 | ...::must_use(...) | main.rs:93:10:93:26 | MacroExpr | provenance | | +| main.rs:93:18:93:25 | MacroExpr | main.rs:93:18:93:25 | ...::format(...) | provenance | MaD:7 | +| main.rs:93:18:93:25 | { ... } | main.rs:93:18:93:25 | ...::must_use(...) | provenance | MaD:8 | +| main.rs:94:18:94:32 | ...::format(...) | main.rs:94:18:94:32 | { ... } | provenance | | +| main.rs:94:18:94:32 | ...::must_use(...) | main.rs:94:10:94:33 | MacroExpr | provenance | | +| main.rs:94:18:94:32 | MacroExpr | main.rs:94:18:94:32 | ...::format(...) | provenance | MaD:7 | +| main.rs:94:18:94:32 | { ... } | main.rs:94:18:94:32 | ...::must_use(...) | provenance | MaD:8 | nodes -| main.rs:26:9:26:9 | s | semmle.label | s | -| main.rs:26:13:26:22 | source(...) | semmle.label | source(...) | -| main.rs:27:9:27:14 | sliced [&ref] | semmle.label | sliced [&ref] | -| main.rs:27:18:27:25 | &... [&ref] | semmle.label | &... [&ref] | -| main.rs:27:19:27:19 | s | semmle.label | s | -| main.rs:27:19:27:25 | s[...] | semmle.label | s[...] | -| main.rs:28:16:28:21 | sliced | semmle.label | sliced | -| main.rs:32:9:32:10 | s1 | semmle.label | s1 | -| main.rs:32:14:32:23 | source(...) | semmle.label | source(...) | -| main.rs:35:9:35:10 | s4 | semmle.label | s4 | -| main.rs:35:14:35:15 | s1 | semmle.label | s1 | -| main.rs:35:14:35:20 | ... + ... | semmle.label | ... + ... | -| main.rs:38:10:38:11 | s4 | semmle.label | s4 | -| main.rs:43:9:43:10 | s1 | semmle.label | s1 | -| main.rs:43:14:43:23 | source(...) | semmle.label | source(...) | -| main.rs:46:10:46:35 | ... + ... | semmle.label | ... + ... | -| main.rs:46:33:46:35 | &s1 [&ref] | semmle.label | &s1 [&ref] | -| main.rs:46:34:46:35 | s1 | semmle.label | s1 | -| main.rs:51:9:51:10 | s1 | semmle.label | s1 | -| main.rs:51:14:51:29 | source_slice(...) | semmle.label | source_slice(...) | -| main.rs:52:9:52:10 | s2 | semmle.label | s2 | -| main.rs:52:14:52:29 | ...::from(...) | semmle.label | ...::from(...) | -| main.rs:52:27:52:28 | s1 | semmle.label | s1 | -| main.rs:53:10:53:11 | s2 | semmle.label | s2 | -| main.rs:57:9:57:10 | s1 | semmle.label | s1 | -| main.rs:57:14:57:29 | source_slice(...) | semmle.label | source_slice(...) | -| main.rs:58:9:58:10 | s2 | semmle.label | s2 | -| main.rs:58:14:58:15 | s1 | semmle.label | s1 | -| main.rs:58:14:58:27 | s1.to_string() | semmle.label | s1.to_string() | -| main.rs:59:10:59:11 | s2 | semmle.label | s2 | -| main.rs:63:9:63:9 | s | semmle.label | s | -| main.rs:63:13:63:22 | source(...) | semmle.label | source(...) | -| main.rs:64:16:64:16 | s | semmle.label | s | -| main.rs:64:16:64:25 | s.as_str() | semmle.label | s.as_str() | -| main.rs:68:9:68:9 | s | semmle.label | s | -| main.rs:68:13:68:22 | source(...) | semmle.label | source(...) | -| main.rs:70:9:70:18 | formatted1 | semmle.label | formatted1 | -| main.rs:70:22:70:62 | ...::format(...) | semmle.label | ...::format(...) | -| main.rs:70:34:70:61 | MacroExpr | semmle.label | MacroExpr | -| main.rs:71:10:71:19 | formatted1 | semmle.label | formatted1 | -| main.rs:73:9:73:18 | formatted2 | semmle.label | formatted2 | -| main.rs:73:22:73:60 | ...::format(...) | semmle.label | ...::format(...) | -| main.rs:73:34:73:59 | MacroExpr | semmle.label | MacroExpr | -| main.rs:74:10:74:19 | formatted2 | semmle.label | formatted2 | -| main.rs:76:9:76:13 | width | semmle.label | width | -| main.rs:76:17:76:32 | source_usize(...) | semmle.label | source_usize(...) | -| main.rs:77:9:77:18 | formatted3 | semmle.label | formatted3 | -| main.rs:77:22:77:75 | ...::format(...) | semmle.label | ...::format(...) | -| main.rs:77:34:77:74 | MacroExpr | semmle.label | MacroExpr | -| main.rs:78:10:78:19 | formatted3 | semmle.label | formatted3 | -| main.rs:82:9:82:10 | s1 | semmle.label | s1 | -| main.rs:82:14:82:23 | source(...) | semmle.label | source(...) | -| main.rs:86:10:86:26 | MacroExpr | semmle.label | MacroExpr | -| main.rs:86:18:86:25 | ...::format(...) | semmle.label | ...::format(...) | -| main.rs:86:18:86:25 | ...::must_use(...) | semmle.label | ...::must_use(...) | -| main.rs:86:18:86:25 | MacroExpr | semmle.label | MacroExpr | -| main.rs:86:18:86:25 | { ... } | semmle.label | { ... } | -| main.rs:87:10:87:33 | MacroExpr | semmle.label | MacroExpr | -| main.rs:87:18:87:32 | ...::format(...) | semmle.label | ...::format(...) | -| main.rs:87:18:87:32 | ...::must_use(...) | semmle.label | ...::must_use(...) | -| main.rs:87:18:87:32 | MacroExpr | semmle.label | MacroExpr | -| main.rs:87:18:87:32 | { ... } | semmle.label | { ... } | +| main.rs:27:9:27:9 | s | semmle.label | s | +| main.rs:27:13:27:22 | source(...) | semmle.label | source(...) | +| main.rs:28:9:28:14 | sliced [&ref] | semmle.label | sliced [&ref] | +| main.rs:28:18:28:25 | &... [&ref] | semmle.label | &... [&ref] | +| main.rs:28:19:28:19 | s | semmle.label | s | +| main.rs:28:19:28:25 | s[...] | semmle.label | s[...] | +| main.rs:29:16:29:21 | sliced | semmle.label | sliced | +| main.rs:33:9:33:10 | s1 | semmle.label | s1 | +| main.rs:33:14:33:23 | source(...) | semmle.label | source(...) | +| main.rs:36:9:36:10 | s4 | semmle.label | s4 | +| main.rs:36:14:36:15 | s1 | semmle.label | s1 | +| main.rs:36:14:36:20 | ... + ... | semmle.label | ... + ... | +| main.rs:39:10:39:11 | s4 | semmle.label | s4 | +| main.rs:44:9:44:10 | s1 | semmle.label | s1 | +| main.rs:44:14:44:23 | source(...) | semmle.label | source(...) | +| main.rs:47:10:47:35 | ... + ... | semmle.label | ... + ... | +| main.rs:47:33:47:35 | &s1 [&ref] | semmle.label | &s1 [&ref] | +| main.rs:47:34:47:35 | s1 | semmle.label | s1 | +| main.rs:52:9:52:10 | s1 | semmle.label | s1 | +| main.rs:52:14:52:29 | source_slice(...) | semmle.label | source_slice(...) | +| main.rs:53:9:53:10 | s2 | semmle.label | s2 | +| main.rs:53:14:53:29 | ...::from(...) | semmle.label | ...::from(...) | +| main.rs:53:27:53:28 | s1 | semmle.label | s1 | +| main.rs:54:10:54:11 | s2 | semmle.label | s2 | +| main.rs:58:9:58:10 | s1 | semmle.label | s1 | +| main.rs:58:14:58:29 | source_slice(...) | semmle.label | source_slice(...) | +| main.rs:59:9:59:10 | s2 | semmle.label | s2 | +| main.rs:59:14:59:15 | s1 | semmle.label | s1 | +| main.rs:59:14:59:27 | s1.to_string() | semmle.label | s1.to_string() | +| main.rs:60:10:60:11 | s2 | semmle.label | s2 | +| main.rs:64:9:64:9 | s | semmle.label | s | +| main.rs:64:13:64:22 | source(...) | semmle.label | source(...) | +| main.rs:65:16:65:16 | s | semmle.label | s | +| main.rs:65:16:65:25 | s.as_str() | semmle.label | s.as_str() | +| main.rs:69:9:69:9 | s | semmle.label | s | +| main.rs:69:13:69:22 | source(...) | semmle.label | source(...) | +| main.rs:71:9:71:18 | formatted1 | semmle.label | formatted1 | +| main.rs:71:22:71:62 | ...::format(...) | semmle.label | ...::format(...) | +| main.rs:71:34:71:61 | MacroExpr | semmle.label | MacroExpr | +| main.rs:72:10:72:19 | formatted1 | semmle.label | formatted1 | +| main.rs:74:9:74:18 | formatted2 | semmle.label | formatted2 | +| main.rs:74:22:74:60 | ...::format(...) | semmle.label | ...::format(...) | +| main.rs:74:34:74:59 | MacroExpr | semmle.label | MacroExpr | +| main.rs:75:10:75:19 | formatted2 | semmle.label | formatted2 | +| main.rs:77:9:77:13 | width | semmle.label | width | +| main.rs:77:17:77:32 | source_usize(...) | semmle.label | source_usize(...) | +| main.rs:78:9:78:18 | formatted3 | semmle.label | formatted3 | +| main.rs:78:22:78:75 | ...::format(...) | semmle.label | ...::format(...) | +| main.rs:78:34:78:74 | MacroExpr | semmle.label | MacroExpr | +| main.rs:79:10:79:19 | formatted3 | semmle.label | formatted3 | +| main.rs:89:9:89:10 | s1 | semmle.label | s1 | +| main.rs:89:14:89:23 | source(...) | semmle.label | source(...) | +| main.rs:93:10:93:26 | MacroExpr | semmle.label | MacroExpr | +| main.rs:93:18:93:25 | ...::format(...) | semmle.label | ...::format(...) | +| main.rs:93:18:93:25 | ...::must_use(...) | semmle.label | ...::must_use(...) | +| main.rs:93:18:93:25 | MacroExpr | semmle.label | MacroExpr | +| main.rs:93:18:93:25 | { ... } | semmle.label | { ... } | +| main.rs:94:10:94:33 | MacroExpr | semmle.label | MacroExpr | +| main.rs:94:18:94:32 | ...::format(...) | semmle.label | ...::format(...) | +| main.rs:94:18:94:32 | ...::must_use(...) | semmle.label | ...::must_use(...) | +| main.rs:94:18:94:32 | MacroExpr | semmle.label | MacroExpr | +| main.rs:94:18:94:32 | { ... } | semmle.label | { ... } | subpaths testFailures #select -| main.rs:28:16:28:21 | sliced | main.rs:26:13:26:22 | source(...) | main.rs:28:16:28:21 | sliced | $@ | main.rs:26:13:26:22 | source(...) | source(...) | -| main.rs:38:10:38:11 | s4 | main.rs:32:14:32:23 | source(...) | main.rs:38:10:38:11 | s4 | $@ | main.rs:32:14:32:23 | source(...) | source(...) | -| main.rs:46:10:46:35 | ... + ... | main.rs:43:14:43:23 | source(...) | main.rs:46:10:46:35 | ... + ... | $@ | main.rs:43:14:43:23 | source(...) | source(...) | -| main.rs:53:10:53:11 | s2 | main.rs:51:14:51:29 | source_slice(...) | main.rs:53:10:53:11 | s2 | $@ | main.rs:51:14:51:29 | source_slice(...) | source_slice(...) | -| main.rs:59:10:59:11 | s2 | main.rs:57:14:57:29 | source_slice(...) | main.rs:59:10:59:11 | s2 | $@ | main.rs:57:14:57:29 | source_slice(...) | source_slice(...) | -| main.rs:64:16:64:25 | s.as_str() | main.rs:63:13:63:22 | source(...) | main.rs:64:16:64:25 | s.as_str() | $@ | main.rs:63:13:63:22 | source(...) | source(...) | -| main.rs:71:10:71:19 | formatted1 | main.rs:68:13:68:22 | source(...) | main.rs:71:10:71:19 | formatted1 | $@ | main.rs:68:13:68:22 | source(...) | source(...) | -| main.rs:74:10:74:19 | formatted2 | main.rs:68:13:68:22 | source(...) | main.rs:74:10:74:19 | formatted2 | $@ | main.rs:68:13:68:22 | source(...) | source(...) | -| main.rs:78:10:78:19 | formatted3 | main.rs:76:17:76:32 | source_usize(...) | main.rs:78:10:78:19 | formatted3 | $@ | main.rs:76:17:76:32 | source_usize(...) | source_usize(...) | -| main.rs:86:10:86:26 | MacroExpr | main.rs:82:14:82:23 | source(...) | main.rs:86:10:86:26 | MacroExpr | $@ | main.rs:82:14:82:23 | source(...) | source(...) | -| main.rs:87:10:87:33 | MacroExpr | main.rs:82:14:82:23 | source(...) | main.rs:87:10:87:33 | MacroExpr | $@ | main.rs:82:14:82:23 | source(...) | source(...) | +| main.rs:29:16:29:21 | sliced | main.rs:27:13:27:22 | source(...) | main.rs:29:16:29:21 | sliced | $@ | main.rs:27:13:27:22 | source(...) | source(...) | +| main.rs:39:10:39:11 | s4 | main.rs:33:14:33:23 | source(...) | main.rs:39:10:39:11 | s4 | $@ | main.rs:33:14:33:23 | source(...) | source(...) | +| main.rs:47:10:47:35 | ... + ... | main.rs:44:14:44:23 | source(...) | main.rs:47:10:47:35 | ... + ... | $@ | main.rs:44:14:44:23 | source(...) | source(...) | +| main.rs:54:10:54:11 | s2 | main.rs:52:14:52:29 | source_slice(...) | main.rs:54:10:54:11 | s2 | $@ | main.rs:52:14:52:29 | source_slice(...) | source_slice(...) | +| main.rs:60:10:60:11 | s2 | main.rs:58:14:58:29 | source_slice(...) | main.rs:60:10:60:11 | s2 | $@ | main.rs:58:14:58:29 | source_slice(...) | source_slice(...) | +| main.rs:65:16:65:25 | s.as_str() | main.rs:64:13:64:22 | source(...) | main.rs:65:16:65:25 | s.as_str() | $@ | main.rs:64:13:64:22 | source(...) | source(...) | +| main.rs:72:10:72:19 | formatted1 | main.rs:69:13:69:22 | source(...) | main.rs:72:10:72:19 | formatted1 | $@ | main.rs:69:13:69:22 | source(...) | source(...) | +| main.rs:75:10:75:19 | formatted2 | main.rs:69:13:69:22 | source(...) | main.rs:75:10:75:19 | formatted2 | $@ | main.rs:69:13:69:22 | source(...) | source(...) | +| main.rs:79:10:79:19 | formatted3 | main.rs:77:17:77:32 | source_usize(...) | main.rs:79:10:79:19 | formatted3 | $@ | main.rs:77:17:77:32 | source_usize(...) | source_usize(...) | +| main.rs:93:10:93:26 | MacroExpr | main.rs:89:14:89:23 | source(...) | main.rs:93:10:93:26 | MacroExpr | $@ | main.rs:89:14:89:23 | source(...) | source(...) | +| main.rs:94:10:94:33 | MacroExpr | main.rs:89:14:89:23 | source(...) | main.rs:94:10:94:33 | MacroExpr | $@ | main.rs:89:14:89:23 | source(...) | source(...) | diff --git a/rust/ql/test/library-tests/dataflow/strings/main.rs b/rust/ql/test/library-tests/dataflow/strings/main.rs index 0afcc290e568..9b53e1ea72c5 100644 --- a/rust/ql/test/library-tests/dataflow/strings/main.rs +++ b/rust/ql/test/library-tests/dataflow/strings/main.rs @@ -1,5 +1,6 @@ use std::fmt; + // Taint tests for strings fn source(i: i64) -> String { @@ -76,6 +77,12 @@ fn format_args_built_in() { let width = source_usize(10); let formatted3 = fmt::format(format_args!("Hello {:width$}!", "World")); sink(formatted3); // $ hasTaintFlow=10 + + + + + + } fn format_macro() { From 6a137d8d6c4e87afd363dde1e885bace70898ff9 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 21 Jul 2026 09:07:03 +0100 Subject: [PATCH 016/188] Rust: Test direct calls to std::fmt::format and alloc::fmt::format. --- .../strings/inline-taint-flow.expected | 18 ++++++++++++++++++ .../library-tests/dataflow/strings/main.rs | 10 +++++----- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/rust/ql/test/library-tests/dataflow/strings/inline-taint-flow.expected b/rust/ql/test/library-tests/dataflow/strings/inline-taint-flow.expected index 638ac1bb9737..4f8a04f22ab3 100644 --- a/rust/ql/test/library-tests/dataflow/strings/inline-taint-flow.expected +++ b/rust/ql/test/library-tests/dataflow/strings/inline-taint-flow.expected @@ -39,6 +39,8 @@ edges | main.rs:65:16:65:16 | s | main.rs:65:16:65:25 | s.as_str() | provenance | MaD:6 | | main.rs:69:9:69:9 | s | main.rs:71:34:71:61 | MacroExpr | provenance | | | main.rs:69:9:69:9 | s | main.rs:74:34:74:59 | MacroExpr | provenance | | +| main.rs:69:9:69:9 | s | main.rs:81:39:81:64 | MacroExpr | provenance | | +| main.rs:69:9:69:9 | s | main.rs:84:41:84:66 | MacroExpr | provenance | | | main.rs:69:13:69:22 | source(...) | main.rs:69:9:69:9 | s | provenance | | | main.rs:71:9:71:18 | formatted1 | main.rs:72:10:72:19 | formatted1 | provenance | | | main.rs:71:22:71:62 | ...::format(...) | main.rs:71:9:71:18 | formatted1 | provenance | | @@ -51,6 +53,12 @@ edges | main.rs:78:9:78:18 | formatted3 | main.rs:79:10:79:19 | formatted3 | provenance | | | main.rs:78:22:78:75 | ...::format(...) | main.rs:78:9:78:18 | formatted3 | provenance | | | main.rs:78:34:78:74 | MacroExpr | main.rs:78:22:78:75 | ...::format(...) | provenance | MaD:7 | +| main.rs:81:9:81:18 | formatted4 | main.rs:82:10:82:19 | formatted4 | provenance | | +| main.rs:81:22:81:65 | ...::format(...) | main.rs:81:9:81:18 | formatted4 | provenance | | +| main.rs:81:39:81:64 | MacroExpr | main.rs:81:22:81:65 | ...::format(...) | provenance | MaD:7 | +| main.rs:84:9:84:18 | formatted5 | main.rs:85:10:85:19 | formatted5 | provenance | | +| main.rs:84:22:84:67 | ...::format(...) | main.rs:84:9:84:18 | formatted5 | provenance | | +| main.rs:84:41:84:66 | MacroExpr | main.rs:84:22:84:67 | ...::format(...) | provenance | MaD:7 | | main.rs:89:9:89:10 | s1 | main.rs:93:18:93:25 | MacroExpr | provenance | | | main.rs:89:9:89:10 | s1 | main.rs:94:18:94:32 | MacroExpr | provenance | | | main.rs:89:14:89:23 | source(...) | main.rs:89:9:89:10 | s1 | provenance | | @@ -113,6 +121,14 @@ nodes | main.rs:78:22:78:75 | ...::format(...) | semmle.label | ...::format(...) | | main.rs:78:34:78:74 | MacroExpr | semmle.label | MacroExpr | | main.rs:79:10:79:19 | formatted3 | semmle.label | formatted3 | +| main.rs:81:9:81:18 | formatted4 | semmle.label | formatted4 | +| main.rs:81:22:81:65 | ...::format(...) | semmle.label | ...::format(...) | +| main.rs:81:39:81:64 | MacroExpr | semmle.label | MacroExpr | +| main.rs:82:10:82:19 | formatted4 | semmle.label | formatted4 | +| main.rs:84:9:84:18 | formatted5 | semmle.label | formatted5 | +| main.rs:84:22:84:67 | ...::format(...) | semmle.label | ...::format(...) | +| main.rs:84:41:84:66 | MacroExpr | semmle.label | MacroExpr | +| main.rs:85:10:85:19 | formatted5 | semmle.label | formatted5 | | main.rs:89:9:89:10 | s1 | semmle.label | s1 | | main.rs:89:14:89:23 | source(...) | semmle.label | source(...) | | main.rs:93:10:93:26 | MacroExpr | semmle.label | MacroExpr | @@ -137,5 +153,7 @@ testFailures | main.rs:72:10:72:19 | formatted1 | main.rs:69:13:69:22 | source(...) | main.rs:72:10:72:19 | formatted1 | $@ | main.rs:69:13:69:22 | source(...) | source(...) | | main.rs:75:10:75:19 | formatted2 | main.rs:69:13:69:22 | source(...) | main.rs:75:10:75:19 | formatted2 | $@ | main.rs:69:13:69:22 | source(...) | source(...) | | main.rs:79:10:79:19 | formatted3 | main.rs:77:17:77:32 | source_usize(...) | main.rs:79:10:79:19 | formatted3 | $@ | main.rs:77:17:77:32 | source_usize(...) | source_usize(...) | +| main.rs:82:10:82:19 | formatted4 | main.rs:69:13:69:22 | source(...) | main.rs:82:10:82:19 | formatted4 | $@ | main.rs:69:13:69:22 | source(...) | source(...) | +| main.rs:85:10:85:19 | formatted5 | main.rs:69:13:69:22 | source(...) | main.rs:85:10:85:19 | formatted5 | $@ | main.rs:69:13:69:22 | source(...) | source(...) | | main.rs:93:10:93:26 | MacroExpr | main.rs:89:14:89:23 | source(...) | main.rs:93:10:93:26 | MacroExpr | $@ | main.rs:89:14:89:23 | source(...) | source(...) | | main.rs:94:10:94:33 | MacroExpr | main.rs:89:14:89:23 | source(...) | main.rs:94:10:94:33 | MacroExpr | $@ | main.rs:89:14:89:23 | source(...) | source(...) | diff --git a/rust/ql/test/library-tests/dataflow/strings/main.rs b/rust/ql/test/library-tests/dataflow/strings/main.rs index 9b53e1ea72c5..12ee31663b82 100644 --- a/rust/ql/test/library-tests/dataflow/strings/main.rs +++ b/rust/ql/test/library-tests/dataflow/strings/main.rs @@ -1,5 +1,5 @@ use std::fmt; - +extern crate alloc; // Taint tests for strings @@ -78,11 +78,11 @@ fn format_args_built_in() { let formatted3 = fmt::format(format_args!("Hello {:width$}!", "World")); sink(formatted3); // $ hasTaintFlow=10 + let formatted4 = std::fmt::format(format_args!("Hello {s}!")); + sink(formatted4); // $ hasTaintFlow=88 - - - - + let formatted5 = alloc::fmt::format(format_args!("Hello {s}!")); + sink(formatted5); // $ hasTaintFlow=88 } fn format_macro() { From 661463d4433d0d3fc03121bab7167b7057fefdeb Mon Sep 17 00:00:00 2001 From: yoff Date: Mon, 20 Jul 2026 12:47:12 +0200 Subject: [PATCH 017/188] python: remove non-actionable change notes --- python/ql/lib/change-notes/2026-05-19-add-shared-cfg.md | 4 ---- .../lib/change-notes/2026-06-04-cfg-parameter-annotations.md | 4 ---- 2 files changed, 8 deletions(-) delete mode 100644 python/ql/lib/change-notes/2026-05-19-add-shared-cfg.md delete mode 100644 python/ql/lib/change-notes/2026-06-04-cfg-parameter-annotations.md diff --git a/python/ql/lib/change-notes/2026-05-19-add-shared-cfg.md b/python/ql/lib/change-notes/2026-05-19-add-shared-cfg.md deleted file mode 100644 index 913f95320d87..000000000000 --- a/python/ql/lib/change-notes/2026-05-19-add-shared-cfg.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* A new Python control flow graph implementation has been added under `semmle.python.controlflow.internal.Cfg` (backed by `AstNodeImpl.qll`), built on the shared `codeql.controlflow.ControlFlowGraph` library. It is not yet used by the dataflow library or any production query; the legacy CFG in `semmle/python/Flow.qll` remains the default. The new library is exposed for tests and for upcoming migrations. diff --git a/python/ql/lib/change-notes/2026-06-04-cfg-parameter-annotations.md b/python/ql/lib/change-notes/2026-06-04-cfg-parameter-annotations.md deleted file mode 100644 index 96ba81e1610e..000000000000 --- a/python/ql/lib/change-notes/2026-06-04-cfg-parameter-annotations.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* The new (shared-CFG-based) Python control flow graph now visits parameter and return type annotations as CFG nodes for function definitions, matching the legacy CFG. This restores annotation-based type tracking through framework models such as FastAPI's `Depends()`, Pydantic request models, Starlette `WebSocket` handlers, and any other models that flow a class reference through `Parameter.getAnnotation()` to identify instances of the annotated class. From cc0156d8ace667e96fa9679e3cd82ff3266149b0 Mon Sep 17 00:00:00 2001 From: yoff Date: Tue, 21 Jul 2026 11:56:03 +0200 Subject: [PATCH 018/188] python: remove the use of toAst - AST navigation such as `getObject` and `getChild` now only moves through nodes identified via `injects` - identification such as `isSubscript` only holds for injected nodes - subclasses such as `AttrNode` are injected nodes (no, say after-nodes) --- .../python/controlflow/internal/Cfg.qll | 321 +++++++----------- 1 file changed, 130 insertions(+), 191 deletions(-) diff --git a/python/ql/lib/semmle/python/controlflow/internal/Cfg.qll b/python/ql/lib/semmle/python/controlflow/internal/Cfg.qll index 2d39ae8450ed..ac8493f98ae9 100644 --- a/python/ql/lib/semmle/python/controlflow/internal/Cfg.qll +++ b/python/ql/lib/semmle/python/controlflow/internal/Cfg.qll @@ -39,17 +39,6 @@ module CfgForBb implements BB::CfgSig { predicate dominatingEdge = CfgImpl::Cfg::dominatingEdge/2; } -/** - * Gets the Python AST node corresponding to CFG node `n`, if any. - * - * Multiple CFG nodes may map to the same AST node (e.g. `TBeforeNode(Call)` - * and `TAstNode(Call)` both map to `Py::Call`). This is a pure translation; - * uniqueness constraints are enforced at the dataflow layer where needed. - */ -private Py::AstNode toAst(CfgImpl::ControlFlowNode n) { - result = CfgImpl::astNodeToPyNode(n.getAstNode()) -} - /** * A control flow node. * @@ -64,7 +53,11 @@ private Py::AstNode toAst(CfgImpl::ControlFlowNode n) { */ class ControlFlowNode extends CfgImpl::ControlFlowNode { /** Gets the syntactic element corresponding to this flow node, if any. */ - Py::AstNode getNode() { result = toAst(this) } + Py::AstNode getNode() { + exists(CfgImpl::Ast::AstNode n | this.injects(n) | result = CfgImpl::astNodeToPyNode(n)) + } + + Py::Expr asPyExpr() { result = this.getNode() } /** Gets a predecessor of this flow node. */ ControlFlowNode getAPredecessor() { this = result.getASuccessor() } @@ -145,18 +138,16 @@ class ControlFlowNode extends CfgImpl::ControlFlowNode { * which holds on the destination of compound and unary assignments * even though the destination is also a write. */ - predicate isLoad() { exists(Py::Expr e | e = toAst(this) | py_expr_contexts(_, 3, e)) } + predicate isLoad() { py_expr_contexts(_, 3, this.asPyExpr()) } /** Holds if this flow node is a store (including those in augmented assignments). */ - predicate isStore() { - exists(Py::Expr e | e = toAst(this) | py_expr_contexts(_, 5, e) or augstore(_, this)) - } + predicate isStore() { py_expr_contexts(_, 5, this.asPyExpr()) or augstore(_, this) } /** Holds if this flow node is a delete. */ - predicate isDelete() { exists(Py::Expr e | e = toAst(this) | py_expr_contexts(_, 2, e)) } + predicate isDelete() { py_expr_contexts(_, 2, this.asPyExpr()) } /** Holds if this flow node is a parameter. */ - predicate isParameter() { exists(Py::Expr e | e = toAst(this) | py_expr_contexts(_, 4, e)) } + predicate isParameter() { py_expr_contexts(_, 4, this.asPyExpr()) } /** Holds if this flow node is a store in an augmented assignment. */ predicate isAugStore() { augstore(_, this) } @@ -166,45 +157,45 @@ class ControlFlowNode extends CfgImpl::ControlFlowNode { /** Holds if this flow node corresponds to a literal. */ predicate isLiteral() { - toAst(this) instanceof Py::Bytes or - toAst(this) instanceof Py::Dict or - toAst(this) instanceof Py::DictComp or - toAst(this) instanceof Py::Set or - toAst(this) instanceof Py::SetComp or - toAst(this) instanceof Py::Ellipsis or - toAst(this) instanceof Py::GeneratorExp or - toAst(this) instanceof Py::Lambda or - toAst(this) instanceof Py::ListComp or - toAst(this) instanceof Py::List or - toAst(this) instanceof Py::Num or - toAst(this) instanceof Py::Tuple or - toAst(this) instanceof Py::Unicode or - toAst(this) instanceof Py::NameConstant + this.getNode() instanceof Py::Bytes or + this.getNode() instanceof Py::Dict or + this.getNode() instanceof Py::DictComp or + this.getNode() instanceof Py::Set or + this.getNode() instanceof Py::SetComp or + this.getNode() instanceof Py::Ellipsis or + this.getNode() instanceof Py::GeneratorExp or + this.getNode() instanceof Py::Lambda or + this.getNode() instanceof Py::ListComp or + this.getNode() instanceof Py::List or + this.getNode() instanceof Py::Num or + this.getNode() instanceof Py::Tuple or + this.getNode() instanceof Py::Unicode or + this.getNode() instanceof Py::NameConstant } /** Holds if this flow node corresponds to an attribute expression. */ - predicate isAttribute() { toAst(this) instanceof Py::Attribute } + predicate isAttribute() { this.getNode() instanceof Py::Attribute } /** Holds if this flow node corresponds to a subscript expression. */ - predicate isSubscript() { toAst(this) instanceof Py::Subscript } + predicate isSubscript() { this.getNode() instanceof Py::Subscript } /** Holds if this flow node corresponds to an import member. */ - predicate isImportMember() { toAst(this) instanceof Py::ImportMember } + predicate isImportMember() { this.getNode() instanceof Py::ImportMember } /** Holds if this flow node corresponds to a call. */ - predicate isCall() { toAst(this) instanceof Py::Call } + predicate isCall() { this.getNode() instanceof Py::Call } /** Holds if this flow node corresponds to an import. */ - predicate isImport() { toAst(this) instanceof Py::ImportExpr } + predicate isImport() { this.getNode() instanceof Py::ImportExpr } /** Holds if this flow node corresponds to a conditional expression. */ - predicate isIfExp() { toAst(this) instanceof Py::IfExp } + predicate isIfExp() { this.getNode() instanceof Py::IfExp } /** Holds if this flow node corresponds to a function definition expression. */ - predicate isFunction() { toAst(this) instanceof Py::FunctionExpr } + predicate isFunction() { this.getNode() instanceof Py::FunctionExpr } /** Holds if this flow node corresponds to a class definition expression. */ - predicate isClass() { toAst(this) instanceof Py::ClassExpr } + predicate isClass() { this.getNode() instanceof Py::ClassExpr } /** * Holds if this flow node is a branch (i.e. has both a true and a @@ -223,7 +214,7 @@ class ControlFlowNode extends CfgImpl::ControlFlowNode { */ pragma[nomagic] ControlFlowNode getAChild() { - toAst(this).(Py::Expr).getAChildNode() = toAst(result) and + this.getNode().(Py::Expr).getAChildNode() = result.getNode() and result.getBasicBlock().dominates(this.getBasicBlock()) and not this instanceof UnaryExprNode } @@ -247,7 +238,7 @@ class ControlFlowNode extends CfgImpl::ControlFlowNode { * target's canonical node. */ private predicate augstore(ControlFlowNode load, ControlFlowNode store) { - exists(Py::AugAssign aa | aa.getTarget() = toAst(load)) and + exists(Py::AugAssign aa | aa.getTarget() = load.getNode()) and load = store } @@ -402,9 +393,9 @@ ControlFlowNode astExprToCfg(Py::Expr e) { result.getNode() = e } /** A control flow node corresponding to a `Name` or `PlaceHolder` expression. */ class NameNode extends ControlFlowNode { NameNode() { - toAst(this) instanceof Py::Name + this.getNode() instanceof Py::Name or - toAst(this) instanceof Py::PlaceHolder + this.getNode() instanceof Py::PlaceHolder } /** @@ -416,26 +407,26 @@ class NameNode extends ControlFlowNode { * semantics where compound assignments register both a write * (`VarWrite`) and a read (`VarRead`) on the destination. */ - predicate defines(Py::Variable v) { exists(Py::Name n | n = toAst(this) and n.defines(v)) } + predicate defines(Py::Variable v) { exists(Py::Name n | n = this.getNode() and n.defines(v)) } /** Holds if this flow node deletes the variable `v`. */ - predicate deletes(Py::Variable v) { exists(Py::Name n | n = toAst(this) and n.deletes(v)) } + predicate deletes(Py::Variable v) { exists(Py::Name n | n = this.getNode() and n.deletes(v)) } /** Holds if this flow node uses the variable `v`. */ predicate uses(Py::Variable v) { this.isLoad() and - exists(Py::Name u | u = toAst(this) and u.uses(v)) + exists(Py::Name u | u = this.getNode() and u.uses(v)) or exists(Py::PlaceHolder u | - u = toAst(this) and u.getVariable() = v and u.getCtx() instanceof Py::Load + u = this.getNode() and u.getVariable() = v and u.getCtx() instanceof Py::Load ) } /** Gets the identifier of this name node. */ string getId() { - result = toAst(this).(Py::Name).getId() + result = this.getNode().(Py::Name).getId() or - result = toAst(this).(Py::PlaceHolder).getId() + result = this.getNode().(Py::PlaceHolder).getId() } /** Holds if this is a use of a local variable. */ @@ -469,42 +460,35 @@ class NameNode extends ControlFlowNode { /** A control flow node corresponding to a named constant (`None`, `True`, `False`). */ class NameConstantNode extends NameNode { - NameConstantNode() { toAst(this) instanceof Py::NameConstant } + NameConstantNode() { this.getNode() instanceof Py::NameConstant } } /** A control flow node corresponding to a call. */ class CallNode extends ControlFlowNode { - CallNode() { toAst(this) instanceof Py::Call } + CallNode() { super.getNode() instanceof Py::Call } override Py::Call getNode() { result = super.getNode() } /** Gets the underlying Python `Call`. */ - Py::Call getCall() { result = toAst(this) } + Py::Call getCall() { result = this.getNode() } /** Gets the flow node for the function component of this call. */ ControlFlowNode getFunction() { - exists(Py::Call c | - c = toAst(this) and - c.getFunc() = toAst(result) and - result.getBasicBlock().dominates(this.getBasicBlock()) - ) + this.getCall().getFunc() = result.getNode() and + result.getBasicBlock().dominates(this.getBasicBlock()) } /** Gets the flow node for the `n`th positional argument. */ ControlFlowNode getArg(int n) { - exists(Py::Call c | - c = toAst(this) and - c.getArg(n) = toAst(result) and - result.getBasicBlock().dominates(this.getBasicBlock()) - ) + this.getCall().getArg(n) = result.getNode() and + result.getBasicBlock().dominates(this.getBasicBlock()) } /** Gets the flow node for the named argument with name `name`. */ ControlFlowNode getArgByName(string name) { - exists(Py::Call c, Py::Keyword k | - c = toAst(this) and - k = c.getANamedArg() and - k.getValue() = toAst(result) and + exists(Py::Keyword k | + k = this.getCall().getANamedArg() and + k.getValue() = result.getNode() and k.getArg() = name and result.getBasicBlock().dominates(this.getBasicBlock()) ) @@ -515,20 +499,14 @@ class CallNode extends ControlFlowNode { /** Gets the first tuple (`*args`) argument, if any. */ ControlFlowNode getStarArg() { - exists(Py::Call c | - c = toAst(this) and - c.getStarArg() = toAst(result) and - result.getBasicBlock().dominates(this.getBasicBlock()) - ) + this.getCall().getStarArg() = result.getNode() and + result.getBasicBlock().dominates(this.getBasicBlock()) } /** Gets a dictionary (`**kwargs`) argument, if any. */ ControlFlowNode getKwargs() { - exists(Py::Call c | - c = toAst(this) and - c.getKwargs() = toAst(result) and - result.getBasicBlock().dominates(this.getBasicBlock()) - ) + this.getCall().getKwargs() = result.getNode() and + result.getBasicBlock().dominates(this.getBasicBlock()) } /** Holds if this call is a decorator call applied to a class or a function. */ @@ -536,62 +514,55 @@ class CallNode extends ControlFlowNode { /** Holds if this call is a decorator call applied to a class. */ predicate isClassDecoratorCall() { - exists(Py::ClassExpr cls | toAst(this) = cls.getADecoratorCall()) + exists(Py::ClassExpr cls | this.getNode() = cls.getADecoratorCall()) } /** Holds if this call is a decorator call applied to a function. */ predicate isFunctionDecoratorCall() { - exists(Py::FunctionExpr func | toAst(this) = func.getADecoratorCall()) + exists(Py::FunctionExpr func | this.getNode() = func.getADecoratorCall()) } } /** A control flow node corresponding to an attribute expression. */ class AttrNode extends ControlFlowNode { - AttrNode() { toAst(this) instanceof Py::Attribute } + AttrNode() { super.getNode() instanceof Py::Attribute } override Py::Attribute getNode() { result = super.getNode() } /** Gets the flow node for the object of the attribute expression. */ ControlFlowNode getObject() { - exists(Py::Attribute a | - a = toAst(this) and - a.getObject() = toAst(result) and - result.getBasicBlock().dominates(this.getBasicBlock()) - ) + this.getNode().getObject() = result.getNode() and + result.getBasicBlock().dominates(this.getBasicBlock()) } /** Gets the flow node for the object of this attribute expression, with the matching name. */ ControlFlowNode getObject(string name) { - exists(Py::Attribute a | - a = toAst(this) and - a.getObject() = toAst(result) and - a.getName() = name and - result.getBasicBlock().dominates(this.getBasicBlock()) - ) + this.getName() = name and + result = this.getObject() } /** Gets the attribute name. */ - string getName() { exists(Py::Attribute a | a = toAst(this) and a.getName() = result) } + string getName() { result = this.getNode().getName() } } /** A control flow node corresponding to an import statement (`import x`). */ class ImportExprNode extends ControlFlowNode { - ImportExprNode() { toAst(this) instanceof Py::ImportExpr } + ImportExprNode() { super.getNode() instanceof Py::ImportExpr } override Py::ImportExpr getNode() { result = super.getNode() } } /** A control flow node corresponding to a `from ... import name` expression. */ class ImportMemberNode extends ControlFlowNode { - ImportMemberNode() { toAst(this) instanceof Py::ImportMember } + ImportMemberNode() { super.getNode() instanceof Py::ImportMember } override Py::ImportMember getNode() { result = super.getNode() } /** Gets the flow node for the module being imported from, with the matching name. */ ControlFlowNode getModule(string name) { exists(Py::ImportMember i | - i = toAst(this) and - i.getModule() = toAst(result) and + i = this.getNode() and + i.getModule() = result.getNode() and i.getName() = name and result.getBasicBlock().dominates(this.getBasicBlock()) ) @@ -600,55 +571,46 @@ class ImportMemberNode extends ControlFlowNode { /** A control flow node corresponding to a `from ... import *` statement. */ class ImportStarNode extends ControlFlowNode { - ImportStarNode() { toAst(this) instanceof Py::ImportStar } + ImportStarNode() { super.getNode() instanceof Py::ImportStar } override Py::ImportStar getNode() { result = super.getNode() } /** Gets the flow node for the module being imported from. */ ControlFlowNode getModule() { - exists(Py::ImportStar i | - i = toAst(this) and - i.getModuleExpr() = toAst(result) and - result.getBasicBlock().dominates(this.getBasicBlock()) - ) + this.getNode().getModuleExpr() = result.getNode() and + result.getBasicBlock().dominates(this.getBasicBlock()) } } /** A control flow node corresponding to a subscript expression. */ class SubscriptNode extends ControlFlowNode { - SubscriptNode() { toAst(this) instanceof Py::Subscript } + SubscriptNode() { super.getNode() instanceof Py::Subscript } override Py::Subscript getNode() { result = super.getNode() } /** Gets the flow node for the value being subscripted. */ ControlFlowNode getObject() { - exists(Py::Subscript s | - s = toAst(this) and - s.getObject() = toAst(result) and - result.getBasicBlock().dominates(this.getBasicBlock()) - ) + this.getNode().getObject() = result.getNode() and + result.getBasicBlock().dominates(this.getBasicBlock()) } /** Gets the flow node for the index expression. */ ControlFlowNode getIndex() { - exists(Py::Subscript s | - s = toAst(this) and - s.getIndex() = toAst(result) and - result.getBasicBlock().dominates(this.getBasicBlock()) - ) + this.getNode().getIndex() = result.getNode() and + result.getBasicBlock().dominates(this.getBasicBlock()) } } /** A control flow node corresponding to a comparison operation. */ class CompareNode extends ControlFlowNode { - CompareNode() { toAst(this) instanceof Py::Compare } + CompareNode() { super.getNode() instanceof Py::Compare } override Py::Compare getNode() { result = super.getNode() } /** Holds if `left` and `right` are a pair of operands for this comparison. */ predicate operands(ControlFlowNode left, Py::Cmpop op, ControlFlowNode right) { exists(Py::Compare c, Py::Expr eleft, Py::Expr eright | - c = toAst(this) and eleft = toAst(left) and eright = toAst(right) + c = this.getNode() and eleft = left.getNode() and eright = right.getNode() | eleft = c.getLeft() and eright = c.getComparator(0) and op = c.getOp(0) or @@ -663,67 +625,55 @@ class CompareNode extends ControlFlowNode { /** A control flow node corresponding to a conditional expression (`x if c else y`). */ class IfExprNode extends ControlFlowNode { - IfExprNode() { toAst(this) instanceof Py::IfExp } + IfExprNode() { super.getNode() instanceof Py::IfExp } override Py::IfExp getNode() { result = super.getNode() } /** Gets the flow node for one of the value operands (true-branch or false-branch). */ ControlFlowNode getAnOperand() { exists(Py::IfExp ie | - ie = toAst(this) and - (toAst(result) = ie.getBody() or toAst(result) = ie.getOrelse()) + ie = this.getNode() and + (result.getNode() = ie.getBody() or result.getNode() = ie.getOrelse()) ) } } /** A control flow node corresponding to an assignment expression (walrus `:=`). */ class AssignmentExprNode extends ControlFlowNode { - AssignmentExprNode() { toAst(this) instanceof Py::AssignExpr } + AssignmentExprNode() { super.getNode() instanceof Py::AssignExpr } override Py::AssignExpr getNode() { result = super.getNode() } /** Gets the flow node for the left-hand side. */ ControlFlowNode getTarget() { - exists(Py::AssignExpr a | - a = toAst(this) and - a.getTarget() = toAst(result) and - result.getBasicBlock().dominates(this.getBasicBlock()) - ) + this.getNode().getTarget() = result.getNode() and + result.getBasicBlock().dominates(this.getBasicBlock()) } /** Gets the flow node for the right-hand side. */ ControlFlowNode getValue() { - exists(Py::AssignExpr a | - a = toAst(this) and - a.getValue() = toAst(result) and - result.getBasicBlock().dominates(this.getBasicBlock()) - ) + this.getNode().getValue() = result.getNode() and + result.getBasicBlock().dominates(this.getBasicBlock()) } } /** A control flow node corresponding to a binary expression (`a + b` etc.). */ class BinaryExprNode extends ControlFlowNode { - BinaryExprNode() { toAst(this) instanceof Py::BinaryExpr } + BinaryExprNode() { super.getNode() instanceof Py::BinaryExpr } override Py::BinaryExpr getNode() { result = super.getNode() } ControlFlowNode getLeft() { - exists(Py::BinaryExpr be | - be = toAst(this) and - be.getLeft() = toAst(result) and - result.getBasicBlock().dominates(this.getBasicBlock()) - ) + this.getNode().getLeft() = result.getNode() and + result.getBasicBlock().dominates(this.getBasicBlock()) } ControlFlowNode getRight() { - exists(Py::BinaryExpr be | - be = toAst(this) and - be.getRight() = toAst(result) and - result.getBasicBlock().dominates(this.getBasicBlock()) - ) + this.getNode().getRight() = result.getNode() and + result.getBasicBlock().dominates(this.getBasicBlock()) } - Py::Operator getOp() { result = toAst(this).(Py::BinaryExpr).getOp() } + Py::Operator getOp() { result = this.getNode().(Py::BinaryExpr).getOp() } /** Holds if `left` and `right` are the operands and `op` is the operator. */ predicate operands(ControlFlowNode left, Py::Operator op, ControlFlowNode right) { @@ -736,36 +686,28 @@ class BinaryExprNode extends ControlFlowNode { /** A control flow node corresponding to a boolean expression (`a and b`, `a or b`). */ class BoolExprNode extends ControlFlowNode { - BoolExprNode() { toAst(this) instanceof Py::BoolExpr } + BoolExprNode() { super.getNode() instanceof Py::BoolExpr } override Py::BoolExpr getNode() { result = super.getNode() } - Py::Boolop getOp() { result = toAst(this).(Py::BoolExpr).getOp() } + Py::Boolop getOp() { result = this.getNode().(Py::BoolExpr).getOp() } /** Gets any operand of this boolean expression. */ - ControlFlowNode getAnOperand() { - exists(Py::BoolExpr be | - be = toAst(this) and - be.getAValue() = toAst(result) - ) - } + ControlFlowNode getAnOperand() { this.getNode().getAValue() = result.getNode() } } /** A control flow node corresponding to a unary expression (`-x`, `not x`, etc.). */ class UnaryExprNode extends ControlFlowNode { - UnaryExprNode() { toAst(this) instanceof Py::UnaryExpr } + UnaryExprNode() { super.getNode() instanceof Py::UnaryExpr } override Py::UnaryExpr getNode() { result = super.getNode() } ControlFlowNode getOperand() { - exists(Py::UnaryExpr u | - u = toAst(this) and - u.getOperand() = toAst(result) and - result.getBasicBlock().dominates(this.getBasicBlock()) - ) + this.getNode().getOperand() = result.getNode() and + result.getBasicBlock().dominates(this.getBasicBlock()) } - Py::Unaryop getOp() { result = toAst(this).(Py::UnaryExpr).getOp() } + Py::Unaryop getOp() { result = this.getNode().(Py::UnaryExpr).getOp() } } /** @@ -783,12 +725,12 @@ class DefinitionNode extends ControlFlowNode { // is no AST node holding the result of `iter(next(seq))`; we use // the iter expression's CFG node as the stand-in. exists(Py::For f | - f.getTarget() = toAst(this) and - toAst(result) = f.getIter() + f.getTarget() = this.getNode() and + result.getNode() = f.getIter() ) or - exists(Py::AstNode value | value = assignedValue(toAst(this)) | - toAst(result) = value and + exists(Py::AstNode value | value = assignedValue(this.getNode()) | + result.getNode() = value and ( result.getBasicBlock().dominates(this.getBasicBlock()) or @@ -797,7 +739,7 @@ class DefinitionNode extends ControlFlowNode { // The default value for a parameter is evaluated in the same basic block as // the function definition, but the parameter belongs to the basic block of the // function, so there is no dominance relationship between the two. - exists(Py::Parameter param | toAst(this) = param.asName()) + exists(Py::Parameter param | this.getNode() = param.asName()) ) ) } @@ -857,7 +799,7 @@ class DeletionNode extends ControlFlowNode { /** A control flow node corresponding to a `for` loop target. */ class ForNode extends ControlFlowNode { - ForNode() { exists(Py::For f | toAst(this) = f.getIter()) } + ForNode() { exists(Py::For f | this.getNode() = f.getIter()) } /** Gets the iterable expression. */ ControlFlowNode getIter() { @@ -870,8 +812,8 @@ class ForNode extends ControlFlowNode { /** Gets the target (loop variable) of the `for` loop. */ ControlFlowNode getTarget() { exists(Py::For f | - f.getIter() = toAst(this) and - f.getTarget() = toAst(result) + f.getIter() = this.getNode() and + f.getTarget() = result.getNode() ) } @@ -883,29 +825,26 @@ class ForNode extends ControlFlowNode { /** A control flow node corresponding to a `raise` statement. */ class RaiseStmtNode extends ControlFlowNode { - RaiseStmtNode() { toAst(this) instanceof Py::Raise } + RaiseStmtNode() { super.getNode() instanceof Py::Raise } override Py::Raise getNode() { result = super.getNode() } /** Gets the exception expression, if any. */ ControlFlowNode getException() { - exists(Py::Raise r | - r = toAst(this) and - r.getException() = toAst(result) and - result.getBasicBlock().dominates(this.getBasicBlock()) - ) + this.getNode().getException() = result.getNode() and + result.getBasicBlock().dominates(this.getBasicBlock()) } } /** A control flow node corresponding to a starred expression (`*x`). */ class StarredNode extends ControlFlowNode { - StarredNode() { toAst(this) instanceof Py::Starred } + StarredNode() { this.getNode() instanceof Py::Starred } /** Gets the value being starred. */ ControlFlowNode getValue() { exists(Py::Starred s | - s = toAst(this) and - s.getValue() = toAst(result) and + s = this.getNode() and + s.getValue() = result.getNode() and result.getBasicBlock().dominates(this.getBasicBlock()) ) } @@ -913,7 +852,7 @@ class StarredNode extends ControlFlowNode { /** A control flow node corresponding to an `except` clause's name binding. */ class ExceptFlowNode extends ControlFlowNode { - ExceptFlowNode() { exists(Py::ExceptStmt e | toAst(this) = e.getName()) } + ExceptFlowNode() { exists(Py::ExceptStmt e | this.getNode() = e.getName()) } /** Gets the CFG node for the bound `as`-name itself. */ ControlFlowNode getName() { result = this } @@ -921,8 +860,8 @@ class ExceptFlowNode extends ControlFlowNode { /** Gets the type expression of this exception handler. */ ControlFlowNode getType() { exists(Py::ExceptStmt e | - e.getName() = toAst(this) and - e.getType() = toAst(result) and + e.getName() = this.getNode() and + e.getType() = result.getNode() and result.getBasicBlock().dominates(this.getBasicBlock()) ) } @@ -930,7 +869,7 @@ class ExceptFlowNode extends ControlFlowNode { /** A control flow node corresponding to an `except*` clause's name binding. */ class ExceptGroupFlowNode extends ControlFlowNode { - ExceptGroupFlowNode() { exists(Py::ExceptGroupStmt e | toAst(this) = e.getName()) } + ExceptGroupFlowNode() { exists(Py::ExceptGroupStmt e | this.getNode() = e.getName()) } /** Gets the CFG node for the bound `as`-name itself. */ ControlFlowNode getName() { result = this } @@ -947,12 +886,12 @@ abstract class SequenceNode extends ControlFlowNode { /** A control flow node corresponding to a tuple literal. */ class TupleNode extends SequenceNode { - TupleNode() { toAst(this) instanceof Py::Tuple } + TupleNode() { this.getNode() instanceof Py::Tuple } override ControlFlowNode getElement(int n) { exists(Py::Tuple t | - t = toAst(this) and - t.getElt(n) = toAst(result) and + t = this.getNode() and + t.getElt(n) = result.getNode() and result.getBasicBlock().dominates(this.getBasicBlock()) ) } @@ -960,12 +899,12 @@ class TupleNode extends SequenceNode { /** A control flow node corresponding to a list literal. */ class ListNode extends SequenceNode { - ListNode() { toAst(this) instanceof Py::List } + ListNode() { this.getNode() instanceof Py::List } override ControlFlowNode getElement(int n) { exists(Py::List l | - l = toAst(this) and - l.getElt(n) = toAst(result) and + l = this.getNode() and + l.getElt(n) = result.getNode() and result.getBasicBlock().dominates(this.getBasicBlock()) ) } @@ -973,13 +912,13 @@ class ListNode extends SequenceNode { /** A control flow node corresponding to a set literal. */ class SetNode extends ControlFlowNode { - SetNode() { toAst(this) instanceof Py::Set } + SetNode() { this.getNode() instanceof Py::Set } /** Gets the flow node for an element of the set. */ ControlFlowNode getAnElement() { exists(Py::Set s | - s = toAst(this) and - s.getAnElt() = toAst(result) and + s = this.getNode() and + s.getAnElt() = result.getNode() and result.getBasicBlock().dominates(this.getBasicBlock()) ) } @@ -987,13 +926,13 @@ class SetNode extends ControlFlowNode { /** A control flow node corresponding to a dict literal. */ class DictNode extends ControlFlowNode { - DictNode() { toAst(this) instanceof Py::Dict } + DictNode() { this.getNode() instanceof Py::Dict } /** Gets the flow node for a key of the dict. */ ControlFlowNode getAKey() { exists(Py::Dict d | - d = toAst(this) and - d.getAKey() = toAst(result) and + d = this.getNode() and + d.getAKey() = result.getNode() and result.getBasicBlock().dominates(this.getBasicBlock()) ) } @@ -1001,8 +940,8 @@ class DictNode extends ControlFlowNode { /** Gets the flow node for a value of the dict. */ ControlFlowNode getAValue() { exists(Py::Dict d | - d = toAst(this) and - d.getAValue() = toAst(result) and + d = this.getNode() and + d.getAValue() = result.getNode() and result.getBasicBlock().dominates(this.getBasicBlock()) ) } From a683b641ccb99fd23d0625049ae5d8a081974818 Mon Sep 17 00:00:00 2001 From: yoff Date: Tue, 21 Jul 2026 12:05:37 +0200 Subject: [PATCH 019/188] python: removed superflous module We have CfgImpl::Cfg already. --- .../semmle/python/controlflow/internal/Cfg.qll | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/python/ql/lib/semmle/python/controlflow/internal/Cfg.qll b/python/ql/lib/semmle/python/controlflow/internal/Cfg.qll index ac8493f98ae9..ec8b44d5a821 100644 --- a/python/ql/lib/semmle/python/controlflow/internal/Cfg.qll +++ b/python/ql/lib/semmle/python/controlflow/internal/Cfg.qll @@ -20,24 +20,6 @@ module; private import python as Py private import semmle.python.controlflow.internal.AstNodeImpl as CfgImpl private import codeql.controlflow.SuccessorType -private import codeql.controlflow.BasicBlock as BB - -/** - * A nested sub-module that explicitly implements `BB::CfgSig`, so this - * `Cfg` facade can be passed to parameterised shared modules such as - * `codeql.dataflow.VariableCapture::Flow`. The sub-module - * exposes the *raw* shared-CFG types from `AstNodeImpl.qll` (where the - * signature is satisfied natively), not the facade's wrapped types. - */ -module CfgForBb implements BB::CfgSig { - class ControlFlowNode = CfgImpl::ControlFlowNode; - - class BasicBlock = CfgImpl::BasicBlock; - - class EntryBasicBlock = CfgImpl::Cfg::EntryBasicBlock; - - predicate dominatingEdge = CfgImpl::Cfg::dominatingEdge/2; -} /** * A control flow node. From c6448548a3d6f260b4bf6301a073b2749d03c912 Mon Sep 17 00:00:00 2001 From: Scott Talbot Date: Wed, 22 Jul 2026 17:42:39 +1000 Subject: [PATCH 020/188] JS: Recognize @fastify/rate-limit as a rate limiter --- .../javascript/security/dataflow/MissingRateLimiting.qll | 4 +++- .../ql/src/change-notes/2026-07-22-fastify-rate-limit.md | 4 ++++ .../CWE-770/MissingRateLimit/MissingRateLimiting.expected | 3 ++- .../query-tests/Security/CWE-770/MissingRateLimit/tst.js | 8 +++++++- 4 files changed, 16 insertions(+), 3 deletions(-) create mode 100644 javascript/ql/src/change-notes/2026-07-22-fastify-rate-limit.md diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/MissingRateLimiting.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/MissingRateLimiting.qll index 8dd9c4831446..5cac49d6dd66 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/MissingRateLimiting.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/MissingRateLimiting.qll @@ -189,7 +189,9 @@ class RouteHandlerLimitedByRateLimiterFlexible extends RateLimitingMiddleware in { } private class FastifyRateLimiter extends RateLimitingMiddleware { - FastifyRateLimiter() { this = DataFlow::moduleImport("fastify-rate-limit") } + FastifyRateLimiter() { + this = DataFlow::moduleImport(["fastify-rate-limit", "@fastify/rate-limit"]) + } } /** diff --git a/javascript/ql/src/change-notes/2026-07-22-fastify-rate-limit.md b/javascript/ql/src/change-notes/2026-07-22-fastify-rate-limit.md new file mode 100644 index 000000000000..55e23b9dc111 --- /dev/null +++ b/javascript/ql/src/change-notes/2026-07-22-fastify-rate-limit.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* The `js/missing-rate-limiting` query now recognizes the `@fastify/rate-limit` package as a rate limiter. diff --git a/javascript/ql/test/query-tests/Security/CWE-770/MissingRateLimit/MissingRateLimiting.expected b/javascript/ql/test/query-tests/Security/CWE-770/MissingRateLimit/MissingRateLimiting.expected index 8d197d6e37f6..5e2265f64b49 100644 --- a/javascript/ql/test/query-tests/Security/CWE-770/MissingRateLimit/MissingRateLimiting.expected +++ b/javascript/ql/test/query-tests/Security/CWE-770/MissingRateLimit/MissingRateLimiting.expected @@ -9,4 +9,5 @@ | tst.js:64:25:64:63 | functio ... req); } | This route handler performs $@, but is not rate-limited. | tst.js:64:46:64:60 | verifyUser(req) | authorization | | tst.js:76:25:76:53 | catchAs ... ndler1) | This route handler performs $@, but is not rate-limited. | tst.js:14:40:14:46 | login() | authorization | | tst.js:88:24:88:40 | expensiveHandler1 | This route handler performs $@, but is not rate-limited. | tst.js:14:40:14:46 | login() | authorization | -| tst.js:112:28:112:44 | expensiveHandler1 | This route handler performs $@, but is not rate-limited. | tst.js:14:40:14:46 | login() | authorization | +| tst.js:111:28:111:44 | expensiveHandler1 | This route handler performs $@, but is not rate-limited. | tst.js:14:40:14:46 | login() | authorization | +| tst.js:116:39:116:55 | expensiveHandler1 | This route handler performs $@, but is not rate-limited. | tst.js:14:40:14:46 | login() | authorization | diff --git a/javascript/ql/test/query-tests/Security/CWE-770/MissingRateLimit/tst.js b/javascript/ql/test/query-tests/Security/CWE-770/MissingRateLimit/tst.js index 5b4312bbbe0e..7ff0c067fb51 100644 --- a/javascript/ql/test/query-tests/Security/CWE-770/MissingRateLimit/tst.js +++ b/javascript/ql/test/query-tests/Security/CWE-770/MissingRateLimit/tst.js @@ -91,7 +91,6 @@ fastifyApp.get('/bar', expensiveHandler1); // Fastify per-route rate limiting via config.rateLimit const fastifyApp2 = require('fastify')(); -fastifyApp2.register(require('@fastify/rate-limit')); fastifyApp2.post('/login', { config: { @@ -110,3 +109,10 @@ fastifyApp2.post('/signup', { }, expensiveHandler1); // OK - has per-route rateLimit directly in options fastifyApp2.post('/other', expensiveHandler1); // $ Alert - no rate limiting + +// rate limiting using the scoped package name +const fastifyApp3 = require('fastify')(); + +fastifyApp3.get('/before-rate-limit', expensiveHandler1); // $ Alert +fastifyApp3.register(require('@fastify/rate-limit')); +fastifyApp3.get('/after-rate-limit', expensiveHandler1); From 8facacd6a106dfc6d9351877a77d3c934ad91815 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 Jul 2026 12:14:51 +0000 Subject: [PATCH 021/188] build(deps): bump rules_nodejs from 6.7.3 to 6.7.5 Bumps [rules_nodejs](https://github.com/bazel-contrib/rules_nodejs) from 6.7.3 to 6.7.5. - [Release notes](https://github.com/bazel-contrib/rules_nodejs/releases) - [Changelog](https://github.com/bazel-contrib/rules_nodejs/blob/main/CHANGELOG.md) - [Commits](https://github.com/bazel-contrib/rules_nodejs/compare/v6.7.3...v6.7.5) --- updated-dependencies: - dependency-name: rules_nodejs dependency-version: 6.7.5 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- MODULE.bazel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MODULE.bazel b/MODULE.bazel index 24b1c757e37b..7781b42d151f 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -19,7 +19,7 @@ bazel_dep(name = "rules_cc", version = "0.2.17") bazel_dep(name = "rules_go", version = "0.60.0") bazel_dep(name = "rules_java", version = "9.6.1") bazel_dep(name = "rules_pkg", version = "1.2.0") -bazel_dep(name = "rules_nodejs", version = "6.7.3") +bazel_dep(name = "rules_nodejs", version = "6.7.5") bazel_dep(name = "rules_python", version = "1.9.0") bazel_dep(name = "rules_shell", version = "0.7.1") bazel_dep(name = "bazel_skylib", version = "1.9.0") From e7b6f91973dd7a81efcc64c3f819cd562a1becd5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 23 Jul 2026 17:33:24 +0000 Subject: [PATCH 022/188] Post-release preparation for codeql-cli-2.26.2 --- actions/ql/lib/qlpack.yml | 2 +- actions/ql/src/qlpack.yml | 2 +- cpp/ql/lib/qlpack.yml | 2 +- cpp/ql/src/qlpack.yml | 2 +- csharp/ql/campaigns/Solorigate/lib/qlpack.yml | 2 +- csharp/ql/campaigns/Solorigate/src/qlpack.yml | 2 +- csharp/ql/lib/qlpack.yml | 2 +- csharp/ql/src/qlpack.yml | 2 +- go/ql/consistency-queries/qlpack.yml | 2 +- go/ql/lib/qlpack.yml | 2 +- go/ql/src/qlpack.yml | 2 +- java/ql/lib/qlpack.yml | 2 +- java/ql/src/qlpack.yml | 2 +- javascript/ql/lib/qlpack.yml | 2 +- javascript/ql/src/qlpack.yml | 2 +- misc/suite-helpers/qlpack.yml | 2 +- python/ql/lib/qlpack.yml | 2 +- python/ql/src/qlpack.yml | 2 +- ruby/ql/lib/qlpack.yml | 2 +- ruby/ql/src/qlpack.yml | 2 +- rust/ql/lib/qlpack.yml | 2 +- rust/ql/src/qlpack.yml | 2 +- shared/concepts/qlpack.yml | 2 +- shared/controlflow/qlpack.yml | 2 +- shared/dataflow/qlpack.yml | 2 +- shared/mad/qlpack.yml | 2 +- shared/namebinding/qlpack.yml | 2 +- shared/quantum/qlpack.yml | 2 +- shared/rangeanalysis/qlpack.yml | 2 +- shared/regex/qlpack.yml | 2 +- shared/ssa/qlpack.yml | 2 +- shared/threat-models/qlpack.yml | 2 +- shared/tutorial/qlpack.yml | 2 +- shared/typeflow/qlpack.yml | 2 +- shared/typeinference/qlpack.yml | 2 +- shared/typetracking/qlpack.yml | 2 +- shared/typos/qlpack.yml | 2 +- shared/util/qlpack.yml | 2 +- shared/xml/qlpack.yml | 2 +- shared/yaml/qlpack.yml | 2 +- swift/ql/lib/qlpack.yml | 2 +- swift/ql/src/qlpack.yml | 2 +- 42 files changed, 42 insertions(+), 42 deletions(-) diff --git a/actions/ql/lib/qlpack.yml b/actions/ql/lib/qlpack.yml index f581f735dd6a..5111dd27cc89 100644 --- a/actions/ql/lib/qlpack.yml +++ b/actions/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/actions-all -version: 0.4.40 +version: 0.4.41-dev library: true warnOnImplicitThis: true dependencies: diff --git a/actions/ql/src/qlpack.yml b/actions/ql/src/qlpack.yml index 6449c6f5a40a..6d2a221c1b4a 100644 --- a/actions/ql/src/qlpack.yml +++ b/actions/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/actions-queries -version: 0.6.32 +version: 0.6.33-dev library: false warnOnImplicitThis: true groups: [actions, queries] diff --git a/cpp/ql/lib/qlpack.yml b/cpp/ql/lib/qlpack.yml index 3f588d959579..2932987ec152 100644 --- a/cpp/ql/lib/qlpack.yml +++ b/cpp/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cpp-all -version: 12.0.1 +version: 12.0.2-dev groups: cpp dbscheme: semmlecode.cpp.dbscheme extractor: cpp diff --git a/cpp/ql/src/qlpack.yml b/cpp/ql/src/qlpack.yml index 57b8e535aeba..ad0a0cd8943b 100644 --- a/cpp/ql/src/qlpack.yml +++ b/cpp/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cpp-queries -version: 1.8.0 +version: 1.8.1-dev groups: - cpp - queries diff --git a/csharp/ql/campaigns/Solorigate/lib/qlpack.yml b/csharp/ql/campaigns/Solorigate/lib/qlpack.yml index 5a0ebdc92e66..9968c6570e7d 100644 --- a/csharp/ql/campaigns/Solorigate/lib/qlpack.yml +++ b/csharp/ql/campaigns/Solorigate/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-solorigate-all -version: 1.7.71 +version: 1.7.72-dev groups: - csharp - solorigate diff --git a/csharp/ql/campaigns/Solorigate/src/qlpack.yml b/csharp/ql/campaigns/Solorigate/src/qlpack.yml index a0d3ba43b9e6..9ccab68881a5 100644 --- a/csharp/ql/campaigns/Solorigate/src/qlpack.yml +++ b/csharp/ql/campaigns/Solorigate/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-solorigate-queries -version: 1.7.71 +version: 1.7.72-dev groups: - csharp - solorigate diff --git a/csharp/ql/lib/qlpack.yml b/csharp/ql/lib/qlpack.yml index 715b17a5c201..035a38389157 100644 --- a/csharp/ql/lib/qlpack.yml +++ b/csharp/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-all -version: 7.1.1 +version: 7.1.2-dev groups: csharp dbscheme: semmlecode.csharp.dbscheme extractor: csharp diff --git a/csharp/ql/src/qlpack.yml b/csharp/ql/src/qlpack.yml index abd86552bb07..8d3728935138 100644 --- a/csharp/ql/src/qlpack.yml +++ b/csharp/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-queries -version: 1.9.0 +version: 1.9.1-dev groups: - csharp - queries diff --git a/go/ql/consistency-queries/qlpack.yml b/go/ql/consistency-queries/qlpack.yml index 3f52b158fc70..e21cc5f01830 100644 --- a/go/ql/consistency-queries/qlpack.yml +++ b/go/ql/consistency-queries/qlpack.yml @@ -1,5 +1,5 @@ name: codeql-go-consistency-queries -version: 1.0.54 +version: 1.0.55-dev groups: - go - queries diff --git a/go/ql/lib/qlpack.yml b/go/ql/lib/qlpack.yml index ba1129203eed..47c1077e0992 100644 --- a/go/ql/lib/qlpack.yml +++ b/go/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/go-all -version: 7.2.2 +version: 7.2.3-dev groups: go dbscheme: go.dbscheme extractor: go diff --git a/go/ql/src/qlpack.yml b/go/ql/src/qlpack.yml index 1800db532cb4..25a573adf8a0 100644 --- a/go/ql/src/qlpack.yml +++ b/go/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/go-queries -version: 1.6.7 +version: 1.6.8-dev groups: - go - queries diff --git a/java/ql/lib/qlpack.yml b/java/ql/lib/qlpack.yml index 47703e958a23..782d89ff8172 100644 --- a/java/ql/lib/qlpack.yml +++ b/java/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/java-all -version: 9.2.2 +version: 9.2.3-dev groups: java dbscheme: config/semmlecode.dbscheme extractor: java diff --git a/java/ql/src/qlpack.yml b/java/ql/src/qlpack.yml index 1b8cd80983ae..f85ddd4d3f6a 100644 --- a/java/ql/src/qlpack.yml +++ b/java/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/java-queries -version: 1.11.7 +version: 1.11.8-dev groups: - java - queries diff --git a/javascript/ql/lib/qlpack.yml b/javascript/ql/lib/qlpack.yml index ae298ba83811..6e10c05aa596 100644 --- a/javascript/ql/lib/qlpack.yml +++ b/javascript/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/javascript-all -version: 2.8.2 +version: 2.8.3-dev groups: javascript dbscheme: semmlecode.javascript.dbscheme extractor: javascript diff --git a/javascript/ql/src/qlpack.yml b/javascript/ql/src/qlpack.yml index 3de8be964060..1c534df4d85b 100644 --- a/javascript/ql/src/qlpack.yml +++ b/javascript/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/javascript-queries -version: 2.4.2 +version: 2.4.3-dev groups: - javascript - queries diff --git a/misc/suite-helpers/qlpack.yml b/misc/suite-helpers/qlpack.yml index 9ff990aba75a..12203ff110fa 100644 --- a/misc/suite-helpers/qlpack.yml +++ b/misc/suite-helpers/qlpack.yml @@ -1,4 +1,4 @@ name: codeql/suite-helpers -version: 1.0.54 +version: 1.0.55-dev groups: shared warnOnImplicitThis: true diff --git a/python/ql/lib/qlpack.yml b/python/ql/lib/qlpack.yml index f2e1d18d2e19..51fbf227e0b9 100644 --- a/python/ql/lib/qlpack.yml +++ b/python/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/python-all -version: 7.2.2 +version: 7.2.3-dev groups: python dbscheme: semmlecode.python.dbscheme extractor: python diff --git a/python/ql/src/qlpack.yml b/python/ql/src/qlpack.yml index c866e30b7e74..7d54edbaa03f 100644 --- a/python/ql/src/qlpack.yml +++ b/python/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/python-queries -version: 1.8.7 +version: 1.8.8-dev groups: - python - queries diff --git a/ruby/ql/lib/qlpack.yml b/ruby/ql/lib/qlpack.yml index a491cb61462a..29d38c9a1948 100644 --- a/ruby/ql/lib/qlpack.yml +++ b/ruby/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/ruby-all -version: 6.0.2 +version: 6.0.3-dev groups: ruby extractor: ruby dbscheme: ruby.dbscheme diff --git a/ruby/ql/src/qlpack.yml b/ruby/ql/src/qlpack.yml index 0f833109f18e..f73004c8530d 100644 --- a/ruby/ql/src/qlpack.yml +++ b/ruby/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/ruby-queries -version: 1.6.7 +version: 1.6.8-dev groups: - ruby - queries diff --git a/rust/ql/lib/qlpack.yml b/rust/ql/lib/qlpack.yml index 70a11bff45fc..14e8ab08f4d9 100644 --- a/rust/ql/lib/qlpack.yml +++ b/rust/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/rust-all -version: 0.2.18 +version: 0.2.19-dev groups: rust extractor: rust dbscheme: rust.dbscheme diff --git a/rust/ql/src/qlpack.yml b/rust/ql/src/qlpack.yml index dee21284edae..74a67365b1da 100644 --- a/rust/ql/src/qlpack.yml +++ b/rust/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/rust-queries -version: 0.1.39 +version: 0.1.40-dev groups: - rust - queries diff --git a/shared/concepts/qlpack.yml b/shared/concepts/qlpack.yml index 682474b6be37..c5f8b2831ab0 100644 --- a/shared/concepts/qlpack.yml +++ b/shared/concepts/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/concepts -version: 0.0.28 +version: 0.0.29-dev groups: shared library: true dependencies: diff --git a/shared/controlflow/qlpack.yml b/shared/controlflow/qlpack.yml index 9d89f4e45026..e4358bf4e80d 100644 --- a/shared/controlflow/qlpack.yml +++ b/shared/controlflow/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/controlflow -version: 2.0.38 +version: 2.0.39-dev groups: shared library: true dependencies: diff --git a/shared/dataflow/qlpack.yml b/shared/dataflow/qlpack.yml index ce4f56dd87f1..a9aa3a70f451 100644 --- a/shared/dataflow/qlpack.yml +++ b/shared/dataflow/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/dataflow -version: 2.1.10 +version: 2.1.11-dev groups: shared library: true dependencies: diff --git a/shared/mad/qlpack.yml b/shared/mad/qlpack.yml index 02fff19b4d6e..a160bab98f55 100644 --- a/shared/mad/qlpack.yml +++ b/shared/mad/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/mad -version: 1.0.54 +version: 1.0.55-dev groups: shared library: true dependencies: diff --git a/shared/namebinding/qlpack.yml b/shared/namebinding/qlpack.yml index 5f70711b4497..ecb08c95dda6 100644 --- a/shared/namebinding/qlpack.yml +++ b/shared/namebinding/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/namebinding -version: 0.0.3 +version: 0.0.4-dev groups: shared library: true dependencies: diff --git a/shared/quantum/qlpack.yml b/shared/quantum/qlpack.yml index f0041559dc38..6a7a0abe44a2 100644 --- a/shared/quantum/qlpack.yml +++ b/shared/quantum/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/quantum -version: 0.0.32 +version: 0.0.33-dev groups: shared library: true dependencies: diff --git a/shared/rangeanalysis/qlpack.yml b/shared/rangeanalysis/qlpack.yml index 2897d92e18ca..d37c35c424e8 100644 --- a/shared/rangeanalysis/qlpack.yml +++ b/shared/rangeanalysis/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/rangeanalysis -version: 1.0.54 +version: 1.0.55-dev groups: shared library: true dependencies: diff --git a/shared/regex/qlpack.yml b/shared/regex/qlpack.yml index 9bd5da070ba2..eb4f9f9bff24 100644 --- a/shared/regex/qlpack.yml +++ b/shared/regex/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/regex -version: 1.0.54 +version: 1.0.55-dev groups: shared library: true dependencies: diff --git a/shared/ssa/qlpack.yml b/shared/ssa/qlpack.yml index 54c3f98c10b8..30c04dc81b95 100644 --- a/shared/ssa/qlpack.yml +++ b/shared/ssa/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/ssa -version: 2.0.30 +version: 2.0.31-dev groups: shared library: true dependencies: diff --git a/shared/threat-models/qlpack.yml b/shared/threat-models/qlpack.yml index 3a70d4a69374..785d18c741c0 100644 --- a/shared/threat-models/qlpack.yml +++ b/shared/threat-models/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/threat-models -version: 1.0.54 +version: 1.0.55-dev library: true groups: shared dataExtensions: diff --git a/shared/tutorial/qlpack.yml b/shared/tutorial/qlpack.yml index ccbde048c98d..d8d6ee9cdaa8 100644 --- a/shared/tutorial/qlpack.yml +++ b/shared/tutorial/qlpack.yml @@ -1,7 +1,7 @@ name: codeql/tutorial description: Library for the CodeQL detective tutorials, helping new users learn to write CodeQL queries. -version: 1.0.54 +version: 1.0.55-dev groups: shared library: true warnOnImplicitThis: true diff --git a/shared/typeflow/qlpack.yml b/shared/typeflow/qlpack.yml index 5a0bb1315c2c..e7d3ae0279be 100644 --- a/shared/typeflow/qlpack.yml +++ b/shared/typeflow/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/typeflow -version: 1.0.54 +version: 1.0.55-dev groups: shared library: true dependencies: diff --git a/shared/typeinference/qlpack.yml b/shared/typeinference/qlpack.yml index add1c0c7d055..4d48222f41aa 100644 --- a/shared/typeinference/qlpack.yml +++ b/shared/typeinference/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/typeinference -version: 0.0.35 +version: 0.0.36-dev groups: shared library: true dependencies: diff --git a/shared/typetracking/qlpack.yml b/shared/typetracking/qlpack.yml index 744a79cb9b43..e9fb4f6c0447 100644 --- a/shared/typetracking/qlpack.yml +++ b/shared/typetracking/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/typetracking -version: 2.0.38 +version: 2.0.39-dev groups: shared library: true dependencies: diff --git a/shared/typos/qlpack.yml b/shared/typos/qlpack.yml index f91961fd5796..9218a86a215b 100644 --- a/shared/typos/qlpack.yml +++ b/shared/typos/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/typos -version: 1.0.54 +version: 1.0.55-dev groups: shared library: true warnOnImplicitThis: true diff --git a/shared/util/qlpack.yml b/shared/util/qlpack.yml index 022b0557fc51..0a58c95a984d 100644 --- a/shared/util/qlpack.yml +++ b/shared/util/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/util -version: 2.0.41 +version: 2.0.42-dev groups: shared library: true dependencies: null diff --git a/shared/xml/qlpack.yml b/shared/xml/qlpack.yml index 81159c215cb9..d1c821414117 100644 --- a/shared/xml/qlpack.yml +++ b/shared/xml/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/xml -version: 1.0.54 +version: 1.0.55-dev groups: shared library: true dependencies: diff --git a/shared/yaml/qlpack.yml b/shared/yaml/qlpack.yml index 0216ed463ad4..272b9f20f8fc 100644 --- a/shared/yaml/qlpack.yml +++ b/shared/yaml/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/yaml -version: 1.0.54 +version: 1.0.55-dev groups: shared library: true warnOnImplicitThis: true diff --git a/swift/ql/lib/qlpack.yml b/swift/ql/lib/qlpack.yml index 811270faed34..46bbe03047d3 100644 --- a/swift/ql/lib/qlpack.yml +++ b/swift/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/swift-all -version: 6.8.0 +version: 6.8.1-dev groups: swift extractor: swift dbscheme: swift.dbscheme diff --git a/swift/ql/src/qlpack.yml b/swift/ql/src/qlpack.yml index ef34bce7e957..a738635a8d07 100644 --- a/swift/ql/src/qlpack.yml +++ b/swift/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/swift-queries -version: 1.3.7 +version: 1.3.8-dev groups: - swift - queries From 7a573c4619374ef0328237fcfd4b6ed366d1f730 Mon Sep 17 00:00:00 2001 From: Taus Date: Thu, 16 Jul 2026 15:57:35 +0000 Subject: [PATCH 023/188] yeast: Order AST dump fields by schema-declared order The AST dump previously emitted named fields in field-id order, which made it dependant on registration order and so it could differ between front-ends. We now emit them in the order declared in the node-types YAML instead, so that the order is kept stable. --- shared/yeast-schema/src/node_types_yaml.rs | 35 ++++++++++++ shared/yeast-schema/src/schema.rs | 17 ++++++ shared/yeast/src/dump.rs | 42 +++++++++++++-- .../closures/closure-with-capture-list.output | 12 ++--- .../closure-with-explicit-parameters.output | 24 ++++----- .../closure-with-shorthand-parameters.output | 2 +- .../closures/multi-statement-closure.output | 26 ++++----- .../swift/closures/trailing-closure.output | 14 ++--- .../collections/dictionary-subscript.output | 6 +-- .../swift/collections/subscript-access.output | 6 +-- ...g-modifier-does-not-leak-to-sibling.output | 22 ++++---- .../swift/control-flow/guard-let.output | 10 ++-- ...t-with-shadowing-in-condition-value.output | 8 +-- .../control-flow/if-else-if-chain.output | 40 +++++++------- .../corpus/swift/control-flow/if-else.output | 28 +++++----- .../if-let-optional-binding.output | 16 +++--- .../swift/control-flow/if-statement.output | 8 +-- .../control-flow/switch-statement.output | 38 ++++++------- .../switch-with-binding-pattern.output | 52 +++++++++--------- ...with-labeled-case-pattern-arguments.output | 54 +++++++++---------- .../control-flow/ternary-expression.output | 4 +- .../additive-expression-is-desugared.output | 2 +- ...er-additive-expression-is-desugared.output | 2 +- ...with-deeply-nested-path-three-parts.output | 2 +- .../import-with-dotted-path-two-parts.output | 2 +- .../scoped-import-uses-name-pattern.output | 6 +-- .../simple-import-with-single-name.output | 2 +- ...nction-call-with-labelled-arguments.output | 6 +-- .../swift/functions/function-call.output | 6 +-- ...nction-with-default-parameter-value.output | 20 +++---- .../function-with-named-parameters.output | 20 +++---- .../function-with-no-parameters.output | 8 +-- ...ion-with-parameters-and-return-type.output | 26 ++++----- .../swift/functions/generic-function.output | 14 ++--- .../leading-dot-expression-call.output | 6 +-- .../corpus/swift/functions/method-call.output | 6 +-- .../swift/functions/variadic-function.output | 32 +++++------ .../swift/loops/break-and-continue.output | 22 ++++---- .../loops/for-in-over-array-literal.output | 24 ++++----- .../swift/loops/for-in-over-range.output | 22 ++++---- .../loops/for-in-with-where-clause.output | 32 +++++------ .../swift/loops/repeat-while-loop.output | 4 +- .../corpus/swift/loops/while-loop.output | 16 +++--- .../corpus/swift/operators/addition.output | 2 +- .../corpus/swift/operators/comparison.output | 2 +- .../corpus/swift/operators/division.output | 2 +- .../corpus/swift/operators/equality.output | 2 +- .../corpus/swift/operators/logical-and.output | 2 +- .../corpus/swift/operators/logical-or.output | 2 +- .../swift/operators/multiplication.output | 2 +- ...cedence-addition-and-multiplication.output | 4 +- .../operators/parenthesised-expression.output | 2 +- .../swift/operators/range-operator.output | 2 +- .../corpus/swift/operators/subtraction.output | 2 +- .../optionals-and-errors/do-catch.output | 6 +-- .../nil-coalescing.output | 2 +- .../throwing-function.output | 8 +-- ...er-does-not-leak-into-accessor-body.output | 28 +++++----- .../swift/types/class-with-initializer.output | 4 +- .../swift/types/class-with-method.output | 8 +-- .../types/class-with-stored-properties.output | 4 +- .../swift/types/computed-property.output | 18 +++---- .../types/enum-with-associated-values.output | 28 +++++----- .../corpus/swift/types/enum-with-cases.output | 4 +- ...separated-cases-chained-declaration.output | 4 +- .../tests/corpus/swift/types/extension.output | 14 ++--- .../property-with-getter-and-setter.output | 26 ++++----- .../swift/types/protocol-declaration.output | 6 +-- ...nd-read-write-property-requirements.output | 10 ++-- .../tests/corpus/swift/types/struct.output | 4 +- ...fier-does-not-leak-into-initializer.output | 12 ++--- .../variables/compound-assignment.output | 2 +- ...y-with-willset-and-didset-observers.output | 30 +++++------ 73 files changed, 536 insertions(+), 450 deletions(-) diff --git a/shared/yeast-schema/src/node_types_yaml.rs b/shared/yeast-schema/src/node_types_yaml.rs index 5f6a3906f7cb..97052f9a835b 100644 --- a/shared/yeast-schema/src/node_types_yaml.rs +++ b/shared/yeast-schema/src/node_types_yaml.rs @@ -252,6 +252,41 @@ pub fn extend_schema_from_yaml( let yaml: YamlNodeTypes = serde_yaml::from_str(yaml_input).map_err(|e| format!("Failed to parse YAML: {e}"))?; apply_yaml_to_schema(&yaml, schema); + // The typed `YamlNodeTypes` stores each node's fields in a `BTreeMap` + // (alphabetical), losing the authored order. Re-parse as an ordered value to + // record the declared field order for presentation (see the AST dump). + record_field_order(schema, yaml_input)?; + Ok(()) +} + +/// Record each node kind's declared (named) field order from the source YAML, +/// which `serde`'s `BTreeMap`-based deserialization does not preserve. +/// `serde_yaml::Value` mappings keep insertion (source) order. +fn record_field_order(schema: &mut crate::schema::Schema, yaml_input: &str) -> Result<(), String> { + let value: serde_yaml::Value = serde_yaml::from_str(yaml_input) + .map_err(|e| format!("Failed to parse YAML for field order: {e}"))?; + let Some(named) = value.get("named").and_then(|v| v.as_mapping()) else { + return Ok(()); + }; + for (node_name, fields) in named { + let Some(node_name) = node_name.as_str() else { + continue; + }; + let Some(fields) = fields.as_mapping() else { + continue; // node with no fields (null) + }; + let mut order = Vec::new(); + for (raw_field_name, _) in fields { + let Some(raw) = raw_field_name.as_str() else { + continue; + }; + // Skip the unnamed/`child` slot; the dump handles it separately. + if let Some(name) = parse_field_name(raw).name { + order.push(schema.register_field(&name)); + } + } + schema.set_field_order(node_name, order); + } Ok(()) } diff --git a/shared/yeast-schema/src/schema.rs b/shared/yeast-schema/src/schema.rs index 9c438d7c22e8..0675d8913422 100644 --- a/shared/yeast-schema/src/schema.rs +++ b/shared/yeast-schema/src/schema.rs @@ -44,6 +44,11 @@ pub struct Schema { field_types: BTreeMap<(String, FieldId), Vec>, field_cardinalities: BTreeMap<(String, FieldId), FieldCardinality>, supertypes: BTreeMap>, + /// Per-node-kind declared field order (named fields only), as written in + /// the source node-types YAML. Field ids are not a stable ordering key + /// across front-ends, so this preserves the authored order for + /// presentation (see the AST dump). + field_order: BTreeMap>, } impl Default for Schema { @@ -65,6 +70,7 @@ impl Schema { field_types: BTreeMap::new(), field_cardinalities: BTreeMap::new(), supertypes: BTreeMap::new(), + field_order: BTreeMap::new(), } } @@ -269,6 +275,17 @@ impl Schema { .get(&(parent_kind.to_string(), field_id)) } + /// Record the declared (named) field order for a node kind, as authored in + /// the source node-types YAML. + pub fn set_field_order(&mut self, kind: &str, field_ids: Vec) { + self.field_order.insert(kind.to_string(), field_ids); + } + + /// The declared (named) field order for a node kind, if known. + pub fn field_order(&self, kind: &str) -> Option<&Vec> { + self.field_order.get(kind) + } + pub fn set_field_cardinality( &mut self, parent_kind: &str, diff --git a/shared/yeast/src/dump.rs b/shared/yeast/src/dump.rs index 34b614323600..f217f1798068 100644 --- a/shared/yeast/src/dump.rs +++ b/shared/yeast/src/dump.rs @@ -223,11 +223,45 @@ fn dump_node( writeln!(out).unwrap(); - // Named fields first - for (&field_id, children) in &node.fields { - if field_id == CHILD_FIELD { - continue; // Handle unnamed children last + // Named fields first, in the schema's declared order when available + // (front-end-independent), else in field-id order. Any present fields not + // covered by the declared order are appended in field-id order. + // + // The declared order lives in the validation schema, keyed by *its* field + // ids; the AST being dumped may key the same field names under different + // ids. So map the declared order through field NAMES into this AST's own id + // space, keeping the two schemas independent (they share names, not ids). + let named_field_ids: Vec = { + let present: Vec = node + .fields + .keys() + .copied() + .filter(|&f| f != CHILD_FIELD) + .collect(); + match type_check.and_then(|(schema, _, _)| { + schema + .field_order(node.kind_name()) + .map(|order| (schema, order)) + }) { + Some((schema, order)) => { + let mut result: Vec = order + .iter() + .filter_map(|&f| schema.field_name_for_id(f)) + .filter_map(|name| ast.field_id_for_name(name)) + .filter(|&f| f != CHILD_FIELD && node.fields.contains_key(&f)) + .collect(); + for &f in &present { + if !result.contains(&f) { + result.push(f); + } + } + result + } + None => present, } + }; + for field_id in named_field_ids { + let children = &node.fields[&field_id]; let field_name = ast.field_name_for_id(field_id).unwrap_or("?"); let child_type_check = type_check.map(|(schema, _, _)| { let expected = diff --git a/unified/extractor/tests/corpus/swift/closures/closure-with-capture-list.output b/unified/extractor/tests/corpus/swift/closures/closure-with-capture-list.output index 8f28322b4930..b4760e35591c 100644 --- a/unified/extractor/tests/corpus/swift/closures/closure-with-capture-list.output +++ b/unified/extractor/tests/corpus/swift/closures/closure-with-capture-list.output @@ -51,6 +51,12 @@ top_level identifier: identifier "f" value: function_expr + capture_declaration: + variable_declaration + modifier: modifier "weak" + pattern: + name_pattern + identifier: identifier "self" body: block stmt: @@ -61,9 +67,3 @@ top_level name_expr identifier: identifier "self" member: identifier "doThing" - capture_declaration: - variable_declaration - modifier: modifier "weak" - pattern: - name_pattern - identifier: identifier "self" diff --git a/unified/extractor/tests/corpus/swift/closures/closure-with-explicit-parameters.output b/unified/extractor/tests/corpus/swift/closures/closure-with-explicit-parameters.output index 95d638118d84..bb6b878b8bb9 100644 --- a/unified/extractor/tests/corpus/swift/closures/closure-with-explicit-parameters.output +++ b/unified/extractor/tests/corpus/swift/closures/closure-with-explicit-parameters.output @@ -55,23 +55,23 @@ top_level identifier: identifier "f" value: function_expr - body: - block - stmt: - binary_expr - operator: infix_operator "*" - left: - name_expr - identifier: identifier "x" - right: int_literal "2" parameter: parameter - pattern: - name_pattern - identifier: identifier "x" type: named_type_expr name: identifier "Int" + pattern: + name_pattern + identifier: identifier "x" return_type: named_type_expr name: identifier "Int" + body: + block + stmt: + binary_expr + left: + name_expr + identifier: identifier "x" + operator: infix_operator "*" + right: int_literal "2" diff --git a/unified/extractor/tests/corpus/swift/closures/closure-with-shorthand-parameters.output b/unified/extractor/tests/corpus/swift/closures/closure-with-shorthand-parameters.output index bd286c385799..67cdf3df63f2 100644 --- a/unified/extractor/tests/corpus/swift/closures/closure-with-shorthand-parameters.output +++ b/unified/extractor/tests/corpus/swift/closures/closure-with-shorthand-parameters.output @@ -38,10 +38,10 @@ top_level block stmt: binary_expr - operator: infix_operator "+" left: name_expr identifier: identifier "$0" + operator: infix_operator "+" right: name_expr identifier: identifier "$1" diff --git a/unified/extractor/tests/corpus/swift/closures/multi-statement-closure.output b/unified/extractor/tests/corpus/swift/closures/multi-statement-closure.output index 6c9a403f19c1..0d07ea6f7bbb 100644 --- a/unified/extractor/tests/corpus/swift/closures/multi-statement-closure.output +++ b/unified/extractor/tests/corpus/swift/closures/multi-statement-closure.output @@ -75,6 +75,17 @@ top_level identifier: identifier "f" value: function_expr + parameter: + parameter + type: + named_type_expr + name: identifier "Int" + pattern: + name_pattern + identifier: identifier "x" + return_type: + named_type_expr + name: identifier "Int" body: block stmt: @@ -85,27 +96,16 @@ top_level identifier: identifier "y" value: binary_expr - operator: infix_operator "+" left: name_expr identifier: identifier "x" + operator: infix_operator "+" right: int_literal "1" return_expr value: binary_expr - operator: infix_operator "*" left: name_expr identifier: identifier "y" + operator: infix_operator "*" right: int_literal "2" - parameter: - parameter - pattern: - name_pattern - identifier: identifier "x" - type: - named_type_expr - name: identifier "Int" - return_type: - named_type_expr - name: identifier "Int" diff --git a/unified/extractor/tests/corpus/swift/closures/trailing-closure.output b/unified/extractor/tests/corpus/swift/closures/trailing-closure.output index 56b8bf9a7c20..ef8d6bd21c6a 100644 --- a/unified/extractor/tests/corpus/swift/closures/trailing-closure.output +++ b/unified/extractor/tests/corpus/swift/closures/trailing-closure.output @@ -28,6 +28,12 @@ top_level block stmt: call_expr + callee: + member_access_expr + base: + name_expr + identifier: identifier "xs" + member: identifier "map" argument: argument value: @@ -36,14 +42,8 @@ top_level block stmt: binary_expr - operator: infix_operator "*" left: name_expr identifier: identifier "$0" + operator: infix_operator "*" right: int_literal "2" - callee: - member_access_expr - base: - name_expr - identifier: identifier "xs" - member: identifier "map" diff --git a/unified/extractor/tests/corpus/swift/collections/dictionary-subscript.output b/unified/extractor/tests/corpus/swift/collections/dictionary-subscript.output index 59afc51867a2..c30ab9326bb6 100644 --- a/unified/extractor/tests/corpus/swift/collections/dictionary-subscript.output +++ b/unified/extractor/tests/corpus/swift/collections/dictionary-subscript.output @@ -43,9 +43,9 @@ top_level identifier: identifier "v" value: call_expr - argument: - argument - value: string_literal "\"key\"" callee: name_expr identifier: identifier "d" + argument: + argument + value: string_literal "\"key\"" diff --git a/unified/extractor/tests/corpus/swift/collections/subscript-access.output b/unified/extractor/tests/corpus/swift/collections/subscript-access.output index 481a3e95f774..681afca891a7 100644 --- a/unified/extractor/tests/corpus/swift/collections/subscript-access.output +++ b/unified/extractor/tests/corpus/swift/collections/subscript-access.output @@ -43,9 +43,9 @@ top_level identifier: identifier "first" value: call_expr - argument: - argument - value: int_literal "0" callee: name_expr identifier: identifier "xs" + argument: + argument + value: int_literal "0" diff --git a/unified/extractor/tests/corpus/swift/control-flow/binding-modifier-does-not-leak-to-sibling.output b/unified/extractor/tests/corpus/swift/control-flow/binding-modifier-does-not-leak-to-sibling.output index 3919b875b96a..9c4088845f14 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/binding-modifier-does-not-leak-to-sibling.output +++ b/unified/extractor/tests/corpus/swift/control-flow/binding-modifier-does-not-leak-to-sibling.output @@ -60,27 +60,27 @@ top_level identifier: identifier "x" value: int_literal "1" switch_expr + value: + name_expr + identifier: identifier "y" case: switch_case + pattern: + expr_equality_pattern + expr: + name_expr + identifier: identifier "someConstant" body: block stmt: call_expr - argument: - argument - value: string_literal "\"matched\"" callee: name_expr identifier: identifier "print" - pattern: - expr_equality_pattern - expr: - name_expr - identifier: identifier "someConstant" + argument: + argument + value: string_literal "\"matched\"" switch_case body: block stmt: break_expr "break" - value: - name_expr - identifier: identifier "y" diff --git a/unified/extractor/tests/corpus/swift/control-flow/guard-let.output b/unified/extractor/tests/corpus/swift/control-flow/guard-let.output index a21962341217..2e90e9820640 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/guard-let.output +++ b/unified/extractor/tests/corpus/swift/control-flow/guard-let.output @@ -33,17 +33,17 @@ top_level pattern_guard_expr pattern: constructor_pattern - element: - pattern_element - pattern: - name_pattern - identifier: identifier "value" constructor: member_access_expr base: named_type_expr name: identifier "Optional" member: identifier "some" + element: + pattern_element + pattern: + name_pattern + identifier: identifier "value" value: name_expr identifier: identifier "optional" diff --git a/unified/extractor/tests/corpus/swift/control-flow/if-case-let-with-shadowing-in-condition-value.output b/unified/extractor/tests/corpus/swift/control-flow/if-case-let-with-shadowing-in-condition-value.output index 6a53c87d21a2..61ca65811e97 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/if-case-let-with-shadowing-in-condition-value.output +++ b/unified/extractor/tests/corpus/swift/control-flow/if-case-let-with-shadowing-in-condition-value.output @@ -53,20 +53,20 @@ top_level identifier: identifier "x" value: binary_expr - operator: infix_operator "+" left: name_expr identifier: identifier "x" + operator: infix_operator "+" right: int_literal "10" then: block stmt: call_expr + callee: + name_expr + identifier: identifier "print" argument: argument value: name_expr identifier: identifier "x" - callee: - name_expr - identifier: identifier "print" diff --git a/unified/extractor/tests/corpus/swift/control-flow/if-else-if-chain.output b/unified/extractor/tests/corpus/swift/control-flow/if-else-if-chain.output index e8f413726466..268a2d1f97c9 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/if-else-if-chain.output +++ b/unified/extractor/tests/corpus/swift/control-flow/if-else-if-chain.output @@ -73,47 +73,47 @@ top_level if_expr condition: binary_expr - operator: infix_operator ">" left: name_expr identifier: identifier "x" + operator: infix_operator ">" right: int_literal "0" + then: + block + stmt: + call_expr + callee: + name_expr + identifier: identifier "print" + argument: + argument + value: int_literal "1" else: if_expr condition: binary_expr - operator: infix_operator "<" left: name_expr identifier: identifier "x" + operator: infix_operator "<" right: int_literal "0" - else: + then: block stmt: call_expr - argument: - argument - value: int_literal "3" callee: name_expr identifier: identifier "print" - then: - block - stmt: - call_expr argument: argument value: int_literal "2" + else: + block + stmt: + call_expr callee: name_expr identifier: identifier "print" - then: - block - stmt: - call_expr - argument: - argument - value: int_literal "1" - callee: - name_expr - identifier: identifier "print" + argument: + argument + value: int_literal "3" diff --git a/unified/extractor/tests/corpus/swift/control-flow/if-else.output b/unified/extractor/tests/corpus/swift/control-flow/if-else.output index 469861214676..e891cb4e2f6c 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/if-else.output +++ b/unified/extractor/tests/corpus/swift/control-flow/if-else.output @@ -53,35 +53,35 @@ top_level if_expr condition: binary_expr - operator: infix_operator ">" left: name_expr identifier: identifier "x" + operator: infix_operator ">" right: int_literal "0" - else: + then: block stmt: call_expr - argument: - argument - value: - unary_expr - operand: - name_expr - identifier: identifier "x" - operator: prefix_operator "-" callee: name_expr identifier: identifier "print" - then: - block - stmt: - call_expr argument: argument value: name_expr identifier: identifier "x" + else: + block + stmt: + call_expr callee: name_expr identifier: identifier "print" + argument: + argument + value: + unary_expr + operand: + name_expr + identifier: identifier "x" + operator: prefix_operator "-" diff --git a/unified/extractor/tests/corpus/swift/control-flow/if-let-optional-binding.output b/unified/extractor/tests/corpus/swift/control-flow/if-let-optional-binding.output index f6b605a7461c..0436a559236b 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/if-let-optional-binding.output +++ b/unified/extractor/tests/corpus/swift/control-flow/if-let-optional-binding.output @@ -42,17 +42,17 @@ top_level pattern_guard_expr pattern: constructor_pattern - element: - pattern_element - pattern: - name_pattern - identifier: identifier "value" constructor: member_access_expr base: named_type_expr name: identifier "Optional" member: identifier "some" + element: + pattern_element + pattern: + name_pattern + identifier: identifier "value" value: name_expr identifier: identifier "optional" @@ -60,11 +60,11 @@ top_level block stmt: call_expr + callee: + name_expr + identifier: identifier "print" argument: argument value: name_expr identifier: identifier "value" - callee: - name_expr - identifier: identifier "print" diff --git a/unified/extractor/tests/corpus/swift/control-flow/if-statement.output b/unified/extractor/tests/corpus/swift/control-flow/if-statement.output index 2c29ab1dc69b..6e89490b0128 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/if-statement.output +++ b/unified/extractor/tests/corpus/swift/control-flow/if-statement.output @@ -36,20 +36,20 @@ top_level if_expr condition: binary_expr - operator: infix_operator ">" left: name_expr identifier: identifier "x" + operator: infix_operator ">" right: int_literal "0" then: block stmt: call_expr + callee: + name_expr + identifier: identifier "print" argument: argument value: name_expr identifier: identifier "x" - callee: - name_expr - identifier: identifier "print" diff --git a/unified/extractor/tests/corpus/swift/control-flow/switch-statement.output b/unified/extractor/tests/corpus/swift/control-flow/switch-statement.output index bb90cb60fc5b..e016a650787f 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/switch-statement.output +++ b/unified/extractor/tests/corpus/swift/control-flow/switch-statement.output @@ -76,32 +76,25 @@ top_level block stmt: switch_expr + value: + name_expr + identifier: identifier "x" case: switch_case - body: - block - stmt: - call_expr - argument: - argument - value: string_literal "\"one\"" - callee: - name_expr - identifier: identifier "print" pattern: expr_equality_pattern expr: int_literal "1" - switch_case body: block stmt: call_expr - argument: - argument - value: string_literal "\"two or three\"" callee: name_expr identifier: identifier "print" + argument: + argument + value: string_literal "\"one\"" + switch_case pattern: or_pattern pattern: @@ -109,17 +102,24 @@ top_level expr: int_literal "2" expr_equality_pattern expr: int_literal "3" - switch_case body: block stmt: call_expr + callee: + name_expr + identifier: identifier "print" argument: argument - value: string_literal "\"other\"" + value: string_literal "\"two or three\"" + switch_case + body: + block + stmt: + call_expr callee: name_expr identifier: identifier "print" - value: - name_expr - identifier: identifier "x" + argument: + argument + value: string_literal "\"other\"" diff --git a/unified/extractor/tests/corpus/swift/control-flow/switch-with-binding-pattern.output b/unified/extractor/tests/corpus/swift/control-flow/switch-with-binding-pattern.output index 4d98620fe8f4..b995854d5999 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/switch-with-binding-pattern.output +++ b/unified/extractor/tests/corpus/swift/control-flow/switch-with-binding-pattern.output @@ -86,55 +86,55 @@ top_level block stmt: switch_expr + value: + name_expr + identifier: identifier "shape" case: switch_case + pattern: + constructor_pattern + constructor: + member_access_expr + base: inferred_type_expr "." + member: identifier "circle" + element: + pattern_element + pattern: + name_pattern + identifier: identifier "r" body: block stmt: call_expr + callee: + name_expr + identifier: identifier "print" argument: argument value: name_expr identifier: identifier "r" - callee: - name_expr - identifier: identifier "print" + switch_case pattern: constructor_pattern + constructor: + member_access_expr + base: inferred_type_expr "." + member: identifier "square" element: pattern_element pattern: name_pattern - identifier: identifier "r" - constructor: - member_access_expr - base: inferred_type_expr "." - member: identifier "circle" - switch_case + identifier: identifier "s" body: block stmt: call_expr + callee: + name_expr + identifier: identifier "print" argument: argument value: name_expr identifier: identifier "s" - callee: - name_expr - identifier: identifier "print" - pattern: - constructor_pattern - element: - pattern_element - pattern: - name_pattern - identifier: identifier "s" - constructor: - member_access_expr - base: inferred_type_expr "." - member: identifier "square" - value: - name_expr - identifier: identifier "shape" diff --git a/unified/extractor/tests/corpus/swift/control-flow/switch-with-labeled-case-pattern-arguments.output b/unified/extractor/tests/corpus/swift/control-flow/switch-with-labeled-case-pattern-arguments.output index aef36c168558..f8f6f2a0fe89 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/switch-with-labeled-case-pattern-arguments.output +++ b/unified/extractor/tests/corpus/swift/control-flow/switch-with-labeled-case-pattern-arguments.output @@ -88,45 +88,40 @@ top_level block stmt: switch_expr + value: + name_expr + identifier: identifier "x" case: switch_case - body: - block - stmt: - call_expr - argument: - argument - value: string_literal "\"yes\"" - callee: - name_expr - identifier: identifier "print" pattern: constructor_pattern + constructor: + member_access_expr + base: inferred_type_expr "." + member: identifier "implicit" element: pattern_element key: identifier "isAcknowledged" pattern: expr_equality_pattern expr: boolean_literal "false" - constructor: - member_access_expr - base: inferred_type_expr "." - member: identifier "implicit" - switch_case body: block stmt: call_expr - argument: - argument - value: - name_expr - identifier: identifier "rowId" callee: name_expr identifier: identifier "print" + argument: + argument + value: string_literal "\"yes\"" + switch_case pattern: constructor_pattern + constructor: + member_access_expr + base: inferred_type_expr "." + member: identifier "thread" element: pattern_element key: identifier "threadRowId" @@ -135,10 +130,15 @@ top_level pattern: name_pattern identifier: identifier "rowId" - constructor: - member_access_expr - base: inferred_type_expr "." - member: identifier "thread" - value: - name_expr - identifier: identifier "x" + body: + block + stmt: + call_expr + callee: + name_expr + identifier: identifier "print" + argument: + argument + value: + name_expr + identifier: identifier "rowId" diff --git a/unified/extractor/tests/corpus/swift/control-flow/ternary-expression.output b/unified/extractor/tests/corpus/swift/control-flow/ternary-expression.output index 7f9da80d34ac..482bd2382a9e 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/ternary-expression.output +++ b/unified/extractor/tests/corpus/swift/control-flow/ternary-expression.output @@ -41,13 +41,13 @@ top_level if_expr condition: binary_expr - operator: infix_operator ">" left: name_expr identifier: identifier "x" + operator: infix_operator ">" right: int_literal "0" + then: int_literal "1" else: unary_expr operand: int_literal "1" operator: prefix_operator "-" - then: int_literal "1" diff --git a/unified/extractor/tests/corpus/swift/desugar/additive-expression-is-desugared.output b/unified/extractor/tests/corpus/swift/desugar/additive-expression-is-desugared.output index 07aa40618bd1..849fe74107b6 100644 --- a/unified/extractor/tests/corpus/swift/desugar/additive-expression-is-desugared.output +++ b/unified/extractor/tests/corpus/swift/desugar/additive-expression-is-desugared.output @@ -16,6 +16,6 @@ top_level block stmt: binary_expr - operator: infix_operator "+" left: int_literal "1" + operator: infix_operator "+" right: int_literal "2" diff --git a/unified/extractor/tests/corpus/swift/desugar/another-additive-expression-is-desugared.output b/unified/extractor/tests/corpus/swift/desugar/another-additive-expression-is-desugared.output index ff830fd4b894..88de56051393 100644 --- a/unified/extractor/tests/corpus/swift/desugar/another-additive-expression-is-desugared.output +++ b/unified/extractor/tests/corpus/swift/desugar/another-additive-expression-is-desugared.output @@ -16,10 +16,10 @@ top_level block stmt: binary_expr - operator: infix_operator "+" left: name_expr identifier: identifier "foo" + operator: infix_operator "+" right: name_expr identifier: identifier "bar" diff --git a/unified/extractor/tests/corpus/swift/desugar/import-with-deeply-nested-path-three-parts.output b/unified/extractor/tests/corpus/swift/desugar/import-with-deeply-nested-path-three-parts.output index 4f312dabb151..3d31437a66ef 100644 --- a/unified/extractor/tests/corpus/swift/desugar/import-with-deeply-nested-path-three-parts.output +++ b/unified/extractor/tests/corpus/swift/desugar/import-with-deeply-nested-path-three-parts.output @@ -19,7 +19,6 @@ top_level block stmt: import_declaration - pattern: bulk_importing_pattern "import Foundation.Networking.URLSession" imported_expr: member_access_expr base: @@ -29,3 +28,4 @@ top_level identifier: identifier "Foundation" member: identifier "Networking" member: identifier "URLSession" + pattern: bulk_importing_pattern "import Foundation.Networking.URLSession" diff --git a/unified/extractor/tests/corpus/swift/desugar/import-with-dotted-path-two-parts.output b/unified/extractor/tests/corpus/swift/desugar/import-with-dotted-path-two-parts.output index efd2a6461243..f1c1dbcfb979 100644 --- a/unified/extractor/tests/corpus/swift/desugar/import-with-dotted-path-two-parts.output +++ b/unified/extractor/tests/corpus/swift/desugar/import-with-dotted-path-two-parts.output @@ -18,10 +18,10 @@ top_level block stmt: import_declaration - pattern: bulk_importing_pattern "import Foundation.Networking" imported_expr: member_access_expr base: name_expr identifier: identifier "Foundation" member: identifier "Networking" + pattern: bulk_importing_pattern "import Foundation.Networking" diff --git a/unified/extractor/tests/corpus/swift/desugar/scoped-import-uses-name-pattern.output b/unified/extractor/tests/corpus/swift/desugar/scoped-import-uses-name-pattern.output index fbf8e8100af7..79d1fa8bcb6d 100644 --- a/unified/extractor/tests/corpus/swift/desugar/scoped-import-uses-name-pattern.output +++ b/unified/extractor/tests/corpus/swift/desugar/scoped-import-uses-name-pattern.output @@ -20,12 +20,12 @@ top_level stmt: import_declaration modifier: modifier "struct" - pattern: - name_pattern - identifier: identifier "Date" imported_expr: member_access_expr base: name_expr identifier: identifier "Foundation" member: identifier "Date" + pattern: + name_pattern + identifier: identifier "Date" diff --git a/unified/extractor/tests/corpus/swift/desugar/simple-import-with-single-name.output b/unified/extractor/tests/corpus/swift/desugar/simple-import-with-single-name.output index 7a6be1c35e4c..8db7e15e3dc2 100644 --- a/unified/extractor/tests/corpus/swift/desugar/simple-import-with-single-name.output +++ b/unified/extractor/tests/corpus/swift/desugar/simple-import-with-single-name.output @@ -16,7 +16,7 @@ top_level block stmt: import_declaration - pattern: bulk_importing_pattern "import Foundation" imported_expr: name_expr identifier: identifier "Foundation" + pattern: bulk_importing_pattern "import Foundation" diff --git a/unified/extractor/tests/corpus/swift/functions/function-call-with-labelled-arguments.output b/unified/extractor/tests/corpus/swift/functions/function-call-with-labelled-arguments.output index ba0c002a4527..6c975e37be04 100644 --- a/unified/extractor/tests/corpus/swift/functions/function-call-with-labelled-arguments.output +++ b/unified/extractor/tests/corpus/swift/functions/function-call-with-labelled-arguments.output @@ -26,10 +26,10 @@ top_level block stmt: call_expr + callee: + name_expr + identifier: identifier "greet" argument: argument name: identifier "person" value: string_literal "\"Bob\"" - callee: - name_expr - identifier: identifier "greet" diff --git a/unified/extractor/tests/corpus/swift/functions/function-call.output b/unified/extractor/tests/corpus/swift/functions/function-call.output index ed604730d33c..2e8e107b3a20 100644 --- a/unified/extractor/tests/corpus/swift/functions/function-call.output +++ b/unified/extractor/tests/corpus/swift/functions/function-call.output @@ -23,11 +23,11 @@ top_level block stmt: call_expr + callee: + name_expr + identifier: identifier "foo" argument: argument value: int_literal "1" argument value: int_literal "2" - callee: - name_expr - identifier: identifier "foo" diff --git a/unified/extractor/tests/corpus/swift/functions/function-with-default-parameter-value.output b/unified/extractor/tests/corpus/swift/functions/function-with-default-parameter-value.output index fdd737e1258d..2c55abad52d9 100644 --- a/unified/extractor/tests/corpus/swift/functions/function-with-default-parameter-value.output +++ b/unified/extractor/tests/corpus/swift/functions/function-with-default-parameter-value.output @@ -43,22 +43,22 @@ top_level block stmt: function_declaration + name: identifier "greet" + parameter: + parameter + pattern: + name_pattern + identifier: identifier "name" + default: string_literal "\"world\"" body: block stmt: call_expr + callee: + name_expr + identifier: identifier "print" argument: argument value: name_expr identifier: identifier "name" - callee: - name_expr - identifier: identifier "print" - name: identifier "greet" - parameter: - parameter - default: string_literal "\"world\"" - pattern: - name_pattern - identifier: identifier "name" diff --git a/unified/extractor/tests/corpus/swift/functions/function-with-named-parameters.output b/unified/extractor/tests/corpus/swift/functions/function-with-named-parameters.output index bfa68c645ea1..d9eb41963965 100644 --- a/unified/extractor/tests/corpus/swift/functions/function-with-named-parameters.output +++ b/unified/extractor/tests/corpus/swift/functions/function-with-named-parameters.output @@ -41,22 +41,22 @@ top_level block stmt: function_declaration + name: identifier "greet" + parameter: + parameter + external_name: identifier "person" + pattern: + name_pattern + identifier: identifier "name" body: block stmt: call_expr + callee: + name_expr + identifier: identifier "print" argument: argument value: name_expr identifier: identifier "name" - callee: - name_expr - identifier: identifier "print" - name: identifier "greet" - parameter: - parameter - external_name: identifier "person" - pattern: - name_pattern - identifier: identifier "name" diff --git a/unified/extractor/tests/corpus/swift/functions/function-with-no-parameters.output b/unified/extractor/tests/corpus/swift/functions/function-with-no-parameters.output index b5cdfd73d48f..b59ed702f296 100644 --- a/unified/extractor/tests/corpus/swift/functions/function-with-no-parameters.output +++ b/unified/extractor/tests/corpus/swift/functions/function-with-no-parameters.output @@ -30,14 +30,14 @@ top_level block stmt: function_declaration + name: identifier "greet" body: block stmt: call_expr - argument: - argument - value: string_literal "\"hello\"" callee: name_expr identifier: identifier "print" - name: identifier "greet" + argument: + argument + value: string_literal "\"hello\"" diff --git a/unified/extractor/tests/corpus/swift/functions/function-with-parameters-and-return-type.output b/unified/extractor/tests/corpus/swift/functions/function-with-parameters-and-return-type.output index 6544f4313cd7..eca072fed022 100644 --- a/unified/extractor/tests/corpus/swift/functions/function-with-parameters-and-return-type.output +++ b/unified/extractor/tests/corpus/swift/functions/function-with-parameters-and-return-type.output @@ -58,19 +58,6 @@ top_level block stmt: function_declaration - body: - block - stmt: - return_expr - value: - binary_expr - operator: infix_operator "+" - left: - name_expr - identifier: identifier "a" - right: - name_expr - identifier: identifier "b" name: identifier "add" parameter: parameter @@ -86,3 +73,16 @@ top_level return_type: named_type_expr name: identifier "Int" + body: + block + stmt: + return_expr + value: + binary_expr + left: + name_expr + identifier: identifier "a" + operator: infix_operator "+" + right: + name_expr + identifier: identifier "b" diff --git a/unified/extractor/tests/corpus/swift/functions/generic-function.output b/unified/extractor/tests/corpus/swift/functions/generic-function.output index f42367a8fca2..5fb2d4b03899 100644 --- a/unified/extractor/tests/corpus/swift/functions/generic-function.output +++ b/unified/extractor/tests/corpus/swift/functions/generic-function.output @@ -47,13 +47,6 @@ top_level block stmt: function_declaration - body: - block - stmt: - return_expr - value: - name_expr - identifier: identifier "x" name: identifier "identity" parameter: parameter @@ -64,3 +57,10 @@ top_level return_type: named_type_expr name: identifier "T" + body: + block + stmt: + return_expr + value: + name_expr + identifier: identifier "x" diff --git a/unified/extractor/tests/corpus/swift/functions/leading-dot-expression-call.output b/unified/extractor/tests/corpus/swift/functions/leading-dot-expression-call.output index 8db16da8ab8b..75fa887f25ac 100644 --- a/unified/extractor/tests/corpus/swift/functions/leading-dot-expression-call.output +++ b/unified/extractor/tests/corpus/swift/functions/leading-dot-expression-call.output @@ -40,10 +40,10 @@ top_level identifier: identifier "y" value: call_expr - argument: - argument - value: int_literal "1" callee: member_access_expr base: inferred_type_expr ".some" member: identifier "some" + argument: + argument + value: int_literal "1" diff --git a/unified/extractor/tests/corpus/swift/functions/method-call.output b/unified/extractor/tests/corpus/swift/functions/method-call.output index 5a8a23f5658a..76d6d3206d19 100644 --- a/unified/extractor/tests/corpus/swift/functions/method-call.output +++ b/unified/extractor/tests/corpus/swift/functions/method-call.output @@ -26,12 +26,12 @@ top_level block stmt: call_expr - argument: - argument - value: int_literal "1" callee: member_access_expr base: name_expr identifier: identifier "list" member: identifier "append" + argument: + argument + value: int_literal "1" diff --git a/unified/extractor/tests/corpus/swift/functions/variadic-function.output b/unified/extractor/tests/corpus/swift/functions/variadic-function.output index 7ca1dfbad4eb..da8d4afd4d7c 100644 --- a/unified/extractor/tests/corpus/swift/functions/variadic-function.output +++ b/unified/extractor/tests/corpus/swift/functions/variadic-function.output @@ -60,12 +60,28 @@ top_level block stmt: function_declaration + name: identifier "sum" + parameter: + parameter + external_name: identifier "_" + pattern: + name_pattern + identifier: identifier "values" + return_type: + named_type_expr + name: identifier "Int" body: block stmt: return_expr value: call_expr + callee: + member_access_expr + base: + name_expr + identifier: identifier "values" + member: identifier "reduce" argument: argument value: int_literal "0" @@ -73,19 +89,3 @@ top_level value: name_expr identifier: identifier "+" - callee: - member_access_expr - base: - name_expr - identifier: identifier "values" - member: identifier "reduce" - name: identifier "sum" - parameter: - parameter - external_name: identifier "_" - pattern: - name_pattern - identifier: identifier "values" - return_type: - named_type_expr - name: identifier "Int" diff --git a/unified/extractor/tests/corpus/swift/loops/break-and-continue.output b/unified/extractor/tests/corpus/swift/loops/break-and-continue.output index 702cd0cbc68b..76b2c77b968d 100644 --- a/unified/extractor/tests/corpus/swift/loops/break-and-continue.output +++ b/unified/extractor/tests/corpus/swift/loops/break-and-continue.output @@ -59,16 +59,22 @@ top_level block stmt: for_each_stmt + pattern: + name_pattern + identifier: identifier "x" + iterable: + name_expr + identifier: identifier "xs" body: block stmt: if_expr condition: binary_expr - operator: infix_operator "<" left: name_expr identifier: identifier "x" + operator: infix_operator "<" right: int_literal "0" then: block @@ -76,26 +82,20 @@ top_level if_expr condition: binary_expr - operator: infix_operator ">" left: name_expr identifier: identifier "x" + operator: infix_operator ">" right: int_literal "100" then: block stmt: break_expr "break" call_expr + callee: + name_expr + identifier: identifier "print" argument: argument value: name_expr identifier: identifier "x" - callee: - name_expr - identifier: identifier "print" - pattern: - name_pattern - identifier: identifier "x" - iterable: - name_expr - identifier: identifier "xs" diff --git a/unified/extractor/tests/corpus/swift/loops/for-in-over-array-literal.output b/unified/extractor/tests/corpus/swift/loops/for-in-over-array-literal.output index bb1711a23412..cd1e6d8baab1 100644 --- a/unified/extractor/tests/corpus/swift/loops/for-in-over-array-literal.output +++ b/unified/extractor/tests/corpus/swift/loops/for-in-over-array-literal.output @@ -36,18 +36,6 @@ top_level block stmt: for_each_stmt - body: - block - stmt: - call_expr - argument: - argument - value: - name_expr - identifier: identifier "x" - callee: - name_expr - identifier: identifier "print" pattern: name_pattern identifier: identifier "x" @@ -57,3 +45,15 @@ top_level int_literal "1" int_literal "2" int_literal "3" + body: + block + stmt: + call_expr + callee: + name_expr + identifier: identifier "print" + argument: + argument + value: + name_expr + identifier: identifier "x" diff --git a/unified/extractor/tests/corpus/swift/loops/for-in-over-range.output b/unified/extractor/tests/corpus/swift/loops/for-in-over-range.output index 87a0baf328b0..eb65a677d45b 100644 --- a/unified/extractor/tests/corpus/swift/loops/for-in-over-range.output +++ b/unified/extractor/tests/corpus/swift/loops/for-in-over-range.output @@ -35,23 +35,23 @@ top_level block stmt: for_each_stmt + pattern: + name_pattern + identifier: identifier "i" + iterable: + binary_expr + left: int_literal "0" + operator: infix_operator "..<" + right: int_literal "10" body: block stmt: call_expr + callee: + name_expr + identifier: identifier "print" argument: argument value: name_expr identifier: identifier "i" - callee: - name_expr - identifier: identifier "print" - pattern: - name_pattern - identifier: identifier "i" - iterable: - binary_expr - operator: infix_operator "..<" - left: int_literal "0" - right: int_literal "10" diff --git a/unified/extractor/tests/corpus/swift/loops/for-in-with-where-clause.output b/unified/extractor/tests/corpus/swift/loops/for-in-with-where-clause.output index 84e832c2be5d..be538bde4473 100644 --- a/unified/extractor/tests/corpus/swift/loops/for-in-with-where-clause.output +++ b/unified/extractor/tests/corpus/swift/loops/for-in-with-where-clause.output @@ -39,28 +39,28 @@ top_level block stmt: for_each_stmt - body: - block - stmt: - call_expr - argument: - argument - value: - name_expr - identifier: identifier "x" - callee: - name_expr - identifier: identifier "print" pattern: name_pattern identifier: identifier "x" + iterable: + name_expr + identifier: identifier "xs" guard: binary_expr - operator: infix_operator ">" left: name_expr identifier: identifier "x" + operator: infix_operator ">" right: int_literal "0" - iterable: - name_expr - identifier: identifier "xs" + body: + block + stmt: + call_expr + callee: + name_expr + identifier: identifier "print" + argument: + argument + value: + name_expr + identifier: identifier "x" diff --git a/unified/extractor/tests/corpus/swift/loops/repeat-while-loop.output b/unified/extractor/tests/corpus/swift/loops/repeat-while-loop.output index 15b673109f2f..547a50de735b 100644 --- a/unified/extractor/tests/corpus/swift/loops/repeat-while-loop.output +++ b/unified/extractor/tests/corpus/swift/loops/repeat-while-loop.output @@ -35,15 +35,15 @@ top_level block stmt: compound_assign_expr - operator: infix_operator "-=" target: name_expr identifier: identifier "x" + operator: infix_operator "-=" value: int_literal "1" condition: binary_expr - operator: infix_operator ">" left: name_expr identifier: identifier "x" + operator: infix_operator ">" right: int_literal "0" diff --git a/unified/extractor/tests/corpus/swift/loops/while-loop.output b/unified/extractor/tests/corpus/swift/loops/while-loop.output index 516ab43a2ee5..7a57bb42068f 100644 --- a/unified/extractor/tests/corpus/swift/loops/while-loop.output +++ b/unified/extractor/tests/corpus/swift/loops/while-loop.output @@ -31,19 +31,19 @@ top_level block stmt: while_stmt + condition: + binary_expr + left: + name_expr + identifier: identifier "x" + operator: infix_operator ">" + right: int_literal "0" body: block stmt: compound_assign_expr - operator: infix_operator "-=" target: name_expr identifier: identifier "x" + operator: infix_operator "-=" value: int_literal "1" - condition: - binary_expr - operator: infix_operator ">" - left: - name_expr - identifier: identifier "x" - right: int_literal "0" diff --git a/unified/extractor/tests/corpus/swift/operators/addition.output b/unified/extractor/tests/corpus/swift/operators/addition.output index 42c0ca9de617..072682f6f381 100644 --- a/unified/extractor/tests/corpus/swift/operators/addition.output +++ b/unified/extractor/tests/corpus/swift/operators/addition.output @@ -16,10 +16,10 @@ top_level block stmt: binary_expr - operator: infix_operator "+" left: name_expr identifier: identifier "a" + operator: infix_operator "+" right: name_expr identifier: identifier "b" diff --git a/unified/extractor/tests/corpus/swift/operators/comparison.output b/unified/extractor/tests/corpus/swift/operators/comparison.output index f9428ad17589..aeee98ecd535 100644 --- a/unified/extractor/tests/corpus/swift/operators/comparison.output +++ b/unified/extractor/tests/corpus/swift/operators/comparison.output @@ -16,10 +16,10 @@ top_level block stmt: binary_expr - operator: infix_operator "<" left: name_expr identifier: identifier "a" + operator: infix_operator "<" right: name_expr identifier: identifier "b" diff --git a/unified/extractor/tests/corpus/swift/operators/division.output b/unified/extractor/tests/corpus/swift/operators/division.output index 765549543023..c2a0a03a23f3 100644 --- a/unified/extractor/tests/corpus/swift/operators/division.output +++ b/unified/extractor/tests/corpus/swift/operators/division.output @@ -16,10 +16,10 @@ top_level block stmt: binary_expr - operator: infix_operator "/" left: name_expr identifier: identifier "a" + operator: infix_operator "/" right: name_expr identifier: identifier "b" diff --git a/unified/extractor/tests/corpus/swift/operators/equality.output b/unified/extractor/tests/corpus/swift/operators/equality.output index cc891492c75f..64c2fb78b178 100644 --- a/unified/extractor/tests/corpus/swift/operators/equality.output +++ b/unified/extractor/tests/corpus/swift/operators/equality.output @@ -16,10 +16,10 @@ top_level block stmt: binary_expr - operator: infix_operator "==" left: name_expr identifier: identifier "a" + operator: infix_operator "==" right: name_expr identifier: identifier "b" diff --git a/unified/extractor/tests/corpus/swift/operators/logical-and.output b/unified/extractor/tests/corpus/swift/operators/logical-and.output index bf852cd46146..fbdbd904eafe 100644 --- a/unified/extractor/tests/corpus/swift/operators/logical-and.output +++ b/unified/extractor/tests/corpus/swift/operators/logical-and.output @@ -16,10 +16,10 @@ top_level block stmt: binary_expr - operator: infix_operator "&&" left: name_expr identifier: identifier "a" + operator: infix_operator "&&" right: name_expr identifier: identifier "b" diff --git a/unified/extractor/tests/corpus/swift/operators/logical-or.output b/unified/extractor/tests/corpus/swift/operators/logical-or.output index e246174844c1..5d15828065cf 100644 --- a/unified/extractor/tests/corpus/swift/operators/logical-or.output +++ b/unified/extractor/tests/corpus/swift/operators/logical-or.output @@ -16,10 +16,10 @@ top_level block stmt: binary_expr - operator: infix_operator "||" left: name_expr identifier: identifier "a" + operator: infix_operator "||" right: name_expr identifier: identifier "b" diff --git a/unified/extractor/tests/corpus/swift/operators/multiplication.output b/unified/extractor/tests/corpus/swift/operators/multiplication.output index b4c33b132863..77ce11a659e4 100644 --- a/unified/extractor/tests/corpus/swift/operators/multiplication.output +++ b/unified/extractor/tests/corpus/swift/operators/multiplication.output @@ -16,10 +16,10 @@ top_level block stmt: binary_expr - operator: infix_operator "*" left: name_expr identifier: identifier "a" + operator: infix_operator "*" right: name_expr identifier: identifier "b" diff --git a/unified/extractor/tests/corpus/swift/operators/operator-precedence-addition-and-multiplication.output b/unified/extractor/tests/corpus/swift/operators/operator-precedence-addition-and-multiplication.output index b1467474e7c6..2c89c306a6d0 100644 --- a/unified/extractor/tests/corpus/swift/operators/operator-precedence-addition-and-multiplication.output +++ b/unified/extractor/tests/corpus/swift/operators/operator-precedence-addition-and-multiplication.output @@ -20,16 +20,16 @@ top_level block stmt: binary_expr - operator: infix_operator "+" left: name_expr identifier: identifier "a" + operator: infix_operator "+" right: binary_expr - operator: infix_operator "*" left: name_expr identifier: identifier "b" + operator: infix_operator "*" right: name_expr identifier: identifier "c" diff --git a/unified/extractor/tests/corpus/swift/operators/parenthesised-expression.output b/unified/extractor/tests/corpus/swift/operators/parenthesised-expression.output index dfc60e5b7f72..36216b4201f4 100644 --- a/unified/extractor/tests/corpus/swift/operators/parenthesised-expression.output +++ b/unified/extractor/tests/corpus/swift/operators/parenthesised-expression.output @@ -24,8 +24,8 @@ top_level block stmt: binary_expr - operator: infix_operator "*" left: tuple_expr "(a + b)" + operator: infix_operator "*" right: name_expr identifier: identifier "c" diff --git a/unified/extractor/tests/corpus/swift/operators/range-operator.output b/unified/extractor/tests/corpus/swift/operators/range-operator.output index 03d0290bb7c5..574eccd9795e 100644 --- a/unified/extractor/tests/corpus/swift/operators/range-operator.output +++ b/unified/extractor/tests/corpus/swift/operators/range-operator.output @@ -16,6 +16,6 @@ top_level block stmt: binary_expr - operator: infix_operator "..." left: int_literal "1" + operator: infix_operator "..." right: int_literal "10" diff --git a/unified/extractor/tests/corpus/swift/operators/subtraction.output b/unified/extractor/tests/corpus/swift/operators/subtraction.output index 69f75e720408..993a6c3b6838 100644 --- a/unified/extractor/tests/corpus/swift/operators/subtraction.output +++ b/unified/extractor/tests/corpus/swift/operators/subtraction.output @@ -16,10 +16,10 @@ top_level block stmt: binary_expr - operator: infix_operator "-" left: name_expr identifier: identifier "a" + operator: infix_operator "-" right: name_expr identifier: identifier "b" diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/do-catch.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/do-catch.output index c807bd9b7b9c..1178570e5117 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors/do-catch.output +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/do-catch.output @@ -61,11 +61,11 @@ top_level block stmt: call_expr + callee: + name_expr + identifier: identifier "print" argument: argument value: name_expr identifier: identifier "error" - callee: - name_expr - identifier: identifier "print" diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/nil-coalescing.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/nil-coalescing.output index 81a9a9187c04..c0b3a3a9783a 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors/nil-coalescing.output +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/nil-coalescing.output @@ -31,8 +31,8 @@ top_level identifier: identifier "n" value: binary_expr - operator: infix_operator "??" left: name_expr identifier: identifier "opt" + operator: infix_operator "??" right: int_literal "0" diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/throwing-function.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/throwing-function.output index f1240bd0b3ef..880128cd372f 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors/throwing-function.output +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/throwing-function.output @@ -31,12 +31,12 @@ top_level block stmt: function_declaration + name: identifier "read" + return_type: + named_type_expr + name: identifier "String" body: block stmt: return_expr value: string_literal "\"\"" - name: identifier "read" - return_type: - named_type_expr - name: identifier "String" diff --git a/unified/extractor/tests/corpus/swift/types/binding-modifier-does-not-leak-into-accessor-body.output b/unified/extractor/tests/corpus/swift/types/binding-modifier-does-not-leak-into-accessor-body.output index 4ee195672bb2..dc137a3e621f 100644 --- a/unified/extractor/tests/corpus/swift/types/binding-modifier-does-not-leak-into-accessor-body.output +++ b/unified/extractor/tests/corpus/swift/types/binding-modifier-does-not-leak-into-accessor-body.output @@ -67,34 +67,34 @@ top_level block stmt: accessor_declaration + modifier: modifier "var" + name: identifier "p" + accessor_kind: accessor_kind "get" + type: + named_type_expr + name: identifier "Int" body: block stmt: switch_expr + value: + name_expr + identifier: identifier "y" case: switch_case - body: - block - stmt: - return_expr - value: int_literal "1" pattern: expr_equality_pattern expr: name_expr identifier: identifier "someConstant" + body: + block + stmt: + return_expr + value: int_literal "1" switch_case body: block stmt: return_expr value: int_literal "2" - value: - name_expr - identifier: identifier "y" - modifier: modifier "var" - name: identifier "p" - type: - named_type_expr - name: identifier "Int" - accessor_kind: accessor_kind "get" diff --git a/unified/extractor/tests/corpus/swift/types/class-with-initializer.output b/unified/extractor/tests/corpus/swift/types/class-with-initializer.output index 13e0097172cc..77cfa70ac351 100644 --- a/unified/extractor/tests/corpus/swift/types/class-with-initializer.output +++ b/unified/extractor/tests/corpus/swift/types/class-with-initializer.output @@ -69,6 +69,8 @@ top_level block stmt: class_like_declaration + modifier: modifier "class" + name: identifier "Point" member: variable_declaration modifier: modifier "var" @@ -92,5 +94,3 @@ top_level value: name_expr identifier: identifier "x" - modifier: modifier "class" - name: identifier "Point" diff --git a/unified/extractor/tests/corpus/swift/types/class-with-method.output b/unified/extractor/tests/corpus/swift/types/class-with-method.output index 770030d884a7..20152cd26c8e 100644 --- a/unified/extractor/tests/corpus/swift/types/class-with-method.output +++ b/unified/extractor/tests/corpus/swift/types/class-with-method.output @@ -44,6 +44,8 @@ top_level block stmt: class_like_declaration + modifier: modifier "class" + name: identifier "Counter" member: variable_declaration modifier: modifier "var" @@ -52,15 +54,13 @@ top_level identifier: identifier "n" value: int_literal "0" function_declaration + name: identifier "bump" body: block stmt: compound_assign_expr - operator: infix_operator "+=" target: name_expr identifier: identifier "n" + operator: infix_operator "+=" value: int_literal "1" - name: identifier "bump" - modifier: modifier "class" - name: identifier "Counter" diff --git a/unified/extractor/tests/corpus/swift/types/class-with-stored-properties.output b/unified/extractor/tests/corpus/swift/types/class-with-stored-properties.output index 9d28afe6ae0e..c2ae82ea3dae 100644 --- a/unified/extractor/tests/corpus/swift/types/class-with-stored-properties.output +++ b/unified/extractor/tests/corpus/swift/types/class-with-stored-properties.output @@ -57,6 +57,8 @@ top_level block stmt: class_like_declaration + modifier: modifier "class" + name: identifier "Point" member: variable_declaration modifier: modifier "var" @@ -74,5 +76,3 @@ top_level type: named_type_expr name: identifier "Int" - modifier: modifier "class" - name: identifier "Point" diff --git a/unified/extractor/tests/corpus/swift/types/computed-property.output b/unified/extractor/tests/corpus/swift/types/computed-property.output index 8803e652d316..287f75956330 100644 --- a/unified/extractor/tests/corpus/swift/types/computed-property.output +++ b/unified/extractor/tests/corpus/swift/types/computed-property.output @@ -88,6 +88,8 @@ top_level block stmt: class_like_declaration + modifier: modifier "class" + name: identifier "Rect" member: variable_declaration modifier: modifier "var" @@ -106,24 +108,22 @@ top_level named_type_expr name: identifier "Double" accessor_declaration + modifier: modifier "var" + name: identifier "area" + accessor_kind: accessor_kind "get" + type: + named_type_expr + name: identifier "Double" body: block stmt: return_expr value: binary_expr - operator: infix_operator "*" left: name_expr identifier: identifier "w" + operator: infix_operator "*" right: name_expr identifier: identifier "h" - modifier: modifier "var" - name: identifier "area" - type: - named_type_expr - name: identifier "Double" - accessor_kind: accessor_kind "get" - modifier: modifier "class" - name: identifier "Rect" diff --git a/unified/extractor/tests/corpus/swift/types/enum-with-associated-values.output b/unified/extractor/tests/corpus/swift/types/enum-with-associated-values.output index 12b5191f69f9..f520b649095a 100644 --- a/unified/extractor/tests/corpus/swift/types/enum-with-associated-values.output +++ b/unified/extractor/tests/corpus/swift/types/enum-with-associated-values.output @@ -53,34 +53,34 @@ top_level block stmt: class_like_declaration + modifier: modifier "enum" + name: identifier "Shape" member: class_like_declaration + modifier: modifier "enum_case" + name: identifier "circle" member: constructor_declaration - body: block "circle(radius: Double)" parameter: parameter - pattern: - name_pattern - identifier: identifier "radius" type: named_type_expr name: identifier "Double" - modifier: modifier "enum_case" - name: identifier "circle" + pattern: + name_pattern + identifier: identifier "radius" + body: block "circle(radius: Double)" class_like_declaration + modifier: modifier "enum_case" + name: identifier "square" member: constructor_declaration - body: block "square(side: Double)" parameter: parameter - pattern: - name_pattern - identifier: identifier "side" type: named_type_expr name: identifier "Double" - modifier: modifier "enum_case" - name: identifier "square" - modifier: modifier "enum" - name: identifier "Shape" + pattern: + name_pattern + identifier: identifier "side" + body: block "square(side: Double)" diff --git a/unified/extractor/tests/corpus/swift/types/enum-with-cases.output b/unified/extractor/tests/corpus/swift/types/enum-with-cases.output index 72435fd2b1f7..f70f43bfb8ec 100644 --- a/unified/extractor/tests/corpus/swift/types/enum-with-cases.output +++ b/unified/extractor/tests/corpus/swift/types/enum-with-cases.output @@ -39,6 +39,8 @@ top_level block stmt: class_like_declaration + modifier: modifier "enum" + name: identifier "Direction" member: variable_declaration modifier: modifier "enum_case" @@ -60,5 +62,3 @@ top_level pattern: name_pattern identifier: identifier "west" - modifier: modifier "enum" - name: identifier "Direction" diff --git a/unified/extractor/tests/corpus/swift/types/enum-with-comma-separated-cases-chained-declaration.output b/unified/extractor/tests/corpus/swift/types/enum-with-comma-separated-cases-chained-declaration.output index 6a4aac4b552d..56e793247bbf 100644 --- a/unified/extractor/tests/corpus/swift/types/enum-with-comma-separated-cases-chained-declaration.output +++ b/unified/extractor/tests/corpus/swift/types/enum-with-comma-separated-cases-chained-declaration.output @@ -30,6 +30,8 @@ top_level block stmt: class_like_declaration + modifier: modifier "enum" + name: identifier "Suit" member: variable_declaration modifier: modifier "enum_case" @@ -57,5 +59,3 @@ top_level pattern: name_pattern identifier: identifier "spades" - modifier: modifier "enum" - name: identifier "Suit" diff --git a/unified/extractor/tests/corpus/swift/types/extension.output b/unified/extractor/tests/corpus/swift/types/extension.output index ad663cb86e16..894b8c530c81 100644 --- a/unified/extractor/tests/corpus/swift/types/extension.output +++ b/unified/extractor/tests/corpus/swift/types/extension.output @@ -45,24 +45,24 @@ top_level block stmt: class_like_declaration + modifier: modifier "extension" + name: identifier "Int" member: function_declaration + name: identifier "squared" + return_type: + named_type_expr + name: identifier "Int" body: block stmt: return_expr value: binary_expr - operator: infix_operator "*" left: name_expr identifier: identifier "self" + operator: infix_operator "*" right: name_expr identifier: identifier "self" - name: identifier "squared" - return_type: - named_type_expr - name: identifier "Int" - modifier: modifier "extension" - name: identifier "Int" diff --git a/unified/extractor/tests/corpus/swift/types/property-with-getter-and-setter.output b/unified/extractor/tests/corpus/swift/types/property-with-getter-and-setter.output index 0a8b2d8cc5d7..a44c6fc3c127 100644 --- a/unified/extractor/tests/corpus/swift/types/property-with-getter-and-setter.output +++ b/unified/extractor/tests/corpus/swift/types/property-with-getter-and-setter.output @@ -80,6 +80,8 @@ top_level block stmt: class_like_declaration + modifier: modifier "class" + name: identifier "Box" member: variable_declaration modifier: modifier "var" @@ -88,6 +90,12 @@ top_level identifier: identifier "_v" value: int_literal "0" accessor_declaration + modifier: modifier "var" + name: identifier "v" + accessor_kind: accessor_kind "get" + type: + named_type_expr + name: identifier "Int" body: block stmt: @@ -95,13 +103,15 @@ top_level value: name_expr identifier: identifier "_v" - modifier: modifier "var" + accessor_declaration + modifier: + modifier "var" + modifier "chained_declaration" name: identifier "v" + accessor_kind: accessor_kind "set" type: named_type_expr name: identifier "Int" - accessor_kind: accessor_kind "get" - accessor_declaration body: block stmt: @@ -112,13 +122,3 @@ top_level value: name_expr identifier: identifier "newValue" - modifier: - modifier "var" - modifier "chained_declaration" - name: identifier "v" - type: - named_type_expr - name: identifier "Int" - accessor_kind: accessor_kind "set" - modifier: modifier "class" - name: identifier "Box" diff --git a/unified/extractor/tests/corpus/swift/types/protocol-declaration.output b/unified/extractor/tests/corpus/swift/types/protocol-declaration.output index 55a71218c18c..628b58e979f6 100644 --- a/unified/extractor/tests/corpus/swift/types/protocol-declaration.output +++ b/unified/extractor/tests/corpus/swift/types/protocol-declaration.output @@ -21,9 +21,9 @@ top_level block stmt: class_like_declaration + modifier: modifier "protocol" + name: identifier "Drawable" member: function_declaration - body: block "func draw()" name: identifier "draw" - modifier: modifier "protocol" - name: identifier "Drawable" + body: block "func draw()" diff --git a/unified/extractor/tests/corpus/swift/types/protocol-with-read-only-and-read-write-property-requirements.output b/unified/extractor/tests/corpus/swift/types/protocol-with-read-only-and-read-write-property-requirements.output index 0293534adf76..11296b02e005 100644 --- a/unified/extractor/tests/corpus/swift/types/protocol-with-read-only-and-read-write-property-requirements.output +++ b/unified/extractor/tests/corpus/swift/types/protocol-with-read-only-and-read-write-property-requirements.output @@ -61,25 +61,25 @@ top_level block stmt: class_like_declaration + modifier: modifier "protocol" + name: identifier "P" member: accessor_declaration name: identifier "foo" + accessor_kind: accessor_kind "get" type: named_type_expr name: identifier "Int" - accessor_kind: accessor_kind "get" accessor_declaration name: identifier "bar" + accessor_kind: accessor_kind "get" type: named_type_expr name: identifier "String" - accessor_kind: accessor_kind "get" accessor_declaration modifier: modifier "chained_declaration" name: identifier "bar" + accessor_kind: accessor_kind "set" type: named_type_expr name: identifier "String" - accessor_kind: accessor_kind "set" - modifier: modifier "protocol" - name: identifier "P" diff --git a/unified/extractor/tests/corpus/swift/types/struct.output b/unified/extractor/tests/corpus/swift/types/struct.output index e130ef9b8623..7de3a4f5fde5 100644 --- a/unified/extractor/tests/corpus/swift/types/struct.output +++ b/unified/extractor/tests/corpus/swift/types/struct.output @@ -57,6 +57,8 @@ top_level block stmt: class_like_declaration + modifier: modifier "struct" + name: identifier "Point" member: variable_declaration modifier: modifier "let" @@ -74,5 +76,3 @@ top_level type: named_type_expr name: identifier "Int" - modifier: modifier "struct" - name: identifier "Point" diff --git a/unified/extractor/tests/corpus/swift/variables/binding-modifier-does-not-leak-into-initializer.output b/unified/extractor/tests/corpus/swift/variables/binding-modifier-does-not-leak-into-initializer.output index 65364c1ef918..a6d554ca8370 100644 --- a/unified/extractor/tests/corpus/swift/variables/binding-modifier-does-not-leak-into-initializer.output +++ b/unified/extractor/tests/corpus/swift/variables/binding-modifier-does-not-leak-into-initializer.output @@ -44,20 +44,20 @@ top_level identifier: identifier "x" value: switch_expr + value: + name_expr + identifier: identifier "y" case: switch_case - body: - block - stmt: int_literal "1" pattern: expr_equality_pattern expr: name_expr identifier: identifier "someConstant" + body: + block + stmt: int_literal "1" switch_case body: block stmt: int_literal "2" - value: - name_expr - identifier: identifier "y" diff --git a/unified/extractor/tests/corpus/swift/variables/compound-assignment.output b/unified/extractor/tests/corpus/swift/variables/compound-assignment.output index 95b7edb0a6ba..5385e0ae46be 100644 --- a/unified/extractor/tests/corpus/swift/variables/compound-assignment.output +++ b/unified/extractor/tests/corpus/swift/variables/compound-assignment.output @@ -18,8 +18,8 @@ top_level block stmt: compound_assign_expr - operator: infix_operator "+=" target: name_expr identifier: identifier "x" + operator: infix_operator "+=" value: int_literal "1" diff --git a/unified/extractor/tests/corpus/swift/variables/property-with-willset-and-didset-observers.output b/unified/extractor/tests/corpus/swift/variables/property-with-willset-and-didset-observers.output index 2d612e1d950e..5bf4b48efbcc 100644 --- a/unified/extractor/tests/corpus/swift/variables/property-with-willset-and-didset-observers.output +++ b/unified/extractor/tests/corpus/swift/variables/property-with-willset-and-didset-observers.output @@ -72,6 +72,8 @@ top_level block stmt: class_like_declaration + modifier: modifier "class" + name: identifier "C" member: variable_declaration modifier: modifier "var" @@ -83,40 +85,38 @@ top_level name: identifier "Int" value: int_literal "0" accessor_declaration + modifier: + modifier "var" + modifier "chained_declaration" + name: identifier "x" + accessor_kind: accessor_kind "willSet" body: block stmt: call_expr + callee: + name_expr + identifier: identifier "print" argument: argument value: name_expr identifier: identifier "newValue" - callee: - name_expr - identifier: identifier "print" + accessor_declaration modifier: modifier "var" modifier "chained_declaration" name: identifier "x" - accessor_kind: accessor_kind "willSet" - accessor_declaration + accessor_kind: accessor_kind "didSet" body: block stmt: call_expr + callee: + name_expr + identifier: identifier "print" argument: argument value: name_expr identifier: identifier "oldValue" - callee: - name_expr - identifier: identifier "print" - modifier: - modifier "var" - modifier "chained_declaration" - name: identifier "x" - accessor_kind: accessor_kind "didSet" - modifier: modifier "class" - name: identifier "C" From 8206f6fa9785381b1a571074496b3a957bcf7675 Mon Sep 17 00:00:00 2001 From: Taus Date: Thu, 16 Jul 2026 12:05:37 +0000 Subject: [PATCH 024/188] swift-syntax-rs: Fold local and stdlib operators In our swift-syntax wrapper, we now attempt to fold all operator sequences (i.e. `sequenceExpr` nodes) into appropriate `infixOperatorExpr` nodes, assuming the requisite operator definitions are present. Currently, we only consider operators that are defined in the standard library, and operators that are defined in the current file, leaving operators defined in separate modules as future work. The folding is done maximally -- if an argument of an unknown operator can be folded in isolation, then this is done. Each top-level sequence is folded independently, so a single unknown operator leaves only its own sequence flat rather than aborting folding elsewhere. --- unified/swift-syntax-rs/BUILD.bazel | 1 + unified/swift-syntax-rs/README.md | 31 +++++++ unified/swift-syntax-rs/src/lib.rs | 83 +++++++++++++++++++ unified/swift-syntax-rs/swift/Package.swift | 1 + .../SwiftSyntaxFFI/SwiftSyntaxFFI.swift | 69 ++++++++++++++- 5 files changed, 184 insertions(+), 1 deletion(-) diff --git a/unified/swift-syntax-rs/BUILD.bazel b/unified/swift-syntax-rs/BUILD.bazel index 5c2360d4deba..11484736ca8f 100644 --- a/unified/swift-syntax-rs/BUILD.bazel +++ b/unified/swift-syntax-rs/BUILD.bazel @@ -27,6 +27,7 @@ xcode_transition_swift_library( module_name = "SwiftSyntaxFFI", target_compatible_with = _SWIFT_SUPPORTED_PLATFORMS, deps = [ + "@swift-syntax//:SwiftOperators", "@swift-syntax//:SwiftParser", "@swift-syntax//:SwiftSyntax", ], diff --git a/unified/swift-syntax-rs/README.md b/unified/swift-syntax-rs/README.md index d43969199f91..7d15c6f2c23e 100644 --- a/unified/swift-syntax-rs/README.md +++ b/unified/swift-syntax-rs/README.md @@ -91,6 +91,37 @@ arrays (their collection nodes are elided), layout children such as comment rides along as `trailingTrivia` on the token it follows. Tokens without trivia (most of them) simply omit the `leadingTrivia`/`trailingTrivia` keys. +### Operator folding + +Swift's grammar does not encode operator precedence, so the parser represents an +expression like `a + b * c` as a flat `sequenceExpr` (an alternating list of +operands and operators). Before serializing, we fold these sequences into +precedence-correct `infixOperatorExpr` (and `ternaryExpr`) trees — so `1 + 2 * 3` +becomes `1 + (2 * 3)`. + +Folding needs to know each operator's precedence group, which comes from +declarations rather than the grammar. We resolve operators from two sources: + +- the **Swift standard library** operators (a built-in approximation), and +- operator / precedence-group declarations **in the file being parsed**. + +Operators defined anywhere else (for example, imported from another module) are +unknown, so their precedence cannot be determined. Rather than guess — which +would silently produce a wrongly-structured tree — each top-level sequence is +folded independently, and any sequence that uses an unknown operator is left as +a flat `sequenceExpr`. So `a <+> b` (with an undeclared `<+>`) stays flat, while +a neighbouring `1 + 2` in the same file still folds. Supporting operators from +other modules is future work. + +Folding is bottom-up, so a *grouped* subexpression still folds even when the +sequence enclosing it uses an unknown operator: in `a *** (b + c)` (with an +unknown `***`) the parenthesised `b + c` is its own sequence and folds, while +the outer `a *** …` stays flat. This only applies when the subexpression is +syntactically isolated (parentheses, call arguments, collection elements, …); +an unparenthesised `a *** b + c` is a single flat sequence whose structure +cannot be determined without knowing `***`'s precedence, so it is left flat in +its entirety. + ## Prerequisites The build does not depend on any particular version manager. You need: diff --git a/unified/swift-syntax-rs/src/lib.rs b/unified/swift-syntax-rs/src/lib.rs index 2a8fe0411af8..5f558d942fc8 100644 --- a/unified/swift-syntax-rs/src/lib.rs +++ b/unified/swift-syntax-rs/src/lib.rs @@ -132,4 +132,87 @@ mod tests { "comment trivia not captured: {json}" ); } + + #[test] + fn folds_standard_library_operators() { + // Standard-library operators are folded into a precedence-correct tree: + // the flat `sequenceExpr` becomes nested `infixOperatorExpr` nodes. + let json = parse_to_json("let x = 1 + 2 * 3").expect("parsing should succeed"); + assert!( + json.contains("\"kind\":\"infixOperatorExpr\""), + "operators were not folded: {json}" + ); + assert!( + !json.contains("\"kind\":\"sequenceExpr\""), + "a foldable sequence was left flat: {json}" + ); + } + + #[test] + fn folds_file_defined_operators() { + // An operator declared in the same file (with a known precedence group) + // is folded, just like a standard-library one. + let json = parse_to_json("infix operator |>: AdditionPrecedence\nlet y = a |> b |> c") + .expect("parsing should succeed"); + assert!( + json.contains("\"kind\":\"infixOperatorExpr\""), + "file-defined operator was not folded: {json}" + ); + assert!( + !json.contains("\"kind\":\"sequenceExpr\""), + "a foldable sequence was left flat: {json}" + ); + } + + #[test] + fn leaves_unknown_operators_unfolded() { + // An operator that is neither in the standard library nor declared in + // this file (e.g. imported from another module) has unknown precedence, + // so its sequence is left flat rather than folded incorrectly. + let json = parse_to_json("let z = a <+> b").expect("parsing should succeed"); + assert!( + json.contains("\"kind\":\"sequenceExpr\""), + "unknown-operator sequence should stay flat: {json}" + ); + assert!( + !json.contains("\"kind\":\"infixOperatorExpr\""), + "unknown operator should not be folded: {json}" + ); + } + + #[test] + fn folds_each_sequence_independently() { + // Folding is isolated per sequence: a statement using a known operator + // folds even when another statement uses an unknown one. One unfoldable + // expression does not suppress folding elsewhere. + let json = parse_to_json("let x = 1 + 2\nlet y = a <+> b").expect("parsing should succeed"); + assert!( + json.contains("\"kind\":\"infixOperatorExpr\""), + "the known-operator statement should fold: {json}" + ); + assert!( + json.contains("\"kind\":\"sequenceExpr\""), + "the unknown-operator statement should stay flat: {json}" + ); + } + + #[test] + fn folds_grouped_subexpressions_under_unknown_operators() { + // A parenthesized (or otherwise bracketed) subexpression is its own + // sequence, so it folds independently even when the enclosing sequence + // uses an unknown operator. Here `***` is unknown (outer stays flat) but + // the grouped `b + c` still folds. Note this only works because the + // parentheses isolate `b + c`: in an unparenthesized `a *** b + c` the + // whole thing is one flat sequence whose structure can't be determined + // without `***`'s precedence, so it is left flat entirely. + let json = parse_to_json("let r = a *** (b + c)").expect("parsing should succeed"); + assert!( + json.contains("\"kind\":\"infixOperatorExpr\""), + "the grouped known-operator subexpression should fold: {json}" + ); + assert!( + json.contains("\"kind\":\"sequenceExpr\""), + "the enclosing unknown-operator sequence should stay flat: {json}" + ); + } } diff --git a/unified/swift-syntax-rs/swift/Package.swift b/unified/swift-syntax-rs/swift/Package.swift index a58b7c1a479b..37fa5a1eed7b 100644 --- a/unified/swift-syntax-rs/swift/Package.swift +++ b/unified/swift-syntax-rs/swift/Package.swift @@ -29,6 +29,7 @@ let package = Package( dependencies: [ .product(name: "SwiftSyntax", package: "swift-syntax"), .product(name: "SwiftParser", package: "swift-syntax"), + .product(name: "SwiftOperators", package: "swift-syntax"), ] ) ] diff --git a/unified/swift-syntax-rs/swift/Sources/SwiftSyntaxFFI/SwiftSyntaxFFI.swift b/unified/swift-syntax-rs/swift/Sources/SwiftSyntaxFFI/SwiftSyntaxFFI.swift index 6305b1610d06..9471c2ea143d 100644 --- a/unified/swift-syntax-rs/swift/Sources/SwiftSyntaxFFI/SwiftSyntaxFFI.swift +++ b/unified/swift-syntax-rs/swift/Sources/SwiftSyntaxFFI/SwiftSyntaxFFI.swift @@ -1,4 +1,5 @@ import Foundation +import SwiftOperators import SwiftParser // `@_spi(RawSyntax)` exposes the `childName(_:)` helper that maps a child's @@ -151,6 +152,68 @@ private func serialize( return result } +/// Fold the flat operator sequences in `tree` into structured binary/ternary +/// expressions, using operator precedence. +/// +/// Swift's grammar does not encode operator precedence: an expression like +/// `a + b * c` is parsed as a flat `SequenceExpr` (a list of operands and +/// operators). Resolving it into a precedence-correct tree requires knowing the +/// operators' precedence groups, which live in declarations rather than the +/// grammar. We fold using two sources of operator definitions: +/// +/// * `OperatorTable.standardOperators` — the Swift standard library's +/// operators (a built-in approximation), and +/// * the operator / precedence-group declarations in *this* file +/// (via `addSourceFile`). +/// +/// Operators from anywhere else (e.g. imported from another module) are +/// unknown to us. Rather than guess their precedence — which would silently +/// produce an incorrectly-structured tree — we fold each top-level sequence +/// *independently* and leave any sequence containing an unknown operator as a +/// flat `SequenceExpr`. Downstream can treat such a sequence as unsupported. +/// This keeps folding correct for the operators we do know while isolating the +/// rest per sequence, so one exotic operator doesn't block folding elsewhere. +private func foldOperators(in tree: SourceFileSyntax) -> Syntax { + var operators = OperatorTable.standardOperators + // Register operators and precedence groups declared in this file. Swallow + // errors (e.g. a redeclaration of a standard operator): keep whatever we + // can and carry on. + operators.addSourceFile(tree, errorHandler: { _ in }) + return PerSequenceFolder(operators: operators).rewrite(tree) +} + +/// A `SyntaxRewriter` that folds each `SequenceExpr` on its own, leaving +/// sequences it cannot fold (because they use an operator we don't know) flat. +/// +/// This is deliberately more conservative than `OperatorTable.foldAll`, which +/// is all-or-nothing: with a throwing error handler a single unknown operator +/// aborts folding for the *entire* tree, while with a non-throwing handler +/// unknown operators are folded *arbitrarily* (left-associatively), silently +/// producing a wrong tree. Folding each sequence with a throwing handler and +/// catching the error gives us per-sequence isolation instead. +private final class PerSequenceFolder: SyntaxRewriter { + private let operators: OperatorTable + + init(operators: OperatorTable) { + self.operators = operators + super.init() + } + + override func visit(_ node: SequenceExprSyntax) -> ExprSyntax { + // Fold any nested sequences first (bottom-up), so that an unfoldable + // outer sequence still keeps its foldable inner sequences folded. + let inner = super.visit(node).as(SequenceExprSyntax.self)! + do { + // The default error handler throws on the first unknown operator or + // incomparable-precedence pair. + return try operators.foldSingle(inner) + } catch { + // Leave this sequence flat; it uses an operator we don't know. + return ExprSyntax(inner) + } + } +} + /// Parse the given NUL-terminated Swift source string and return a /// heap-allocated, NUL-terminated JSON representation of the syntax tree. /// @@ -161,8 +224,12 @@ public func ssr_parse_json(_ source: UnsafePointer?) -> UnsafeMutablePoin guard let source = source else { return nil } let code = String(cString: source) let tree = Parser.parse(source: code) + // Fold operator sequences before serializing. Source positions are + // preserved by folding (the same tokens, in the same places), so a + // converter built from the original tree maps the folded tree correctly. + let folded = foldOperators(in: tree) let converter = SourceLocationConverter(fileName: "", tree: tree) - let json = serialize(Syntax(tree), converter) + let json = serialize(folded, converter) guard let data = try? JSONSerialization.data( From 2e74c1d83f791776b2f109f6ff0007a4dbc9ee5c Mon Sep 17 00:00:00 2001 From: Taus Date: Thu, 16 Jul 2026 20:47:45 +0000 Subject: [PATCH 025/188] yeast: Desugar an externally-built AST, and validate by field name Prepare yeast for front-ends that do not parse with tree-sitter (e.g. the swift-syntax front-end, whose parser hands us a ready-built `yeast::Ast`): - `Runner`/`ConcreteDesugarer` now hold `Option`. New constructors `Runner::with_schema_no_language`, `ConcreteDesugarer::without_language`, and `DesugaringConfig::build_schema_no_language` build the schema from the output node-types YAML alone. The parsing entry points (`run`/`run_from_tree`) error when no language is present; `run_from_ast` needs none. - `BuildCtx::source_text` is a small convenience for Rust-block rules that read a captured token's source text. - AST-dump type validation now resolves field constraints and required fields by field NAME rather than by field id. A field id is local to the schema that assigned it, so an AST built by one schema (e.g. an external parser's adapter) could not be validated against another (the output node-types schema) without re-keying. Looking up by name keeps the two schemas full independent: they share field names, not ids. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- shared/yeast/src/build.rs | 11 ++++++ shared/yeast/src/dump.rs | 24 +++++++++--- shared/yeast/src/lib.rs | 77 +++++++++++++++++++++++++++++++++------ 3 files changed, 95 insertions(+), 17 deletions(-) diff --git a/shared/yeast/src/build.rs b/shared/yeast/src/build.rs index 508a1e731346..f4f5ae5d18f3 100644 --- a/shared/yeast/src/build.rs +++ b/shared/yeast/src/build.rs @@ -108,6 +108,17 @@ impl<'a, C> BuildCtx<'a, C> { self.captures.get_all(name) } + /// Read the source text of a captured (or any other) node. + /// + /// Convenience for the common `ctx.ast.source_text(id)` reach-through used + /// by Rust-block rules that branch on, or embed, a raw capture's spelling + /// (e.g. an operator or keyword token). Resolves against the stored source + /// bytes, so it works for both parsed nodes and synthesized ones (via their + /// inherited source range). + pub fn source_text(&self, id: Id) -> String { + self.ast.source_text(id) + } + /// Create a named AST node with the given kind and fields. pub fn node(&mut self, kind: &str, fields: Vec<(&str, Vec)>) -> Id { let kind_id = self diff --git a/shared/yeast/src/dump.rs b/shared/yeast/src/dump.rs index f217f1798068..dc348f8789b6 100644 --- a/shared/yeast/src/dump.rs +++ b/shared/yeast/src/dump.rs @@ -162,8 +162,12 @@ fn type_error_for_node( fn expected_for_field<'a>( schema: &'a Schema, parent_kind: &str, - field_id: u16, + field_name: &str, ) -> Option<&'a [crate::schema::NodeType]> { + // Resolve the field NAME in the validation schema's own id space, so the + // AST being dumped and the validation schema stay completely independent: + // they need not share field ids, only field names. + let field_id = schema.field_id_for_name(field_name)?; schema .field_types(parent_kind, field_id) .map(|v| v.as_slice()) @@ -264,8 +268,8 @@ fn dump_node( let children = &node.fields[&field_id]; let field_name = ast.field_name_for_id(field_id).unwrap_or("?"); let child_type_check = type_check.map(|(schema, _, _)| { - let expected = - expected_for_field(schema, node.kind_name(), field_id).or(Some(EMPTY_NODE_TYPES)); + let expected = expected_for_field(schema, node.kind_name(), field_name) + .or(Some(EMPTY_NODE_TYPES)); let parent_field = Some((node.kind_name(), field_name)); (schema, expected, parent_field) }); @@ -307,8 +311,14 @@ fn dump_node( // Check for required fields that are absent if let Some((schema, _, _)) = type_check { - for (field_id, field_name) in schema.required_fields_for_kind(node.kind_name()) { - if !node.fields.contains_key(&field_id) { + for (_field_id, field_name) in schema.required_fields_for_kind(node.kind_name()) { + let present = match field_name { + Some(n) => ast + .field_id_for_name(n) + .is_some_and(|fid| node.fields.contains_key(&fid)), + None => node.fields.contains_key(&CHILD_FIELD), + }; + if !present { let name = field_name.unwrap_or("child"); writeln!(out, "{prefix} <-- ERROR: missing required field '{name}'").unwrap(); } @@ -318,7 +328,9 @@ fn dump_node( // Unnamed children — skip unnamed tokens (keywords, punctuation) if let Some(children) = node.fields.get(&CHILD_FIELD) { let child_type_check = type_check.map(|(schema, _, _)| { - let expected = expected_for_field(schema, node.kind_name(), CHILD_FIELD) + let expected = schema + .field_types(node.kind_name(), CHILD_FIELD) + .map(|v| v.as_slice()) .or(Some(EMPTY_NODE_TYPES)); let parent_field = Some((node.kind_name(), "children")); (schema, expected, parent_field) diff --git a/shared/yeast/src/lib.rs b/shared/yeast/src/lib.rs index 6719a5498e2b..14a0ab055761 100644 --- a/shared/yeast/src/lib.rs +++ b/shared/yeast/src/lib.rs @@ -1329,10 +1329,27 @@ impl DesugaringConfig { None => Ok(schema::from_language(language)), } } + + /// Build the yeast `Schema` from the output YAML alone, with no input + /// tree-sitter grammar. Requires `output_node_types_yaml` to be set (there + /// is no grammar to fall back to). Used by custom (non-tree-sitter) + /// front-ends whose input schema is supplied by their own parser/adapter. + pub fn build_schema_no_language(&self) -> Result { + match self.output_node_types_yaml { + Some(yaml) => node_types_yaml::schema_from_yaml(yaml), + None => Err( + "a language-free desugarer requires output_node_types_yaml to be set".to_string(), + ), + } + } } pub struct Runner<'a, C = ()> { - language: tree_sitter::Language, + /// The input tree-sitter language, used only when parsing (`run_from_tree` + /// / `run`). `None` for pipelines that only ever run over an + /// externally-built AST (`run_from_ast`), so no tree-sitter grammar is + /// required. + language: Option, schema: schema::Schema, phases: &'a [Phase], } @@ -1342,7 +1359,7 @@ impl<'a, C> Runner<'a, C> { pub fn new(language: tree_sitter::Language, phases: &'a [Phase]) -> Self { let schema = schema::from_language(&language); Self { - language, + language: Some(language), schema, phases, } @@ -1355,7 +1372,18 @@ impl<'a, C> Runner<'a, C> { phases: &'a [Phase], ) -> Self { Self { - language, + language: Some(language), + schema: schema.clone(), + phases, + } + } + + /// Create a runner with no input tree-sitter language, for pipelines that + /// only run over an externally-built AST (`run_from_ast`). The parsing + /// entry points (`run_from_tree` / `run`) will error if called. + pub fn with_schema_no_language(schema: &schema::Schema, phases: &'a [Phase]) -> Self { + Self { + language: None, schema: schema.clone(), phases, } @@ -1368,7 +1396,7 @@ impl<'a, C> Runner<'a, C> { ) -> Result { let schema = config.build_schema(&language)?; Ok(Self { - language, + language: Some(language), schema, phases: &config.phases, }) @@ -1388,7 +1416,9 @@ impl<'a, C: Clone> Runner<'a, C> { let mut ast = Ast::from_tree_with_schema_and_source( self.schema.clone(), tree, - &self.language, + self.language + .as_ref() + .ok_or("run_from_tree requires a tree-sitter language")?, source.to_vec(), ); self.run_phases(&mut ast, user_ctx)?; @@ -1398,9 +1428,13 @@ impl<'a, C: Clone> Runner<'a, C> { /// Parse `input` and run all phases, threading `user_ctx` through /// every rule transform. The caller owns the initial context state. pub fn run_with_ctx(&self, input: &str, user_ctx: &mut C) -> Result { + let language = self + .language + .as_ref() + .ok_or("run requires a tree-sitter language")?; let mut parser = tree_sitter::Parser::new(); parser - .set_language(&self.language) + .set_language(language) .map_err(|e| format!("Failed to set language: {e}"))?; let tree = parser .parse(input, None) @@ -1408,7 +1442,7 @@ impl<'a, C: Clone> Runner<'a, C> { let mut ast = Ast::from_tree_with_schema_and_source( self.schema.clone(), &tree, - &self.language, + language, input.as_bytes().to_vec(), ); self.run_phases(&mut ast, user_ctx)?; @@ -1506,7 +1540,10 @@ pub trait Desugarer: Send + Sync { /// schema so that per-call cost is bounded to constructing a transient /// [`Runner`] and cloning the schema (no YAML re-parsing). pub struct ConcreteDesugarer { - language: tree_sitter::Language, + /// The input tree-sitter language, or `None` for a custom (non-tree-sitter) + /// front-end that only ever desugars an externally-built AST + /// (`run_from_ast`). + language: Option, schema: schema::Schema, config: DesugaringConfig, } @@ -1520,7 +1557,20 @@ impl ConcreteDesugarer { ) -> Result { let schema = config.build_schema(&language)?; Ok(Self { - language, + language: Some(language), + schema, + config, + }) + } + + /// Build a desugarer with no input tree-sitter language, for a custom + /// front-end whose parser supplies the input AST directly. Only + /// [`run_from_ast`](Desugarer::run_from_ast) is supported; the schema comes + /// from the config's `output_node_types_yaml` (which must be set). + pub fn without_language(config: DesugaringConfig) -> Result { + let schema = config.build_schema_no_language()?; + Ok(Self { + language: None, schema, config, }) @@ -1533,7 +1583,11 @@ impl Desugarer for ConcreteDesugarer } fn run_from_tree(&self, tree: &tree_sitter::Tree, source: &[u8]) -> Result { - let runner = Runner::with_schema(self.language.clone(), &self.schema, &self.config.phases); + let language = self + .language + .clone() + .ok_or("run_from_tree requires a tree-sitter language")?; + let runner = Runner::with_schema(language, &self.schema, &self.config.phases); runner.run_from_tree(tree, source) } @@ -1541,7 +1595,8 @@ impl Desugarer for ConcreteDesugarer // The AST was built against its own (external) schema; make sure the // output kind/field names the rules build are resolvable in it. ast.register_names_from_schema(&self.schema); - let runner = Runner::with_schema(self.language.clone(), &self.schema, &self.config.phases); + // `run_from_ast` never parses, so no tree-sitter language is needed. + let runner = Runner::with_schema_no_language(&self.schema, &self.config.phases); runner.run_from_ast(ast) } } From bbf52ce7a76bb8b620801863e9d2598210a6e285 Mon Sep 17 00:00:00 2001 From: Taus Date: Fri, 17 Jul 2026 12:26:55 +0000 Subject: [PATCH 026/188] tree-sitter-extractor: Split direct and desugaring extractors Previously the `simple` multi-language extractor carried an optional desugarer, so every language (including plain tree-sitter ones such as ql, dbscheme, json and blame) went through the same desugaring-aware extraction path. This commit splits it into two front-ends that share a private driver: - `simple`: pure tree-sitter extraction with no desugaring. Comments and other `extra` nodes are emitted inline as tokens. (The extractor then extracts these as usual.) - `desugaring`: parses source into a `ParsedTree` (a yeast AST plus side-channel `extra` tokens) and rewrites the AST through a `yeast::Desugarer` before extraction. The parser is a closure, so both tree-sitter grammars (via `tree_sitter_parser`) and custom parsers plug in the same way. The shared multi-file plumbing (threading, glob matching, source-archive copying, TRAP writing) lives in a new private `driver` module behind a `LanguageExtractor` trait, so neither front-end duplicates it. `extract` no longer takes an optional desugarer (it always walks the parse tree directly); `extract_parsed` takes a required desugarer. ql and ruby use the direct path; the unified Swift extractor uses the desugaring path. Also rename the new side-channel identifiers from "trivia" to "extra" (ExtraToken, ParsedTree.extras, emit_extra, ...) to match tree-sitter's own `is_extra()` terminology. The pre-existing `*_trivia_tokeninfo` relation is left unchanged for a separate change. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- ql/Cargo.lock | 10 + ql/extractor/src/extractor.rs | 4 - ruby/extractor/src/extractor.rs | 6 +- .../src/extractor/desugaring.rs | 104 ++++++++ .../src/extractor/driver.rs | 210 +++++++++++++++ .../src/extractor/mod.rs | 219 +++++++++++++--- .../src/extractor/simple.rs | 240 ++++-------------- .../tests/integration_test.rs | 1 - .../tests/multiple_languages.rs | 2 - unified/extractor/src/extractor.rs | 4 +- unified/extractor/src/languages/mod.rs | 4 +- .../extractor/src/languages/swift/swift.rs | 10 +- unified/extractor/tests/corpus_tests.rs | 59 ++--- .../extractor/tests/swift_syntax_pipeline.rs | 2 +- 14 files changed, 586 insertions(+), 289 deletions(-) create mode 100644 shared/tree-sitter-extractor/src/extractor/desugaring.rs create mode 100644 shared/tree-sitter-extractor/src/extractor/driver.rs diff --git a/ql/Cargo.lock b/ql/Cargo.lock index 5c65d88de6a7..d6ea9ea343ef 100644 --- a/ql/Cargo.lock +++ b/ql/Cargo.lock @@ -1017,6 +1017,7 @@ dependencies = [ "tree-sitter-python", "tree-sitter-ruby", "yeast-macros", + "yeast-schema", ] [[package]] @@ -1028,6 +1029,15 @@ dependencies = [ "syn", ] +[[package]] +name = "yeast-schema" +version = "0.1.0" +dependencies = [ + "serde", + "serde_json", + "serde_yaml", +] + [[package]] name = "zstd" version = "0.13.3" diff --git a/ql/extractor/src/extractor.rs b/ql/extractor/src/extractor.rs index 66096442e85f..8383d8424eee 100644 --- a/ql/extractor/src/extractor.rs +++ b/ql/extractor/src/extractor.rs @@ -29,28 +29,24 @@ pub fn run(options: Options) -> std::io::Result<()> { prefix: "ql", ts_language: tree_sitter_ql::LANGUAGE.into(), node_types: tree_sitter_ql::NODE_TYPES, - desugar: None, file_globs: vec!["*.ql".into(), "*.qll".into()], }, simple::LanguageSpec { prefix: "dbscheme", ts_language: tree_sitter_ql_dbscheme::LANGUAGE.into(), node_types: tree_sitter_ql_dbscheme::NODE_TYPES, - desugar: None, file_globs: vec!["*.dbscheme".into()], }, simple::LanguageSpec { prefix: "json", ts_language: tree_sitter_json::LANGUAGE.into(), node_types: tree_sitter_json::NODE_TYPES, - desugar: None, file_globs: vec!["*.json".into(), "*.jsonl".into(), "*.jsonc".into()], }, simple::LanguageSpec { prefix: "blame", ts_language: tree_sitter_blame::LANGUAGE.into(), node_types: tree_sitter_blame::NODE_TYPES, - desugar: None, file_globs: vec!["*.blame".into()], }, ], diff --git a/ruby/extractor/src/extractor.rs b/ruby/extractor/src/extractor.rs index d418c144bfc9..3749609e7885 100644 --- a/ruby/extractor/src/extractor.rs +++ b/ruby/extractor/src/extractor.rs @@ -94,7 +94,9 @@ pub fn run(options: Options) -> std::io::Result<()> { node_types::read_node_types_str("erb", tree_sitter_embedded_template::NODE_TYPES)?; let lines: std::io::Result> = std::io::BufReader::new(file_list).lines().collect(); let lines = lines?; - let source_root = std::env::current_dir().ok().and_then(|d| d.canonicalize().ok()); + let source_root = std::env::current_dir() + .ok() + .and_then(|d| d.canonicalize().ok()); lines .par_iter() .try_for_each(|line| { @@ -126,7 +128,6 @@ pub fn run(options: Options) -> std::io::Result<()> { &path, &source, &[], - None, ); let (ranges, line_breaks) = scan_erb( @@ -215,7 +216,6 @@ pub fn run(options: Options) -> std::io::Result<()> { &path, &source, &code_ranges, - None, ); std::fs::create_dir_all(src_archive_file.parent().unwrap())?; if needs_conversion { diff --git a/shared/tree-sitter-extractor/src/extractor/desugaring.rs b/shared/tree-sitter-extractor/src/extractor/desugaring.rs new file mode 100644 index 000000000000..c52659750c77 --- /dev/null +++ b/shared/tree-sitter-extractor/src/extractor/desugaring.rs @@ -0,0 +1,104 @@ +//! Extraction for languages that rewrite their syntax tree before extraction. +//! +//! Unlike [`crate::extractor::simple`] (direct tree-sitter extraction), a +//! desugaring language parses source into a [`ParsedTree`] — a `yeast::Ast` +//! plus side-channel `extra` tokens (comments and similar) — and rewrites the +//! AST through a [`yeast::Desugarer`] before emitting TRAP. The parser is a +//! closure, so both tree-sitter grammars (via +//! [`crate::extractor::tree_sitter_parser`]) and fully custom parsers plug in +//! the same way. + +use crate::trap; +use std::path::PathBuf; + +use crate::diagnostics; +use crate::extractor::ParsedTree; +use crate::extractor::driver::{self, LanguageExtractor}; +use crate::node_types::{self, NodeTypeMap}; + +/// A parser turns source bytes into a [`ParsedTree`]. Tree-sitter grammars plug +/// in via [`crate::extractor::tree_sitter_parser`]; custom (non-tree-sitter) +/// parsers supply their own closure. +pub type Parser = Box Result + Send + Sync>; + +pub struct LanguageSpec { + pub prefix: &'static str, + /// The parser: source -> `yeast::Ast` + `extra` tokens (see [`Parser`]). + pub parser: Parser, + /// Fallback TRAP schema, used only when `desugarer` does not supply its own + /// output schema (via [`yeast::Desugarer::output_node_types_yaml`]). May be + /// empty for a custom parser whose desugarer always provides the schema. + pub node_types: &'static str, + /// The desugarer applied to the parsed AST before extraction. Its + /// `output_node_types_yaml()` (when set) provides the TRAP schema. + /// + /// `Box` so the shared extractor is agnostic to the + /// user-defined context type the desugarer uses internally. + pub desugarer: Box, + pub file_globs: Vec, +} + +impl LanguageExtractor for LanguageSpec { + fn file_globs(&self) -> &[String] { + &self.file_globs + } + + fn build_schema(&self) -> std::io::Result { + let effective_node_types: String = match self.desugarer.output_node_types_yaml() { + Some(yaml) => yeast::node_types_yaml::convert(yaml).map_err(|e| { + std::io::Error::other(format!( + "Failed to convert YAML node-types to JSON for {}: {e}", + self.prefix + )) + })?, + None => self.node_types.to_string(), + }; + node_types::read_node_types_str(self.prefix, &effective_node_types) + } + + fn extract_file( + &self, + schema: &NodeTypeMap, + diagnostics_writer: &mut diagnostics::LogWriter, + trap_writer: &mut trap::Writer, + path: &std::path::Path, + source: &[u8], + ) { + crate::extractor::extract_parsed( + self.parser.as_ref(), + self.prefix, + schema, + diagnostics_writer, + trap_writer, + None, + path, + source, + self.desugarer.as_ref(), + ); + } +} + +pub struct Extractor { + pub prefix: String, + pub languages: Vec, + pub trap_dir: PathBuf, + pub source_archive_dir: PathBuf, + pub file_lists: Vec, + // Typically constructed via `trap::Compression::from_env`. + // This allow us to report the error using our diagnostics system + // without exposing it to consumers. + pub trap_compression: Result, +} + +impl Extractor { + pub fn run(&self) -> std::io::Result<()> { + driver::run_extractor( + &self.prefix, + &self.languages, + &self.trap_dir, + &self.source_archive_dir, + &self.file_lists, + &self.trap_compression, + ) + } +} diff --git a/shared/tree-sitter-extractor/src/extractor/driver.rs b/shared/tree-sitter-extractor/src/extractor/driver.rs new file mode 100644 index 000000000000..d97d8f4c75c2 --- /dev/null +++ b/shared/tree-sitter-extractor/src/extractor/driver.rs @@ -0,0 +1,210 @@ +//! Shared multi-file extraction driver. +//! +//! The `simple` (direct tree-sitter) and `desugaring` (parse + desugar) +//! extractors differ only in how a language's schema is built and how a single +//! file is extracted. Everything else — threading, matching files to languages +//! by glob, writing TRAP, and copying into the source archive — is identical +//! and lives here, parameterised over the [`LanguageExtractor`] trait. + +use globset::{GlobBuilder, GlobSetBuilder}; +use rayon::prelude::*; +use std::fs::File; +use std::io::BufRead; +use std::path::{Path, PathBuf}; + +use crate::diagnostics; +use crate::file_paths; +use crate::node_types::NodeTypeMap; +use crate::trap; + +/// A language that [`run_extractor`] can process: it knows its file globs, its +/// TRAP schema, and how to extract a single file. Implemented by +/// [`super::simple::LanguageSpec`] (direct tree-sitter extraction) and +/// [`super::desugaring::LanguageSpec`] (parse into an AST and desugar it). +pub(crate) trait LanguageExtractor: Sync { + /// The file-name globs that select files for this language. + fn file_globs(&self) -> &[String]; + /// Build the TRAP node-type schema used to validate emitted tuples. + fn build_schema(&self) -> std::io::Result; + /// Extract a single file's `source` into `trap_writer`. + fn extract_file( + &self, + schema: &NodeTypeMap, + diagnostics_writer: &mut diagnostics::LogWriter, + trap_writer: &mut trap::Writer, + path: &Path, + source: &[u8], + ); +} + +/// Drive extraction over `languages` for every file listed in `file_lists`. +/// +/// Sets up the thread pool, builds a combined glob set, and for each input file +/// dispatches to the matching language's [`LanguageExtractor::extract_file`], +/// writing the resulting TRAP and a source-archive copy. +pub(crate) fn run_extractor( + prefix: &str, + languages: &[L], + trap_dir: &Path, + source_archive_dir: &Path, + file_lists: &[PathBuf], + trap_compression: &Result, +) -> std::io::Result<()> { + tracing::info!("Extraction started"); + let diagnostics = diagnostics::DiagnosticLoggers::new(prefix); + let mut main_thread_logger = diagnostics.logger(); + let num_threads = match crate::options::num_threads() { + Ok(num) => num, + Err(e) => { + main_thread_logger.write( + main_thread_logger + .new_entry("configuration-error", "Configuration error") + .message( + "{}; defaulting to 1 thread.", + &[diagnostics::MessageArg::Code(&e)], + ) + .severity(diagnostics::Severity::Warning), + ); + 1 + } + }; + tracing::info!( + "Using {} {}", + num_threads, + if num_threads == 1 { + "thread" + } else { + "threads" + } + ); + let trap_compression = match trap_compression { + Ok(x) => *x, + Err(e) => { + main_thread_logger.write( + main_thread_logger + .new_entry("configuration-error", "Configuration error") + .message("{}; using gzip.", &[diagnostics::MessageArg::Code(e)]) + .severity(diagnostics::Severity::Warning), + ); + trap::Compression::Gzip + } + }; + drop(main_thread_logger); + + rayon::ThreadPoolBuilder::new() + .num_threads(num_threads) + .build_global() + .unwrap(); + + let file_lists: Vec = file_lists + .iter() + .map(|file_list| { + File::open(file_list) + .unwrap_or_else(|_| panic!("Unable to open file list at {file_list:?}")) + }) + .collect(); + + let mut schemas = vec![]; + for lang in languages { + schemas.push(lang.build_schema()?); + } + + // Construct a single globset containing all language globs, + // and a mapping from glob index to language index. + let (globset, glob_language_mapping) = { + let mut builder = GlobSetBuilder::new(); + let mut glob_lang_mapping = vec![]; + for (i, lang) in languages.iter().enumerate() { + for glob_str in lang.file_globs() { + let glob = GlobBuilder::new(glob_str) + .literal_separator(true) + .build() + .expect("invalid glob"); + builder.add(glob); + glob_lang_mapping.push(i); + } + } + ( + builder.build().expect("failed to build globset"), + glob_lang_mapping, + ) + }; + + let path_transformer = file_paths::load_path_transformer()?; + + let lines: std::io::Result> = file_lists + .iter() + .flat_map(|file_list| std::io::BufReader::new(file_list).lines()) + .collect(); + let lines = lines?; + + lines + .par_iter() + .try_for_each(|line| { + let mut diagnostics_writer = diagnostics.logger(); + let path = PathBuf::from(line).canonicalize()?; + let src_archive_file = crate::file_paths::path_for( + source_archive_dir, + &path, + "", + path_transformer.as_ref(), + ); + let source = std::fs::read(&path)?; + let mut trap_writer = trap::Writer::new(); + + match path.file_name() { + None => { + tracing::error!(?path, "No file name found, skipping file."); + } + Some(filename) => { + let matches = globset.matches(filename); + if matches.is_empty() { + tracing::error!(?path, "No matching language found, skipping file."); + } else { + let mut languages_processed = vec![false; languages.len()]; + + for m in matches { + let i = glob_language_mapping[m]; + if languages_processed[i] { + continue; + } + languages_processed[i] = true; + let lang = &languages[i]; + + lang.extract_file( + &schemas[i], + &mut diagnostics_writer, + &mut trap_writer, + &path, + &source, + ); + std::fs::create_dir_all(src_archive_file.parent().unwrap())?; + std::fs::copy(&path, &src_archive_file)?; + write_trap(trap_dir, &path, &trap_writer, trap_compression)?; + } + } + } + } + Ok(()) as std::io::Result<()> + }) + .expect("failed to extract files"); + + let path = PathBuf::from("extras"); + let mut trap_writer = trap::Writer::new(); + crate::extractor::populate_empty_location(&mut trap_writer); + + let res = write_trap(trap_dir, &path, &trap_writer, trap_compression); + tracing::info!("Extraction complete"); + res +} + +fn write_trap( + trap_dir: &Path, + path: &Path, + trap_writer: &trap::Writer, + trap_compression: trap::Compression, +) -> std::io::Result<()> { + let trap_file = crate::file_paths::path_for(trap_dir, path, trap_compression.extension(), None); + std::fs::create_dir_all(trap_file.parent().unwrap())?; + trap_writer.write_to_file(&trap_file, trap_compression) +} diff --git a/shared/tree-sitter-extractor/src/extractor/mod.rs b/shared/tree-sitter-extractor/src/extractor/mod.rs index 474dc096a2a6..1a8b9e820164 100644 --- a/shared/tree-sitter-extractor/src/extractor/mod.rs +++ b/shared/tree-sitter-extractor/src/extractor/mod.rs @@ -16,6 +16,8 @@ use tracing_subscriber::layer::SubscriberExt; use tracing_subscriber::util::SubscriberInitExt; use tree_sitter::{Language, Node, Parser, Range, Tree}; +pub mod desugaring; +mod driver; pub mod simple; /// Trait abstracting over tree-sitter and yeast node types for extraction. @@ -294,6 +296,10 @@ pub fn location_label(writer: &mut trap::Writer, location: trap::Location) -> tr /// caller's responsibility, allowing it to be done once and shared across /// files. #[allow(clippy::too_many_arguments)] +/// Extract a file with a tree-sitter grammar, walking the parse tree directly. +/// Comments and other `extra` nodes are emitted inline as tokens. This is the +/// path for languages that don't desugar their syntax tree (and hence have no +/// `extra` side channel); desugaring languages use [`extract_parsed`] instead. pub fn extract( language: &Language, language_prefix: &str, @@ -304,7 +310,6 @@ pub fn extract( path: &Path, source: &[u8], ranges: &[Range], - desugarer: Option<&dyn yeast::Desugarer>, ) { let path_str = file_paths::normalize_and_transform_path(path, transformer); let source_root = std::env::current_dir() @@ -337,21 +342,173 @@ pub fn extract( schema, ); - if let Some(desugarer) = desugarer { - let ast = desugarer - .run_from_tree(&tree, source) - .unwrap_or_else(|e| panic!("Desugaring failed for {path_str}: {e}")); - traverse_yeast(&ast, &mut visitor); - // Comments and other `extra` nodes are not represented in the desugared - // AST, so recover them directly from the original parse tree. - traverse_extras(&tree, &mut visitor); - } else { - traverse(&tree, &mut visitor); - } + traverse(&tree, &mut visitor); parser.reset(); } +/// A source tree produced by a parser: the raw `yeast::Ast` (pre-desugaring) +/// plus side-channel `extra` tokens (comments and similar) that are not +/// attached to the AST proper. +pub struct ParsedTree { + pub ast: yeast::Ast, + pub extras: Vec, +} + +/// A piece of side-channel `extra` content (a comment or unexpected text) +/// recovered by a parser. `kind` is a language-defined id written verbatim into +/// the `_trivia_tokeninfo` table (the tree-sitter parser uses the +/// grammar's node kind id here; a custom parser supplies its own stable +/// enumeration). +pub struct ExtraToken { + pub kind: usize, + pub range: yeast::Range, + pub text: String, +} + +/// Build a parser closure that parses `source` with a tree-sitter `language`, +/// producing a [`ParsedTree`]: a `yeast::Ast` (via [`yeast::Ast::from_tree`]) +/// plus the `extra` nodes (comments and similar) recovered as side-channel +/// tokens. This lets a tree-sitter language plug into the same +/// `ParsedTree`-producing interface as a custom parser. +pub fn tree_sitter_parser( + language: tree_sitter::Language, +) -> impl Fn(&[u8]) -> Result + Send + Sync { + move |source: &[u8]| { + let mut parser = Parser::new(); + parser + .set_language(&language) + .map_err(|e| format!("failed to set tree-sitter language: {e}"))?; + let tree = parser + .parse(source, None) + .ok_or_else(|| "tree-sitter failed to parse".to_string())?; + let ast = yeast::Ast::from_tree_with_schema_and_source( + yeast::schema::from_language(&language), + &tree, + &language, + source.to_vec(), + ); + let mut extras = Vec::new(); + collect_extras(tree.root_node(), source, &mut extras); + Ok(ParsedTree { ast, extras }) + } +} + +/// Collect `extra` nodes (comments and similar) under `node` into `out` as +/// [`ExtraToken`]s, keyed by the grammar's node kind id, for a desugaring +/// language whose rewritten AST won't retain them. +fn collect_extras(node: Node<'_>, source: &[u8], out: &mut Vec) { + let mut cursor = node.walk(); + for child in node.children(&mut cursor) { + if child.is_extra() { + let text = String::from_utf8_lossy(&source[child.byte_range()]).into_owned(); + out.push(ExtraToken { + kind: child.kind_id() as usize, + range: child.range().into(), + text, + }); + } else { + collect_extras(child, source, out); + } + } +} + +/// Extract a file from a [`ParsedTree`]-producing parser that desugars. The +/// parser yields a `yeast::Ast` plus side-channel `extra` tokens; the AST is +/// rewritten through `desugarer` ([`yeast::Desugarer::run_from_ast`]) before +/// TRAP extraction, and the `extra` tokens (comments and similar, which the +/// desugared AST does not carry) are emitted from the side channel. Both +/// tree-sitter grammars (via [`tree_sitter_parser`]) and custom parsers plug in +/// here; languages that don't desugar use [`extract`] instead. +#[allow(clippy::too_many_arguments)] +pub fn extract_parsed( + parse: &(dyn Fn(&[u8]) -> Result + Send + Sync), + language_prefix: &str, + schema: &NodeTypeMap, + diagnostics_writer: &mut diagnostics::LogWriter, + trap_writer: &mut trap::Writer, + transformer: Option<&file_paths::PathTransformer>, + path: &Path, + source: &[u8], + desugarer: &dyn yeast::Desugarer, +) { + let path_str = file_paths::normalize_and_transform_path(path, transformer); + let source_root = std::env::current_dir() + .ok() + .and_then(|d| d.canonicalize().ok()); + let diagnostics_path = file_paths::relativize_for_diagnostic(path, source_root.as_deref()); + let span = tracing::span!(tracing::Level::TRACE, "extract", file = %path_str); + let _enter = span.enter(); + tracing::debug!("extracting: {}", path_str); + + trap_writer.comment(format!("Auto-generated TRAP file for {path_str}")); + let file_label = populate_file(trap_writer, path, transformer); + let mut visitor = Visitor::new( + source, + diagnostics_writer, + trap_writer, + &diagnostics_path, + file_label, + language_prefix, + schema, + ); + + let parsed = parse(source).unwrap_or_else(|e| panic!("Parsing failed for {path_str}: {e}")); + let ast = desugarer + .run_from_ast(parsed.ast) + .unwrap_or_else(|e| panic!("Desugaring failed for {path_str}: {e}")); + traverse_yeast(&ast, &mut visitor); + // Comments and other `extra` tokens are not part of the desugared AST; emit + // them directly from the parser's side channel. + for extra in &parsed.extras { + visitor.emit_extra(extra); + } +} + +/// A lightweight [`AstNode`] over a piece of side-channel `extra` content +/// recovered by a custom parser, so it can reuse the tree-sitter location +/// machinery. +struct ExtraNode { + range: yeast::Range, + text: String, +} + +impl AstNode for ExtraNode { + fn kind(&self) -> &str { + "extra" + } + fn is_named(&self) -> bool { + false + } + fn is_missing(&self) -> bool { + false + } + fn is_error(&self) -> bool { + false + } + fn is_extra(&self) -> bool { + true + } + fn start_position(&self) -> tree_sitter::Point { + tree_sitter::Point { + row: self.range.start_point.row, + column: self.range.start_point.column, + } + } + fn end_position(&self) -> tree_sitter::Point { + tree_sitter::Point { + row: self.range.end_point.row, + column: self.range.end_point.column, + } + } + fn byte_range(&self) -> std::ops::Range { + self.range.start_byte..self.range.end_byte + } + fn opt_string_content(&self) -> Option { + Some(self.text.clone()) + } +} + struct ChildNode { field_name: Option<&'static str>, label: trap::Label, @@ -415,10 +572,11 @@ impl<'a> Visitor<'a> { } } - /// Emits a `TriviaToken` for the given `extra` node (e.g. a comment) from - /// the original parse tree. Trivia tokens carry a location and their source - /// text, but are not attached to a parent in the (possibly desugared) AST. - fn emit_trivia_token(&mut self, node: &Node) { + /// Emit an `extra` token (a location row plus a `trivia_tokeninfo` row) for + /// any [`AstNode`], with an explicit `kind` id. Shared by the tree-sitter + /// path (kind = the grammar's node kind id) and the custom-parser path + /// (kind = a language-defined `extra` kind id). + fn emit_extra_from(&mut self, node: &N, kind: usize) { let id = self.trap_writer.fresh_id(); let loc = location_for(self, self.file_label, node); let loc_label = location_label(self.trap_writer, loc); @@ -430,12 +588,21 @@ impl<'a> Visitor<'a> { &self.trivia_tokeninfo_table_name, vec![ trap::Arg::Label(id), - trap::Arg::Int(node.kind_id() as usize), + trap::Arg::Int(kind), sliced_source_arg(self.source, node), ], ); } + /// Emit an `extra` token recovered from a parser's side channel. + fn emit_extra(&mut self, extra: &ExtraToken) { + let node = ExtraNode { + range: extra.range, + text: extra.text.clone(), + }; + self.emit_extra_from(&node, extra.kind); + } + fn record_parse_error(&mut self, loc: trap::Label, mesg: &diagnostics::DiagnosticMessage) { self.diagnostics_writer.write(mesg); let id = self.trap_writer.fresh_id(); @@ -871,24 +1038,6 @@ fn traverse(tree: &Tree, visitor: &mut Visitor) { } } -/// Walks the original tree-sitter tree and emits a `TriviaToken` for every -/// `extra` node (e.g. a comment). Used to preserve comments that would -/// otherwise be lost after a desugaring pass rewrites the tree. -fn traverse_extras(tree: &Tree, visitor: &mut Visitor) { - emit_extras_in(visitor, tree.root_node()); -} - -fn emit_extras_in(visitor: &mut Visitor, node: Node<'_>) { - let mut cursor = node.walk(); - for child in node.children(&mut cursor) { - if child.is_extra() { - visitor.emit_trivia_token(&child); - } else { - emit_extras_in(visitor, child); - } - } -} - fn traverse_yeast(tree: &yeast::Ast, visitor: &mut Visitor) { let mut cursor = tree.walk(); visitor.enter_node(cursor.node()); diff --git a/shared/tree-sitter-extractor/src/extractor/simple.rs b/shared/tree-sitter-extractor/src/extractor/simple.rs index 9ba6f21778cf..1c6691fa8cf3 100644 --- a/shared/tree-sitter-extractor/src/extractor/simple.rs +++ b/shared/tree-sitter-extractor/src/extractor/simple.rs @@ -1,29 +1,52 @@ -use crate::{file_paths, trap}; -use globset::{GlobBuilder, GlobSetBuilder}; -use rayon::prelude::*; -use std::fs::File; -use std::io::BufRead; -use std::path::{Path, PathBuf}; +use crate::trap; +use std::path::PathBuf; use crate::diagnostics; -use crate::node_types; -use yeast; +use crate::extractor::driver::{self, LanguageExtractor}; +use crate::node_types::{self, NodeTypeMap}; +/// A tree-sitter language extracted directly from its parse tree, with no +/// desugaring. Comments and other `extra` nodes are emitted inline as tokens. +/// Languages that rewrite their syntax tree use +/// [`crate::extractor::desugaring`] instead. pub struct LanguageSpec { pub prefix: &'static str, pub ts_language: tree_sitter::Language, pub node_types: &'static str, - /// Optional desugarer. When set, the parsed tree is rewritten through - /// the desugarer before TRAP extraction. The desugarer's - /// `output_node_types_yaml()` (if set) provides the schema used both - /// at runtime (for the rewriter) and for TRAP validation. - /// - /// `Box` so the shared extractor is agnostic to - /// the user-defined context type the desugarer uses internally. - pub desugar: Option>, pub file_globs: Vec, } +impl LanguageExtractor for LanguageSpec { + fn file_globs(&self) -> &[String] { + &self.file_globs + } + + fn build_schema(&self) -> std::io::Result { + node_types::read_node_types_str(self.prefix, self.node_types) + } + + fn extract_file( + &self, + schema: &NodeTypeMap, + diagnostics_writer: &mut diagnostics::LogWriter, + trap_writer: &mut trap::Writer, + path: &std::path::Path, + source: &[u8], + ) { + crate::extractor::extract( + &self.ts_language, + self.prefix, + schema, + diagnostics_writer, + trap_writer, + None, + path, + source, + &[], + ); + } +} + pub struct Extractor { pub prefix: String, pub languages: Vec, @@ -38,182 +61,13 @@ pub struct Extractor { impl Extractor { pub fn run(&self) -> std::io::Result<()> { - tracing::info!("Extraction started"); - let diagnostics = diagnostics::DiagnosticLoggers::new(&self.prefix); - let mut main_thread_logger = diagnostics.logger(); - let num_threads = match crate::options::num_threads() { - Ok(num) => num, - Err(e) => { - main_thread_logger.write( - main_thread_logger - .new_entry("configuration-error", "Configuration error") - .message( - "{}; defaulting to 1 thread.", - &[diagnostics::MessageArg::Code(&e)], - ) - .severity(diagnostics::Severity::Warning), - ); - 1 - } - }; - tracing::info!( - "Using {} {}", - num_threads, - if num_threads == 1 { - "thread" - } else { - "threads" - } - ); - let trap_compression = match &self.trap_compression { - Ok(x) => *x, - Err(e) => { - main_thread_logger.write( - main_thread_logger - .new_entry("configuration-error", "Configuration error") - .message("{}; using gzip.", &[diagnostics::MessageArg::Code(e)]) - .severity(diagnostics::Severity::Warning), - ); - trap::Compression::Gzip - } - }; - drop(main_thread_logger); - - rayon::ThreadPoolBuilder::new() - .num_threads(num_threads) - .build_global() - .unwrap(); - - let file_lists: Vec = self - .file_lists - .iter() - .map(|file_list| { - File::open(file_list) - .unwrap_or_else(|_| panic!("Unable to open file list at {file_list:?}")) - }) - .collect(); - - let mut schemas = vec![]; - for lang in &self.languages { - let effective_node_types: String = match lang - .desugar - .as_ref() - .and_then(|d| d.output_node_types_yaml()) - { - Some(yaml) => yeast::node_types_yaml::convert(yaml).map_err(|e| { - std::io::Error::other(format!( - "Failed to convert YAML node-types to JSON for {}: {e}", - lang.prefix - )) - })?, - None => lang.node_types.to_string(), - }; - let schema = node_types::read_node_types_str(lang.prefix, &effective_node_types)?; - schemas.push(schema); - } - - // Construct a single globset containing all language globs, - // and a mapping from glob index to language index. - let (globset, glob_language_mapping) = { - let mut builder = GlobSetBuilder::new(); - let mut glob_lang_mapping = vec![]; - for (i, lang) in self.languages.iter().enumerate() { - for glob_str in &lang.file_globs { - let glob = GlobBuilder::new(glob_str) - .literal_separator(true) - .build() - .expect("invalid glob"); - builder.add(glob); - glob_lang_mapping.push(i); - } - } - ( - builder.build().expect("failed to build globset"), - glob_lang_mapping, - ) - }; - - let path_transformer = file_paths::load_path_transformer()?; - - let lines: std::io::Result> = file_lists - .iter() - .flat_map(|file_list| std::io::BufReader::new(file_list).lines()) - .collect(); - let lines = lines?; - - lines - .par_iter() - .try_for_each(|line| { - let mut diagnostics_writer = diagnostics.logger(); - let path = PathBuf::from(line).canonicalize()?; - let src_archive_file = crate::file_paths::path_for( - &self.source_archive_dir, - &path, - "", - path_transformer.as_ref(), - ); - let source = std::fs::read(&path)?; - let mut trap_writer = trap::Writer::new(); - - match path.file_name() { - None => { - tracing::error!(?path, "No file name found, skipping file."); - } - Some(filename) => { - let matches = globset.matches(filename); - if matches.is_empty() { - tracing::error!(?path, "No matching language found, skipping file."); - } else { - let mut languages_processed = vec![false; self.languages.len()]; - - for m in matches { - let i = glob_language_mapping[m]; - if languages_processed[i] { - continue; - } - languages_processed[i] = true; - let lang = &self.languages[i]; - - crate::extractor::extract( - &lang.ts_language, - lang.prefix, - &schemas[i], - &mut diagnostics_writer, - &mut trap_writer, - None, - &path, - &source, - &[], - lang.desugar.as_deref(), - ); - std::fs::create_dir_all(src_archive_file.parent().unwrap())?; - std::fs::copy(&path, &src_archive_file)?; - write_trap(&self.trap_dir, &path, &trap_writer, trap_compression)?; - } - } - } - } - Ok(()) as std::io::Result<()> - }) - .expect("failed to extract files"); - - let path = PathBuf::from("extras"); - let mut trap_writer = trap::Writer::new(); - crate::extractor::populate_empty_location(&mut trap_writer); - - let res = write_trap(&self.trap_dir, &path, &trap_writer, trap_compression); - tracing::info!("Extraction complete"); - res + driver::run_extractor( + &self.prefix, + &self.languages, + &self.trap_dir, + &self.source_archive_dir, + &self.file_lists, + &self.trap_compression, + ) } } - -fn write_trap( - trap_dir: &Path, - path: &Path, - trap_writer: &trap::Writer, - trap_compression: trap::Compression, -) -> std::io::Result<()> { - let trap_file = crate::file_paths::path_for(trap_dir, path, trap_compression.extension(), None); - std::fs::create_dir_all(trap_file.parent().unwrap())?; - trap_writer.write_to_file(&trap_file, trap_compression) -} diff --git a/shared/tree-sitter-extractor/tests/integration_test.rs b/shared/tree-sitter-extractor/tests/integration_test.rs index 694eb526f394..2b243ff7945b 100644 --- a/shared/tree-sitter-extractor/tests/integration_test.rs +++ b/shared/tree-sitter-extractor/tests/integration_test.rs @@ -13,7 +13,6 @@ fn simple_extractor() { prefix: "ql", ts_language: tree_sitter_ql::LANGUAGE.into(), node_types: tree_sitter_ql::NODE_TYPES, - desugar: None, file_globs: vec!["*.qll".into()], }; diff --git a/shared/tree-sitter-extractor/tests/multiple_languages.rs b/shared/tree-sitter-extractor/tests/multiple_languages.rs index e345eec58280..2e45e56754a3 100644 --- a/shared/tree-sitter-extractor/tests/multiple_languages.rs +++ b/shared/tree-sitter-extractor/tests/multiple_languages.rs @@ -13,14 +13,12 @@ fn multiple_language_extractor() { prefix: "ql", ts_language: tree_sitter_ql::LANGUAGE.into(), node_types: tree_sitter_ql::NODE_TYPES, - desugar: None, file_globs: vec!["*.qll".into()], }; let lang_json = simple::LanguageSpec { prefix: "json", ts_language: tree_sitter_json::LANGUAGE.into(), node_types: tree_sitter_json::NODE_TYPES, - desugar: None, file_globs: vec!["*.json".into(), "*Jsonfile".into()], }; diff --git a/unified/extractor/src/extractor.rs b/unified/extractor/src/extractor.rs index 301c6cf533f4..82bfe81219b5 100644 --- a/unified/extractor/src/extractor.rs +++ b/unified/extractor/src/extractor.rs @@ -2,7 +2,7 @@ use clap::Args; use std::path::PathBuf; use crate::languages; -use codeql_extractor::extractor::simple; +use codeql_extractor::extractor::desugaring; use codeql_extractor::trap; #[derive(Args)] @@ -31,7 +31,7 @@ pub fn run(options: Options) -> std::io::Result<()> { lang.prefix = "unified"; } - let extractor = simple::Extractor { + let extractor = desugaring::Extractor { prefix: "unified".to_string(), languages, trap_dir: options.output_dir, diff --git a/unified/extractor/src/languages/mod.rs b/unified/extractor/src/languages/mod.rs index 52a1bd40ffc7..a1f5c88cf3aa 100644 --- a/unified/extractor/src/languages/mod.rs +++ b/unified/extractor/src/languages/mod.rs @@ -1,4 +1,4 @@ -use codeql_extractor::extractor::simple; +use codeql_extractor::extractor::desugaring; #[path = "swift/swift.rs"] mod swift; @@ -15,6 +15,6 @@ pub mod swift_adapter; /// Shared YEAST output AST schema for all languages. pub(crate) const OUTPUT_AST_SCHEMA: &str = include_str!("../../ast_types.yml"); -pub fn all_language_specs() -> Vec { +pub fn all_language_specs() -> Vec { vec![swift::language_spec(OUTPUT_AST_SCHEMA)] } diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index 13f1a6beadf0..991e95aaa6d7 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -1,4 +1,4 @@ -use codeql_extractor::extractor::simple; +use codeql_extractor::extractor::desugaring; use yeast::{ConcreteDesugarer, DesugaringConfig, PhaseKind, Rule, rule, tree}; /// User context propagated from outer rules down to the inner rules that @@ -1249,18 +1249,18 @@ fn translation_rules() -> Vec> { ] } -pub fn language_spec(desugared_ast_schema: &'static str) -> simple::LanguageSpec { +pub fn language_spec(desugared_ast_schema: &'static str) -> desugaring::LanguageSpec { let ts_language: tree_sitter::Language = tree_sitter_swift::LANGUAGE.into(); let config = DesugaringConfig::::new() .add_phase("translate", PhaseKind::OneShot, translation_rules()) .with_output_node_types_yaml(desugared_ast_schema); let desugarer = ConcreteDesugarer::new(ts_language.clone(), config) .expect("failed to build Swift desugarer"); - simple::LanguageSpec { + desugaring::LanguageSpec { prefix: "swift", - ts_language, + parser: Box::new(codeql_extractor::extractor::tree_sitter_parser(ts_language)), node_types: tree_sitter_swift::NODE_TYPES, file_globs: vec!["*.swift".into(), "*.swiftinterface".into()], - desugar: Some(Box::new(desugarer)), + desugarer: Box::new(desugarer), } } diff --git a/unified/extractor/tests/corpus_tests.rs b/unified/extractor/tests/corpus_tests.rs index ac93f06622cf..d192b19485e7 100644 --- a/unified/extractor/tests/corpus_tests.rs +++ b/unified/extractor/tests/corpus_tests.rs @@ -1,8 +1,8 @@ use std::fs; use std::path::Path; -use codeql_extractor::extractor::simple; -use yeast::{Runner, dump::dump_ast, dump::dump_ast_with_type_errors}; +use codeql_extractor::extractor::desugaring; +use yeast::{dump::dump_ast, dump::dump_ast_with_type_errors}; #[path = "../src/languages/mod.rs"] mod languages; @@ -59,40 +59,21 @@ fn render_corpus(case: &CorpusCase) -> String { ) } -fn run_desugaring(lang: &simple::LanguageSpec, input: &str) -> Result { - match lang.desugar.as_deref() { - Some(desugarer) => { - // Parse the input ourselves so we don't depend on the desugarer - // knowing about the language. - let mut parser = tree_sitter::Parser::new(); - parser - .set_language(&lang.ts_language) - .map_err(|e| format!("Failed to set language: {e}"))?; - let tree = parser - .parse(input, None) - .ok_or_else(|| "Failed to parse input".to_string())?; - desugarer - .run_from_tree(&tree, input.as_bytes()) - .map_err(|e| format!("Desugaring failed: {e}")) - } - None => { - let runner: Runner = Runner::new(lang.ts_language.clone(), &[]); - runner - .run(input) - .map_err(|e| format!("Failed to parse input: {e}")) - } - } +/// Parse `input` through the language's parser and desugar it, returning the +/// mapped AST. +fn run_desugaring(lang: &desugaring::LanguageSpec, input: &str) -> Result { + let parsed = (lang.parser)(input.as_bytes())?; + lang.desugarer + .run_from_ast(parsed.ast) + .map_err(|e| format!("Desugaring failed: {e}")) } -/// Produce the raw tree-sitter parse tree dump for `input`, with no -/// desugaring rules applied. Uses a `Runner` with an empty phase list and -/// the input grammar's own schema. -fn dump_raw_parse(lang: &simple::LanguageSpec, input: &str) -> Result { - let runner: Runner = Runner::new(lang.ts_language.clone(), &[]); - let ast = runner - .run(input) - .map_err(|e| format!("Failed to parse input: {e}"))?; - Ok(dump_ast(&ast, ast.get_root(), input)) +/// Produce the raw (pre-desugar) parse tree dump for `input` — the `yeast::Ast` +/// the language's parser builds, before any desugaring rules. Useful for seeing +/// what the mapping rules operate on. +fn dump_raw_parse(lang: &desugaring::LanguageSpec, input: &str) -> Result { + let parsed = (lang.parser)(input.as_bytes())?; + Ok(dump_ast(&parsed.ast, parsed.ast.get_root(), input)) } /// Collect the set of corpus test "stems" (paths without an extension) under @@ -122,11 +103,8 @@ fn test_corpus() { let corpus_dir = Path::new("tests/corpus"); for lang in all_languages { - let output_schema = yeast::node_types_yaml::schema_from_yaml_with_language( - languages::OUTPUT_AST_SCHEMA, - &lang.ts_language, - ) - .expect("Failed to parse OUTPUT_AST_SCHEMA YAML"); + let output_schema = yeast::node_types_yaml::schema_from_yaml(languages::OUTPUT_AST_SCHEMA) + .expect("Failed to parse OUTPUT_AST_SCHEMA YAML"); let lang_corpus_dir = corpus_dir.join(&lang.prefix); if !lang_corpus_dir.exists() { @@ -236,8 +214,7 @@ fn test_corpus() { ); if update_mode { case.expected = actual_dump.trim().to_string(); - } else if output_path.exists() - && case.expected.trim() != actual_dump.trim() + } else if output_path.exists() && case.expected.trim() != actual_dump.trim() { failures.push(format!( "Test failed in {}:\nEXPECTED:\n\n{}\n\nACTUAL:\n\n{}", diff --git a/unified/extractor/tests/swift_syntax_pipeline.rs b/unified/extractor/tests/swift_syntax_pipeline.rs index cdaae1f47c6e..fde060f98203 100644 --- a/unified/extractor/tests/swift_syntax_pipeline.rs +++ b/unified/extractor/tests/swift_syntax_pipeline.rs @@ -22,7 +22,7 @@ fn swift_syntax_json_runs_through_the_desugarer() { .into_iter() .find(|l| l.file_globs.iter().any(|g| g.contains("swift"))) .expect("swift language spec"); - let desugarer = lang.desugar.as_deref().expect("swift desugarer"); + let desugarer = lang.desugarer.as_ref(); // Adapt the swift-syntax JSON into a yeast AST (pure Rust, no Swift FFI). let adapted = From 79954ce19ee7d25d76e780f14f5d445c90c9dfa5 Mon Sep 17 00:00:00 2001 From: Taus Date: Fri, 17 Jul 2026 13:37:49 +0000 Subject: [PATCH 027/188] unified: Add the swift-syntax parser and unresolved operator sequence (dormant) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds the plumbing for the swift-syntax front-end, without yet switching the runtime over to it (the Swift front-end still parses with tree-sitter): - `languages/swift/parse.rs` shells out to the separate `swift-syntax-parse` binary and adapts its JSON into a `yeast::Ast` (plus side-channel `extra` tokens) via `swift_adapter`. Running the parser out-of-process keeps the Swift toolchain out of the extractor's own build. It is wired in as a module but left `allow(dead_code)` until the runtime uses it. - `swift_node_types.yml` is the authoritative swift-syntax input schema (generated from swift-syntax by a one-off tool). The adapter seeds every parse with it, pre-registering every input kind and field so that rule matching never references a name absent from a given file's tree. The adapter now emits `ExtraToken`s directly during its single traversal, so `parse.rs` hands the parsed tree straight through with no second pass. - `ast_types.yml` gains an `unresolved_operator_sequence` type (with an `expr_or_operator` union) for flat operator chains the parser can't resolve — e.g. a chain using an operator imported from another module, whose precedence is unknown. Nothing produces it yet; the mapping rules that do are added when the rules are ported. The dbscheme and QL library are regenerated to match. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- unified/extractor/ast_types.yml | 19 + unified/extractor/src/languages/mod.rs | 11 + .../extractor/src/languages/swift/adapter.rs | 95 +- .../extractor/src/languages/swift/parse.rs | 73 + unified/extractor/swift_node_types.yml | 1281 +++++++++++++++++ unified/ql/lib/codeql/unified/Ast.qll | 20 + unified/ql/lib/unified.dbscheme | 17 +- 7 files changed, 1473 insertions(+), 43 deletions(-) create mode 100644 unified/extractor/src/languages/swift/parse.rs create mode 100644 unified/extractor/swift_node_types.yml diff --git a/unified/extractor/ast_types.yml b/unified/extractor/ast_types.yml index 418772aa2680..4fa1ff169428 100644 --- a/unified/extractor/ast_types.yml +++ b/unified/extractor/ast_types.yml @@ -31,6 +31,7 @@ supertypes: - throw_expr - try_expr - switch_expr + - unresolved_operator_sequence - unsupported_node expr_or_pattern: - expr @@ -38,6 +39,11 @@ supertypes: expr_or_type: - expr - type_expr + # An element of an `unresolved_operator_sequence`: either an operand (`expr`) + # or one of the infix operators separating the operands. + expr_or_operator: + - expr + - infix_operator pattern: - name_pattern - tuple_pattern @@ -137,6 +143,19 @@ named: operand: expr operator: operator + # A flat, unresolved operator sequence such as `a <+> b <+> c`. + # + # Swift's grammar doesn't encode operator precedence, so an operator chain is + # first parsed as a flat list of operands and operators. The parser front-end + # resolves this into structured `binary_expr` trees when it knows the + # operators' precedence (standard-library operators, and operators declared in + # the same file). When it encounters an operator whose precedence it can't + # determine (e.g. one imported from another module), it leaves that chain + # unresolved and emits it here rather than guessing a (possibly wrong) + # structure. The `element`s alternate operands (`expr`) and infix operators. + unresolved_operator_sequence: + element*: expr_or_operator + # Plain assignment assign_expr: target: expr_or_pattern diff --git a/unified/extractor/src/languages/mod.rs b/unified/extractor/src/languages/mod.rs index a1f5c88cf3aa..032bc884ca34 100644 --- a/unified/extractor/src/languages/mod.rs +++ b/unified/extractor/src/languages/mod.rs @@ -12,6 +12,17 @@ mod swift; #[allow(dead_code)] pub mod swift_adapter; +/// Swift front-end parser: shells out to `swift-syntax-parse` and adapts its +/// JSON output via [`swift_adapter`]. +/// +/// Dormant for now: the runtime Swift front-end is still tree-sitter, so +/// nothing in the binary calls this yet. `allow(dead_code)` for the same +/// binary-crate reason as [`swift_adapter`]; both allows are removed once the +/// runtime switches the Swift front-end to swift-syntax. +#[path = "swift/parse.rs"] +#[allow(dead_code)] +pub mod swift_parse; + /// Shared YEAST output AST schema for all languages. pub(crate) const OUTPUT_AST_SCHEMA: &str = include_str!("../../ast_types.yml"); diff --git a/unified/extractor/src/languages/swift/adapter.rs b/unified/extractor/src/languages/swift/adapter.rs index 37d5aac00d2d..696fce889708 100644 --- a/unified/extractor/src/languages/swift/adapter.rs +++ b/unified/extractor/src/languages/swift/adapter.rs @@ -2,9 +2,8 @@ //! in-memory format the CodeQL desugaring rules operate on. //! //! The JSON tree is produced by the `swift-syntax-rs` crate's Swift FFI shim -//! (`parse_to_json`). This module is pure Rust (only `yeast` + `serde_json`), -//! so the extractor consumes swift-syntax output without pulling in the Swift -//! toolchain (the JSON is produced out-of-process). +//! (`parse_to_json`). This module needs no Swift toolchain, so the extractor +//! consumes swift-syntax output out-of-process. //! //! The mapping mirrors tree-sitter's node model, which is what yeast (and the //! extractor's rewrite rules) expect: @@ -24,31 +23,19 @@ use std::collections::BTreeMap; +use codeql_extractor::extractor::ExtraToken; use serde_json::Value; -use yeast::schema::Schema; use yeast::{Ast, Id, NodeContent, Point, Range}; -/// A comment (or `unexpectedText`) recovered from the syntax tree's trivia. +/// The result of adapting a swift-syntax JSON tree: the [`yeast::Ast`] plus the +/// comment/`unexpectedText` [`ExtraToken`]s harvested from it (in source order). /// -/// These are collected into a side channel rather than embedded in the -/// [`yeast::Ast`], mirroring how the extractor treats tree-sitter `extra` +/// The extra tokens are collected into a side channel rather than embedded in +/// the [`yeast::Ast`], mirroring how the extractor treats tree-sitter `extra` /// nodes: they carry a location and text but are not attached to a parent. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct TriviaToken { - /// The trivia kind (e.g. `lineComment`, `blockComment`, `docLineComment`, - /// `docBlockComment`, `unexpectedText`). - pub kind: String, - /// The verbatim source text of the piece (e.g. `// comment`). - pub text: String, - /// The source range the piece occupies. - pub range: Range, -} - -/// The result of adapting a swift-syntax JSON tree: the [`yeast::Ast`] plus the -/// comment/`unexpectedText` trivia harvested from it (in source order). pub struct AdaptedTree { pub ast: Ast, - pub trivia: Vec, + pub extras: Vec, } /// swift-syntax `TokenKind` cases whose text is *not* determined by the kind @@ -170,17 +157,18 @@ fn children_of(value: &Value) -> Vec<&Value> { /// in the schema on the fly, immediately before the node is created. Children /// are built first so a parent's field lists reference existing ids. Any /// comment/`unexpectedText` trivia carried by a token is harvested into -/// `trivia` during the same pass rather than embedded in the tree. -fn build(node: &Value, ast: &mut Ast, trivia: &mut Vec) -> Result { +/// `extras` (as [`ExtraToken`]s) during the same pass rather than embedded in +/// the tree. +fn build(node: &Value, ast: &mut Ast, extras: &mut Vec) -> Result { let info = classify(node)?; - collect_trivia(node, trivia); + collect_extras(node, extras); let mut fields: BTreeMap> = BTreeMap::new(); for (field, value) in field_entries(node) { let field_id = ast.register_field(field); let mut ids = Vec::new(); for child in children_of(value) { - ids.push(build(child, ast, trivia)?); + ids.push(build(child, ast, extras)?); } fields.insert(field_id, ids); } @@ -201,9 +189,10 @@ fn build(node: &Value, ast: &mut Ast, trivia: &mut Vec) -> Result) { +/// filtered to comments/`unexpectedText` upstream) into `out` as +/// [`ExtraToken`]s. Non-token nodes have no trivia keys, so this is a no-op for +/// them. +fn collect_extras(node: &Value, out: &mut Vec) { for key in ["leadingTrivia", "trailingTrivia"] { let Some(Value::Array(pieces)) = node.get(key) else { continue; @@ -220,8 +209,8 @@ fn collect_trivia(node: &Value, out: &mut Vec) { .and_then(Value::as_str) .unwrap_or("") .to_string(); - out.push(TriviaToken { - kind: kind.to_string(), + out.push(ExtraToken { + kind: trivia_kind_id(kind), text, range, }); @@ -229,6 +218,21 @@ fn collect_trivia(node: &Value, out: &mut Vec) { } } +/// Map a swift-syntax trivia kind name to the stable integer id stored in an +/// [`ExtraToken`]'s `kind` (and written to the `unified_trivia_tokeninfo` +/// table). The value is opaque to the QL library (which reads only the text), +/// but is kept stable and meaningful. +fn trivia_kind_id(kind: &str) -> usize { + match kind { + "lineComment" => 1, + "blockComment" => 2, + "docLineComment" => 3, + "docBlockComment" => 4, + "unexpectedText" => 5, + _ => 0, + } +} + /// Parse a node's `range` into a [`yeast::Range`]. /// /// The JSON carries, for `start` and `end`, a 0-based UTF-8 file byte `offset`, @@ -258,21 +262,29 @@ fn parse_range(node: &Value) -> Option { }) } +/// The authoritative swift-syntax input node-types schema, generated from +/// swift-syntax (see the schemagen tool). [`json_to_ast`] seeds every parse +/// with the schema built from this, pre-registering every input kind and field +/// so rule matching never references a name absent from a given file's tree. +const SWIFT_NODE_TYPES: &str = include_str!("../../../swift_node_types.yml"); + /// Convert a swift-syntax JSON tree (as produced by [`crate::parse_to_json`]) /// into a [`yeast::Ast`] plus the comment/`unexpectedText` trivia harvested -/// from it. Both are produced in a single traversal. +/// from it. Both are produced in a single traversal. The AST is seeded with the +/// authoritative swift-syntax schema ([`SWIFT_NODE_TYPES`]); the adapter only +/// ever consumes swift-syntax input, so the schema is not a parameter. pub fn json_to_ast(json: &str) -> Result { let root: Value = serde_json::from_str(json).map_err(|e| format!("invalid JSON: {e}"))?; - let mut ast = Ast::with_schema(Schema::new()); - let mut trivia = Vec::new(); - let root_id = build(&root, &mut ast, &mut trivia)?; + let mut ast = Ast::with_schema(yeast::node_types_yaml::schema_from_yaml(SWIFT_NODE_TYPES)?); + let mut extras = Vec::new(); + let root_id = build(&root, &mut ast, &mut extras)?; ast.set_root(root_id); - // Emit trivia in source order (the traversal visits nodes bottom-up). - trivia.sort_by_key(|t| t.range.start_byte); + // Emit extras in source order (the traversal visits nodes bottom-up). + extras.sort_by_key(|t| t.range.start_byte); - Ok(AdaptedTree { ast, trivia }) + Ok(AdaptedTree { ast, extras }) } #[cfg(test)] @@ -373,7 +385,7 @@ mod tests { } #[test] - fn collects_trivia_into_side_channel() { + fn collects_extras_into_side_channel() { // A token carrying a trailing line comment in its trivia. let json = r#"{ "kind": "sourceFile", @@ -395,9 +407,10 @@ mod tests { let adapted = json_to_ast(json).expect("adapter should succeed"); // The comment is in the side channel, with its text and location. - assert_eq!(adapted.trivia.len(), 1); - let comment = &adapted.trivia[0]; - assert_eq!(comment.kind, "lineComment"); + assert_eq!(adapted.extras.len(), 1); + let comment = &adapted.extras[0]; + // `lineComment` maps to extra kind id 1. + assert_eq!(comment.kind, 1); assert_eq!(comment.text, "// c"); assert_eq!(comment.range.start_byte, 2); assert_eq!(comment.range.end_byte, 6); diff --git a/unified/extractor/src/languages/swift/parse.rs b/unified/extractor/src/languages/swift/parse.rs new file mode 100644 index 000000000000..21ef1b9ad215 --- /dev/null +++ b/unified/extractor/src/languages/swift/parse.rs @@ -0,0 +1,73 @@ +//! Swift front-end parser: shells out to the separate `swift-syntax-parse` +//! binary (which links swift-syntax) to obtain a JSON syntax tree, then adapts +//! that JSON into a `yeast::Ast` via the pure-Rust [`swift_adapter`] module. +//! +//! Running the parser in a separate process keeps the Swift toolchain out of +//! the extractor's own build: the extractor never links Swift, so working on +//! other (e.g. tree-sitter based) languages needs no Swift toolchain. Each call +//! spawns the parser afresh; a longer-lived parser process could be swapped in +//! behind this same seam later without touching the extraction pipeline. + +use std::io::Write; +use std::process::{Command, Stdio}; + +use codeql_extractor::extractor::ParsedTree; + +use super::swift_adapter; + +/// Environment variable naming the `swift-syntax-parse` executable. When unset, +/// `swift-syntax-parse` is looked up on `PATH`. +const PARSE_BIN_ENV: &str = "CODEQL_EXTRACTOR_UNIFIED_SWIFT_SYNTAX_PARSE"; + +/// Parse Swift `source` into a [`ParsedTree`] (a raw `yeast::Ast` plus +/// side-channel `extra` tokens), ready to be desugared via `run_from_ast`. +pub fn parse(source: &[u8]) -> Result { + let source = + std::str::from_utf8(source).map_err(|e| format!("Swift source is not valid UTF-8: {e}"))?; + let json = run_parser(source)?; + let mut adapted = swift_adapter::json_to_ast(&json)?; + adapted.ast.set_source(source.as_bytes().to_vec()); + Ok(ParsedTree { + ast: adapted.ast, + extras: adapted.extras, + }) +} + +/// The `swift-syntax-parse` executable to invoke. +fn parse_bin() -> String { + std::env::var(PARSE_BIN_ENV).unwrap_or_else(|_| "swift-syntax-parse".to_string()) +} + +/// Run the external parser, feeding `source` on stdin and returning its JSON +/// stdout. +fn run_parser(source: &str) -> Result { + let bin = parse_bin(); + let mut child = Command::new(&bin) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn() + .map_err(|e| format!("failed to spawn Swift parser `{bin}`: {e}"))?; + + // The parser reads all of stdin before writing any stdout, so writing the + // whole source and then closing stdin (by dropping it) cannot deadlock. + child + .stdin + .take() + .expect("child stdin was piped") + .write_all(source.as_bytes()) + .map_err(|e| format!("failed to write source to Swift parser `{bin}`: {e}"))?; + + let output = child + .wait_with_output() + .map_err(|e| format!("failed to run Swift parser `{bin}`: {e}"))?; + if !output.status.success() { + return Err(format!( + "Swift parser `{bin}` failed ({}): {}", + output.status, + String::from_utf8_lossy(&output.stderr).trim() + )); + } + String::from_utf8(output.stdout) + .map_err(|e| format!("Swift parser produced non-UTF-8 output: {e}")) +} diff --git a/unified/extractor/swift_node_types.yml b/unified/extractor/swift_node_types.yml new file mode 100644 index 000000000000..d8793acce2ca --- /dev/null +++ b/unified/extractor/swift_node_types.yml @@ -0,0 +1,1281 @@ +# GENERATED from swift-syntax by the one-off schemagen tool. Do not edit. +supertypes: + decl: + - accessorDecl + - actorDecl + - associatedTypeDecl + - classDecl + - deinitializerDecl + - editorPlaceholderDecl + - enumCaseDecl + - enumDecl + - extensionDecl + - functionDecl + - ifConfigDecl + - importDecl + - initializerDecl + - macroDecl + - macroExpansionDecl + - missingDecl + - operatorDecl + - poundSourceLocation + - precedenceGroupDecl + - protocolDecl + - structDecl + - subscriptDecl + - typeAliasDecl + - unexpectedCodeDecl + - usingDecl + - variableDecl + expr: + - _canImportExpr + - _canImportVersionInfo + - arrayExpr + - arrowExpr + - asExpr + - assignmentExpr + - awaitExpr + - binaryOperatorExpr + - booleanLiteralExpr + - borrowExpr + - closureExpr + - consumeExpr + - copyExpr + - declReferenceExpr + - dictionaryExpr + - discardAssignmentExpr + - doExpr + - editorPlaceholderExpr + - floatLiteralExpr + - forceUnwrapExpr + - functionCallExpr + - genericSpecializationExpr + - ifExpr + - inOutExpr + - infixOperatorExpr + - integerLiteralExpr + - isExpr + - keyPathExpr + - macroExpansionExpr + - memberAccessExpr + - missingExpr + - nilLiteralExpr + - optionalChainingExpr + - packElementExpr + - packExpansionExpr + - patternExpr + - postfixIfConfigExpr + - postfixOperatorExpr + - prefixOperatorExpr + - regexLiteralExpr + - sequenceExpr + - simpleStringLiteralExpr + - stringLiteralExpr + - subscriptCallExpr + - superExpr + - switchExpr + - ternaryExpr + - tryExpr + - tupleExpr + - typeExpr + - unresolvedAsExpr + - unresolvedIsExpr + - unresolvedTernaryExpr + - unsafeExpr + pattern: + - expressionPattern + - identifierPattern + - isTypePattern + - missingPattern + - tuplePattern + - valueBindingPattern + - wildcardPattern + stmt: + - breakStmt + - continueStmt + - deferStmt + - discardStmt + - doStmt + - expressionStmt + - fallThroughStmt + - forStmt + - guardStmt + - labeledStmt + - missingStmt + - repeatStmt + - returnStmt + - thenStmt + - throwStmt + - whileStmt + - yieldStmt + syntax: + - abiAttributeArguments + - accessorBlock + - accessorBlockFile + - accessorEffectSpecifiers + - accessorParameters + - arrayElement + - attribute + - attributeClauseFile + - availabilityArgument + - availabilityCondition + - availabilityLabeledArgument + - availabilityMacroDefinitionFile + - backDeployedAttributeArguments + - catchClause + - catchItem + - closureCapture + - closureCaptureClause + - closureCaptureSpecifier + - closureParameter + - closureParameterClause + - closureShorthandParameter + - closureSignature + - codeBlock + - codeBlockFile + - codeBlockItem + - compositionTypeElement + - conditionElement + - conformanceRequirement + - declModifier + - declModifierDetail + - declNameArgument + - declNameArguments + - deinitializerEffectSpecifiers + - derivativeAttributeArguments + - designatedType + - dictionaryElement + - differentiabilityArgument + - differentiabilityArguments + - differentiabilityWithRespectToArgument + - differentiableAttributeArguments + - documentationAttributeArgument + - dynamicReplacementAttributeArguments + - enumCaseElement + - enumCaseParameter + - enumCaseParameterClause + - expressionSegment + - functionEffectSpecifiers + - functionParameter + - functionParameterClause + - functionSignature + - genericArgument + - genericArgumentClause + - genericParameter + - genericParameterClause + - genericRequirement + - genericWhereClause + - ifConfigClause + - implementsAttributeArguments + - importPathComponent + - inheritanceClause + - inheritedType + - initializerClause + - keyPathComponent + - keyPathMethodComponent + - keyPathOptionalComponent + - keyPathPropertyComponent + - keyPathSubscriptComponent + - labeledExpr + - labeledSpecializeArgument + - layoutRequirement + - lifetimeSpecifierArgument + - lifetimeTypeSpecifier + - matchingPatternCondition + - memberBlock + - memberBlockItem + - memberBlockItemListFile + - missing + - moduleSelector + - multipleTrailingClosureElement + - nonisolatedSpecifierArgument + - nonisolatedTypeSpecifier + - objCSelectorPiece + - operatorPrecedenceAndTypes + - optionalBindingCondition + - originallyDefinedInAttributeArguments + - patternBinding + - platformVersion + - platformVersionItem + - poundSourceLocationArguments + - precedenceGroupAssignment + - precedenceGroupAssociativity + - precedenceGroupName + - precedenceGroupRelation + - primaryAssociatedType + - primaryAssociatedTypeClause + - returnClause + - sameTypeRequirement + - simpleTypeSpecifier + - sourceFile + - specializeAvailabilityArgument + - specializeTargetFunctionArgument + - specializedAttributeArgument + - stringSegment + - switchCase + - switchCaseItem + - switchCaseLabel + - switchDefaultLabel + - throwsClause + - tuplePatternElement + - tupleTypeElement + - typeAnnotation + - typeEffectSpecifiers + - typeInitializerClause + - versionComponent + - versionTuple + - whereClause + - yieldedExpression + - yieldedExpressionsClause + type: + - arrayType + - attributedType + - classRestrictionType + - compositionType + - dictionaryType + - functionType + - identifierType + - implicitlyUnwrappedOptionalType + - inlineArrayType + - memberType + - metatypeType + - missingType + - namedOpaqueReturnType + - optionalType + - packElementType + - packExpansionType + - someOrAnyType + - suppressedType + - tupleType +named: + _canImportExpr: + canImportKeyword: _token + leftParen: _token + importPath: _token + versionInfo?: _canImportVersionInfo + rightParen: _token + _canImportVersionInfo: + comma: _token + label: _token + colon: _token + version: versionTuple + abiAttributeArguments: + provider: [associatedTypeDecl, deinitializerDecl, enumCaseDecl, functionDecl, initializerDecl, missingDecl, subscriptDecl, typeAliasDecl, variableDecl] + accessorBlock: + leftBrace: _token + accessors: [accessorDecl, codeBlockItemList] + rightBrace: _token + accessorBlockFile: + leftBrace?: _token + accessors*: accessorDecl + rightBrace?: _token + endOfFileToken: _token + accessorDecl: + attributes*: [attribute, ifConfigDecl] + modifier?: declModifier + accessorSpecifier: _token + parameters?: accessorParameters + effectSpecifiers?: accessorEffectSpecifiers + body?: codeBlock + accessorEffectSpecifiers: + asyncSpecifier?: _token + throwsClause?: throwsClause + accessorParameters: + leftParen: _token + name: _token + rightParen: _token + actorDecl: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + actorKeyword: _token + name: _token + genericParameterClause?: genericParameterClause + inheritanceClause?: inheritanceClause + genericWhereClause?: genericWhereClause + memberBlock: memberBlock + arrayElement: + expression: expr + trailingComma?: _token + arrayExpr: + leftSquare: _token + elements*: arrayElement + rightSquare: _token + arrayType: + leftSquare: _token + element: type + rightSquare: _token + arrowExpr: + effectSpecifiers?: typeEffectSpecifiers + arrow: _token + asExpr: + expression: expr + asKeyword: _token + questionOrExclamationMark?: _token + type: type + assignmentExpr: + equal: _token + associatedTypeDecl: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + associatedtypeKeyword: _token + name: _token + inheritanceClause?: inheritanceClause + initializer?: typeInitializerClause + genericWhereClause?: genericWhereClause + attribute: + atSign: _token + attributeName: type + leftParen?: _token + arguments?: [labeledExprList, availabilityArgumentList, specializeAttributeArgumentList, specializedAttributeArgument, objCSelectorPieceList, implementsAttributeArguments, differentiableAttributeArguments, derivativeAttributeArguments, backDeployedAttributeArguments, originallyDefinedInAttributeArguments, dynamicReplacementAttributeArguments, effectsAttributeArgumentList, documentationAttributeArgumentList, abiAttributeArguments] + rightParen?: _token + attributeClauseFile: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + endOfFileToken: _token + attributedType: + specifiers*: [simpleTypeSpecifier, lifetimeTypeSpecifier, nonisolatedTypeSpecifier] + attributes*: [attribute, ifConfigDecl] + lateSpecifiers*: [simpleTypeSpecifier, lifetimeTypeSpecifier, nonisolatedTypeSpecifier] + baseType: type + availabilityArgument: + argument: [_token, platformVersion, availabilityLabeledArgument] + trailingComma?: _token + availabilityCondition: + availabilityKeyword: _token + leftParen: _token + availabilityArguments*: availabilityArgument + rightParen: _token + availabilityLabeledArgument: + label: _token + colon: _token + value: [simpleStringLiteralExpr, versionTuple] + availabilityMacroDefinitionFile: + platformVersion: platformVersion + colon: _token + specs*: availabilityArgument + endOfFileToken: _token + awaitExpr: + awaitKeyword: _token + expression: expr + backDeployedAttributeArguments: + beforeLabel: _token + colon: _token + platforms*: platformVersionItem + binaryOperatorExpr: + operator: _token + booleanLiteralExpr: + literal: _token + borrowExpr: + borrowKeyword: _token + expression: expr + breakStmt: + breakKeyword: _token + label?: _token + catchClause: + catchKeyword: _token + catchItems*: catchItem + body: codeBlock + catchItem: + pattern?: pattern + whereClause?: whereClause + trailingComma?: _token + classDecl: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + classKeyword: _token + name: _token + genericParameterClause?: genericParameterClause + inheritanceClause?: inheritanceClause + genericWhereClause?: genericWhereClause + memberBlock: memberBlock + classRestrictionType: + classKeyword: _token + closureCapture: + specifier?: closureCaptureSpecifier + name: _token + initializer?: initializerClause + trailingComma?: _token + closureCaptureClause: + leftSquare: _token + items*: closureCapture + rightSquare: _token + closureCaptureSpecifier: + specifier: _token + leftParen?: _token + detail?: _token + rightParen?: _token + closureExpr: + leftBrace: _token + signature?: closureSignature + statements*: codeBlockItem + rightBrace: _token + closureParameter: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + firstName: _token + secondName?: _token + colon?: _token + type?: type + ellipsis?: _token + trailingComma?: _token + closureParameterClause: + leftParen: _token + parameters*: closureParameter + rightParen: _token + closureShorthandParameter: + name: _token + trailingComma?: _token + closureSignature: + attributes*: [attribute, ifConfigDecl] + capture?: closureCaptureClause + parameterClause?: [closureShorthandParameterList, closureParameterClause] + effectSpecifiers?: typeEffectSpecifiers + returnClause?: returnClause + inKeyword: _token + codeBlock: + leftBrace: _token + statements*: codeBlockItem + rightBrace: _token + codeBlockFile: + body: codeBlock + endOfFileToken: _token + codeBlockItem: + item: [decl, stmt, expr] + semicolon?: _token + compositionType: + elements*: compositionTypeElement + compositionTypeElement: + type: type + ampersand?: token + conditionElement: + condition: [expr, availabilityCondition, matchingPatternCondition, optionalBindingCondition] + trailingComma?: _token + conformanceRequirement: + leftType: type + colon: _token + rightType: type + consumeExpr: + consumeKeyword: _token + expression: expr + continueStmt: + continueKeyword: _token + label?: _token + copyExpr: + copyKeyword: _token + expression: expr + declModifier: + name: _token + detail?: declModifierDetail + declModifierDetail: + leftParen: _token + detail: _token + rightParen: _token + declNameArgument: + name: token + colon: _token + declNameArguments: + leftParen: _token + arguments*: declNameArgument + rightParen: _token + declReferenceExpr: + moduleSelector?: moduleSelector + baseName: _token + argumentNames?: declNameArguments + deferStmt: + deferKeyword: _token + body: codeBlock + deinitializerDecl: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + deinitKeyword: _token + effectSpecifiers?: deinitializerEffectSpecifiers + body?: codeBlock + deinitializerEffectSpecifiers: + asyncSpecifier?: _token + derivativeAttributeArguments: + ofLabel: _token + colon: _token + originalDeclName: expr + period?: _token + accessorSpecifier?: _token + comma?: _token + arguments?: differentiabilityWithRespectToArgument + designatedType: + leadingComma: _token + name: token + dictionaryElement: + key: expr + colon: _token + value: expr + trailingComma?: _token + dictionaryExpr: + leftSquare: _token + content: [_token, dictionaryElementList] + rightSquare: _token + dictionaryType: + leftSquare: _token + key: type + colon: _token + value: type + rightSquare: _token + differentiabilityArgument: + argument: _token + trailingComma?: _token + differentiabilityArguments: + leftParen: _token + arguments*: differentiabilityArgument + rightParen: _token + differentiabilityWithRespectToArgument: + wrtLabel: _token + colon: _token + arguments: [differentiabilityArgument, differentiabilityArguments] + differentiableAttributeArguments: + kindSpecifier?: _token + kindSpecifierComma?: _token + arguments?: differentiabilityWithRespectToArgument + argumentsComma?: _token + genericWhereClause?: genericWhereClause + discardAssignmentExpr: + wildcard: _token + discardStmt: + discardKeyword: _token + expression: expr + doExpr: + doKeyword: _token + body: codeBlock + catchClauses*: catchClause + doStmt: + doKeyword: _token + throwsClause?: throwsClause + body: codeBlock + catchClauses*: catchClause + documentationAttributeArgument: + label: _token + colon: _token + value: [_token, stringLiteralExpr] + trailingComma?: _token + dynamicReplacementAttributeArguments: + forLabel: _token + colon: _token + declName: declReferenceExpr + editorPlaceholderDecl: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + placeholder: _token + editorPlaceholderExpr: + placeholder: _token + enumCaseDecl: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + caseKeyword: _token + elements*: enumCaseElement + enumCaseElement: + name: _token + parameterClause?: enumCaseParameterClause + rawValue?: initializerClause + trailingComma?: _token + enumCaseParameter: + modifiers*: declModifier + firstName?: _token + secondName?: _token + colon?: _token + type: type + defaultValue?: initializerClause + trailingComma?: _token + enumCaseParameterClause: + leftParen: _token + parameters*: enumCaseParameter + rightParen: _token + enumDecl: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + enumKeyword: _token + name: _token + genericParameterClause?: genericParameterClause + inheritanceClause?: inheritanceClause + genericWhereClause?: genericWhereClause + memberBlock: memberBlock + expressionPattern: + expression: expr + expressionSegment: + backslash: _token + pounds?: _token + leftParen: _token + expressions*: labeledExpr + rightParen: _token + expressionStmt: + expression: expr + extensionDecl: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + extensionKeyword: _token + extendedType: type + inheritanceClause?: inheritanceClause + genericWhereClause?: genericWhereClause + memberBlock: memberBlock + fallThroughStmt: + fallthroughKeyword: _token + floatLiteralExpr: + literal: _token + forStmt: + forKeyword: _token + tryKeyword?: _token + awaitKeyword?: _token + unsafeKeyword?: _token + caseKeyword?: _token + pattern: pattern + typeAnnotation?: typeAnnotation + inKeyword: _token + sequence: expr + whereClause?: whereClause + body: codeBlock + forceUnwrapExpr: + expression: expr + exclamationMark: _token + functionCallExpr: + calledExpression: expr + leftParen?: _token + arguments*: labeledExpr + rightParen?: _token + trailingClosure?: closureExpr + additionalTrailingClosures*: multipleTrailingClosureElement + functionDecl: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + funcKeyword: _token + name: _token + genericParameterClause?: genericParameterClause + signature: functionSignature + genericWhereClause?: genericWhereClause + body?: codeBlock + functionEffectSpecifiers: + asyncSpecifier?: _token + throwsClause?: throwsClause + functionParameter: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + firstName: _token + secondName?: _token + colon: _token + type: type + ellipsis?: _token + defaultValue?: initializerClause + trailingComma?: _token + functionParameterClause: + leftParen: _token + parameters*: functionParameter + rightParen: _token + functionSignature: + parameterClause: functionParameterClause + effectSpecifiers?: functionEffectSpecifiers + returnClause?: returnClause + functionType: + leftParen: _token + parameters*: tupleTypeElement + rightParen: _token + effectSpecifiers?: typeEffectSpecifiers + returnClause: returnClause + genericArgument: + argument: [type, expr] + trailingComma?: _token + genericArgumentClause: + leftAngle: _token + arguments*: genericArgument + rightAngle: _token + genericParameter: + attributes*: [attribute, ifConfigDecl] + specifier?: _token + name: _token + colon?: _token + inheritedType?: type + trailingComma?: _token + genericParameterClause: + leftAngle: _token + parameters*: genericParameter + genericWhereClause?: genericWhereClause + rightAngle: _token + genericRequirement: + requirement: [sameTypeRequirement, conformanceRequirement, layoutRequirement] + trailingComma?: _token + genericSpecializationExpr: + expression: expr + genericArgumentClause: genericArgumentClause + genericWhereClause: + whereKeyword: _token + requirements*: genericRequirement + guardStmt: + guardKeyword: _token + conditions*: conditionElement + elseKeyword: _token + body: codeBlock + identifierPattern: + identifier: _token + identifierType: + moduleSelector?: moduleSelector + name: _token + genericArgumentClause?: genericArgumentClause + ifConfigClause: + poundKeyword: _token + condition?: expr + elements?: [codeBlockItemList, switchCaseList, memberBlockItemList, expr, attributeList] + ifConfigDecl: + clauses*: ifConfigClause + poundEndif: _token + ifExpr: + ifKeyword: _token + conditions*: conditionElement + body: codeBlock + elseKeyword?: _token + elseBody?: [ifExpr, codeBlock] + implementsAttributeArguments: + type: type + comma: _token + declName: declReferenceExpr + implicitlyUnwrappedOptionalType: + wrappedType: type + exclamationMark: _token + importDecl: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + importKeyword: _token + importKindSpecifier?: _token + path*: importPathComponent + importPathComponent: + name: _token + trailingPeriod?: _token + inOutExpr: + ampersand: _token + expression: expr + infixOperatorExpr: + leftOperand: expr + operator: expr + rightOperand: expr + inheritanceClause: + colon: _token + inheritedTypes*: inheritedType + inheritedType: + type: type + trailingComma?: _token + initializerClause: + equal: _token + value: expr + initializerDecl: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + initKeyword: _token + optionalMark?: _token + genericParameterClause?: genericParameterClause + signature: functionSignature + genericWhereClause?: genericWhereClause + body?: codeBlock + inlineArrayType: + leftSquare: _token + count: genericArgument + separator: _token + element: genericArgument + rightSquare: _token + integerLiteralExpr: + literal: _token + isExpr: + expression: expr + isKeyword: _token + type: type + isTypePattern: + isKeyword: _token + type: type + keyPathComponent: + period?: _token + component: [keyPathPropertyComponent, keyPathMethodComponent, keyPathSubscriptComponent, keyPathOptionalComponent] + keyPathExpr: + backslash: _token + root?: type + components*: keyPathComponent + keyPathMethodComponent: + declName: declReferenceExpr + leftParen: _token + arguments*: labeledExpr + rightParen: _token + keyPathOptionalComponent: + questionOrExclamationMark: _token + keyPathPropertyComponent: + declName: declReferenceExpr + genericArgumentClause?: genericArgumentClause + keyPathSubscriptComponent: + leftSquare: _token + arguments*: labeledExpr + rightSquare: _token + labeledExpr: + label?: _token + colon?: _token + expression: expr + trailingComma?: _token + labeledSpecializeArgument: + label: _token + colon: _token + value: token + trailingComma?: _token + labeledStmt: + label: _token + colon: _token + statement: stmt + layoutRequirement: + type: type + colon: _token + layoutSpecifier: _token + leftParen?: _token + size?: _token + comma?: _token + alignment?: _token + rightParen?: _token + lifetimeSpecifierArgument: + parameter: _token + trailingComma?: _token + lifetimeTypeSpecifier: + dependsOnKeyword: _token + leftParen: _token + scopedKeyword?: _token + arguments*: lifetimeSpecifierArgument + rightParen: _token + macroDecl: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + macroKeyword: _token + name: _token + genericParameterClause?: genericParameterClause + signature: functionSignature + definition?: initializerClause + genericWhereClause?: genericWhereClause + macroExpansionDecl: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + pound: _token + moduleSelector?: moduleSelector + macroName: _token + genericArgumentClause?: genericArgumentClause + leftParen?: _token + arguments*: labeledExpr + rightParen?: _token + trailingClosure?: closureExpr + additionalTrailingClosures*: multipleTrailingClosureElement + macroExpansionExpr: + pound: _token + moduleSelector?: moduleSelector + macroName: _token + genericArgumentClause?: genericArgumentClause + leftParen?: _token + arguments*: labeledExpr + rightParen?: _token + trailingClosure?: closureExpr + additionalTrailingClosures*: multipleTrailingClosureElement + matchingPatternCondition: + caseKeyword: _token + pattern: pattern + typeAnnotation?: typeAnnotation + initializer: initializerClause + memberAccessExpr: + base?: expr + period: _token + declName: declReferenceExpr + memberBlock: + leftBrace: _token + members*: memberBlockItem + rightBrace: _token + memberBlockItem: + decl: decl + semicolon?: _token + memberBlockItemListFile: + members*: memberBlockItem + endOfFileToken: _token + memberType: + baseType: type + period: _token + moduleSelector?: moduleSelector + name: _token + genericArgumentClause?: genericArgumentClause + metatypeType: + baseType: type + period: _token + metatypeSpecifier: _token + missing: + placeholder: _token + missingDecl: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + placeholder: _token + missingExpr: + placeholder: _token + missingPattern: + placeholder: _token + missingStmt: + placeholder: _token + missingType: + placeholder: _token + moduleSelector: + moduleName: _token + colonColon: _token + multipleTrailingClosureElement: + label: _token + colon: _token + closure: closureExpr + namedOpaqueReturnType: + genericParameterClause: genericParameterClause + type: type + nilLiteralExpr: + nilKeyword: _token + nonisolatedSpecifierArgument: + leftParen: _token + nonsendingKeyword: _token + rightParen: _token + nonisolatedTypeSpecifier: + nonisolatedKeyword: _token + argument?: nonisolatedSpecifierArgument + objCSelectorPiece: + name?: token + colon?: _token + operatorDecl: + fixitySpecifier: _token + operatorKeyword: _token + name: _token + operatorPrecedenceAndTypes?: operatorPrecedenceAndTypes + operatorPrecedenceAndTypes: + colon: _token + precedenceGroup: _token + designatedTypes*: designatedType + optionalBindingCondition: + bindingSpecifier: _token + pattern: pattern + typeAnnotation?: typeAnnotation + initializer?: initializerClause + optionalChainingExpr: + expression: expr + questionMark: _token + optionalType: + wrappedType: type + questionMark: _token + originallyDefinedInAttributeArguments: + moduleLabel: _token + colon: _token + moduleName: stringLiteralExpr + comma: _token + platforms*: platformVersionItem + packElementExpr: + eachKeyword: _token + pack: expr + packElementType: + eachKeyword: _token + pack: type + packExpansionExpr: + repeatKeyword: _token + repetitionPattern: expr + packExpansionType: + repeatKeyword: _token + repetitionPattern: type + patternBinding: + pattern: pattern + typeAnnotation?: typeAnnotation + initializer?: initializerClause + accessorBlock?: accessorBlock + trailingComma?: _token + patternExpr: + pattern: pattern + platformVersion: + platform: _token + version?: versionTuple + platformVersionItem: + platformVersion: platformVersion + trailingComma?: _token + postfixIfConfigExpr: + base?: expr + config: ifConfigDecl + postfixOperatorExpr: + expression: expr + operator: _token + poundSourceLocation: + poundSourceLocation: _token + leftParen: _token + arguments?: poundSourceLocationArguments + rightParen: _token + poundSourceLocationArguments: + fileLabel: _token + fileColon: _token + fileName: simpleStringLiteralExpr + comma: _token + lineLabel: _token + lineColon: _token + lineNumber: _token + precedenceGroupAssignment: + assignmentLabel: _token + colon: _token + value: _token + precedenceGroupAssociativity: + associativityLabel: _token + colon: _token + value: _token + precedenceGroupDecl: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + precedencegroupKeyword: _token + name: _token + leftBrace: _token + groupAttributes*: [precedenceGroupRelation, precedenceGroupAssignment, precedenceGroupAssociativity] + rightBrace: _token + precedenceGroupName: + name: _token + trailingComma?: _token + precedenceGroupRelation: + higherThanOrLowerThanLabel: _token + colon: _token + precedenceGroups*: precedenceGroupName + prefixOperatorExpr: + operator: _token + expression: expr + primaryAssociatedType: + name: _token + trailingComma?: _token + primaryAssociatedTypeClause: + leftAngle: _token + primaryAssociatedTypes*: primaryAssociatedType + rightAngle: _token + protocolDecl: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + protocolKeyword: _token + name: _token + primaryAssociatedTypeClause?: primaryAssociatedTypeClause + inheritanceClause?: inheritanceClause + genericWhereClause?: genericWhereClause + memberBlock: memberBlock + regexLiteralExpr: + openingPounds?: _token + openingSlash: _token + regex: _token + closingSlash: _token + closingPounds?: _token + repeatStmt: + repeatKeyword: _token + body: codeBlock + whileKeyword: _token + condition: expr + returnClause: + arrow: _token + type: type + returnStmt: + returnKeyword: _token + expression?: expr + sameTypeRequirement: + leftType: [type, expr] + equal: _token + rightType: [type, expr] + sequenceExpr: + elements*: expr + simpleStringLiteralExpr: + openingQuote: _token + segments*: stringSegment + closingQuote: _token + simpleTypeSpecifier: + specifier: _token + someOrAnyType: + someOrAnySpecifier: _token + constraint: type + sourceFile: + shebang?: _token + statements*: codeBlockItem + endOfFileToken: _token + specializeAvailabilityArgument: + availabilityLabel: _token + colon: _token + availabilityArguments*: availabilityArgument + semicolon: _token + specializeTargetFunctionArgument: + targetLabel: _token + colon: _token + declName: declReferenceExpr + trailingComma?: _token + specializedAttributeArgument: + genericWhereClause: genericWhereClause + stringLiteralExpr: + openingPounds?: _token + openingQuote: _token + segments*: [stringSegment, expressionSegment] + closingQuote: _token + closingPounds?: _token + stringSegment: + content: _token + structDecl: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + structKeyword: _token + name: _token + genericParameterClause?: genericParameterClause + inheritanceClause?: inheritanceClause + genericWhereClause?: genericWhereClause + memberBlock: memberBlock + subscriptCallExpr: + calledExpression: expr + leftSquare: _token + arguments*: labeledExpr + rightSquare: _token + trailingClosure?: closureExpr + additionalTrailingClosures*: multipleTrailingClosureElement + subscriptDecl: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + subscriptKeyword: _token + genericParameterClause?: genericParameterClause + parameterClause: functionParameterClause + returnClause: returnClause + genericWhereClause?: genericWhereClause + accessorBlock?: accessorBlock + superExpr: + superKeyword: _token + suppressedType: + withoutTilde: _token + type: type + switchCase: + attribute?: attribute + label: [switchDefaultLabel, switchCaseLabel] + statements*: codeBlockItem + switchCaseItem: + pattern: pattern + whereClause?: whereClause + trailingComma?: _token + switchCaseLabel: + caseKeyword: _token + caseItems*: switchCaseItem + colon: _token + switchDefaultLabel: + defaultKeyword: _token + colon: _token + switchExpr: + switchKeyword: _token + subject: expr + leftBrace: _token + cases*: [switchCase, ifConfigDecl] + rightBrace: _token + ternaryExpr: + condition: expr + questionMark: _token + thenExpression: expr + colon: _token + elseExpression: expr + thenStmt: + thenKeyword: _token + expression: expr + throwStmt: + throwKeyword: _token + expression: expr + throwsClause: + throwsSpecifier: _token + leftParen?: _token + type?: type + rightParen?: _token + tryExpr: + tryKeyword: _token + questionOrExclamationMark?: _token + expression: expr + tupleExpr: + leftParen: _token + elements*: labeledExpr + rightParen: _token + tuplePattern: + leftParen: _token + elements*: tuplePatternElement + rightParen: _token + tuplePatternElement: + label?: _token + colon?: _token + pattern: pattern + trailingComma?: _token + tupleType: + leftParen: _token + elements*: tupleTypeElement + rightParen: _token + tupleTypeElement: + inoutKeyword?: _token + firstName?: _token + secondName?: _token + colon?: _token + type: type + ellipsis?: _token + trailingComma?: _token + typeAliasDecl: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + typealiasKeyword: _token + name: _token + genericParameterClause?: genericParameterClause + initializer: typeInitializerClause + genericWhereClause?: genericWhereClause + typeAnnotation: + colon: _token + type: type + typeEffectSpecifiers: + asyncSpecifier?: _token + throwsClause?: throwsClause + typeExpr: + type: type + typeInitializerClause: + equal: _token + value: type + unexpectedCodeDecl: + unresolvedAsExpr: + asKeyword: _token + questionOrExclamationMark?: _token + unresolvedIsExpr: + isKeyword: _token + unresolvedTernaryExpr: + questionMark: _token + thenExpression: expr + colon: _token + unsafeExpr: + unsafeKeyword: _token + expression: expr + usingDecl: + usingKeyword: _token + specifier: [attribute, _token] + valueBindingPattern: + bindingSpecifier: _token + pattern: pattern + variableDecl: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + bindingSpecifier: _token + bindings*: patternBinding + versionComponent: + period: _token + number: _token + versionTuple: + major: _token + components*: versionComponent + whereClause: + whereKeyword: _token + condition: expr + whileStmt: + whileKeyword: _token + conditions*: conditionElement + body: codeBlock + wildcardPattern: + wildcard: _token + yieldStmt: + yieldKeyword: _token + yieldedExpressions: [yieldedExpressionsClause, expr] + yieldedExpression: + expression: expr + comma?: _token + yieldedExpressionsClause: + leftParen: _token + elements*: yieldedExpression + rightParen: _token + _token: + binaryOperator: + dollarIdentifier: + floatLiteral: + identifier: + integerLiteral: + postfixOperator: + prefixOperator: + rawStringPoundDelimiter: + regexLiteralPattern: + regexPoundDelimiter: + shebang: + unknown: diff --git a/unified/ql/lib/codeql/unified/Ast.qll b/unified/ql/lib/codeql/unified/Ast.qll index 8adb4c2e44a0..e9a827269cc4 100644 --- a/unified/ql/lib/codeql/unified/Ast.qll +++ b/unified/ql/lib/codeql/unified/Ast.qll @@ -567,6 +567,8 @@ module Unified { final override AstNode getAFieldOrChild() { unified_expr_equality_pattern_def(this, result) } } + final class ExprOrOperator extends @unified_expr_or_operator, AstNodeImpl { } + final class ExprOrPattern extends @unified_expr_or_pattern, AstNodeImpl { } final class ExprOrType extends @unified_expr_or_type, AstNodeImpl { } @@ -1407,6 +1409,22 @@ module Unified { } } + /** A class representing `unresolved_operator_sequence` nodes. */ + final class UnresolvedOperatorSequence extends @unified_unresolved_operator_sequence, AstNodeImpl { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "UnresolvedOperatorSequence" } + + /** Gets the node corresponding to the field `element`. */ + final ExprOrOperator getElement(int i) { + unified_unresolved_operator_sequence_element(this, i, result) + } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + unified_unresolved_operator_sequence_element(this, _, result) + } + } + /** A class representing `unsupported_node` tokens. */ final class UnsupportedNode extends @unified_token_unsupported_node, TokenImpl { /** Gets the name of the primary QL class for this element. */ @@ -1773,6 +1791,8 @@ module Unified { or result = node.(UnaryExpr).getOperator() and i = -1 and name = "getOperator" or + result = node.(UnresolvedOperatorSequence).getElement(i) and name = "getElement" + or result = node.(VariableDeclaration).getModifier(i) and name = "getModifier" or result = node.(VariableDeclaration).getPattern() and i = -1 and name = "getPattern" diff --git a/unified/ql/lib/unified.dbscheme b/unified/ql/lib/unified.dbscheme index e957e303c22f..3aafb2a494f9 100644 --- a/unified/ql/lib/unified.dbscheme +++ b/unified/ql/lib/unified.dbscheme @@ -452,13 +452,15 @@ unified_equality_type_constraint_def( int right: @unified_type_expr ref ); -@unified_expr = @unified_array_literal | @unified_assign_expr | @unified_binary_expr | @unified_block | @unified_break_expr | @unified_call_expr | @unified_compound_assign_expr | @unified_continue_expr | @unified_function_expr | @unified_if_expr | @unified_key_value_pair | @unified_map_literal | @unified_member_access_expr | @unified_name_expr | @unified_pattern_guard_expr | @unified_return_expr | @unified_switch_expr | @unified_throw_expr | @unified_token_boolean_literal | @unified_token_builtin_expr | @unified_token_empty_expr | @unified_token_float_literal | @unified_token_int_literal | @unified_token_regex_literal | @unified_token_string_literal | @unified_token_super_expr | @unified_token_unsupported_node | @unified_try_expr | @unified_tuple_expr | @unified_type_cast_expr | @unified_type_test_expr | @unified_unary_expr +@unified_expr = @unified_array_literal | @unified_assign_expr | @unified_binary_expr | @unified_block | @unified_break_expr | @unified_call_expr | @unified_compound_assign_expr | @unified_continue_expr | @unified_function_expr | @unified_if_expr | @unified_key_value_pair | @unified_map_literal | @unified_member_access_expr | @unified_name_expr | @unified_pattern_guard_expr | @unified_return_expr | @unified_switch_expr | @unified_throw_expr | @unified_token_boolean_literal | @unified_token_builtin_expr | @unified_token_empty_expr | @unified_token_float_literal | @unified_token_int_literal | @unified_token_regex_literal | @unified_token_string_literal | @unified_token_super_expr | @unified_token_unsupported_node | @unified_try_expr | @unified_tuple_expr | @unified_type_cast_expr | @unified_type_test_expr | @unified_unary_expr | @unified_unresolved_operator_sequence unified_expr_equality_pattern_def( unique int id: @unified_expr_equality_pattern, int expr: @unified_expr ref ); +@unified_expr_or_operator = @unified_expr | @unified_token_infix_operator + @unified_expr_or_pattern = @unified_expr | @unified_pattern @unified_expr_or_type = @unified_expr | @unified_type_expr @@ -999,6 +1001,17 @@ unified_unary_expr_def( int operator: @unified_operator ref ); +#keyset[unified_unresolved_operator_sequence, index] +unified_unresolved_operator_sequence_element( + int unified_unresolved_operator_sequence: @unified_unresolved_operator_sequence ref, + int index: int ref, + unique int element: @unified_expr_or_operator ref +); + +unified_unresolved_operator_sequence_def( + unique int id: @unified_unresolved_operator_sequence +); + #keyset[unified_variable_declaration, index] unified_variable_declaration_modifier( int unified_variable_declaration: @unified_variable_declaration ref, @@ -1072,7 +1085,7 @@ unified_trivia_tokeninfo( string value: string ref ); -@unified_ast_node = @unified_accessor_declaration | @unified_argument | @unified_array_literal | @unified_assign_expr | @unified_associated_type_declaration | @unified_base_type | @unified_binary_expr | @unified_block | @unified_bound_type_constraint | @unified_break_expr | @unified_bulk_importing_pattern | @unified_call_expr | @unified_catch_clause | @unified_class_like_declaration | @unified_compound_assign_expr | @unified_constructor_declaration | @unified_constructor_pattern | @unified_continue_expr | @unified_destructor_declaration | @unified_do_while_stmt | @unified_equality_type_constraint | @unified_expr_equality_pattern | @unified_for_each_stmt | @unified_function_declaration | @unified_function_expr | @unified_function_type_expr | @unified_generic_type_expr | @unified_guard_if_stmt | @unified_if_expr | @unified_import_declaration | @unified_initializer_declaration | @unified_key_value_pair | @unified_labeled_stmt | @unified_map_literal | @unified_member_access_expr | @unified_name_expr | @unified_name_pattern | @unified_named_type_expr | @unified_operator_syntax_declaration | @unified_or_pattern | @unified_parameter | @unified_pattern_element | @unified_pattern_guard_expr | @unified_return_expr | @unified_switch_case | @unified_switch_expr | @unified_throw_expr | @unified_token | @unified_top_level | @unified_trivia_token | @unified_try_expr | @unified_tuple_expr | @unified_tuple_pattern | @unified_tuple_type_element | @unified_tuple_type_expr | @unified_type_alias_declaration | @unified_type_cast_expr | @unified_type_parameter | @unified_type_test_expr | @unified_type_test_pattern | @unified_unary_expr | @unified_variable_declaration | @unified_while_stmt +@unified_ast_node = @unified_accessor_declaration | @unified_argument | @unified_array_literal | @unified_assign_expr | @unified_associated_type_declaration | @unified_base_type | @unified_binary_expr | @unified_block | @unified_bound_type_constraint | @unified_break_expr | @unified_bulk_importing_pattern | @unified_call_expr | @unified_catch_clause | @unified_class_like_declaration | @unified_compound_assign_expr | @unified_constructor_declaration | @unified_constructor_pattern | @unified_continue_expr | @unified_destructor_declaration | @unified_do_while_stmt | @unified_equality_type_constraint | @unified_expr_equality_pattern | @unified_for_each_stmt | @unified_function_declaration | @unified_function_expr | @unified_function_type_expr | @unified_generic_type_expr | @unified_guard_if_stmt | @unified_if_expr | @unified_import_declaration | @unified_initializer_declaration | @unified_key_value_pair | @unified_labeled_stmt | @unified_map_literal | @unified_member_access_expr | @unified_name_expr | @unified_name_pattern | @unified_named_type_expr | @unified_operator_syntax_declaration | @unified_or_pattern | @unified_parameter | @unified_pattern_element | @unified_pattern_guard_expr | @unified_return_expr | @unified_switch_case | @unified_switch_expr | @unified_throw_expr | @unified_token | @unified_top_level | @unified_trivia_token | @unified_try_expr | @unified_tuple_expr | @unified_tuple_pattern | @unified_tuple_type_element | @unified_tuple_type_expr | @unified_type_alias_declaration | @unified_type_cast_expr | @unified_type_parameter | @unified_type_test_expr | @unified_type_test_pattern | @unified_unary_expr | @unified_unresolved_operator_sequence | @unified_variable_declaration | @unified_while_stmt unified_ast_node_location( unique int node: @unified_ast_node ref, From ad2ce9315f20aa3fb486626f8dc7a99f6ab4686c Mon Sep 17 00:00:00 2001 From: Taus Date: Thu, 16 Jul 2026 12:31:26 +0000 Subject: [PATCH 028/188] unified: Port top-level, literal, and name rules to swift-syntax MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Retarget the top-level, literal, and name mapping rules from the tree-sitter grammar to the swift-syntax AST. The output each rule builds is unchanged; only the input pattern differs, reflecting the different AST shape: - `source_file` -> `sourceFile` (statements live in an elided `statements` collection of `codeBlockItem` wrappers); the tree-sitter `global_declaration` / `local_declaration` wrappers have no swift-syntax counterpart. - The lexical integer/string variants (`hex_literal`, `oct_literal`, `multi_line_string_literal`, ...) collapse into single `integerLiteralExpr` / `stringLiteralExpr` kinds. - `simple_identifier` and `referenceable_operator` both become `declReferenceExpr` (its `baseName` is the referenced name or operator). This is the first step of an in-place, rule-by-rule migration; intermediate commits do not pass the corpus test (the runtime front-end is still tree-sitter) — the corpus is regenerated once at the end. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../extractor/src/languages/swift/swift.rs | 56 +++++++------------ 1 file changed, 21 insertions(+), 35 deletions(-) diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index 991e95aaa6d7..546249921671 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -124,25 +124,9 @@ fn member_chain( fn translation_rules() -> Vec> { vec![ // ---- Top-level ---- - // Capture all top-level statements, including unnamed tokens like `nil`. - rule!( - (source_file statement: _* @children) - => - (top_level - body: (block stmt: {children}) - ) - ), - // Declarations may be wrapped in local/global wrapper nodes. - rule!((global_declaration _ @inner) => stmt { inner }), - rule!((local_declaration _ @inner) => stmt { inner }), - // ---- swift-syntax front-end (minimal hook-up) ---- - // These rules target the swift-syntax AST (camelCase kind names), - // produced by the sibling `adapter` module. They coexist with the - // tree-sitter rules (snake_case names): rules are dispatched by exact - // kind name, and the two name spaces never collide, so these are inert - // on the tree-sitter path. Only the minimal top-level mapping lives here - // to demonstrate the pipeline end-to-end; the full translation is added - // separately. Unmatched swift-syntax nodes fall through to the + // These rules translate the swift-syntax AST (camelCase kind names), + // produced by the sibling `adapter` module from the `swift-syntax-parse` + // binary's JSON. Anything unmatched falls through to the // `unsupported_node` fallback at the end. // // `sourceFile` holds its top-level statements in an (elided) @@ -155,23 +139,25 @@ fn translation_rules() -> Vec> { ), rule!((codeBlockItem item: @item) => stmt { item }), // ---- Literals ---- - rule!((integer_literal) => (int_literal)), - rule!((hex_literal) => (int_literal)), - rule!((bin_literal) => (int_literal)), - rule!((oct_literal) => (int_literal)), - rule!((real_literal) => (float_literal)), - rule!((boolean_literal) => (boolean_literal)), - rule!("nil" => (builtin_expr)), - rule!((special_literal) => (builtin_expr)), - rule!((line_string_literal) => (string_literal)), - rule!((multi_line_string_literal) => (string_literal)), - rule!((raw_string_literal) => (string_literal)), - rule!((regex_literal) => (regex_literal)), + // swift-syntax does not distinguish the lexical integer/string forms + // (hex/binary/octal, single- vs multi-line, raw): each is a single + // `*LiteralExpr` kind, so the tree-sitter variants collapse to one rule. + rule!((integerLiteralExpr) => (int_literal)), + rule!((floatLiteralExpr) => (float_literal)), + rule!((booleanLiteralExpr) => (boolean_literal)), + rule!((nilLiteralExpr) => (builtin_expr)), + rule!((stringLiteralExpr) => (string_literal)), + rule!((regexLiteralExpr) => (regex_literal)), // ---- Names ---- - rule!((simple_identifier) @id => (name_expr identifier: (identifier #{id}))), - // A referenceable_operator (e.g. `+` used as a value, as in `reduce(0, +)`) - // is treated as a name reference to the operator symbol. - rule!((referenceable_operator) @op => (name_expr identifier: (identifier #{op}))), + // A bare name reference (`x`), and an operator used as a value (`+` in + // `reduce(0, +)`), are both `declReferenceExpr`; its `baseName` is the + // referenced identifier / operator symbol. + rule!((declReferenceExpr baseName: @name) => (name_expr identifier: (identifier #{name}))), + // A discard `_` used as an expression — e.g. the target of a discarding + // assignment `_ = x`. swift-syntax models it as a `discardAssignmentExpr`; + // the tree-sitter path treated the bare `_` as a name, so map it to a + // `name_expr` too. + rule!((discardAssignmentExpr wildcard: @@w) => (name_expr identifier: (identifier #{w}))), // ---- Operators ---- // All binary operators share the lhs/op/rhs shape. rule!((additive_expression lhs: @l op: @op rhs: @r) => (binary_expr left: {l} operator: (infix_operator #{op}) right: {r})), From 8328fba68a62b54cc25f073cb301c727611b4edc Mon Sep 17 00:00:00 2001 From: Taus Date: Fri, 17 Jul 2026 14:07:40 +0000 Subject: [PATCH 029/188] unified: Port operator rules to swift-syntax MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Retarget operator handling to the swift-syntax AST. Because Swift's grammar has no operator precedence, the parser front-end folds operator chains into nested `infixOperatorExpr`s (see swift-syntax-rs), so a single rule replaces the tree-sitter grammar's per-precedence binary rules (additive, multiplicative, comparison, equality, conjunction, disjunction, bitwise, range, nil-coalescing). The output is unchanged; only the input matching differs: - `binaryOperatorExpr` unwraps to the `infix_operator` leaf. - A `binaryOperator`-based `infixOperatorExpr` becomes `binary_expr`, or `compound_assign_expr` when the operator's spelling is a compound assignment — merging the tree-sitter grammar's separate binary and compound-assignment rules (the operator kinds are structurally identical, distinguishable only by spelling). - An `assignmentExpr`-based `infixOperatorExpr` becomes `assign_expr`. - An unresolved chain stays a flat `sequenceExpr` -> `unresolved_operator_sequence`. - `prefixOperatorExpr` -> prefix `unary_expr`; `tupleExpr` -> opaque `tuple_expr`; `codeBlock` -> `block`. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../extractor/src/languages/swift/swift.rs | 120 +++++++++--------- 1 file changed, 57 insertions(+), 63 deletions(-) diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index 546249921671..3dcd1597b601 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -121,6 +121,13 @@ fn member_chain( ) } +/// Compound-assignment operator spellings (`+=`, `<<=`, ...). Used to tell a +/// compound assignment from an ordinary binary application, both of which +/// arrive as a `binaryOperator`-based `infixOperatorExpr`. +const COMPOUND_ASSIGN_OPS: &[&str] = &[ + "+=", "-=", "*=", "/=", "%=", "<<=", ">>=", "&=", "|=", "^=", "&+=", "&-=", "&*=", +]; + fn translation_rules() -> Vec> { vec![ // ---- Top-level ---- @@ -159,55 +166,56 @@ fn translation_rules() -> Vec> { // `name_expr` too. rule!((discardAssignmentExpr wildcard: @@w) => (name_expr identifier: (identifier #{w}))), // ---- Operators ---- - // All binary operators share the lhs/op/rhs shape. - rule!((additive_expression lhs: @l op: @op rhs: @r) => (binary_expr left: {l} operator: (infix_operator #{op}) right: {r})), - rule!((multiplicative_expression lhs: @l op: @op rhs: @r) => (binary_expr left: {l} operator: (infix_operator #{op}) right: {r})), - rule!((comparison_expression lhs: @l op: @op rhs: @r) => (binary_expr left: {l} operator: (infix_operator #{op}) right: {r})), - rule!((equality_expression lhs: @l op: @op rhs: @r) => (binary_expr left: {l} operator: (infix_operator #{op}) right: {r})), - rule!((conjunction_expression lhs: @l op: @op rhs: @r) => (binary_expr left: {l} operator: (infix_operator #{op}) right: {r})), - rule!((disjunction_expression lhs: @l op: @op rhs: @r) => (binary_expr left: {l} operator: (infix_operator #{op}) right: {r})), - rule!((infix_expression lhs: @l op: @op rhs: @r) => (binary_expr left: {l} operator: (infix_operator #{op}) right: {r})), - // Range expression `a.. (binary_expr left: {l} operator: (infix_operator #{op}) right: {r})), - // Open-ended ranges `a...` / `...b` - rule!((open_end_range_expression start: @l) => (unary_expr operator: (postfix_operator "...") operand: {l})), - rule!((open_start_range_expression end: @r) => (unary_expr operator: (prefix_operator "...") operand: {r})), - // Custom operator declaration: `[prefix|infix|postfix] operator OP [: PrecedenceGroup]`. - // The fixity keyword is an anonymous child of `operator_declaration`, so we - // dispatch on it with one rule per keyword. - rule!( - (operator_declaration "prefix" (referenceable_operator _ @op) (simple_identifier)? @prec) - => - (operator_syntax_declaration name: (identifier #{op}) fixity: (fixity "prefix") precedence: {prec}) - ), - rule!( - (operator_declaration "postfix" (referenceable_operator _ @op) (simple_identifier)? @prec) - => - (operator_syntax_declaration name: (identifier #{op}) fixity: (fixity "postfix") precedence: {prec}) - ), - rule!( - (operator_declaration "infix" (referenceable_operator _ @op) (simple_identifier)? @prec) - => - (operator_syntax_declaration - name: (identifier #{op}) - fixity: (fixity "infix") - precedence: {prec}) - ), - rule!((bitwise_operation lhs: @l op: @op rhs: @r) => (binary_expr left: {l} operator: (infix_operator #{op}) right: {r})), - rule!((nil_coalescing_expression value: @l if_nil: @r) => (binary_expr left: {l} operator: (infix_operator "??") right: {r})), - // Leading-dot member shorthand (e.g. `.some`, `.foo`) means member access - // on a contextually inferred type. - rule!((prefix_expression operation: "." target: @member) => (member_access_expr base: (inferred_type_expr) member: (identifier #{member}))), - // Prefix unary operators - rule!((prefix_expression operation: @op target: @operand) => (unary_expr operator: (prefix_operator #{op}) operand: {operand})), - // Postfix unary operators - rule!((postfix_expression operation: @op target: @operand) => (unary_expr operator: (postfix_operator #{op}) operand: {operand})), - // TODO: Parenthesised single-value tuple is a grouping expression and should pass through. - // Multi-value tuples become tuple_expr. - rule!((tuple_expression value: _* @v) => (tuple_expr element: {v})), - // Blocks contain statement* directly. - rule!((block statement: _+ @stmts) => (block stmt: {stmts})), - rule!((block) => (block)), + // The parser front-end folds operator chains into nested + // `infixOperatorExpr`s by precedence (see swift-syntax-rs), so + // `1 + 2 * 3` arrives here already structured. + // + // A `binaryOperatorExpr` wraps the operator token; unwrap it to the + // operator leaf. Used by `infixOperatorExpr` (folded) and `sequenceExpr` + // (unresolved). + rule!((binaryOperatorExpr operator: @op) => (infix_operator #{op})), + // Compound assignment (`x += y`) vs. an ordinary binary application + // (`a + b`): both are `binaryOperator`-based `infixOperatorExpr`s, + // distinguishable only by the operator's spelling. The query engine + // can't match on token text, so a small Rust block reads the spelling + // and routes to `compound_assign_expr` or `binary_expr`. The operator + // is captured raw (`@@op`) to read its spelling. + rule!( + (infixOperatorExpr leftOperand: @l operator: (binaryOperatorExpr) @@op rightOperand: @r) + => + expr { + if COMPOUND_ASSIGN_OPS.contains(&ctx.source_text(op).as_str()) { + tree!((compound_assign_expr target: {l} operator: (infix_operator #{op}) value: {r})) + } else { + tree!((binary_expr left: {l} operator: (infix_operator #{op}) right: {r})) + } + } + ), + // Plain assignment (`x = y`). In a folded chain the `=` is an + // `assignmentExpr` node (distinct from other operators), matched by kind. + rule!( + (infixOperatorExpr leftOperand: @l operator: (assignmentExpr) rightOperand: @r) + => + (assign_expr target: {l} value: {r}) + ), + // Escape hatch: an operator chain the front-end could not resolve + // (because it uses an operator of unknown precedence, e.g. imported from + // another module) stays a flat `sequenceExpr`. Preserve it as an + // `unresolved_operator_sequence` whose elements alternate operands and + // infix operators, rather than guessing a structure. + rule!((sequenceExpr elements: _* @els) => (unresolved_operator_sequence element: {els})), + // Prefix unary operators (`!a`, `-x`). + rule!((prefixOperatorExpr operator: @op expression: @operand) => (unary_expr operator: (prefix_operator #{op}) operand: {operand})), + // A `tupleExpr` is a tuple literal (`(a, b)`) or a parenthesised + // expression (`(x)`). For now it is kept as an opaque `tuple_expr` leaf + // (its source text); its elements are not descended into. + // + // TODO: a parenthesised single-element `tupleExpr` is really a grouping + // expression and should be elided (unwrapped to its inner expression) + // rather than modelled as a tuple. + rule!((tupleExpr) => (tuple_expr)), + // A code block contains its statements directly. + rule!((codeBlock statements: _* @stmts) => (block stmt: {stmts})), // ---- Variables ---- // property_binding rules — these produce variable_declaration and/or accessor_declaration // nodes for individual declarators. The outer property_declaration rule splices these out @@ -441,22 +449,8 @@ fn translation_rules() -> Vec> { result } ), - // Plain assignment: `x = expr` - rule!( - (assignment operator: "=" target: (directly_assignable_expression expr: @target) result: @value) - => - (assign_expr target: {target} value: {value}) - ), - // Compound assignment: `x += expr` etc. - rule!( - (assignment operator: @op target: (directly_assignable_expression expr: @target) result: @value) - => - (compound_assign_expr target: {target} operator: (infix_operator #{op}) value: {value}) - ), // Unwrap `type` wrapper node rule!((type name: @inner) => type_expr { inner }), - // `directly_assignable_expression` is just a wrapper; unwrap it - rule!((directly_assignable_expression expr: @inner) => expr { inner }), // Pattern with bound_identifier → name_pattern. rule!( (pattern bound_identifier: @name) From 437e48239b15c92cd76adeb993e41f1f89776663 Mon Sep 17 00:00:00 2001 From: Taus Date: Fri, 17 Jul 2026 15:03:34 +0000 Subject: [PATCH 030/188] unified: Port variable-binding rules to swift-syntax MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Retarget `let`/`var` bindings to the swift-syntax AST, preserving the output: - A `variableDecl` publishes its `bindingSpecifier` (`let`/`var`) as the binding modifier, followed by its attributes and modifiers (`@objc`, `public`, `static`, …), and flattens each `patternBinding` into its own `variable_declaration`, tagging non-first ones `chained_declaration`. - One `patternBinding` rule with optional `typeAnnotation`/`initializer` covers `let x`, `let x = e`, `let x: T`, and `let x: T = e`. - `identifierPattern` -> `name_pattern`; `tuplePattern` / `tuplePatternElement` -> `tuple_pattern` / `pattern_element` (tuple destructuring), carrying an optional element label through as the `pattern_element` key. - `codeBlockItem` now captures `_*` / annotates `stmt*` so a multi-binding declaration splices as several statements. - Add a `declModifier` -> `modifier` rule (swift-syntax unifies the visibility/function/member/mutation/ownership modifiers into one kind). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../extractor/src/languages/swift/swift.rs | 93 ++++++++++--------- 1 file changed, 49 insertions(+), 44 deletions(-) diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index 3dcd1597b601..c17f3550aa05 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -144,7 +144,11 @@ fn translation_rules() -> Vec> { => (top_level body: (block stmt: {items})) ), - rule!((codeBlockItem item: @item) => stmt { item }), + // `codeBlockItem` wraps a top-level statement. It is a simple unwrapper, + // but a single wrapped `variableDecl` can translate to *several* + // declarations (`let x = 1, y = 2`), so the wrapped node is captured with + // `_*` and the result annotated `stmt*` to splice all of them. + rule!((codeBlockItem item: _* @item) => stmt* { item }), // ---- Literals ---- // swift-syntax does not distinguish the lexical integer/string forms // (hex/binary/octal, single- vs multi-line, raw): each is a single @@ -328,18 +332,17 @@ fn translation_rules() -> Vec> { result } ), - // property_binding with any pattern name (identifier or - // destructuring). Reads outer modifiers / chained tag from `ctx`. - // - // The enclosing `property_declaration` leads `ctx.outer_modifiers` - // with the `let`/`var` binding modifier, so the auto-translated name - // pattern (the LHS) becomes a binding, while the initializer value is - // translated with a reset context (see `SwiftContext::reset`). + // The individual bindings of a `variableDecl`. The binding modifier and + // chained tag come from `ctx` (set by the `variableDecl` rule below). The + // type annotation and initializer are both optional (one combined rule + // covers `let x`, `let x = e`, `let x: T`, and `let x: T = e`); the + // initializer value is translated in a reset scope so it is not treated + // as a binding. rule!( - (property_binding - name: @pattern - type: _? @ty - value: _? @@val) + (patternBinding + pattern: @pattern + typeAnnotation: (typeAnnotation type: @ty)? + initializer: (initializerClause value: @@val)?) => (variable_declaration modifier: {ctx.outer_modifiers.clone()} @@ -348,34 +351,28 @@ fn translation_rules() -> Vec> { type: {ty} value: {ctx.reset(); ctx.translate(val)?}) ), - // property_declaration: flatten declarators (each may translate - // to multiple nodes — variable_declaration and/or - // accessor_declaration) and attach the binding modifier - // (let/var), outer modifiers, and `chained_declaration` for - // non-first declarations. Manual rule: publishes - // binding/outer modifiers into `ctx` and translates each - // declarator with `ctx.is_chained` toggled per iteration. The - // inner declaration rules (`property_binding` variants, - // accessor inner rules) read these fields and emit complete - // `modifier:` lists from the start. - rule!( - (property_declaration - binding: (value_binding_pattern mutability: @@binding_kind) - declarator: _* @@decls - (modifiers)* @mods) - => - member* { - let binding_text = ctx.ast.source_text(binding_kind); - let binding = ctx.literal("modifier", &binding_text); - // The `let`/`var` binding modifier leads the declaration's - // modifier list and doubles as the "this is a binding" signal - // for pattern translation (see `in_binding_pattern`). - ctx.outer_modifiers = std::iter::once(binding).chain(mods).collect(); - + // A `let`/`var` declaration binds one or more comma-separated patterns + // (`let x = 1, y = 2`). The `bindingSpecifier` (`let`/`var`) is published + // as the binding modifier, followed by any attributes and modifiers + // (`@objc`, `public`, `static`, …); each `patternBinding` becomes its own + // `variable_declaration`, with non-first ones tagged `chained_declaration`. + // Accessor/observer forms are handled by the earlier rules. + rule!( + (variableDecl + attributes: _* @attrs + modifiers: _* @mods + bindingSpecifier: @@spec + bindings: _* @@bindings) + => + stmt* { + let binding = tree!((modifier #{spec})); + // The binding (`let`/`var`) leads, then attributes then modifiers + // in source order (Swift writes attributes before modifiers). + ctx.outer_modifiers = std::iter::once(binding).chain(attrs).chain(mods).collect(); let mut result = Vec::new(); - for (i, decl) in decls.into_iter().enumerate() { + for (i, b) in bindings.into_iter().enumerate() { ctx.is_chained = i > 0; - result.extend(ctx.translate(decl)?); + result.extend(ctx.translate(b)?); } result } @@ -451,9 +448,9 @@ fn translation_rules() -> Vec> { ), // Unwrap `type` wrapper node rule!((type name: @inner) => type_expr { inner }), - // Pattern with bound_identifier → name_pattern. + // `identifierPattern` wraps a single identifier token. rule!( - (pattern bound_identifier: @name) + (identifierPattern identifier: @name) => (name_pattern identifier: (identifier #{name})) ), @@ -485,10 +482,15 @@ fn translation_rules() -> Vec> { constructor: (member_access_expr base: (inferred_type_expr #{dot}) member: (identifier #{name})) element: {items}) ), - // Tuple pattern and its (optionally named) items - rule!((pattern kind: (tuple_pattern item: _* @elems)) => (tuple_pattern element: {elems})), - rule!((tuple_pattern_item name: @key pattern: @pat) => (pattern_element key: (identifier #{key}) pattern: {pat})), - rule!((tuple_pattern_item pattern: @pat) => (pattern_element pattern: {pat})), + // A tuple destructuring pattern (`let (a, b) = …`). A labelled element + // (`let (x: a) = …`) carries its label through as the `pattern_element` + // key; unlabelled elements have no key. + rule!((tuplePattern elements: _* @els) => (tuple_pattern element: {els})), + rule!( + (tuplePatternElement label: _? @label pattern: @p) + => + (pattern_element key: {label.map(|l| tree!((identifier #{l})))} pattern: {p}) + ), // Type casting pattern (TODO) rule!((pattern kind: (type_casting_pattern)) => (unsupported_node)), // Wildcard pattern @@ -906,6 +908,9 @@ fn translation_rules() -> Vec> { // Modifiers — unwrap to individual modifier children rule!((modifiers _* @mods) => modifier* { mods }), rule!((attribute) @m => (modifier #{m})), + // swift-syntax models every access/function/member/mutation/ownership + // modifier as a single `declModifier`; its source text is the modifier. + rule!((declModifier) @m => (modifier #{m})), rule!((visibility_modifier) @m => (modifier #{m})), rule!((function_modifier) @m => (modifier #{m})), rule!((member_modifier) @m => (modifier #{m})), From 191fc542ba47bdd6fc6fa62756b1a5fdf753a20a Mon Sep 17 00:00:00 2001 From: Taus Date: Fri, 17 Jul 2026 15:36:03 +0000 Subject: [PATCH 031/188] unified: Port type-expression rules to swift-syntax Retarget type expressions to the swift-syntax AST, output unchanged: - `user_type` -> `identifierType` (its `name` is the type-name token). - The sugared types keep desugaring to `generic_type_expr`: `optionalType` -> Optional, `arrayType` -> Array, `dictionaryType` -> Dictionary. - A generic type with explicit arguments (`Set`) stays opaque (its whole source text as the name), matched before the plain `identifierType` rule. This matches the tree-sitter `user_type` rule, which was also opaque. - Tuple types (`(Int, String)`) -> `tuple_type_expr` and function types (`(Int) -> Bool`) -> `function_type_expr`. swift-syntax holds both as `tupleTypeElement`s but a tuple element maps to `tuple_type_element` while a function parameter maps to `parameter`; the containers set `SwiftContext::in_function_type` for their direct children so the shared `tupleTypeElement` rule emits the right kind (and nested types stay correct). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../extractor/src/languages/swift/swift.rs | 111 ++++++++++++++---- 1 file changed, 85 insertions(+), 26 deletions(-) diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index c17f3550aa05..d893b21d616e 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -37,6 +37,14 @@ struct SwiftContext { /// `chained_declaration` modifier so the original grouping can be /// recovered downstream. is_chained: bool, + /// True while translating the parameters of a `functionType`. swift-syntax + /// models a function type's parameters with the same `tupleTypeElement` + /// kind as a tuple type's elements, so the shared `tupleTypeElement` rule + /// reads this to emit a `parameter` (function-type param) rather than a + /// `tuple_type_element` (tuple-type element). The `tupleType` / + /// `functionType` rules each set it for their direct children, so nested + /// types are translated in the correct context. + in_function_type: bool, } impl SwiftContext { @@ -920,32 +928,83 @@ fn translation_rules() -> Vec> { rule!((parameter_modifier) @m => (modifier #{m})), rule!((inheritance_modifier) @m => (modifier #{m})), rule!((property_behavior_modifier) @m => (modifier #{m})), - // Type annotations — unwrap - rule!((type_annotation type: @inner) => type_expr { inner }), - // user_type is split into simple_user_type parts. - // Keep a conservative textual fallback to avoid dropping type information. - rule!((user_type) @ty => (named_type_expr name: (identifier #{ty}))), - // Tuple type → tuple_type_expr - rule!((tuple_type element: _* @elems) => (tuple_type_expr element: {elems})), - rule!((tuple_type_item name: @name type: @ty) => (tuple_type_element name: (identifier #{name}) type: {ty})), - rule!((tuple_type_item type: @ty) => (tuple_type_element type: {ty})), - // Array type `[T]` → generic_type_expr with Array base - rule!((array_type element: @e) => (generic_type_expr - base: (named_type_expr name: (identifier "Array")) - type_argument: {e})), - // Dictionary type `[K: V]` → generic_type_expr with Dictionary base - rule!((dictionary_type key: @k value: @v) => (generic_type_expr - base: (named_type_expr name: (identifier "Dictionary")) - type_argument: {k} - type_argument: {v})), - // Optional type `T?` → generic_type_expr with Optional base - rule!((optional_type wrapped: @w) => (generic_type_expr - base: (named_type_expr name: (identifier "Optional")) - type_argument: {w})), - // Function type `(Params) -> Ret` → function_type_expr. - rule!((function_type parameter: _* @ps return_type: @ret) => (function_type_expr parameter: {ps} return_type: {ret})), - rule!((function_type_parameter name: @name type: @ty) => (parameter external_name: (identifier #{name}) type: {ty})), - rule!((function_type_parameter type: @ty) => (parameter type: {ty})), + // Type expressions. A generic type applied with explicit arguments + // (`Set`) is represented opaquely, using the whole source text as + // the name (PARITY(tree-sitter): the generic arguments are not + // structured `type_argument`s). Matched before the plain `identifierType` + // rule, which would otherwise drop the arguments. + rule!( + (identifierType genericArgumentClause: (genericArgumentClause)) @@ty + => + (named_type_expr name: (identifier #{ty})) + ), + // A named type (`Int`). `identifierType.name` is the type-name token. + rule!((identifierType name: @@n) => (named_type_expr name: (identifier #{n}))), + // A qualified type (`Outer.Inner`, `NSString.CompareOptions`). swift-syntax + // nests these as `memberType` nodes; like the old tree-sitter `user_type` + // rule, we keep the whole dotted path as the opaque `named_type_expr` name. + rule!((memberType) @ty => (named_type_expr name: (identifier #{ty}))), + // Sugared types desugar to `generic_type_expr`: `T?` -> Optional, + // `[T]` -> Array, `[K: V]` -> Dictionary. + rule!( + (optionalType wrappedType: @w) + => + (generic_type_expr base: (named_type_expr name: (identifier "Optional")) type_argument: {w}) + ), + rule!( + (arrayType element: @e) + => + (generic_type_expr base: (named_type_expr name: (identifier "Array")) type_argument: {e}) + ), + rule!( + (dictionaryType key: @k value: @v) + => + (generic_type_expr base: (named_type_expr name: (identifier "Dictionary")) type_argument: {k} type_argument: {v}) + ), + // A tuple type (`(Int, String)`) or function type (`(Int) -> Bool`). + // Both hold their contents as `tupleTypeElement`s, but a tuple element + // maps to `tuple_type_element` while a function parameter maps to + // `parameter`. Each container sets `ctx.in_function_type` for its direct + // children (and translates them explicitly, so a nested type is + // translated in the right context) and the shared `tupleTypeElement` + // rule below reads it. An element's label (`firstName`) is optional. + rule!( + (tupleType elements: _* @@elems) + => + tuple_type_expr { + ctx.in_function_type = false; + let mut out = Vec::new(); + for e in elems { + out.extend(ctx.translate(e)?); + } + tree!((tuple_type_expr element: {out})) + } + ), + rule!( + (functionType parameters: _* @@params returnClause: (returnClause type: @ret)) + => + function_type_expr { + ctx.in_function_type = true; + let mut out = Vec::new(); + for p in params { + out.extend(ctx.translate(p)?); + } + ctx.in_function_type = false; + tree!((function_type_expr parameter: {out} return_type: {ret})) + } + ), + rule!( + (tupleTypeElement firstName: _? @@name type: @ty) + => + tuple_type_element { + let name = name.map(|n| tree!((identifier #{n}))); + if ctx.in_function_type { + tree!((parameter external_name: {name} type: {ty})) + } else { + tree!((tuple_type_element name: {name} type: {ty})) + } + } + ), // Selector expression: `#selector(inner)` -- not yet supported rule!( (selector_expression _ @inner) From 52cdf59f2748d33dae412f59fdfc11e2c90cda6d Mon Sep 17 00:00:00 2001 From: Taus Date: Fri, 17 Jul 2026 21:13:21 +0000 Subject: [PATCH 032/188] unified: Port function, call, and member-access rules to swift-syntax Retarget function declarations, calls, member access, and control transfer to the swift-syntax AST, output unchanged: - `functionDecl` -> `function_declaration` (parameters and return type nest under `signature`; the body is a `codeBlock`). A bodyless function (a protocol requirement) still emits an empty `block`. - `functionParameter` -> `parameter`: two names give the external label and internal name, one name just the internal name; the default value is handled inline, so the `ctx.default_value` threading (and its `SwiftContext` field) is removed. The declared type is dropped: in the tree-sitter path the untyped-parameter rule was ordered first and shadowed the typed one, so the baseline emits no parameter type. - A function reference spelled with argument labels (`f(x:y:z:)`) is a `declReferenceExpr` with `argumentNames`; it is mapped to `unsupported_node` (matched before the bare-name rule) so downstream QL isn't handed a malformed reference, as in the tree-sitter path. - `functionCallExpr` -> `call_expr` (a trailing closure becomes a final unlabelled argument); `labeledExpr` -> `argument`; `memberAccessExpr` -> `member_access_expr` (base-ful matched before leading-dot). - `returnStmt`/`breakStmt`/`continueStmt`/`throwStmt` -> `return_expr`/`break_expr`/`continue_expr`/`throw_expr`, collapsing the labelled/unlabelled variants via optional captures. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../extractor/src/languages/swift/swift.rs | 162 ++++++++++-------- 1 file changed, 86 insertions(+), 76 deletions(-) diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index d893b21d616e..74f76202a906 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -21,10 +21,6 @@ struct SwiftContext { /// `protocol_property_declaration` when present; read by the /// accessor inner rules. property_type: Option, - /// Default-value expression for the next translated `parameter`. Set - /// by the outer `function_parameter` rule; read by the `parameter` - /// rules. - default_value: Option, /// Translated outer modifiers to attach to each child of a flattening /// outer rule. Set by `property_declaration`, `binding_pattern`, /// `enum_entry`, and `protocol_property_declaration`. For `let`/`var` @@ -168,6 +164,17 @@ fn translation_rules() -> Vec> { rule!((stringLiteralExpr) => (string_literal)), rule!((regexLiteralExpr) => (regex_literal)), // ---- Names ---- + // A function reference spelled with argument labels (`f(x:y:z:)`) is a + // `declReferenceExpr` carrying `argumentNames`. Mark it unsupported for + // now (rather than let the bare-name rule below treat it as a plain + // reference), so downstream QL isn't handed a malformed reference. In + // the future this should become a lambda expression. Matched before the + // bare-name rule. + rule!( + (declReferenceExpr argumentNames: (declNameArguments)) + => + (unsupported_node) + ), // A bare name reference (`x`), and an operator used as a value (`+` in // `reduce(0, +)`), are both `declReferenceExpr`; its `baseName` is the // referenced identifier / operator symbol. @@ -524,108 +531,111 @@ fn translation_rules() -> Vec> { // the 'expression' case is the only remaining possibility when this rule tries to match. rule!((pattern kind: @expr) => (expr_equality_pattern expr: {expr})), // ---- Functions ---- - // Function declaration - // Function declaration (return type optional, body statements optional). + // A function declaration (parameters/return type/body optional). The + // parameters and return type nest under `signature`; the body is a + // `codeBlock`. A bodyless function (a protocol requirement) still emits + // an empty `block`, matching the tree-sitter path. rule!( - (function_declaration + (functionDecl name: @name - parameter: _* @params - return_type: _? @ret - body: (block statement: _* @body_stmts)) + signature: (functionSignature + parameterClause: (functionParameterClause parameters: _* @params) + returnClause: (returnClause type: @ret)?) + body: (codeBlock statements: _* @body)) => (function_declaration name: (identifier #{name}) parameter: {params} return_type: {ret} - body: (block stmt: {body_stmts})) - ), - // Parameters are wrapped in function_parameter, which also carries - // optional default values. Publishes the default value into `ctx` - // before translating the inner `parameter` so the `parameter` - // rules can include it as a `default:` field directly. - rule!( - (function_parameter parameter: @@p default_value: _? @def) - => - parameter* { - ctx.default_value = def; - ctx.translate(p)? - } - ), - // Parameter with external name and type - rule!( - (parameter external_name: @ext name: @name) - => - (parameter - external_name: (identifier #{ext}) - pattern: (name_pattern identifier: (identifier #{name})) - default: {ctx.default_value}) + body: (block stmt: {body})) ), rule!( - (parameter external_name: @ext name: @name type: @ty) + (functionDecl + name: @name + signature: (functionSignature + parameterClause: (functionParameterClause parameters: _* @params) + returnClause: (returnClause type: @ret)?)) => - (parameter - external_name: (identifier #{ext}) - pattern: (name_pattern identifier: (identifier #{name})) - type: {ty} - default: {ctx.default_value}) + (function_declaration + name: (identifier #{name}) + parameter: {params} + return_type: {ret} + body: (block)) ), - // Parameter with just name and type (no external name) - rule!( - (parameter name: @name) - => - (parameter - pattern: (name_pattern identifier: (identifier #{name})) - default: {ctx.default_value}) + // A function parameter. With two names (`firstName`+`secondName`) the + // first is the external argument label and the second the internal name; + // with one name it is just the internal name. The default value is + // optional. + // + // PARITY: the declared type is intentionally dropped. In the tree-sitter + // path the untyped-parameter rule was ordered before the typed one and + // shadowed it (first match wins), so the baseline emits no parameter + // type; emitting one here would diverge from it. + rule!( + (functionParameter + firstName: @@first + secondName: _? @@second + defaultValue: (initializerClause value: @val)?) + => + parameter { + let (external, name) = match second { + Some(second) => (Some(tree!((identifier #{first}))), second), + None => (None, first), + }; + tree!((parameter + external_name: {external} + pattern: (name_pattern identifier: (identifier #{name})) + default: {val})) + } ), + // A function/method call (`foo(1, 2)`). `calledExpression` is the callee + // and `arguments` is an (elided) list of `labeledExpr`, each translated + // to an `argument` below. A trailing closure (`xs.map { … }`) becomes a + // final unlabelled argument; that variant is matched first. rule!( - (parameter name: @name type: @ty) + (functionCallExpr calledExpression: @callee arguments: _* @args trailingClosure: @tc) => - (parameter - pattern: (name_pattern identifier: (identifier #{name})) - type: {ty} - default: {ctx.default_value}) + (call_expr callee: {callee} argument: {args} argument: (argument value: {tc})) ), - // Reference to a function, f(x:y:z:). This is parsed as a call with a single argument with multiple reference_specifier labels. - // We don't want downstream QL to try to handle this as a call_expr with a weird argument, so explicitly mark it as unsupported for now. - // In the future we probably want to translate this to a lambda expression. rule!( - (call_expression suffix: (call_suffix arguments: (value_arguments argument: (value_argument reference_specifier: _+) @ref_arg))) + (functionCallExpr calledExpression: @callee arguments: _* @args) => - (unsupported_node) + (call_expr callee: {callee} argument: {args}) ), - // Call expression: function(args...) + // A call argument keeps its optional label as the `name` and its value. + // (Enum-case pattern arguments reuse `labeledExpr` too; that handling is + // added with the switch/pattern rules.) rule!( - (call_expression function: @func suffix: (call_suffix arguments: (value_arguments argument: (value_argument)* @args))) + (labeledExpr label: @lbl expression: @val) => - (call_expr callee: {func} argument: {args}) + (argument name: (identifier #{lbl}) value: {val}) ), - // Value argument with label (value: _ matches both named nodes and anonymous tokens like nil) rule!( - (value_argument name: (value_argument_label name: @label) value: @val) + (labeledExpr expression: @val) => - (argument name: (identifier #{label}) value: {val}) + (argument value: {val}) ), - // Value argument without label + // Member access (`list.append`). The `declName` is itself a + // `declReferenceExpr`; pull its `baseName` out as the member identifier. + // A leading-dot access (`.foo`) has no explicit base — the base is an + // `inferred_type_expr`. The base-ful form is matched first. rule!( - (value_argument value: @val) + (memberAccessExpr base: @base declName: (declReferenceExpr baseName: @member)) => - (argument value: {val}) + (member_access_expr base: {base} member: (identifier #{member})) ), - // Navigation expression → member_access_expr rule!( - (navigation_expression target: @target suffix: (navigation_suffix suffix: @member)) + (memberAccessExpr declName: (declReferenceExpr baseName: @member)) => - (member_access_expr base: {target} member: (identifier #{member})) + (member_access_expr base: (inferred_type_expr) member: (identifier #{member})) ), - // Return / break / continue, one rule per keyword. - // The anonymous "return"/"break"/"continue" keywords are matched as - // string literals. - rule!((control_transfer_statement kind: "return" result: _? @val) => (return_expr value: {val})), - rule!((control_transfer_statement kind: "break" result: @lbl) => (break_expr label: (identifier #{lbl}))), - rule!((control_transfer_statement kind: "break") => (break_expr)), - rule!((control_transfer_statement kind: "continue" result: @lbl) => (continue_expr label: (identifier #{lbl}))), - rule!((control_transfer_statement kind: "continue") => (continue_expr)), - rule!((control_transfer_statement kind: (throw_keyword) result: @val) => (throw_expr value: {val})), + // Control transfer, one rule per keyword. `return` carries an optional + // value; `break` / `continue` an optional target label; `throw` its + // thrown expression. + rule!((returnStmt expression: _? @val) => (return_expr value: {val})), + rule!((breakStmt label: _? @@lbl) => (break_expr label: {lbl.map(|l| tree!((identifier #{l})))})), + rule!((continueStmt label: _? @@lbl) => (continue_expr label: {lbl.map(|l| tree!((identifier #{l})))})), + rule!((throwStmt expression: @val) => (throw_expr value: {val})), // ---- Closures ---- // Lambda literal with optional type header (parameters + optional return type). // The return_type capture is optional, so this rule covers both cases. From 6ad1facee1ba8529c543f8cefa3d694599fece14 Mon Sep 17 00:00:00 2001 From: Taus Date: Fri, 17 Jul 2026 21:27:32 +0000 Subject: [PATCH 033/188] unified: Port closure rules to swift-syntax Retarget closures to the swift-syntax AST, output unchanged. swift-syntax nests the whole closure header under an optional `closureSignature`, so a single `closureExpr` rule (with optional attributes, capture list, parameter clause, and return clause) replaces the tree-sitter `lambda_literal` rule. The parameter clause is a union of the parenthesised form (`closureParameterClause`, unwrapped to its `closureParameter` children) and the shorthand form (`closureShorthandParameter`, a bare name); one rule each replaces the four `lambda_parameter` variants. `closureCapture` -> `variable_declaration` (an optional ownership specifier becomes a modifier; an explicit capture initializer becomes the bound value). The trailing-closure call form is already handled by the `functionCallExpr` `trailingClosure` variant, so the tree-sitter trailing-closure call rule is dropped. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../extractor/src/languages/swift/swift.rs | 74 ++++++++----------- 1 file changed, 32 insertions(+), 42 deletions(-) diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index 74f76202a906..a12e42e8ffc3 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -637,16 +637,20 @@ fn translation_rules() -> Vec> { rule!((continueStmt label: _? @@lbl) => (continue_expr label: {lbl.map(|l| tree!((identifier #{l})))})), rule!((throwStmt expression: @val) => (throw_expr value: {val})), // ---- Closures ---- - // Lambda literal with optional type header (parameters + optional return type). - // The return_type capture is optional, so this rule covers both cases. - rule!( - (lambda_literal - attribute: _* @attrs - captures: (capture_list item: _* @captures)? - type: (lambda_function_type - params: (lambda_function_type_parameters parameter: _* @params) - return_type: _? @ret)? - statement: _* @body) + // A closure (`{ (x: Int) -> Int in … }`) becomes a `function_expr`. The + // whole signature is optional, as are its capture list, parameter + // clause, and return clause, so one rule covers everything from a bare + // `{ … }` to `{ [weak self] (x) -> T in … }`. Shorthand `$0` closures + // have no signature and their `$0` references are ordinary name + // expressions. + rule!( + (closureExpr + signature: (closureSignature + attributes: _* @attrs + capture: (closureCaptureClause items: _* @captures)? + parameterClause: _* @params + returnClause: (returnClause type: @ret)?)? + statements: _* @body) => (function_expr modifier: {attrs} @@ -655,51 +659,37 @@ fn translation_rules() -> Vec> { return_type: {ret} body: (block stmt: {body})) ), - // capture_list_item with ownership modifier (e.g. [weak self], [unowned x]) + // A closure capture (`[weak self]`, `[x]`, `[y = expr]`). The optional + // ownership specifier (`weak`/`unowned`) becomes a modifier; the + // captured name becomes the bound `name_pattern`; an explicit capture + // initializer (`[y = expr]`) becomes the bound value. rule!( - (capture_list_item ownership: _? @ownership name: @name value: _? @val) + (closureCapture + specifier: (closureCaptureSpecifier specifier: @@spec)? + name: @@name + initializer: (initializerClause value: @val)?) => (variable_declaration - modifier: {ownership} + modifier: {spec.map(|s| tree!((modifier #{s})))} pattern: (name_pattern identifier: (identifier #{name})) value: {val}) ), - // Lambda parameter with type and optional external name - rule!( - (lambda_parameter external_name: @ext name: @name type: @ty) - => - (parameter - external_name: (identifier #{ext}) - pattern: (name_pattern identifier: (identifier #{name})) - type: {ty}) - ), - rule!( - (lambda_parameter name: @name type: @ty) - => - (parameter - pattern: (name_pattern identifier: (identifier #{name})) - type: {ty}) - ), + // A closure parameter clause (`(x: Int, y)`) unwraps to its parameters. + rule!((closureParameterClause parameters: _* @params) => parameter* { params }), + // A closure parameter (`x: Int`, or just `x`). Unlike a function + // parameter it has no external label; the type is optional. rule!( - (lambda_parameter external_name: @ext name: @name) + (closureParameter firstName: @name type: _? @ty) => - (parameter - external_name: (identifier #{ext}) - pattern: (name_pattern identifier: (identifier #{name}))) + (parameter pattern: (name_pattern identifier: (identifier #{name})) type: {ty}) ), + // A shorthand closure parameter (`x` in `{ x, y in … }`): a bare name + // with no parentheses and no type. rule!( - (lambda_parameter name: @name) + (closureShorthandParameter name: @name) => (parameter pattern: (name_pattern identifier: (identifier #{name}))) ), - // Call expression with trailing closure (no value_arguments) - rule!( - (call_expression function: @func suffix: (call_suffix lambda: (lambda_literal) @closure)) - => - (call_expr - callee: {func} - argument: (argument value: {closure})) - ), // ---- Control flow ---- // If statement rule!( From 2de1549f52de532234660e8c51ec0f9dbb126a98 Mon Sep 17 00:00:00 2001 From: Taus Date: Mon, 20 Jul 2026 11:48:48 +0000 Subject: [PATCH 034/188] unified: Port control-flow and pattern rules to swift-syntax Retarget `if`/`guard`/`switch`/ternary and the case/binding patterns to the swift-syntax AST, output unchanged. swift-syntax distinguishes a binding pattern (`valueBindingPattern`, `let x`) from a match pattern (`expressionPattern`, `someConstant`) by node kind, so the tree-sitter path's context-based `in_binding_pattern` disambiguation is removed: - `ifExpr`/`guardStmt`/`ternaryExpr` -> `if_expr`/`guard_if_stmt`/`if_expr`; `switchExpr` + `switchCase` -> `switch_expr` + `switch_case` (comma cases become an `or_pattern`); `conditionElement`/`switchCaseItem` unwrap; a statement-position `if`/`switch`/`do` is unwrapped from its `expressionStmt`. - `optionalBindingCondition` (`if let`) and `matchingPatternCondition` (`if case`) -> `pattern_guard_expr`. - An `expressionPattern` wrapping a leading-dot or qualified call -> `constructor_pattern` (setting `ctx.in_pattern`); `valueBindingPattern` unwraps; a bare `expressionPattern` -> `expr_equality_pattern`; a wildcard (`discardAssignmentExpr`) -> `ignore_pattern`; a `tupleExpr` match pattern -> `tuple_pattern`; `isTypePattern` (`case is T`) -> `unsupported_node`. - The `labeledExpr` argument rules gain `in_pattern`-aware pattern variants so an enum-case pattern's arguments (`case .foo(let x, _)`) become `pattern_element`s. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../extractor/src/languages/swift/swift.rs | 250 ++++++++++-------- 1 file changed, 142 insertions(+), 108 deletions(-) diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index a12e42e8ffc3..752e5ae90be5 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -22,11 +22,9 @@ struct SwiftContext { /// accessor inner rules. property_type: Option, /// Translated outer modifiers to attach to each child of a flattening - /// outer rule. Set by `property_declaration`, `binding_pattern`, - /// `enum_entry`, and `protocol_property_declaration`. For `let`/`var` - /// declarations and `binding_pattern`s the list is led by the binding - /// modifier, which also serves as the "this is a binding" signal for - /// pattern translation (see `in_binding_pattern`). + /// outer rule — e.g. the `let`/`var` binding modifier on each + /// `patternBinding` of a `variableDecl`, or the binding modifier on each + /// accessor of a property. outer_modifiers: Vec, /// True when the current child of a flattening outer rule is not /// the first one — its inner rule should emit a @@ -41,21 +39,15 @@ struct SwiftContext { /// `functionType` rules each set it for their direct children, so nested /// types are translated in the correct context. in_function_type: bool, + /// True while translating the argument list of an enum-case + /// `constructor_pattern` (e.g. `case .foo(let x, 3)`). Read by the + /// `labeledExpr` rules so a bare expression argument becomes an + /// `expr_equality_pattern` (wrapped in a `pattern_element`) rather than a + /// call `argument`. + in_pattern: bool, } impl SwiftContext { - /// Whether the pattern currently being translated is a binding - /// (the LHS of a `let`/`var` declaration or a `binding_pattern`). - /// - /// True exactly when an enclosing binding has published its modifier into - /// `outer_modifiers`. This is reliable because non-binding subtrees - /// (bodies, initializer values, ...) are translated after resetting the - /// context (see `reset`), so a bare identifier only sees a - /// non-empty `outer_modifiers` when it really is a binding. - fn in_binding_pattern(&self) -> bool { - !self.outer_modifiers.is_empty() - } - /// Clear the context fields that must not propagate into an /// expression / statement / body subtree. /// @@ -469,34 +461,33 @@ fn translation_rules() -> Vec> { => (name_pattern identifier: (identifier #{name})) ), - // Pattern with 'let' or 'var' binding: publish the binding modifier - // into `ctx` and translate the inner pattern under it. - rule!( - (pattern kind: (binding_pattern binding: (value_binding_pattern mutability: @@binding_kind) pattern: @@pattern)) - => - pattern* { - let binding_text = ctx.ast.source_text(binding_kind); - let binding = ctx.literal("modifier", &binding_text); - ctx.outer_modifiers = vec![binding]; - ctx.translate(pattern)? + // A `let`/`var` value-binding pattern (`let x`) inside a case or `if case` + // introduces a new binding; it unwraps to its inner pattern (a + // `name_pattern`). + rule!((valueBindingPattern pattern: @p) => pattern { p }), + // An enum-case pattern with associated values (`case .foo(let x)`, + // `case Color.foo(let x)`) is an expression pattern wrapping a call of a + // member access. It becomes a `constructor_pattern`; its arguments are + // translated as pattern elements (see the `labeledExpr` rules, gated by + // `ctx.in_pattern`). Matched before the generic `expressionPattern` rule. + // The base is optional: a leading-dot form (`.foo`) has none, so the + // constructor's base is an `inferred_type_expr`. + rule!( + (expressionPattern expression: (functionCallExpr + calledExpression: (memberAccessExpr base: _? @base period: @dot declName: (declReferenceExpr baseName: @name)) + arguments: _* @@args)) + => + constructor_pattern { + ctx.in_pattern = true; + let elements = ctx.translate(args)?; + let base = base.unwrap_or_else(|| tree!((inferred_type_expr #{dot}))); + tree!((constructor_pattern + constructor: (member_access_expr + base: {base} + member: (identifier #{name})) + element: {elements})) } ), - // case T.foo(x,y) pattern - rule!( - (pattern kind: (case_pattern type: @typ name: @name arguments: (tuple_pattern item: (tuple_pattern_item)* @items)? )) - => - (constructor_pattern - constructor: (member_access_expr base: {typ} member: (identifier #{name})) - element: {items}) - ), - // case .foo(x,y) pattern - rule!( - (pattern kind: (case_pattern dot: @dot name: @name arguments: (tuple_pattern item: (tuple_pattern_item)* @items)? )) - => - (constructor_pattern - constructor: (member_access_expr base: (inferred_type_expr #{dot}) member: (identifier #{name})) - element: {items}) - ), // A tuple destructuring pattern (`let (a, b) = …`). A labelled element // (`let (x: a) = …`) carries its label through as the `pattern_element` // key; unlabelled elements have no key. @@ -506,30 +497,41 @@ fn translation_rules() -> Vec> { => (pattern_element key: {label.map(|l| tree!((identifier #{l})))} pattern: {p}) ), - // Type casting pattern (TODO) - rule!((pattern kind: (type_casting_pattern)) => (unsupported_node)), - // Wildcard pattern - rule!((pattern kind: (wildcard_pattern)) => (ignore_pattern)), - // A bare identifier used as an expression-pattern. Under a `var`/`let` - // binding it introduces a new variable and becomes a `name_pattern`; - // otherwise it matches by equality and is left as an `expr_equality_pattern` - // over the name expression. - rule!( - (pattern kind: (simple_identifier) @name) - => - pattern { - if ctx.in_binding_pattern() { - tree!((name_pattern identifier: (identifier #{name}))) - } else { - let expr = tree!((name_expr identifier: (identifier #{name}))); - tree!((expr_equality_pattern expr: {expr})) - } + // A type-casting pattern (`case is T`). Not yet supported, so it is + // mapped to `unsupported_node` — an explicit reminder that this needs + // handling in the future. (Redundant with the catch-all fallback, but + // kept as a signpost.) + rule!((isTypePattern) => (unsupported_node)), + // A standalone wildcard pattern (`case _:`, `if case _`): swift-syntax + // models the bare `_` as an `expressionPattern` wrapping a + // `discardAssignmentExpr`. Matched before the generic `expressionPattern` + // rule so `_` becomes an `ignore_pattern` rather than an equality match. + // (Wildcards *inside* an enum-case argument list are handled by the + // `labeledExpr`/`discardAssignmentExpr` rules.) + rule!((expressionPattern expression: (discardAssignmentExpr)) => (ignore_pattern)), + // A wildcard *binding* pattern (`let _ = x`, `for _ in xs`). swift-syntax + // models this as a `wildcardPattern` — distinct from the `_` *match* + // pattern above, which is an `expressionPattern` over a + // `discardAssignmentExpr`. + rule!((wildcardPattern) => (ignore_pattern)), + // A tuple pattern in a match position (`case (let a, 3):`) is parsed by + // swift-syntax as an `expressionPattern` wrapping a `tupleExpr` — unlike a + // binding tuple (`let (a, b)`), which is a real `tuplePattern`. Recognise + // it as a `tuple_pattern`; its `labeledExpr` elements translate to + // `pattern_element`s under `ctx.in_pattern` (a binding element becomes a + // `name_pattern`, any other expression an `expr_equality_pattern`). + rule!( + (expressionPattern expression: (tupleExpr elements: _* @@els)) + => + tuple_pattern { + ctx.in_pattern = true; + let elements = ctx.translate(els)?; + tree!((tuple_pattern element: {elements})) } ), - // Expression pattern - // We lack a way to check if 'expr' is actually an expression, but due to rule ordering - // the 'expression' case is the only remaining possibility when this rule tries to match. - rule!((pattern kind: @expr) => (expr_equality_pattern expr: {expr})), + // A bare expression pattern (`case 1:`, `case someConstant:`) matches by + // equality. + rule!((expressionPattern expression: @e) => (expr_equality_pattern expr: {e})), // ---- Functions ---- // A function declaration (parameters/return type/body optional). The // parameters and return type nest under `signature`; the body is a @@ -602,18 +604,38 @@ fn translation_rules() -> Vec> { => (call_expr callee: {callee} argument: {args}) ), - // A call argument keeps its optional label as the `name` and its value. - // (Enum-case pattern arguments reuse `labeledExpr` too; that handling is - // added with the switch/pattern rules.) + // A call argument or an enum-case pattern argument. When translating an + // enum-case `constructor_pattern`'s arguments (`ctx.in_pattern`), a + // `patternExpr` argument (`let x`) becomes a bound `name_pattern`, a + // wildcard (`_`) becomes an `ignore_pattern`, and any other expression + // becomes an `expr_equality_pattern`; each is wrapped in a + // `pattern_element` carrying the optional argument label as its `key`. + // Otherwise the argument keeps its label as the `name` and its value. + // The pattern-only shapes (`patternExpr`, `discardAssignmentExpr`) are + // matched first; they never occur as ordinary call arguments. rule!( - (labeledExpr label: @lbl expression: @val) + (labeledExpr label: _? @lbl expression: (patternExpr pattern: @p)) => - (argument name: (identifier #{lbl}) value: {val}) + (pattern_element key: {lbl.map(|l| tree!((identifier #{l})))} pattern: {p}) ), rule!( - (labeledExpr expression: @val) + (labeledExpr label: _? @lbl expression: (discardAssignmentExpr) @@wildcard) => - (argument value: {val}) + (pattern_element key: {lbl.map(|l| tree!((identifier #{l})))} pattern: (ignore_pattern #{wildcard})) + ), + rule!( + (labeledExpr label: _? @lbl expression: @val) + => + argument { + let key = lbl.map(|l| tree!((identifier #{l}))); + if ctx.in_pattern { + tree!((pattern_element + key: {key} + pattern: (expr_equality_pattern expr: {val}))) + } else { + tree!((argument name: {key} value: {val})) + } + } ), // Member access (`list.append`). The `declName` is itself a // `declReferenceExpr`; pull its `baseName` out as the member identifier. @@ -691,68 +713,77 @@ fn translation_rules() -> Vec> { (parameter pattern: (name_pattern identifier: (identifier #{name}))) ), // ---- Control flow ---- - // If statement + // An `if`/`else` expression. Conditions are joined via `and_chain`; the + // then-body and optional else-body (another block, or an `ifExpr` for an + // else-if chain) are translated recursively. rule!( - (if_statement condition: _* @cond body: @then_body else_branch: _? @else_stmts) + (ifExpr conditions: _* @cond body: @then_body elseBody: _? @else_stmts) => (if_expr condition: {and_chain(&mut ctx, cond)} then: {then_body} else: {else_stmts}) ), - // Guard statement + // A `guard … else { }` statement. The `body` is the else block. rule!( - (guard_statement condition: _* @cond body: (block statement: _* @else_stmts)) + (guardStmt conditions: _* @cond body: @else_stmts) => (guard_if_stmt condition: {and_chain(&mut ctx, cond)} - else: (block stmt: {else_stmts})) + else: {else_stmts}) ), - // Ternary expression → if_expr + // Ternary (`c ? a : b`) desugars to an `if_expr`, as in the tree-sitter + // path. rule!( - (ternary_expression condition: @cond if_true: @then_val if_false: @else_val) + (ternaryExpr condition: @cond thenExpression: @then_val elseExpression: @else_val) => (if_expr condition: {cond} then: {then_val} else: {else_val}) ), - // Switch statement + // A `switch` statement. Each `switchCase` becomes a `switch_case` with a + // pattern (or an `or_pattern` for comma-separated `case a, b:`) and a + // body; a `default:` case has a body but no pattern. The case items and + // body are auto-translated; the Rust block only picks the pattern shape + // by arity (the query engine can't branch on list length). rule!( - (switch_statement expr: @val entry: (switch_entry)* @cases) + (switchExpr subject: @val cases: _* @cases) => (switch_expr value: {val} case: {cases}) ), - // Switch entry with multiple patterns and body rule!( - (switch_entry - pattern: (switch_pattern pattern: @first) - pattern: (switch_pattern pattern: @rest)+ - statement: _* @body) + (switchCase label: (switchCaseLabel caseItems: _* @items) statements: _* @body) => - (switch_case pattern: (or_pattern pattern: {first} pattern: {rest}) body: (block stmt: {body})) - ), - // Switch entry with exactly one pattern and body - rule!( - (switch_entry pattern: (switch_pattern pattern: @pat) statement: _* @body) - => - (switch_case pattern: {pat} body: (block stmt: {body})) + switch_case { + let pattern = if items.len() == 1 { + items[0] + } else { + tree!((or_pattern pattern: {items})) + }; + tree!((switch_case pattern: {pattern} body: (block stmt: {body}))) + } ), - // Switch entry: default case (no patterns) rule!( - (switch_entry default: (default_keyword) statement: _* @body) + (switchCase label: (switchDefaultLabel) statements: _* @body) => (switch_case body: (block stmt: {body})) ), - // if case PATTERN = expr — preserve the pattern directly (no Optional wrapping) + // A single case item unwraps to its pattern (used as an `or_pattern` + // element). + rule!((switchCaseItem pattern: @p) => pattern { p }), + // A pattern-matching condition (`if case let x = e`, `if case .foo(let x) + // = e`) becomes a `pattern_guard_expr`: the matched pattern and the + // scrutinee value are translated recursively. rule!( - (if_let_binding "case" pattern: @pat value: @val) + (matchingPatternCondition pattern: @pat initializer: (initializerClause value: @val)) => - (pattern_guard_expr - value: {val} - pattern: {pat}) + (pattern_guard_expr pattern: {pat} value: {val}) ), + // Optional binding (`if let x = foo`, or shorthand `if let x`) desugars + // to a `pattern_guard_expr` matching `Optional.some(x)`, exactly as the + // tree-sitter path does. The initialized form is matched first. rule!( - (if_let_binding - pattern: (pattern binding: (value_binding_pattern) bound_identifier: @name) - value: @val) + (optionalBindingCondition + pattern: (identifierPattern identifier: @name) + initializer: (initializerClause value: @val)) => (pattern_guard_expr value: {val} @@ -760,10 +791,8 @@ fn translation_rules() -> Vec> { constructor: (member_access_expr base: (named_type_expr name: (identifier "Optional")) member: (identifier "some")) element: (pattern_element pattern: (name_pattern identifier: (identifier #{name}))))) ), - // Shorthand if let x (Swift 5.7+) — also semantically .some(x) rule!( - (if_let_binding - pattern: (pattern binding: (value_binding_pattern) bound_identifier: @name)) + (optionalBindingCondition pattern: (identifierPattern identifier: @name)) => (pattern_guard_expr value: (name_expr identifier: (identifier #{name})) @@ -771,8 +800,13 @@ fn translation_rules() -> Vec> { constructor: (member_access_expr base: (named_type_expr name: (identifier "Optional")) member: (identifier "some")) element: (pattern_element pattern: (name_pattern identifier: (identifier #{name}))))) ), - // If-condition — unwrap (pass through the inner expression/pattern) - rule!((if_condition kind: @inner) => expr_or_pattern { inner }), + // A single condition in an `if`/`while`/`guard` condition list unwraps to + // its inner expression; `and_chain` joins multiple with `&&`. + rule!((conditionElement condition: @c) => expr { c }), + // `if`/`switch`/`do` are expressions in Swift; when used as a statement + // swift-syntax wraps them in an `expressionStmt`. Unwrap to the inner + // expression (a plain expression statement, e.g. a call, is not wrapped). + rule!((expressionStmt expression: @e) => expr { e }), // ---- Loops ---- // For-in loop with optional where-clause guard. rule!( From 2fcbc9b728c4749da69c4af227e3a04037c0fb07 Mon Sep 17 00:00:00 2001 From: Taus Date: Mon, 20 Jul 2026 12:00:28 +0000 Subject: [PATCH 035/188] unified: Port loop rules to swift-syntax Retarget loops to the swift-syntax AST, output unchanged: `forStmt` -> `for_each_stmt` (the optional `where` clause becomes the `guard`), `whileStmt` -> `while_stmt`, `repeatStmt` -> `do_while_stmt`, and `labeledStmt` -> `labeled_stmt`. Unlike the tree-sitter grammar, swift-syntax stores a labeled statement's label and colon as separate tokens, so the label token is already the bare name (no trailing `:` to strip). A `repeat`-`while` loop has a single condition in swift-syntax (not a condition list), so it needs no `and_chain`. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../extractor/src/languages/swift/swift.rs | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index 752e5ae90be5..e0c2f66e2101 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -808,42 +808,42 @@ fn translation_rules() -> Vec> { // expression (a plain expression statement, e.g. a call, is not wrapped). rule!((expressionStmt expression: @e) => expr { e }), // ---- Loops ---- - // For-in loop with optional where-clause guard. + // A `for`-`in` loop. The optional `where` clause becomes the `guard`. rule!( - (for_statement - item: @pat - collection: @iter - where: (where_clause expr: @guard)? - body: (block statement: _* @body)) + (forStmt + pattern: @pat + sequence: @iter + whereClause: (whereClause condition: @guard)? + body: @body) => (for_each_stmt pattern: {pat} iterable: {iter} guard: {guard} - body: (block stmt: {body})) + body: {body}) ), - // While loop + // A `while` loop. rule!( - (while_statement condition: _* @cond body: (block statement: _* @body)) + (whileStmt conditions: _* @cond body: @body) => (while_stmt condition: {and_chain(&mut ctx, cond)} - body: (block stmt: {body})) + body: {body}) ), - // Repeat-while loop + // A `repeat { } while c` loop desugars to a `do_while_stmt`. rule!( - (repeat_while_statement condition: _* @cond body: (block statement: _* @body)) + (repeatStmt body: @body condition: @cond) => - (do_while_stmt - condition: {and_chain(&mut ctx, cond)} - body: (block stmt: {body})) + (do_while_stmt condition: {cond} body: {body}) + ), + // A labeled statement (`outer: for … { }`). swift-syntax stores the + // label and colon as separate tokens, so the label token is already the + // bare name (no trailing `:` to strip). + rule!( + (labeledStmt label: @@lbl statement: @stmt) + => + (labeled_stmt label: (identifier #{lbl}) stmt: {stmt}) ), - // Labeled statement (e.g. `outer: for ...`). Strip the trailing ':' from the label token. - rule!((labeled_statement label: (statement_label) @lbl statement: @stmt) => labeled_stmt { - let text = ctx.ast.source_text(lbl); - let name = &text[..text.len() - 1]; - tree!((labeled_stmt label: (identifier #{name}) stmt: {stmt})) - }), // ---- Collections ---- // Array literal rule!((array_literal element: _* @elems) => (array_literal element: {elems})), From 4c764b52dc177cbf5565d3fb8f86e4c8f5518cb5 Mon Sep 17 00:00:00 2001 From: Taus Date: Mon, 20 Jul 2026 12:11:54 +0000 Subject: [PATCH 036/188] unified: Port collection rules to swift-syntax Retarget collection literals and subscripts to the swift-syntax AST, output unchanged: `arrayExpr` -> `array_literal` (each `arrayElement` unwraps to its expression); `dictionaryExpr` -> an opaque `map_literal` leaf (its source span, matching the tree-sitter path); and `subscriptCallExpr` (`xs[0]`) -> `call_expr`, mirroring the tree-sitter grammar's treatment of a subscript as a call. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../extractor/src/languages/swift/swift.rs | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index e0c2f66e2101..2068cca7a64a 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -845,20 +845,24 @@ fn translation_rules() -> Vec> { (labeled_stmt label: (identifier #{lbl}) stmt: {stmt}) ), // ---- Collections ---- - // Array literal - rule!((array_literal element: _* @elems) => (array_literal element: {elems})), - // Empty array literal - rule!((array_literal) => (array_literal)), - // Dictionary literal — zip keys and values into key_value_pairs + // An array literal (`[1, 2, 3]`). Each `arrayElement` unwraps to its + // contained expression. rule!( - (dictionary_literal key: _* @keys value: _* @vals) + (arrayExpr elements: _* @els) => - (map_literal element: {keys.into_iter().zip(vals).map(|(k, v)| - tree!((key_value_pair key: {k} value: {v})) - )}) + (array_literal element: {els}) + ), + rule!((arrayElement expression: @e) => expr { e }), + // A dictionary literal (`["a": 1]`) is kept as an opaque `map_literal` + // leaf (its source span), matching the tree-sitter path. + rule!((dictionaryExpr) => (map_literal)), + // A subscript access (`xs[0]`) is modelled as a call, exactly as the + // tree-sitter grammar does (it parses `xs[0]` like `xs(0)`). + rule!( + (subscriptCallExpr calledExpression: @callee arguments: _* @args) + => + (call_expr callee: {callee} argument: {args}) ), - rule!((dictionary_literal element: _* @elems) => (map_literal element: {elems})), - rule!((dictionary_literal_item key: @k value: @v) => (key_value_pair key: {k} value: {v})), // ---- Optionals and errors ---- // Optional chaining — unwrap the marker rule!((optional_chain_marker expr: @inner) => expr { inner }), From 6275977bc53257fe84c5801b40051c38ccd0dc79 Mon Sep 17 00:00:00 2001 From: Taus Date: Mon, 20 Jul 2026 13:15:11 +0000 Subject: [PATCH 037/188] unified: Port optional and error-handling rules to swift-syntax Retarget optional chaining, `try`, `do`/`catch`, casts, type tests, `await`, and force-unwrap to the swift-syntax AST, output unchanged: - `optionalChainingExpr` (`x?`) unwraps transparently (the enclosing member access / call carries the semantics). - `tryExpr` -> prefix `unary_expr`; swift-syntax splits the operator into a `try` keyword and an optional `?`/`!` mark, recombined into one `prefix_operator` spelling. - `doStmt` -> `try_expr` with `catchClause` -> `catch_clause`; a `catch` binds the first `catchItem`'s pattern and optional `where` guard. - `asExpr` (`x as`/`as?`/`as!` `T`) -> `type_cast_expr`, `isExpr` (`x is T`) -> `type_test_expr`, and `awaitExpr` -> prefix `unary_expr`. - `forceUnwrapExpr` (`x!`) -> postfix `unary_expr` (swift-syntax has a dedicated node; the tree-sitter path used the generic postfix operator). A couple of rewritten rules keep their opening inlined so this commit's diff stays readable; a later commit restores the canonical formatting. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../extractor/src/languages/swift/swift.rs | 61 +++++++++---------- 1 file changed, 28 insertions(+), 33 deletions(-) diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index 2068cca7a64a..dfddfa9c66ad 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -865,57 +865,52 @@ fn translation_rules() -> Vec> { ), // ---- Optionals and errors ---- // Optional chaining — unwrap the marker - rule!((optional_chain_marker expr: @inner) => expr { inner }), + rule!((optionalChainingExpr expression: @inner) => expr { inner }), // try/try?/try! expr → unary_expr with operator "try", "try?" or "try!" - rule!((try_expression (try_operator) @op expr: @inner) => (unary_expr operator: (prefix_operator #{op}) operand: {inner})), - rule!((try_expression operator: (try_operator) @op expr: @inner) => (unary_expr operator: (prefix_operator #{op}) operand: {inner})), + rule!( + (tryExpr questionOrExclamationMark: _? @@m expression: @e) + => + expr { + let op = format!("try{}", m.map(|m| ctx.source_text(m)).unwrap_or_default()); + tree!((unary_expr operator: (prefix_operator #{op}) operand: {e})) + } + ), // Do-catch → try_expr rule!( - (do_statement body: (block statement: _* @body) catch: (catch_block)* @catches) + (doStmt body: @body catchClauses: _* @catches) => (try_expr - body: (block stmt: {body}) + body: {body} catch_clause: {catches}) ), // Catch block with bound identifier; optional where-clause guard. rule!( - (catch_block - keyword: (catch_keyword) - error: @pattern - where: (where_clause expr: @guard)? - body: (block statement: _* @body)) + (catchClause + catchItems: (catchItem + pattern: @pattern + whereClause: (whereClause condition: @guard)?) + body: @body) => (catch_clause pattern: {pattern} guard: {guard} - body: (block stmt: {body})) + body: {body}) ), // Catch block without error binding - rule!( - (catch_block keyword: (catch_keyword) body: (block statement: _* @body)) - => - (catch_clause body: (block stmt: {body})) - ), - // Empty catch block: catch {} - rule!( - (catch_block (catch_keyword)) - => - (catch_clause body: (block)) - ), - // Catch block with unhandled pattern — preserve pattern; optional body. - rule!( - (catch_block keyword: (catch_keyword) error: @pat body: (block statement: _* @body)) - => - (catch_clause - pattern: {pat} - body: (block stmt: {body})) - ), + rule!((catchClause body: @body) => (catch_clause body: {body})), // As expression (type cast) — as?, as! - rule!((as_expression (as_operator) @op expr: @val type: @ty) => (type_cast_expr expr: {val} operator: (infix_operator #{op}) type: {ty})), + rule!((asExpr expression: @val questionOrExclamationMark: _? @@mark type: @ty) => type_cast_expr { + let op = format!("as{}", mark.map(|m| ctx.source_text(m)).unwrap_or_default()); + tree!((type_cast_expr expr: {val} operator: (infix_operator #{op}) type: {ty})) + }), // Check expression (`x is T`) → type_test_expr - rule!((check_expression op: @op target: @val type: @ty) => (type_test_expr expr: {val} operator: (infix_operator #{op}) type: {ty})), + rule!((isExpr expression: @val type: @ty) => (type_test_expr expr: {val} operator: (infix_operator "is") type: {ty})), // Await expression → unary_expr with operator "await" - rule!((await_expression expr: @val) => (unary_expr operator: (prefix_operator "await") operand: {val})), + rule!((awaitExpr expression: @val) => (unary_expr operator: (prefix_operator "await") operand: {val})), + // Force-unwrap (`x!`) → postfix unary_expr. swift-syntax has a dedicated + // `forceUnwrapExpr` node (the tree-sitter path used the generic postfix + // operator rule instead). + rule!((forceUnwrapExpr expression: @e) => (unary_expr operator: (postfix_operator "!") operand: {e})), // A multi-part identifier (for example `Foo.Bar.Baz`) is translated to // a member_access_expr chain with a name_expr base. rule!( From 37654b4bcc8398a96913932ac61629e2aa900d80 Mon Sep 17 00:00:00 2001 From: Taus Date: Mon, 20 Jul 2026 13:49:55 +0000 Subject: [PATCH 038/188] unified: Port import rules to swift-syntax Retarget imports to the swift-syntax AST, output unchanged. swift-syntax represents the dotted path as a list of `importPathComponent`s, folded into a `name_expr`/`member_access_expr` chain via `member_chain`. A single rule handles both forms via an optional `importKindSpecifier`: a scoped import (`import struct Foo.Bar`) has one and binds the last path component as a `name_pattern`; a plain import (`import Foundation`) has none and uses a `bulk_importing_pattern`. Leading attributes (`@_exported`) and access modifiers (`public`) become `modifier`s. The tree-sitter multi-part `identifier` rule is dropped: swift-syntax qualified names are already `memberAccessExpr` chains, and import paths are `importPathComponent`s. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../extractor/src/languages/swift/swift.rs | 60 ++++++++++--------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index dfddfa9c66ad..148a2df2218e 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -911,35 +911,37 @@ fn translation_rules() -> Vec> { // `forceUnwrapExpr` node (the tree-sitter path used the generic postfix // operator rule instead). rule!((forceUnwrapExpr expression: @e) => (unary_expr operator: (postfix_operator "!") operand: {e})), - // A multi-part identifier (for example `Foo.Bar.Baz`) is translated to - // a member_access_expr chain with a name_expr base. - rule!( - (identifier part: _+ @parts) - => - expr { member_chain(&mut ctx, parts) } - ), - // Scoped import declaration (for example `import struct Foo.Bar`): - // flatten the identifier parts into a member_access_expr and bind the - // final segment as a name_pattern. - rule!( - (import_declaration scoped_import_kind: @kind name: (identifier part: _+ @parts) @name modifiers: (modifiers)? @mods) - => - (import_declaration - pattern: (name_pattern identifier: (identifier #{parts.last().unwrap()})) - imported_expr: {name} - modifier: (modifier #{kind}) - modifier: {mods}) - ), - // Non-scoped import declaration (for example `import Foundation`): - // flatten the identifier parts into a member_access_expr and use a - // bulk_importing_pattern. - rule!( - (import_declaration name: @name modifiers: (modifiers)? @mods) - => - (import_declaration - pattern: (bulk_importing_pattern) - imported_expr: {name} - modifier: {mods}) + // ---- Imports ---- + // An import declaration. The dotted path (a list of + // `importPathComponent`s) becomes a `name_expr`/`member_access_expr` + // chain (via `member_chain`). A scoped import (`import struct Foo.Bar`) + // has an `importKindSpecifier` and binds the last path component as a + // `name_pattern`; a plain import (`import Foundation`) has none and uses + // a `bulk_importing_pattern` spanning the whole declaration. Any leading + // attributes (`@_exported`) and access modifiers (`public`) become + // `modifier`s. + rule!( + (importDecl + attributes: _* @attrs + modifiers: _* @mods + importKindSpecifier: _? @@kind + path: (importPathComponent name: @@parts)*) + => + import_declaration { + let pattern = match kind { + Some(_) => { + let last = *parts.last().ok_or("import has no path")?; + tree!((name_pattern identifier: (identifier #{last}))) + } + None => tree!((bulk_importing_pattern)), + }; + tree!((import_declaration + modifier: {kind.map(|k| tree!((modifier #{k})))} + modifier: {attrs} + modifier: {mods} + pattern: {pattern} + imported_expr: {member_chain(&mut ctx, parts)})) + } ), // ---- Types and classes ---- // Self expression → name_expr From 8e6651aa9b3cd184fde4bae35018180dbe24d4b8 Mon Sep 17 00:00:00 2001 From: Taus Date: Mon, 20 Jul 2026 14:44:51 +0000 Subject: [PATCH 039/188] unified: Port type-container declarations to swift-syntax Retarget the nominal type declarations to the swift-syntax AST, output unchanged. `classDecl`/`structDecl`/`enumDecl`/`protocolDecl`/`extensionDecl` each become a `class_like_declaration` tagged with a modifier naming the declaration keyword, with members drawn from the `memberBlock`; each `memberBlockItem` unwraps to its contained declaration. `superExpr` maps to `super_expr`; `self` needs no rule (swift-syntax models it as an ordinary `declReferenceExpr`, already a `name_expr`). Following the tree-sitter path (PARITY), the inheritance clause is not emitted as a `base_type` (the tree-sitter rule captured it positionally, but the grammar nests it under a field, so it never actually matched); swift-syntax exposes it cleanly, so that is a correctness improvement to make once tree-sitter is retired. The tree-sitter grammar's standalone `self`, dead modifier (`visibility_modifier`, etc.), key-path, and inheritance-specifier rules are dropped; `#selector`/`#keyPath` (now a `macroExpansionExpr`) stays an `unsupported_node`. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../extractor/src/languages/swift/swift.rs | 95 ++++++++----------- 1 file changed, 39 insertions(+), 56 deletions(-) diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index 148a2df2218e..3b8d8e913f55 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -943,26 +943,15 @@ fn translation_rules() -> Vec> { imported_expr: {member_chain(&mut ctx, parts)})) } ), - // ---- Types and classes ---- - // Self expression → name_expr - rule!((self_expression) => (name_expr identifier: (identifier "self"))), - // Super expression → super_expr - rule!((super_expression) => (super_expr)), - // Modifiers — unwrap to individual modifier children - rule!((modifiers _* @mods) => modifier* { mods }), + // ---- Types and declarations ---- + // A leading attribute (`@objc`) or access/function/member/mutation/ + // ownership modifier (swift-syntax models each as a single `declModifier`) + // becomes a `modifier`; its source text is the modifier spelling. rule!((attribute) @m => (modifier #{m})), - // swift-syntax models every access/function/member/mutation/ownership - // modifier as a single `declModifier`; its source text is the modifier. rule!((declModifier) @m => (modifier #{m})), - rule!((visibility_modifier) @m => (modifier #{m})), - rule!((function_modifier) @m => (modifier #{m})), - rule!((member_modifier) @m => (modifier #{m})), - rule!((mutation_modifier) @m => (modifier #{m})), - rule!((ownership_modifier) @m => (modifier #{m})), - rule!((property_modifier) @m => (modifier #{m})), - rule!((parameter_modifier) @m => (modifier #{m})), - rule!((inheritance_modifier) @m => (modifier #{m})), - rule!((property_behavior_modifier) @m => (modifier #{m})), + // A `super` expression. (`self` needs no rule: swift-syntax models it as + // an ordinary `declReferenceExpr`, already mapped to a `name_expr`.) + rule!((superExpr) => (super_expr)), // Type expressions. A generic type applied with explicit arguments // (`Set`) is represented opaquely, using the whole source text as // the name (PARITY(tree-sitter): the generic arguments are not @@ -1041,77 +1030,71 @@ fn translation_rules() -> Vec> { } ), // Selector expression: `#selector(inner)` -- not yet supported - rule!( - (selector_expression _ @inner) - => - (unsupported_node) - ), - // Key path expressions are currently unsupported. - rule!((key_path_expression) => (unsupported_node)), - // Inheritance specifier → base_type - rule!((inheritance_specifier inherits_from: @ty) => (base_type type: {ty})), + // (swift-syntax represents `#selector`/`#keyPath` and other macro + // expansions uniformly as a `macroExpansionExpr`). + rule!((macroExpansionExpr) => (unsupported_node)), + // PARITY(tree-sitter): a nominal type's `inheritanceClause` (`: Base, + // Proto`) is not emitted as a `base_type` — the tree-sitter path drops + // it (no corpus target has a `base_type`). swift-syntax exposes it + // cleanly, so emitting `base_type` is a correctness improvement to make + // once tree-sitter is retired. Each declaration keyword gets its own + // rule; the bodies are identical but for the keyword. // Class declaration with body containing members rule!( - (class_declaration - declaration_kind: @kind - name: @name - body: (class_body member: _* @members) - (inheritance_specifier)* @bases - (modifiers)* @mods) + (classDecl classKeyword: @kind modifiers: _* @mods name: @name memberBlock: (memberBlock members: _* @members)) => (class_like_declaration modifier: (modifier #{kind}) modifier: {mods} name: (identifier #{name}) - base_type: {bases} member: {members}) ), // Enum class declaration: same as a regular class but with an enum body. rule!( - (class_declaration - declaration_kind: @kind - name: @name - body: (enum_class_body member: _* @members) - (inheritance_specifier)* @bases - (modifiers)* @mods) + (enumDecl enumKeyword: @kind modifiers: _* @mods name: @name memberBlock: (memberBlock members: _* @members)) => (class_like_declaration modifier: (modifier #{kind}) modifier: {mods} name: (identifier #{name}) - base_type: {bases} member: {members}) ), - // Class declaration with empty body + // A `struct` declaration. rule!( - (class_declaration - declaration_kind: @kind - name: @name - body: _ - (inheritance_specifier)* @bases - (modifiers)* @mods) + (structDecl structKeyword: @kind modifiers: _* @mods name: @name memberBlock: (memberBlock members: _* @members)) => (class_like_declaration modifier: (modifier #{kind}) modifier: {mods} name: (identifier #{name}) - base_type: {bases}) + member: {members}) ), // Protocol declaration rule!( - (protocol_declaration - name: @name - body: (protocol_body member: _* @members) - (inheritance_specifier)* @bases - (modifiers)* @mods) + (protocolDecl protocolKeyword: @kind modifiers: _* @mods name: @name memberBlock: (memberBlock members: _* @members)) => (class_like_declaration - modifier: (modifier "protocol") + modifier: (modifier #{kind}) + modifier: {mods} + name: (identifier #{name}) + member: {members}) + ), + // An `extension Foo { … }` is likewise a `class_like_declaration`, named + // by the extended type. The extended type is captured opaquely (as its + // source text) so that qualified names (`extension String.Interpolation`, + // a `memberType`) name the declaration just like simple ones, matching the + // old tree-sitter `user_type` behaviour. + rule!( + (extensionDecl extensionKeyword: @kind modifiers: _* @mods extendedType: @@name memberBlock: (memberBlock members: _* @members)) + => + (class_like_declaration + modifier: (modifier #{kind}) modifier: {mods} name: (identifier #{name}) - base_type: {bases} member: {members}) ), + // A member of a type declaration unwraps to the contained declaration. + rule!((memberBlockItem decl: _* @d) => member* { d }), // Protocol function — return type and body statements both optional. rule!( (protocol_function_declaration From ec0c49a0535f67ae80ad373848298b2daaaa0541 Mon Sep 17 00:00:00 2001 From: Taus Date: Wed, 22 Jul 2026 14:28:48 +0000 Subject: [PATCH 040/188] unified: Port property accessor rules to swift-syntax MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Retarget property accessors to the swift-syntax AST, output unchanged. An accessor-bearing `variableDecl` publishes the property name/type into `ctx`; a computed property (`var v: T { get set }`) emits accessors carrying the type, while a stored property with observers (`var x = e { didSet {…} }`) emits the backing `variable_declaration` first. swift-syntax models get/set/willSet/didSet uniformly as `accessorDecl`, so a single `accessorDecl` rule — with an optional body distinguishing a computed accessor from a bodyless protocol requirement — replaces the tree-sitter grammar's separate computed-getter/setter/modify, willset/didset, and getter-/setter-specifier rules. The tree-sitter protocol property and function requirement rules (`protocol_property_declaration`, `protocol_function_declaration`) are dropped: swift-syntax models those requirements as ordinary `variableDecl`s (with bodyless accessors) and `functionDecl`s, already handled by the general rules. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../extractor/src/languages/swift/swift.rs | 368 ++++++------------ 1 file changed, 109 insertions(+), 259 deletions(-) diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index 3b8d8e913f55..2abc783b9f01 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -8,18 +8,14 @@ use yeast::{ConcreteDesugarer, DesugaringConfig, PhaseKind, Rule, rule, tree}; /// post-hoc mutation. #[derive(Clone, Default)] struct SwiftContext { - /// Identifier node for the property name. Set by the outer - /// `property_binding` (computed accessors / willSet-didSet) and - /// `protocol_property_declaration` rules before translating accessor - /// children; read by the accessor inner rules - /// (`computed_getter`/`computed_setter`/`computed_modify`/ - /// `willset_clause`/`didset_clause`/`getter_specifier`/ - /// `setter_specifier`). + /// Identifier node for the property name. Set by the accessor-bearing + /// `variableDecl` rule before translating the accessor block; read by the + /// inner `accessorDecl` rules to name each `accessor_declaration`. property_name: Option, - /// Translated type node for the property type. Set by the outer - /// `property_binding` rule (computed accessors variant) and - /// `protocol_property_declaration` when present; read by the - /// accessor inner rules. + /// Translated type node for the property type. Set (for computed + /// properties) by the accessor-bearing `variableDecl` rule; read by the + /// inner `accessorDecl` rules. Left `None` for stored properties with + /// observers, so their `willSet`/`didSet` accessors carry no type. property_type: Option, /// Translated outer modifiers to attach to each child of a flattening /// outer rule — e.g. the `let`/`var` binding modifier on each @@ -227,118 +223,123 @@ fn translation_rules() -> Vec> { rule!((tupleExpr) => (tuple_expr)), // A code block contains its statements directly. rule!((codeBlock statements: _* @stmts) => (block stmt: {stmts})), - // ---- Variables ---- - // property_binding rules — these produce variable_declaration and/or accessor_declaration - // nodes for individual declarators. The outer property_declaration rule splices these out - // and attaches binding/modifiers from the parent. - - // Computed property with explicit accessors (get/set/modify) → a - // sequence of `accessor_declaration` nodes. The outer rule - // publishes the property's name and type into `ctx` so that each - // inner accessor rule - // (`computed_getter`/`computed_setter`/`computed_modify`) builds - // its `accessor_declaration` with `name` and `type` set from the - // start — no schema-invalid intermediate state. - // - // Toggles `ctx.is_chained` per accessor iteration: the first - // accessor inherits the outer rule's chained state (i.e. whether - // this whole property_binding is itself a non-first declarator - // of a containing property_declaration); subsequent accessors - // always emit `chained_declaration`. - rule!( - (property_binding - name: @pattern - type: _? @ty - computed_value: (computed_property accessor: _+ @@accessors)) - => - accessor_declaration* { - ctx.property_name = Some(tree!((identifier #{pattern}))); - ctx.property_type = ty; - - let mut result = Vec::new(); - for (i, acc) in accessors.into_iter().enumerate() { - if i > 0 { - ctx.is_chained = true; - } - result.extend(ctx.translate(acc)?); - } - result - } - ), - // Computed property: shorthand getter (no explicit get/set, just - // statements) → a single accessor_declaration with kind "get". - // Reads outer modifiers / chained tag from `ctx` (set by the - // outer `property_declaration` rule). + // ---- Properties with accessors ---- + // A computed property with an implicit getter (`var a: T { }`) + // becomes a single `accessor_declaration` of kind `get`. This form is + // self-contained (no context threading). It must precede the plain + // `variableDecl` rules, which would otherwise match and drop the accessor + // block. rule!( - (property_binding - name: (pattern bound_identifier: @name) - type: _? @ty - computed_value: (computed_property statement: _* @@body)) + (variableDecl + bindingSpecifier: @@spec + bindings: (patternBinding + pattern: (identifierPattern identifier: @@name) + typeAnnotation: (typeAnnotation type: @ty) + accessorBlock: (accessorBlock accessors: (codeBlockItem)+ @body))) => (accessor_declaration - modifier: {ctx.outer_modifiers.clone()} - modifier: {chained_modifier(&mut ctx)} + modifier: (modifier #{spec}) name: (identifier #{name}) type: {ty} accessor_kind: (accessor_kind "get") - body: (block stmt: {ctx.reset(); ctx.translate(body)?})) - ), - // Stored property with willSet/didSet observers (initializer - // optional) → a `variable_declaration` followed by one - // `accessor_declaration` per observer, each born with the - // property name set. Manual rule: we publish the property name - // into `ctx` before translating the observer children so the - // inner `willset_clause` / `didset_clause` rules construct - // valid `accessor_declaration` nodes from the start. + body: (block stmt: {body})) + ), + // A property with an explicit accessor block. The two shapes differ only + // by the presence of an initializer (tree-sitter split them into distinct + // `willset_didset_block` vs computed-accessor node types; swift-syntax + // makes both plain `accessorDecl`s): + // + // * With an initializer (`var x: T = e { willSet {…} didSet {…} }`) it is + // a *stored* property with observers: emit the backing + // `variable_declaration` first, then one `accessor_declaration` per + // observer (observers carry no type). + // * Without an initializer (`var v: T { get set }`, incl. protocol + // requirements) it is a *computed* property: no backing variable; the + // type is published so the get/set accessors carry it. // - // The `variable_declaration` itself inherits the outer rule's - // chained state; observers always get `chained_declaration` - // because they're subsequent outputs of this flattening rule. + // In both cases the first emitted declaration is unchained and every + // subsequent one is tagged `chained_declaration` (the `!result.is_empty()` + // test). Must precede the plain `variableDecl` rules. rule!( - (property_binding - name: (pattern bound_identifier: @name) - type: _? @ty - value: _? @@val - observers: (willset_didset_block willset: _? @@ws didset: _? @@ds)) + (variableDecl + bindingSpecifier: @@spec + bindings: (patternBinding + pattern: (identifierPattern identifier: @@name) + typeAnnotation: (typeAnnotation type: @ty) + initializer: (initializerClause value: @@val)? + accessorBlock: (accessorBlock accessors: (accessorDecl)+ @@accessors))) => member* { - // The initializer value must not inherit the binding - // context (it may contain patterns, e.g. a switch - // expression), so translate it inside a `ctx.scoped` - // block — the block receives a temporary `ctx` whose - // `user_ctx` is a clone; mutations to it are discarded - // when the block returns, so the outer `ctx` is intact - // for the observer loop below. The observers keep the - // outer context: each willSet/didSet accessor emits - // the binding modifier and, in turn, resets the - // context for its own body. - let val = ctx.scoped(|ctx| { - ctx.reset(); - ctx.translate(val) - })?; - - let var_decl = tree!( - (variable_declaration - modifier: {ctx.outer_modifiers.clone()} - modifier: {chained_modifier(&mut ctx)} - pattern: (name_pattern identifier: (identifier #{name})) - type: {ty} - value: {val}) - ); - - // Publish the property name for the observer rules. + ctx.outer_modifiers = vec![tree!((modifier #{spec}))]; ctx.property_name = Some(tree!((identifier #{name}))); - // Observers are subsequent outputs of this flattening - // rule, so they always get `chained_declaration`. - ctx.is_chained = true; - - let mut result = vec![var_decl]; - for obs in ws.into_iter().chain(ds) { - result.extend(ctx.translate(obs)?); + let mut result = Vec::new(); + if let Some(val) = val { + // Stored property with observers: the initializer is not part + // of the binding, so translate it in a reset scope. + let val = ctx.scoped(|ctx| { + ctx.reset(); + ctx.translate(val) + })?; + result.push(tree!( + (variable_declaration + modifier: {ctx.outer_modifiers.clone()} + pattern: (name_pattern identifier: (identifier #{name})) + type: {ty} + value: {val}) + )); + } else { + // Computed property: the accessors carry the type. + ctx.property_type = Some(ty); + } + for acc in accessors.into_iter() { + ctx.is_chained = !result.is_empty(); + result.extend(ctx.translate(acc)?); } result } ), + // Each `accessorDecl` becomes an `accessor_declaration`, reading the + // property name/type and the binding/chained modifiers from `ctx`. The + // accessor kind comes straight from the specifier keyword + // (`get`/`set`/`willSet`/`didSet`). The body is optional: a body-bearing + // accessor (a computed getter/setter, or a `willSet`/`didSet` observer) + // carries the binding modifier and a translated body, whereas a bodyless + // one (a protocol requirement) carries neither. The property context is + // read out *before* translating the body, which resets `ctx` so the + // accessor's context does not leak into the body subtree. + rule!( + (accessorDecl accessorSpecifier: @@spec body: _? @@body) + => + accessor_declaration { + let binding = if body.is_some() { + ctx.outer_modifiers.clone() + } else { + Vec::new() + }; + let chained = chained_modifier(&mut ctx); + let name = ctx + .property_name + .ok_or("accessor outside property context")?; + let ty = ctx.property_type; + let body = match body { + Some(block) => { + ctx.reset(); + ctx.translate(block)?.into_iter().next() + } + None => None, + }; + tree!( + (accessor_declaration + modifier: {binding} + modifier: {chained} + name: {name} + type: {ty} + accessor_kind: (accessor_kind #{spec}) + body: {body}) + ) + } + ), + // ---- Variables ---- // The individual bindings of a `variableDecl`. The binding modifier and // chained tag come from `ctx` (set by the `variableDecl` rule below). The // type annotation and initializer are both optional (one combined rule @@ -1095,22 +1096,6 @@ fn translation_rules() -> Vec> { ), // A member of a type declaration unwraps to the contained declaration. rule!((memberBlockItem decl: _* @d) => member* { d }), - // Protocol function — return type and body statements both optional. - rule!( - (protocol_function_declaration - name: @name - (parameter)* @params - return_type: _? @ret - body: (block statement: _* @body_stmts)? - (modifiers)* @mods) - => - (function_declaration - modifier: {mods} - name: (identifier #{name}) - parameter: {params} - return_type: {ret} - body: (block stmt: {body_stmts})) - ), // Init declaration → constructor_declaration. Body statements optional; // body itself is also optional (protocol requirement). rule!( @@ -1158,141 +1143,6 @@ fn translation_rules() -> Vec> { name: (identifier #{name}) bound: {bound}) ), - // Protocol property declaration: translate each accessor - // requirement to an `accessor_declaration` carrying the property - // name, type, and outer modifiers. Manual rule: we publish the - // property's name/type/modifiers into `ctx` and translate each - // accessor with `ctx.is_chained` toggled per iteration so the - // inner `getter_specifier`/`setter_specifier` rules emit - // complete nodes from the start (including the - // `chained_declaration` tag for non-first accessors). - rule!( - (protocol_property_declaration - name: (pattern bound_identifier: @name) - requirements: (protocol_property_requirements accessor: _+ @@accessors) - type: _? @ty - (modifiers)* @mods) - => - accessor_declaration* { - ctx.property_name = Some(tree!((identifier #{name}))); - ctx.property_type = ty; - ctx.outer_modifiers = mods; - - let mut result = Vec::new(); - for (i, acc) in accessors.into_iter().enumerate() { - ctx.is_chained = i > 0; - result.extend(ctx.translate(acc)?); - } - result - } - ), - // getter_specifier / setter_specifier → bodyless accessor_declaration - // getter_specifier / setter_specifier → bodyless - // accessor_declaration. Reads property name/type/modifiers from - // `ctx` set by the outer `protocol_property_declaration` rule. - rule!( - (getter_specifier) - => - (accessor_declaration - name: {ctx.property_name.ok_or("getter_specifier outside protocol_property_declaration context")?} - type: {ctx.property_type} - accessor_kind: (accessor_kind "get") - modifier: {ctx.outer_modifiers.clone()} - modifier: {chained_modifier(&mut ctx)}) - ), - rule!( - (setter_specifier) - => - (accessor_declaration - name: {ctx.property_name.ok_or("setter_specifier outside protocol_property_declaration context")?} - type: {ctx.property_type} - accessor_kind: (accessor_kind "set") - modifier: {ctx.outer_modifiers.clone()} - modifier: {chained_modifier(&mut ctx)}) - ), - // protocol_property_requirements wrapper — should be consumed by above; fallback - rule!((protocol_property_requirements accessor: _* @accs) => accessor_declaration* { accs }), - // Computed getter → accessor_declaration (body optional). - // Reads property name/type from the outer property_binding rule - // and binding/outer modifiers + chained tag from the outer - // property_declaration rule. - rule!( - (computed_getter body: (block statement: _* @@body)?) - => - (accessor_declaration - modifier: {ctx.outer_modifiers.clone()} - modifier: {chained_modifier(&mut ctx)} - name: {ctx.property_name.ok_or("computed_getter outside property_binding context")?} - type: {ctx.property_type} - accessor_kind: (accessor_kind "get") - body: (block stmt: {ctx.reset(); ctx.translate(body)?})) - ), - // Computed setter with explicit parameter name. - rule!( - (computed_setter parameter: @param body: (block statement: _* @@body)) - => - (accessor_declaration - modifier: {ctx.outer_modifiers.clone()} - modifier: {chained_modifier(&mut ctx)} - name: {ctx.property_name.ok_or("computed_setter outside property_binding context")?} - type: {ctx.property_type} - accessor_kind: (accessor_kind "set") - parameter: (parameter pattern: (name_pattern identifier: (identifier #{param}))) - body: (block stmt: {ctx.reset(); ctx.translate(body)?})) - ), - // Computed setter without explicit parameter name; body optional. - rule!( - (computed_setter body: (block statement: _* @@body)?) - => - (accessor_declaration - modifier: {ctx.outer_modifiers.clone()} - modifier: {chained_modifier(&mut ctx)} - name: {ctx.property_name.ok_or("computed_setter outside property_binding context")?} - type: {ctx.property_type} - accessor_kind: (accessor_kind "set") - body: (block stmt: {ctx.reset(); ctx.translate(body)?})) - ), - // Computed modify → accessor_declaration - rule!( - (computed_modify body: (block statement: _* @@body)) - => - (accessor_declaration - modifier: {ctx.outer_modifiers.clone()} - modifier: {chained_modifier(&mut ctx)} - name: {ctx.property_name.ok_or("computed_modify outside property_binding context")?} - type: {ctx.property_type} - accessor_kind: (accessor_kind "modify") - body: (block stmt: {ctx.reset(); ctx.translate(body)?})) - ), - // willset/didset block — spread to children (only reachable as a - // fallback; the outer property_binding manual rule normally - // captures the willset/didset clauses directly). - rule!((willset_didset_block _* @clauses) => accessor_declaration* { clauses }), - // willset clause → accessor_declaration (body optional). Reads - // `ctx.property_name` set by the outer property_binding rule and - // binding/outer modifiers + chained tag from the outer - // property_declaration rule. - rule!( - (willset_clause body: (block statement: _* @@body)?) - => - (accessor_declaration - modifier: {ctx.outer_modifiers.clone()} - modifier: {chained_modifier(&mut ctx)} - name: {ctx.property_name.ok_or("willset_clause outside property_binding context")?} - accessor_kind: (accessor_kind "willSet") - body: (block stmt: {ctx.reset(); ctx.translate(body)?})) - ), - // didset clause → accessor_declaration (body optional). - rule!( - (didset_clause body: (block statement: _* @@body)?) - => - (accessor_declaration - modifier: {ctx.outer_modifiers.clone()} - modifier: {chained_modifier(&mut ctx)} - name: {ctx.property_name.ok_or("didset_clause outside property_binding context")?} - accessor_kind: (accessor_kind "didSet") - body: (block stmt: {ctx.reset(); ctx.translate(body)?})) - ), // Preprocessor conditionals — unsupported rule!((diagnostic) => (unsupported_node)), // ---- Fallbacks ---- From 90ea1b591d1254e621a20f7eb9f246d992ec3b10 Mon Sep 17 00:00:00 2001 From: Taus Date: Thu, 23 Jul 2026 11:48:10 +0000 Subject: [PATCH 041/188] unified: Port enum-case rules to swift-syntax Retarget enum cases to the swift-syntax AST. An `enumCaseDecl` flattens its comma-separated `enumCaseElement`s (non-first tagged `chained_declaration`) and publishes any case modifiers (e.g. `indirect`) into `ctx`; an element with a payload becomes a nested `class_like_declaration` + constructor, an element with a raw value (`case a = 1`) or a plain element a `variable_declaration`; `enumCaseParameter` becomes a `parameter`. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../extractor/src/languages/swift/swift.rs | 47 +++++++++---------- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index 2abc783b9f01..82709c2da20e 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -386,27 +386,22 @@ fn translation_rules() -> Vec> { } ), // ---- Enums ---- - // enum_type_parameter → parameter (with optional name as pattern). + // An enum-case payload parameter (`radius: Double`, or just `Double`). + // The label (`firstName`) is optional. rule!( - (enum_type_parameter name: @name type: @ty) + (enumCaseParameter firstName: _? @@name type: @ty) => - (parameter - pattern: (name_pattern identifier: (identifier #{name})) - type: {ty}) + (parameter pattern: {name.map(|name| tree!((name_pattern identifier: (identifier #{name}))))} type: {ty}) ), + // An enum element with associated values (`case circle(radius: Double)`) + // becomes a nested `class_like_declaration` whose constructor carries the + // payload parameters; an element with a raw value (`case a = 1`) or a + // plain element (`case north`) becomes a `variable_declaration`. All + // carry the shared case modifiers / chained tag from `ctx` (set by the + // `enumCaseDecl` rule below) and are tagged `enum_case` (after any + // `chained_declaration` tag, matching the tree-sitter modifier order). rule!( - (enum_type_parameter type: @ty) - => - (parameter type: {ty}) - ), - // enum_case_entry with associated values → class_like_declaration - // containing a constructor whose parameters are the data - // parameters. Reads outer modifiers / chained tag from `ctx` - // (set by the outer `enum_entry` rule). - rule!( - (enum_case_entry - name: @name - data_contents: (enum_type_parameters parameter: _* @params)) + (enumCaseElement name: @name parameterClause: (enumCaseParameterClause parameters: _* @params)) => (class_like_declaration modifier: {ctx.outer_modifiers.clone()} @@ -415,9 +410,8 @@ fn translation_rules() -> Vec> { name: (identifier #{name}) member: (constructor_declaration parameter: {params} body: (block))) ), - // enum_case_entry with explicit raw value → variable_declaration with that value. rule!( - (enum_case_entry name: @name raw_value: @val) + (enumCaseElement name: @name rawValue: (initializerClause value: @val)) => (variable_declaration modifier: {ctx.outer_modifiers.clone()} @@ -426,9 +420,8 @@ fn translation_rules() -> Vec> { pattern: (name_pattern identifier: (identifier #{name})) value: {val}) ), - // enum_case_entry without associated values → variable_declaration tagged enum_case. rule!( - (enum_case_entry name: @name) + (enumCaseElement name: @name) => (variable_declaration modifier: {ctx.outer_modifiers.clone()} @@ -436,12 +429,14 @@ fn translation_rules() -> Vec> { modifier: (modifier "enum_case") pattern: (name_pattern identifier: (identifier #{name}))) ), - // enum_entry: flatten case entries; publish outer modifiers - // into `ctx` and translate each case with `ctx.is_chained` - // toggled per iteration so the inner `enum_case_entry` rules - // emit complete `modifier:` lists from the start. + // Enum cases. A single `case` declaration may carry modifiers + // (e.g. `indirect`) and list several comma-separated elements; each + // becomes its own declaration carrying those shared modifiers, and + // non-first ones are tagged `chained_declaration` (mirroring the + // tree-sitter `enum_entry` rule). The modifiers are published into `ctx` + // for the element rules above, which build the actual declaration. rule!( - (enum_entry case: _+ @@cases (modifiers)* @mods) + (enumCaseDecl modifiers: _* @mods elements: _* @@cases) => member* { ctx.outer_modifiers = mods; From c4fbd74cfe1695576d02e9682efbeb45439551dd Mon Sep 17 00:00:00 2001 From: Taus Date: Thu, 23 Jul 2026 12:03:28 +0000 Subject: [PATCH 042/188] unified: Port constructor and related declaration rules to swift-syntax Retarget the remaining member declarations to the swift-syntax AST. An `initializerDecl` becomes a `constructor_declaration` (its body optional, so a bodyless protocol requirement still maps); `deinitializerDecl`, `typeAliasDecl`, and `associatedTypeDecl` map to `destructor_declaration`, `type_alias_declaration`, and `associated_type_declaration` respectively. The tree-sitter subscript and preprocessor-diagnostic rules are dropped: their swift-syntax counterparts (`subscriptDecl`, `ifConfigDecl`) fall through to the `unsupported_node` fallback, producing the same output. This also removes the now-unused `type` unwrap rule (swift-syntax has no such wrapper node) and retires the last `ctx.literal` helper use in favour of a `tree!` leaf. PARITY(tree-sitter): the initializer's parameters are still not emitted, because the tree-sitter path dropped them too. Emitting them is a future improvement. This completes the rule migration: every declaration now maps through the swift-syntax front-end. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../extractor/src/languages/swift/swift.rs | 40 +++++++++---------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index 82709c2da20e..8349214e3046 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -69,7 +69,7 @@ impl SwiftContext { /// rule. Returns `Option` so it splices via `{…}` to 0 or 1 ids. fn chained_modifier(ctx: &mut yeast::build::BuildCtx<'_, SwiftContext>) -> Option { if ctx.is_chained { - Some(ctx.literal("modifier", "chained_declaration")) + Some(tree!((modifier "chained_declaration"))) } else { None } @@ -449,8 +449,6 @@ fn translation_rules() -> Vec> { result } ), - // Unwrap `type` wrapper node - rule!((type name: @inner) => type_expr { inner }), // `identifierPattern` wraps a single identifier token. rule!( (identifierPattern identifier: @name) @@ -1093,22 +1091,24 @@ fn translation_rules() -> Vec> { rule!((memberBlockItem decl: _* @d) => member* { d }), // Init declaration → constructor_declaration. Body statements optional; // body itself is also optional (protocol requirement). + // + // PARITY(tree-sitter): the parameters are not emitted, because the + // tree-sitter path dropped them (its `(parameter)*` capture missed the + // field-attached parameters). Emitting them is a future improvement. rule!( - (init_declaration - (parameter)* @params - body: (block statement: _* @body_stmts)? - (modifiers)* @mods) + (initializerDecl + modifiers: _* @mods + body: (codeBlock statements: _* @body_stmts)?) => (constructor_declaration modifier: {mods} - parameter: {params} body: (block stmt: {body_stmts})) ), // Deinit declaration → destructor_declaration. Body statements optional. rule!( - (deinit_declaration - body: (block statement: _* @body_stmts) - (modifiers)* @mods) + (deinitializerDecl + modifiers: _* @mods + body: (codeBlock statements: _* @body_stmts)) => (destructor_declaration modifier: {mods} @@ -1116,30 +1116,28 @@ fn translation_rules() -> Vec> { ), // Typealias declaration rule!( - (typealias_declaration name: @name value: @val (modifiers)* @mods) + (typeAliasDecl + modifiers: _* @mods + name: @@name + initializer: (typeInitializerClause value: @val)) => (type_alias_declaration modifier: {mods} name: (identifier #{name}) r#type: {val}) ), - // Subscript declaration (not yet supported -- grammar needs to distinguish plain calls from subscript calls) - rule!( - (subscript_declaration (parameter)* @params (modifiers)* @mods) - => - (unsupported_node) - ), // Associated type declaration (with optional bound) rule!( - (associatedtype_declaration name: @name inherits_from: _? @bound (modifiers)* @mods) + (associatedTypeDecl + modifiers: _* @mods + name: @@name + inheritanceClause: (inheritanceClause inheritedTypes: (inheritedType type: @bound))?) => (associated_type_declaration modifier: {mods} name: (identifier #{name}) bound: {bound}) ), - // Preprocessor conditionals — unsupported - rule!((diagnostic) => (unsupported_node)), // ---- Fallbacks ---- // Bare `_` (rather than `(_)`) so this matches both named nodes // and unnamed tokens. Any unnamed token that escapes the From 5c5fd5e1cc9e6b0261766103e1a5ee5475314c19 Mon Sep 17 00:00:00 2001 From: Taus Date: Thu, 23 Jul 2026 12:44:23 +0000 Subject: [PATCH 043/188] unified: Switch the Swift front-end to swift-syntax Flip the runtime Swift front-end from tree-sitter to swift-syntax. The mapping rules were already ported, so the mapped AST is unchanged; this makes the switch live. - `language_spec` now builds a language-free desugarer (`ConcreteDesugarer::without_language`) and wires the swift-syntax parser (`swift_parse::parse`) as the front-end, dropping the tree-sitter language and node types. The desugarer supplies the output schema, so `node_types` is left empty. - The `swift_adapter`/`swift_parse` modules are no longer `allow(dead_code)`: they are now reached from the live extraction path. - `corpus_tests` skips (rather than fails) when the external `swift-syntax-parse` binary is unavailable, since it cannot run without the Swift-backed parser. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- unified/extractor/src/languages/mod.rs | 14 ++------------ unified/extractor/src/languages/swift/swift.rs | 9 ++++----- unified/extractor/tests/corpus_tests.rs | 18 +++++++++++++++++- 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/unified/extractor/src/languages/mod.rs b/unified/extractor/src/languages/mod.rs index 032bc884ca34..c79806dc9d43 100644 --- a/unified/extractor/src/languages/mod.rs +++ b/unified/extractor/src/languages/mod.rs @@ -4,23 +4,13 @@ use codeql_extractor::extractor::desugaring; mod swift; /// swift-syntax JSON -> `yeast::Ast` adapter for the Swift front-end. -/// -/// Currently exercised by tests and the forthcoming runtime extraction path; -/// `allow(dead_code)` because this is a binary crate, so its public API isn't -/// counted as used until the binary itself calls it. #[path = "swift/adapter.rs"] -#[allow(dead_code)] pub mod swift_adapter; /// Swift front-end parser: shells out to `swift-syntax-parse` and adapts its -/// JSON output via [`swift_adapter`]. -/// -/// Dormant for now: the runtime Swift front-end is still tree-sitter, so -/// nothing in the binary calls this yet. `allow(dead_code)` for the same -/// binary-crate reason as [`swift_adapter`]; both allows are removed once the -/// runtime switches the Swift front-end to swift-syntax. +/// JSON output via [`swift_adapter`]. This is the live Swift front-end used by +/// [`all_language_specs`]. #[path = "swift/parse.rs"] -#[allow(dead_code)] pub mod swift_parse; /// Shared YEAST output AST schema for all languages. diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index 8349214e3046..32252f8a0228 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -1155,16 +1155,15 @@ fn translation_rules() -> Vec> { } pub fn language_spec(desugared_ast_schema: &'static str) -> desugaring::LanguageSpec { - let ts_language: tree_sitter::Language = tree_sitter_swift::LANGUAGE.into(); let config = DesugaringConfig::::new() .add_phase("translate", PhaseKind::OneShot, translation_rules()) .with_output_node_types_yaml(desugared_ast_schema); - let desugarer = ConcreteDesugarer::new(ts_language.clone(), config) - .expect("failed to build Swift desugarer"); + let desugarer = + ConcreteDesugarer::without_language(config).expect("failed to build Swift desugarer"); desugaring::LanguageSpec { prefix: "swift", - parser: Box::new(codeql_extractor::extractor::tree_sitter_parser(ts_language)), - node_types: tree_sitter_swift::NODE_TYPES, + parser: Box::new(super::swift_parse::parse), + node_types: "", file_globs: vec!["*.swift".into(), "*.swiftinterface".into()], desugarer: Box::new(desugarer), } diff --git a/unified/extractor/tests/corpus_tests.rs b/unified/extractor/tests/corpus_tests.rs index d192b19485e7..66374e56526e 100644 --- a/unified/extractor/tests/corpus_tests.rs +++ b/unified/extractor/tests/corpus_tests.rs @@ -20,6 +20,14 @@ fn update_mode_enabled() -> bool { .unwrap_or(false) } +/// Whether the external swift-syntax parser is available. When it is not (e.g. +/// no Swift toolchain / the `swift-syntax-parse` binary is not on `PATH` and +/// `CODEQL_EXTRACTOR_UNIFIED_SWIFT_SYNTAX_PARSE` is unset), the corpus test is +/// skipped rather than failed — it cannot run without the Swift-backed parser. +fn parser_available() -> bool { + languages::swift_parse::parse(b"").is_ok() +} + /// Parse a corpus `.output` file. The file holds a single test case made of /// three sections separated by `---` delimiter lines: /// @@ -28,7 +36,7 @@ fn update_mode_enabled() -> bool { /// /// --- /// -/// +/// /// /// --- /// @@ -98,6 +106,14 @@ fn collect_corpus_stems(dir: &Path, out: &mut Vec) { #[test] fn test_corpus() { + if !parser_available() { + eprintln!( + "skipping test_corpus: the swift-syntax parser is unavailable \ + (set CODEQL_EXTRACTOR_UNIFIED_SWIFT_SYNTAX_PARSE or put \ + `swift-syntax-parse` on PATH)" + ); + return; + } let update_mode = update_mode_enabled(); let all_languages = languages::all_language_specs(); let corpus_dir = Path::new("tests/corpus"); From 20a253729977dbd43edaffda0422da0ffa5fb642 Mon Sep 17 00:00:00 2001 From: Taus Date: Thu, 23 Jul 2026 12:50:10 +0000 Subject: [PATCH 044/188] unified: Regenerate the raw-AST corpus section for swift-syntax MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that the Swift front-end is swift-syntax, regenerate the second (raw parse tree) section of the corpus `.output` files to hold the swift-syntax AST the adapter builds, instead of the old tree-sitter parse tree. These 98 cases map to a byte-for-byte identical mapped AST (the third section), so only their raw section changes — the mapping rules were ported to produce the same output. The one case whose mapped AST differs (`types/property-with-getter-and-setter`) is handled separately. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../closures/closure-with-capture-list.output | 90 +++++---- .../closure-with-explicit-parameters.output | 96 +++++---- .../closure-with-shorthand-parameters.output | 52 +++-- .../closures/multi-statement-closure.output | 141 +++++++------ .../swift/closures/trailing-closure.output | 52 +++-- .../swift/collections/array-literal.output | 53 +++-- .../collections/dictionary-literal.output | 71 ++++--- .../collections/dictionary-subscript.output | 59 +++--- .../empty-array-literal-with-type.output | 56 +++--- .../swift/collections/set-literal.output | 82 ++++---- .../swift/collections/subscript-access.output | 54 ++--- .../swift/collections/tuple-literal.output | 60 ++++-- .../collections/tuple-member-access.output | 43 ++-- ...g-modifier-does-not-leak-to-sibling.output | 109 ++++++---- .../swift/control-flow/guard-let.output | 50 +++-- ...t-with-shadowing-in-condition-value.output | 85 ++++---- .../control-flow/if-else-if-chain.output | 152 ++++++++------ .../corpus/swift/control-flow/if-else.output | 101 ++++++---- .../if-let-optional-binding.output | 68 ++++--- .../swift/control-flow/if-statement.output | 63 +++--- .../control-flow/switch-statement.output | 167 ++++++++++------ .../switch-with-binding-pattern.output | 176 ++++++++++------- ...with-labeled-case-pattern-arguments.output | 186 +++++++++++------- .../control-flow/ternary-expression.output | 64 +++--- .../additive-expression-is-desugared.output | 21 +- ...er-additive-expression-is-desugared.output | 21 +- ...with-deeply-nested-path-three-parts.output | 27 ++- .../import-with-dotted-path-two-parts.output | 23 ++- .../scoped-import-uses-name-pattern.output | 25 ++- .../simple-import-with-single-name.output | 18 +- ...nction-call-with-labelled-arguments.output | 37 ++-- .../swift/functions/function-call.output | 33 ++-- ...nction-with-default-parameter-value.output | 85 +++++--- .../function-with-named-parameters.output | 74 ++++--- .../function-with-no-parameters.output | 58 ++++-- ...ion-with-parameters-and-return-type.output | 108 +++++----- .../swift/functions/generic-function.output | 87 ++++---- .../leading-dot-expression-call.output | 57 +++--- .../leading-dot-expression-value.output | 38 ++-- .../corpus/swift/functions/method-call.output | 37 ++-- .../swift/functions/variadic-function.output | 114 ++++++----- .../swift/literals/boolean-literals.output | 15 +- .../literals/floating-point-literal.output | 9 +- .../swift/literals/integer-literal.output | 9 +- .../literals/negative-integer-literal.output | 15 +- .../corpus/swift/literals/nil-literal.output | 9 +- .../swift/literals/string-literal.output | 15 +- .../literals/string-with-interpolation.output | 29 ++- .../swift/loops/break-and-continue.output | 132 ++++++++----- .../loops/for-in-over-array-literal.output | 71 ++++--- .../swift/loops/for-in-over-range.output | 62 +++--- .../loops/for-in-with-where-clause.output | 72 ++++--- .../swift/loops/repeat-while-loop.output | 55 ++++-- .../corpus/swift/loops/while-loop.output | 56 ++++-- .../corpus/swift/operators/addition.output | 21 +- .../corpus/swift/operators/comparison.output | 21 +- .../corpus/swift/operators/division.output | 21 +- .../corpus/swift/operators/equality.output | 21 +- .../corpus/swift/operators/logical-and.output | 21 +- .../corpus/swift/operators/logical-not.output | 15 +- .../corpus/swift/operators/logical-or.output | 21 +- .../swift/operators/multiplication.output | 21 +- ...cedence-addition-and-multiplication.output | 33 +++- .../operators/parenthesised-expression.output | 43 ++-- .../swift/operators/range-operator.output | 21 +- .../corpus/swift/operators/subtraction.output | 21 +- .../optionals-and-errors/do-catch.output | 77 +++++--- .../optionals-and-errors/force-unwrap.output | 38 ++-- .../nil-coalescing.output | 43 ++-- .../optional-chaining.output | 64 +++--- .../optional-type-annotation.output | 52 ++--- .../throwing-function.output | 63 ++++-- .../try-expression-2.output | 52 ++--- .../try-expression.output | 52 ++--- ...er-does-not-leak-into-accessor-body.output | 126 +++++++----- .../swift/types/class-inheritance.output | 37 ++-- .../swift/types/class-with-initializer.output | 130 +++++++----- .../swift/types/class-with-method.output | 92 ++++++--- .../types/class-with-stored-properties.output | 93 ++++----- .../swift/types/computed-property.output | 158 ++++++++------- .../corpus/swift/types/empty-class.output | 22 ++- .../types/enum-with-associated-values.output | 97 +++++---- .../corpus/swift/types/enum-with-cases.output | 75 ++++--- ...separated-cases-chained-declaration.output | 51 +++-- .../tests/corpus/swift/types/extension.output | 90 +++++---- .../swift/types/protocol-declaration.output | 38 +++- ...nd-read-write-property-requirements.output | 116 ++++++----- .../tests/corpus/swift/types/struct.output | 93 ++++----- .../corpus/swift/variables/assignment.output | 23 ++- ...fier-does-not-leak-into-initializer.output | 78 +++++--- .../variables/compound-assignment.output | 23 ++- .../corpus/swift/variables/let-binding.output | 32 +-- .../variables/let-with-type-annotation.output | 47 +++-- .../multiple-bindings-on-one-line.output | 48 +++-- ...y-with-willset-and-didset-observers.output | 144 ++++++++------ .../tuple-destructuring-binding.output | 49 +++-- .../corpus/swift/variables/var-binding.output | 32 +-- .../variables/var-without-initialiser.output | 40 ++-- 98 files changed, 3740 insertions(+), 2257 deletions(-) diff --git a/unified/extractor/tests/corpus/swift/closures/closure-with-capture-list.output b/unified/extractor/tests/corpus/swift/closures/closure-with-capture-list.output index b4760e35591c..6833344de16d 100644 --- a/unified/extractor/tests/corpus/swift/closures/closure-with-capture-list.output +++ b/unified/extractor/tests/corpus/swift/closures/closure-with-capture-list.output @@ -2,41 +2,61 @@ let f = { [weak self] in self?.doThing() } --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "f" - value: - lambda_literal - captures: - capture_list - item: - capture_list_item - name: simple_identifier "self" - ownership: - ownership_modifier - statement: - call_expression - function: - navigation_expression - suffix: - navigation_suffix - suffix: simple_identifier "doThing" - target: - optional_chain_marker - expr: - self_expression - suffix: - call_suffix - arguments: - value_arguments +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + closureExpr + leftBrace: { + rightBrace: } + signature: + closureSignature + attributes: + capture: + closureCaptureClause + leftSquare: [ + rightSquare: ] + items: + closureCapture + name: self + specifier: + closureCaptureSpecifier + specifier: weak + inKeyword: in + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + additionalTrailingClosures: + calledExpression: + memberAccessExpr + period: . + declName: + declReferenceExpr + baseName: identifier "doThing" + base: + optionalChainingExpr + expression: + declReferenceExpr + baseName: self + questionMark: ? + pattern: + identifierPattern + identifier: identifier "f" --- diff --git a/unified/extractor/tests/corpus/swift/closures/closure-with-explicit-parameters.output b/unified/extractor/tests/corpus/swift/closures/closure-with-explicit-parameters.output index bb6b878b8bb9..c20da77c72cb 100644 --- a/unified/extractor/tests/corpus/swift/closures/closure-with-explicit-parameters.output +++ b/unified/extractor/tests/corpus/swift/closures/closure-with-explicit-parameters.output @@ -2,45 +2,63 @@ let f = { (x: Int) -> Int in x * 2 } --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "f" - value: - lambda_literal - statement: - multiplicative_expression - lhs: simple_identifier "x" - op: * - rhs: integer_literal "2" - type: - lambda_function_type - params: - lambda_function_type_parameters - parameter: - lambda_parameter - name: simple_identifier "x" - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" - return_type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + closureExpr + leftBrace: { + rightBrace: } + signature: + closureSignature + attributes: + inKeyword: in + parameterClause: + closureParameterClause + leftParen: ( + rightParen: ) + parameters: + closureParameter + colon: : + attributes: + modifiers: + type: + identifierType + name: identifier "Int" + firstName: identifier "x" + returnClause: + returnClause + arrow: -> + type: + identifierType + name: identifier "Int" + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "*" + leftOperand: + declReferenceExpr + baseName: identifier "x" + rightOperand: + integerLiteralExpr + literal: integerLiteral "2" + pattern: + identifierPattern + identifier: identifier "f" --- diff --git a/unified/extractor/tests/corpus/swift/closures/closure-with-shorthand-parameters.output b/unified/extractor/tests/corpus/swift/closures/closure-with-shorthand-parameters.output index 67cdf3df63f2..1b07604e02c5 100644 --- a/unified/extractor/tests/corpus/swift/closures/closure-with-shorthand-parameters.output +++ b/unified/extractor/tests/corpus/swift/closures/closure-with-shorthand-parameters.output @@ -2,24 +2,40 @@ let f = { $0 + $1 } --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "f" - value: - lambda_literal - statement: - additive_expression - lhs: simple_identifier "$0" - op: + - rhs: simple_identifier "$1" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + closureExpr + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "+" + leftOperand: + declReferenceExpr + baseName: dollarIdentifier "$0" + rightOperand: + declReferenceExpr + baseName: dollarIdentifier "$1" + pattern: + identifierPattern + identifier: identifier "f" --- diff --git a/unified/extractor/tests/corpus/swift/closures/multi-statement-closure.output b/unified/extractor/tests/corpus/swift/closures/multi-statement-closure.output index 0d07ea6f7bbb..4fbc1c8f71f0 100644 --- a/unified/extractor/tests/corpus/swift/closures/multi-statement-closure.output +++ b/unified/extractor/tests/corpus/swift/closures/multi-statement-closure.output @@ -5,62 +5,91 @@ let f = { (x: Int) -> Int in --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "f" - value: - lambda_literal - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "y" - value: - additive_expression - lhs: simple_identifier "x" - op: + - rhs: integer_literal "1" - control_transfer_statement - kind: return - result: - multiplicative_expression - lhs: simple_identifier "y" - op: * - rhs: integer_literal "2" - type: - lambda_function_type - params: - lambda_function_type_parameters - parameter: - lambda_parameter - name: simple_identifier "x" - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" - return_type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + closureExpr + leftBrace: { + rightBrace: } + signature: + closureSignature + attributes: + inKeyword: in + parameterClause: + closureParameterClause + leftParen: ( + rightParen: ) + parameters: + closureParameter + colon: : + attributes: + modifiers: + type: + identifierType + name: identifier "Int" + firstName: identifier "x" + returnClause: + returnClause + arrow: -> + type: + identifierType + name: identifier "Int" + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "+" + leftOperand: + declReferenceExpr + baseName: identifier "x" + rightOperand: + integerLiteralExpr + literal: integerLiteral "1" + pattern: + identifierPattern + identifier: identifier "y" + codeBlockItem + item: + returnStmt + expression: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "*" + leftOperand: + declReferenceExpr + baseName: identifier "y" + rightOperand: + integerLiteralExpr + literal: integerLiteral "2" + returnKeyword: return + pattern: + identifierPattern + identifier: identifier "f" --- diff --git a/unified/extractor/tests/corpus/swift/closures/trailing-closure.output b/unified/extractor/tests/corpus/swift/closures/trailing-closure.output index ef8d6bd21c6a..3e26ff27eb58 100644 --- a/unified/extractor/tests/corpus/swift/closures/trailing-closure.output +++ b/unified/extractor/tests/corpus/swift/closures/trailing-closure.output @@ -2,24 +2,40 @@ xs.map { $0 * 2 } --- -source_file - statement: - call_expression - function: - navigation_expression - suffix: - navigation_suffix - suffix: simple_identifier "map" - target: simple_identifier "xs" - suffix: - call_suffix - lambda: - lambda_literal - statement: - multiplicative_expression - lhs: simple_identifier "$0" - op: * - rhs: integer_literal "2" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + functionCallExpr + arguments: + additionalTrailingClosures: + calledExpression: + memberAccessExpr + period: . + declName: + declReferenceExpr + baseName: identifier "map" + base: + declReferenceExpr + baseName: identifier "xs" + trailingClosure: + closureExpr + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "*" + leftOperand: + declReferenceExpr + baseName: dollarIdentifier "$0" + rightOperand: + integerLiteralExpr + literal: integerLiteral "2" --- diff --git a/unified/extractor/tests/corpus/swift/collections/array-literal.output b/unified/extractor/tests/corpus/swift/collections/array-literal.output index f6ee44c1f809..c6ea2c2094fa 100644 --- a/unified/extractor/tests/corpus/swift/collections/array-literal.output +++ b/unified/extractor/tests/corpus/swift/collections/array-literal.output @@ -2,23 +2,42 @@ let xs = [1, 2, 3] --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "xs" - value: - array_literal - element: - integer_literal "1" - integer_literal "2" - integer_literal "3" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + arrayExpr + elements: + arrayElement + expression: + integerLiteralExpr + literal: integerLiteral "1" + trailingComma: , + arrayElement + expression: + integerLiteralExpr + literal: integerLiteral "2" + trailingComma: , + arrayElement + expression: + integerLiteralExpr + literal: integerLiteral "3" + leftSquare: [ + rightSquare: ] + pattern: + identifierPattern + identifier: identifier "xs" --- diff --git a/unified/extractor/tests/corpus/swift/collections/dictionary-literal.output b/unified/extractor/tests/corpus/swift/collections/dictionary-literal.output index a19028d3f3bb..edd306a69cbd 100644 --- a/unified/extractor/tests/corpus/swift/collections/dictionary-literal.output +++ b/unified/extractor/tests/corpus/swift/collections/dictionary-literal.output @@ -2,30 +2,53 @@ let d = ["a": 1, "b": 2] --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "d" - value: - dictionary_literal - element: - dictionary_literal_item - key: - line_string_literal - text: line_str_text "a" - value: integer_literal "1" - dictionary_literal_item - key: - line_string_literal - text: line_str_text "b" - value: integer_literal "2" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + dictionaryExpr + leftSquare: [ + rightSquare: ] + content: + dictionaryElement + colon: : + trailingComma: , + value: + integerLiteralExpr + literal: integerLiteral "1" + key: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment "a" + dictionaryElement + colon: : + value: + integerLiteralExpr + literal: integerLiteral "2" + key: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment "b" + pattern: + identifierPattern + identifier: identifier "d" --- diff --git a/unified/extractor/tests/corpus/swift/collections/dictionary-subscript.output b/unified/extractor/tests/corpus/swift/collections/dictionary-subscript.output index c30ab9326bb6..e2f939e0683c 100644 --- a/unified/extractor/tests/corpus/swift/collections/dictionary-subscript.output +++ b/unified/extractor/tests/corpus/swift/collections/dictionary-subscript.output @@ -4,31 +4,40 @@ let v = d["key"] --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "v" - value: - call_expression - function: simple_identifier "d" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: - line_string_literal - text: line_str_text "key" - comment "// TODO: same parser issue as the array subscript case above —" - comment "// `d[\"key\"]` is parsed as `call_expression(d, (\"key\"))`." +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + subscriptCallExpr + leftSquare: [ + rightSquare: ] + arguments: + labeledExpr + expression: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment "key" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "d" + pattern: + identifierPattern + identifier: identifier "v" --- diff --git a/unified/extractor/tests/corpus/swift/collections/empty-array-literal-with-type.output b/unified/extractor/tests/corpus/swift/collections/empty-array-literal-with-type.output index 90d1a9dde368..e9a70a43bb42 100644 --- a/unified/extractor/tests/corpus/swift/collections/empty-array-literal-with-type.output +++ b/unified/extractor/tests/corpus/swift/collections/empty-array-literal-with-type.output @@ -2,32 +2,38 @@ let xs: [Int] = [] --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "xs" - type: - type_annotation - type: - type - name: - array_type +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + arrayExpr + elements: + leftSquare: [ + rightSquare: ] + pattern: + identifierPattern + identifier: identifier "xs" + typeAnnotation: + typeAnnotation + colon: : + type: + arrayType + leftSquare: [ + rightSquare: ] element: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" - value: - array_literal + identifierType + name: identifier "Int" --- diff --git a/unified/extractor/tests/corpus/swift/collections/set-literal.output b/unified/extractor/tests/corpus/swift/collections/set-literal.output index a1a1dde75f9a..c29492c9bc0b 100644 --- a/unified/extractor/tests/corpus/swift/collections/set-literal.output +++ b/unified/extractor/tests/corpus/swift/collections/set-literal.output @@ -2,41 +2,57 @@ let s: Set = [1, 2, 3] --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "s" - type: - type_annotation - type: - type - name: - user_type - part: - simple_user_type +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + arrayExpr + elements: + arrayElement + expression: + integerLiteralExpr + literal: integerLiteral "1" + trailingComma: , + arrayElement + expression: + integerLiteralExpr + literal: integerLiteral "2" + trailingComma: , + arrayElement + expression: + integerLiteralExpr + literal: integerLiteral "3" + leftSquare: [ + rightSquare: ] + pattern: + identifierPattern + identifier: identifier "s" + typeAnnotation: + typeAnnotation + colon: : + type: + identifierType + name: identifier "Set" + genericArgumentClause: + genericArgumentClause arguments: - type_arguments + genericArgument argument: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" - name: type_identifier "Set" - value: - array_literal - element: - integer_literal "1" - integer_literal "2" - integer_literal "3" + identifierType + name: identifier "Int" + leftAngle: < + rightAngle: > --- diff --git a/unified/extractor/tests/corpus/swift/collections/subscript-access.output b/unified/extractor/tests/corpus/swift/collections/subscript-access.output index 681afca891a7..f7e518b84773 100644 --- a/unified/extractor/tests/corpus/swift/collections/subscript-access.output +++ b/unified/extractor/tests/corpus/swift/collections/subscript-access.output @@ -5,30 +5,36 @@ let first = xs[0] --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "first" - value: - call_expression - function: simple_identifier "xs" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: integer_literal "0" - comment "// TODO: tree-sitter-swift parses `xs[0]` as a call_expression (same shape" - comment "// as `xs(0)`), so the mapping currently produces a call_expr. Update the" - comment "// parser / add a separate subscript_expr node and remap when fixed." +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + subscriptCallExpr + leftSquare: [ + rightSquare: ] + arguments: + labeledExpr + expression: + integerLiteralExpr + literal: integerLiteral "0" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "xs" + pattern: + identifierPattern + identifier: identifier "first" --- diff --git a/unified/extractor/tests/corpus/swift/collections/tuple-literal.output b/unified/extractor/tests/corpus/swift/collections/tuple-literal.output index a0ac8861674b..facbc2fcbb45 100644 --- a/unified/extractor/tests/corpus/swift/collections/tuple-literal.output +++ b/unified/extractor/tests/corpus/swift/collections/tuple-literal.output @@ -2,28 +2,46 @@ let t = (1, "two", 3.0) --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "t" - value: - tuple_expression - element: - tuple_expression_item - value: integer_literal "1" - tuple_expression_item +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = value: - line_string_literal - text: line_str_text "two" - tuple_expression_item - value: real_literal "3.0" + tupleExpr + leftParen: ( + rightParen: ) + elements: + labeledExpr + expression: + integerLiteralExpr + literal: integerLiteral "1" + trailingComma: , + labeledExpr + expression: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment "two" + trailingComma: , + labeledExpr + expression: + floatLiteralExpr + literal: floatLiteral "3.0" + pattern: + identifierPattern + identifier: identifier "t" --- diff --git a/unified/extractor/tests/corpus/swift/collections/tuple-member-access.output b/unified/extractor/tests/corpus/swift/collections/tuple-member-access.output index 29b234f30e26..6ecbd22eebe0 100644 --- a/unified/extractor/tests/corpus/swift/collections/tuple-member-access.output +++ b/unified/extractor/tests/corpus/swift/collections/tuple-member-access.output @@ -2,23 +2,32 @@ let n = t.0 --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "n" - value: - navigation_expression - suffix: - navigation_suffix - suffix: integer_literal "0" - target: simple_identifier "t" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + memberAccessExpr + period: . + declName: + declReferenceExpr + baseName: integerLiteral "0" + base: + declReferenceExpr + baseName: identifier "t" + pattern: + identifierPattern + identifier: identifier "n" --- diff --git a/unified/extractor/tests/corpus/swift/control-flow/binding-modifier-does-not-leak-to-sibling.output b/unified/extractor/tests/corpus/swift/control-flow/binding-modifier-does-not-leak-to-sibling.output index 9c4088845f14..800647eb7474 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/binding-modifier-does-not-leak-to-sibling.output +++ b/unified/extractor/tests/corpus/swift/control-flow/binding-modifier-does-not-leak-to-sibling.output @@ -8,44 +8,79 @@ default: --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "x" - value: integer_literal "1" - switch_statement - entry: - switch_entry - pattern: - switch_pattern +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + integerLiteralExpr + literal: integerLiteral "1" pattern: - pattern - kind: simple_identifier "someConstant" - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: - line_string_literal - text: line_str_text "matched" - switch_entry - default: default_keyword "default" - statement: - control_transfer_statement - kind: break - expr: simple_identifier "y" + identifierPattern + identifier: identifier "x" + codeBlockItem + item: + expressionStmt + expression: + switchExpr + leftBrace: { + rightBrace: } + cases: + switchCase + label: + switchCaseLabel + colon: : + caseKeyword: case + caseItems: + switchCaseItem + pattern: + expressionPattern + expression: + declReferenceExpr + baseName: identifier "someConstant" + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment "matched" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + switchCase + label: + switchDefaultLabel + colon: : + defaultKeyword: default + statements: + codeBlockItem + item: + breakStmt + breakKeyword: break + subject: + declReferenceExpr + baseName: identifier "y" + switchKeyword: switch --- diff --git a/unified/extractor/tests/corpus/swift/control-flow/guard-let.output b/unified/extractor/tests/corpus/swift/control-flow/guard-let.output index 2e90e9820640..d739eca564b5 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/guard-let.output +++ b/unified/extractor/tests/corpus/swift/control-flow/guard-let.output @@ -2,25 +2,37 @@ guard let value = optional else { return } --- -source_file - statement: - guard_statement - body: - block - statement: - control_transfer_statement - kind: return - condition: - if_condition - kind: - if_let_binding - pattern: - pattern - binding: - value_binding_pattern - mutability: let - bound_identifier: simple_identifier "value" - value: simple_identifier "optional" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + guardStmt + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + returnStmt + returnKeyword: return + conditions: + conditionElement + condition: + optionalBindingCondition + initializer: + initializerClause + equal: = + value: + declReferenceExpr + baseName: identifier "optional" + pattern: + identifierPattern + identifier: identifier "value" + bindingSpecifier: let + elseKeyword: else + guardKeyword: guard --- diff --git a/unified/extractor/tests/corpus/swift/control-flow/if-case-let-with-shadowing-in-condition-value.output b/unified/extractor/tests/corpus/swift/control-flow/if-case-let-with-shadowing-in-condition-value.output index 61ca65811e97..2a0676513f23 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/if-case-let-with-shadowing-in-condition-value.output +++ b/unified/extractor/tests/corpus/swift/control-flow/if-case-let-with-shadowing-in-condition-value.output @@ -4,40 +4,59 @@ if case let x = x + 10 { --- -source_file - statement: - if_statement - body: - block - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: simple_identifier "x" - condition: - if_condition - kind: - if_let_binding - pattern: - pattern - kind: - binding_pattern - binding: - value_binding_pattern - mutability: let +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + expressionStmt + expression: + ifExpr + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + declReferenceExpr + baseName: identifier "x" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + conditions: + conditionElement + condition: + matchingPatternCondition + initializer: + initializerClause + equal: = + value: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "+" + leftOperand: + declReferenceExpr + baseName: identifier "x" + rightOperand: + integerLiteralExpr + literal: integerLiteral "10" pattern: - pattern - bound_identifier: simple_identifier "x" - value: - additive_expression - lhs: simple_identifier "x" - op: + - rhs: integer_literal "10" + valueBindingPattern + pattern: + identifierPattern + identifier: identifier "x" + bindingSpecifier: let + caseKeyword: case + ifKeyword: if --- diff --git a/unified/extractor/tests/corpus/swift/control-flow/if-else-if-chain.output b/unified/extractor/tests/corpus/swift/control-flow/if-else-if-chain.output index 268a2d1f97c9..35f1c2c46d2c 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/if-else-if-chain.output +++ b/unified/extractor/tests/corpus/swift/control-flow/if-else-if-chain.output @@ -8,61 +8,103 @@ if x > 0 { --- -source_file - statement: - if_statement - body: - block - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: integer_literal "1" - condition: - if_condition - kind: - comparison_expression - lhs: simple_identifier "x" - op: > - rhs: integer_literal "0" - else_branch: - if_statement - body: - block - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: integer_literal "2" - condition: - if_condition - kind: - comparison_expression - lhs: simple_identifier "x" - op: < - rhs: integer_literal "0" - else_branch: - block - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: integer_literal "3" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + expressionStmt + expression: + ifExpr + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + integerLiteralExpr + literal: integerLiteral "1" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + conditions: + conditionElement + condition: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator ">" + leftOperand: + declReferenceExpr + baseName: identifier "x" + rightOperand: + integerLiteralExpr + literal: integerLiteral "0" + elseKeyword: else + elseBody: + ifExpr + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + integerLiteralExpr + literal: integerLiteral "2" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + conditions: + conditionElement + condition: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "<" + leftOperand: + declReferenceExpr + baseName: identifier "x" + rightOperand: + integerLiteralExpr + literal: integerLiteral "0" + elseKeyword: else + elseBody: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + integerLiteralExpr + literal: integerLiteral "3" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + ifKeyword: if + ifKeyword: if --- diff --git a/unified/extractor/tests/corpus/swift/control-flow/if-else.output b/unified/extractor/tests/corpus/swift/control-flow/if-else.output index e891cb4e2f6c..744b5c51ab24 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/if-else.output +++ b/unified/extractor/tests/corpus/swift/control-flow/if-else.output @@ -6,43 +6,70 @@ if x > 0 { --- -source_file - statement: - if_statement - body: - block - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: simple_identifier "x" - condition: - if_condition - kind: - comparison_expression - lhs: simple_identifier "x" - op: > - rhs: integer_literal "0" - else_branch: - block - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: - prefix_expression - operation: - - target: simple_identifier "x" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + expressionStmt + expression: + ifExpr + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + declReferenceExpr + baseName: identifier "x" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + conditions: + conditionElement + condition: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator ">" + leftOperand: + declReferenceExpr + baseName: identifier "x" + rightOperand: + integerLiteralExpr + literal: integerLiteral "0" + elseKeyword: else + elseBody: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + prefixOperatorExpr + expression: + declReferenceExpr + baseName: identifier "x" + operator: prefixOperator "-" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + ifKeyword: if --- diff --git a/unified/extractor/tests/corpus/swift/control-flow/if-let-optional-binding.output b/unified/extractor/tests/corpus/swift/control-flow/if-let-optional-binding.output index 0436a559236b..d1bcf82b0faa 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/if-let-optional-binding.output +++ b/unified/extractor/tests/corpus/swift/control-flow/if-let-optional-binding.output @@ -4,32 +4,48 @@ if let value = optional { --- -source_file - statement: - if_statement - body: - block - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: simple_identifier "value" - condition: - if_condition - kind: - if_let_binding - pattern: - pattern - binding: - value_binding_pattern - mutability: let - bound_identifier: simple_identifier "value" - value: simple_identifier "optional" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + expressionStmt + expression: + ifExpr + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + declReferenceExpr + baseName: identifier "value" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + conditions: + conditionElement + condition: + optionalBindingCondition + initializer: + initializerClause + equal: = + value: + declReferenceExpr + baseName: identifier "optional" + pattern: + identifierPattern + identifier: identifier "value" + bindingSpecifier: let + ifKeyword: if --- diff --git a/unified/extractor/tests/corpus/swift/control-flow/if-statement.output b/unified/extractor/tests/corpus/swift/control-flow/if-statement.output index 6e89490b0128..77bba019ffb9 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/if-statement.output +++ b/unified/extractor/tests/corpus/swift/control-flow/if-statement.output @@ -4,28 +4,47 @@ if x > 0 { --- -source_file - statement: - if_statement - body: - block - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: simple_identifier "x" - condition: - if_condition - kind: - comparison_expression - lhs: simple_identifier "x" - op: > - rhs: integer_literal "0" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + expressionStmt + expression: + ifExpr + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + declReferenceExpr + baseName: identifier "x" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + conditions: + conditionElement + condition: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator ">" + leftOperand: + declReferenceExpr + baseName: identifier "x" + rightOperand: + integerLiteralExpr + literal: integerLiteral "0" + ifKeyword: if --- diff --git a/unified/extractor/tests/corpus/swift/control-flow/switch-statement.output b/unified/extractor/tests/corpus/swift/control-flow/switch-statement.output index e016a650787f..a88579852947 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/switch-statement.output +++ b/unified/extractor/tests/corpus/swift/control-flow/switch-statement.output @@ -9,65 +9,114 @@ default: --- -source_file - statement: - switch_statement - entry: - switch_entry - pattern: - switch_pattern - pattern: - pattern - kind: integer_literal "1" - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: - line_string_literal - text: line_str_text "one" - switch_entry - pattern: - switch_pattern - pattern: - pattern - kind: integer_literal "2" - switch_pattern - pattern: - pattern - kind: integer_literal "3" - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: - line_string_literal - text: line_str_text "two or three" - switch_entry - default: default_keyword "default" - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: - line_string_literal - text: line_str_text "other" - expr: simple_identifier "x" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + expressionStmt + expression: + switchExpr + leftBrace: { + rightBrace: } + cases: + switchCase + label: + switchCaseLabel + colon: : + caseKeyword: case + caseItems: + switchCaseItem + pattern: + expressionPattern + expression: + integerLiteralExpr + literal: integerLiteral "1" + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment "one" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + switchCase + label: + switchCaseLabel + colon: : + caseKeyword: case + caseItems: + switchCaseItem + trailingComma: , + pattern: + expressionPattern + expression: + integerLiteralExpr + literal: integerLiteral "2" + switchCaseItem + pattern: + expressionPattern + expression: + integerLiteralExpr + literal: integerLiteral "3" + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment "two or three" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + switchCase + label: + switchDefaultLabel + colon: : + defaultKeyword: default + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment "other" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + subject: + declReferenceExpr + baseName: identifier "x" + switchKeyword: switch --- diff --git a/unified/extractor/tests/corpus/swift/control-flow/switch-with-binding-pattern.output b/unified/extractor/tests/corpus/swift/control-flow/switch-with-binding-pattern.output index b995854d5999..90bb6b44e6e5 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/switch-with-binding-pattern.output +++ b/unified/extractor/tests/corpus/swift/control-flow/switch-with-binding-pattern.output @@ -7,77 +7,111 @@ case .square(let s): --- -source_file - statement: - switch_statement - entry: - switch_entry - pattern: - switch_pattern - pattern: - pattern - kind: - case_pattern - arguments: - tuple_pattern - item: - tuple_pattern_item - pattern: - pattern - kind: - binding_pattern - binding: - value_binding_pattern - mutability: let - pattern: - pattern - bound_identifier: simple_identifier "r" - dot: . - name: simple_identifier "circle" - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: simple_identifier "r" - switch_entry - pattern: - switch_pattern - pattern: - pattern - kind: - case_pattern - arguments: - tuple_pattern - item: - tuple_pattern_item - pattern: - pattern - kind: - binding_pattern - binding: - value_binding_pattern - mutability: let - pattern: - pattern - bound_identifier: simple_identifier "s" - dot: . - name: simple_identifier "square" - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: simple_identifier "s" - expr: simple_identifier "shape" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + expressionStmt + expression: + switchExpr + leftBrace: { + rightBrace: } + cases: + switchCase + label: + switchCaseLabel + colon: : + caseKeyword: case + caseItems: + switchCaseItem + pattern: + expressionPattern + expression: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + patternExpr + pattern: + valueBindingPattern + pattern: + identifierPattern + identifier: identifier "r" + bindingSpecifier: let + additionalTrailingClosures: + calledExpression: + memberAccessExpr + period: . + declName: + declReferenceExpr + baseName: identifier "circle" + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + declReferenceExpr + baseName: identifier "r" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + switchCase + label: + switchCaseLabel + colon: : + caseKeyword: case + caseItems: + switchCaseItem + pattern: + expressionPattern + expression: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + patternExpr + pattern: + valueBindingPattern + pattern: + identifierPattern + identifier: identifier "s" + bindingSpecifier: let + additionalTrailingClosures: + calledExpression: + memberAccessExpr + period: . + declName: + declReferenceExpr + baseName: identifier "square" + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + declReferenceExpr + baseName: identifier "s" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + subject: + declReferenceExpr + baseName: identifier "shape" + switchKeyword: switch --- diff --git a/unified/extractor/tests/corpus/swift/control-flow/switch-with-labeled-case-pattern-arguments.output b/unified/extractor/tests/corpus/swift/control-flow/switch-with-labeled-case-pattern-arguments.output index f8f6f2a0fe89..20b17d160e44 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/switch-with-labeled-case-pattern-arguments.output +++ b/unified/extractor/tests/corpus/swift/control-flow/switch-with-labeled-case-pattern-arguments.output @@ -7,79 +7,119 @@ case .thread(threadRowId: _, let rowId): --- -source_file - statement: - switch_statement - entry: - switch_entry - pattern: - switch_pattern - pattern: - pattern - kind: - case_pattern - arguments: - tuple_pattern - item: - tuple_pattern_item - name: simple_identifier "isAcknowledged" - pattern: - pattern - kind: - boolean_literal - dot: . - name: simple_identifier "implicit" - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: - line_string_literal - text: line_str_text "yes" - switch_entry - pattern: - switch_pattern - pattern: - pattern - kind: - case_pattern - arguments: - tuple_pattern - item: - tuple_pattern_item - name: simple_identifier "threadRowId" - pattern: - pattern - kind: wildcard_pattern "_" - tuple_pattern_item - pattern: - pattern - kind: - binding_pattern - binding: - value_binding_pattern - mutability: let - pattern: - pattern - bound_identifier: simple_identifier "rowId" - dot: . - name: simple_identifier "thread" - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: simple_identifier "rowId" - expr: simple_identifier "x" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + expressionStmt + expression: + switchExpr + leftBrace: { + rightBrace: } + cases: + switchCase + label: + switchCaseLabel + colon: : + caseKeyword: case + caseItems: + switchCaseItem + pattern: + expressionPattern + expression: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + colon: : + label: identifier "isAcknowledged" + expression: + booleanLiteralExpr + literal: false + additionalTrailingClosures: + calledExpression: + memberAccessExpr + period: . + declName: + declReferenceExpr + baseName: identifier "implicit" + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment "yes" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + switchCase + label: + switchCaseLabel + colon: : + caseKeyword: case + caseItems: + switchCaseItem + pattern: + expressionPattern + expression: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + colon: : + label: identifier "threadRowId" + expression: + discardAssignmentExpr + wildcard: _ + trailingComma: , + labeledExpr + expression: + patternExpr + pattern: + valueBindingPattern + pattern: + identifierPattern + identifier: identifier "rowId" + bindingSpecifier: let + additionalTrailingClosures: + calledExpression: + memberAccessExpr + period: . + declName: + declReferenceExpr + baseName: identifier "thread" + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + declReferenceExpr + baseName: identifier "rowId" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + subject: + declReferenceExpr + baseName: identifier "x" + switchKeyword: switch --- diff --git a/unified/extractor/tests/corpus/swift/control-flow/ternary-expression.output b/unified/extractor/tests/corpus/swift/control-flow/ternary-expression.output index 482bd2382a9e..88c7bc1b886c 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/ternary-expression.output +++ b/unified/extractor/tests/corpus/swift/control-flow/ternary-expression.output @@ -2,29 +2,47 @@ let y = x > 0 ? 1 : -1 --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "y" - value: - ternary_expression - condition: - comparison_expression - lhs: simple_identifier "x" - op: > - rhs: integer_literal "0" - if_false: - prefix_expression - operation: - - target: integer_literal "1" - if_true: integer_literal "1" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + ternaryExpr + colon: : + condition: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator ">" + leftOperand: + declReferenceExpr + baseName: identifier "x" + rightOperand: + integerLiteralExpr + literal: integerLiteral "0" + questionMark: ? + elseExpression: + prefixOperatorExpr + expression: + integerLiteralExpr + literal: integerLiteral "1" + operator: prefixOperator "-" + thenExpression: + integerLiteralExpr + literal: integerLiteral "1" + pattern: + identifierPattern + identifier: identifier "y" --- diff --git a/unified/extractor/tests/corpus/swift/desugar/additive-expression-is-desugared.output b/unified/extractor/tests/corpus/swift/desugar/additive-expression-is-desugared.output index 849fe74107b6..30d9570f3bee 100644 --- a/unified/extractor/tests/corpus/swift/desugar/additive-expression-is-desugared.output +++ b/unified/extractor/tests/corpus/swift/desugar/additive-expression-is-desugared.output @@ -2,12 +2,21 @@ --- -source_file - statement: - additive_expression - lhs: integer_literal "1" - op: + - rhs: integer_literal "2" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "+" + leftOperand: + integerLiteralExpr + literal: integerLiteral "1" + rightOperand: + integerLiteralExpr + literal: integerLiteral "2" --- diff --git a/unified/extractor/tests/corpus/swift/desugar/another-additive-expression-is-desugared.output b/unified/extractor/tests/corpus/swift/desugar/another-additive-expression-is-desugared.output index 88de56051393..982309ffa5af 100644 --- a/unified/extractor/tests/corpus/swift/desugar/another-additive-expression-is-desugared.output +++ b/unified/extractor/tests/corpus/swift/desugar/another-additive-expression-is-desugared.output @@ -2,12 +2,21 @@ foo + bar --- -source_file - statement: - additive_expression - lhs: simple_identifier "foo" - op: + - rhs: simple_identifier "bar" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "+" + leftOperand: + declReferenceExpr + baseName: identifier "foo" + rightOperand: + declReferenceExpr + baseName: identifier "bar" --- diff --git a/unified/extractor/tests/corpus/swift/desugar/import-with-deeply-nested-path-three-parts.output b/unified/extractor/tests/corpus/swift/desugar/import-with-deeply-nested-path-three-parts.output index 3d31437a66ef..cacdc64a46de 100644 --- a/unified/extractor/tests/corpus/swift/desugar/import-with-deeply-nested-path-three-parts.output +++ b/unified/extractor/tests/corpus/swift/desugar/import-with-deeply-nested-path-three-parts.output @@ -2,15 +2,24 @@ import Foundation.Networking.URLSession --- -source_file - statement: - import_declaration - name: - identifier - part: - simple_identifier "Foundation" - simple_identifier "Networking" - simple_identifier "URLSession" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + importDecl + attributes: + modifiers: + importKeyword: import + path: + importPathComponent + name: identifier "Foundation" + trailingPeriod: . + importPathComponent + name: identifier "Networking" + trailingPeriod: . + importPathComponent + name: identifier "URLSession" --- diff --git a/unified/extractor/tests/corpus/swift/desugar/import-with-dotted-path-two-parts.output b/unified/extractor/tests/corpus/swift/desugar/import-with-dotted-path-two-parts.output index f1c1dbcfb979..4fc053a7bc53 100644 --- a/unified/extractor/tests/corpus/swift/desugar/import-with-dotted-path-two-parts.output +++ b/unified/extractor/tests/corpus/swift/desugar/import-with-dotted-path-two-parts.output @@ -2,14 +2,21 @@ import Foundation.Networking --- -source_file - statement: - import_declaration - name: - identifier - part: - simple_identifier "Foundation" - simple_identifier "Networking" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + importDecl + attributes: + modifiers: + importKeyword: import + path: + importPathComponent + name: identifier "Foundation" + trailingPeriod: . + importPathComponent + name: identifier "Networking" --- diff --git a/unified/extractor/tests/corpus/swift/desugar/scoped-import-uses-name-pattern.output b/unified/extractor/tests/corpus/swift/desugar/scoped-import-uses-name-pattern.output index 79d1fa8bcb6d..93319c522981 100644 --- a/unified/extractor/tests/corpus/swift/desugar/scoped-import-uses-name-pattern.output +++ b/unified/extractor/tests/corpus/swift/desugar/scoped-import-uses-name-pattern.output @@ -2,15 +2,22 @@ import struct Foundation.Date --- -source_file - statement: - import_declaration - name: - identifier - part: - simple_identifier "Foundation" - simple_identifier "Date" - scoped_import_kind: struct +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + importDecl + attributes: + modifiers: + importKeyword: import + importKindSpecifier: struct + path: + importPathComponent + name: identifier "Foundation" + trailingPeriod: . + importPathComponent + name: identifier "Date" --- diff --git a/unified/extractor/tests/corpus/swift/desugar/simple-import-with-single-name.output b/unified/extractor/tests/corpus/swift/desugar/simple-import-with-single-name.output index 8db7e15e3dc2..583f33563d13 100644 --- a/unified/extractor/tests/corpus/swift/desugar/simple-import-with-single-name.output +++ b/unified/extractor/tests/corpus/swift/desugar/simple-import-with-single-name.output @@ -2,12 +2,18 @@ import Foundation --- -source_file - statement: - import_declaration - name: - identifier - part: simple_identifier "Foundation" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + importDecl + attributes: + modifiers: + importKeyword: import + path: + importPathComponent + name: identifier "Foundation" --- diff --git a/unified/extractor/tests/corpus/swift/functions/function-call-with-labelled-arguments.output b/unified/extractor/tests/corpus/swift/functions/function-call-with-labelled-arguments.output index 6c975e37be04..f885d5762f2d 100644 --- a/unified/extractor/tests/corpus/swift/functions/function-call-with-labelled-arguments.output +++ b/unified/extractor/tests/corpus/swift/functions/function-call-with-labelled-arguments.output @@ -2,22 +2,29 @@ greet(person: "Bob") --- -source_file - statement: - call_expression - function: simple_identifier "greet" - suffix: - call_suffix +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) arguments: - value_arguments - argument: - value_argument - name: - value_argument_label - name: simple_identifier "person" - value: - line_string_literal - text: line_str_text "Bob" + labeledExpr + colon: : + label: identifier "person" + expression: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment "Bob" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "greet" --- diff --git a/unified/extractor/tests/corpus/swift/functions/function-call.output b/unified/extractor/tests/corpus/swift/functions/function-call.output index 2e8e107b3a20..a1e2859ccd6a 100644 --- a/unified/extractor/tests/corpus/swift/functions/function-call.output +++ b/unified/extractor/tests/corpus/swift/functions/function-call.output @@ -2,19 +2,28 @@ foo(1, 2) --- -source_file - statement: - call_expression - function: simple_identifier "foo" - suffix: - call_suffix +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) arguments: - value_arguments - argument: - value_argument - value: integer_literal "1" - value_argument - value: integer_literal "2" + labeledExpr + expression: + integerLiteralExpr + literal: integerLiteral "1" + trailingComma: , + labeledExpr + expression: + integerLiteralExpr + literal: integerLiteral "2" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "foo" --- diff --git a/unified/extractor/tests/corpus/swift/functions/function-with-default-parameter-value.output b/unified/extractor/tests/corpus/swift/functions/function-with-default-parameter-value.output index 2c55abad52d9..01c0ddef8560 100644 --- a/unified/extractor/tests/corpus/swift/functions/function-with-default-parameter-value.output +++ b/unified/extractor/tests/corpus/swift/functions/function-with-default-parameter-value.output @@ -4,37 +4,60 @@ func greet(name: String = "world") { --- -source_file - statement: - function_declaration - body: - block - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: simple_identifier "name" - name: simple_identifier "greet" - parameter: - function_parameter - default_value: - line_string_literal - text: line_str_text "world" - parameter: - parameter - name: simple_identifier "name" - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "String" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + functionDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + declReferenceExpr + baseName: identifier "name" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + name: identifier "greet" + modifiers: + signature: + functionSignature + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + functionParameter + colon: : + attributes: + modifiers: + type: + identifierType + name: identifier "String" + firstName: identifier "name" + defaultValue: + initializerClause + equal: = + value: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment "world" + funcKeyword: func --- diff --git a/unified/extractor/tests/corpus/swift/functions/function-with-named-parameters.output b/unified/extractor/tests/corpus/swift/functions/function-with-named-parameters.output index d9eb41963965..f2024b473620 100644 --- a/unified/extractor/tests/corpus/swift/functions/function-with-named-parameters.output +++ b/unified/extractor/tests/corpus/swift/functions/function-with-named-parameters.output @@ -4,35 +4,51 @@ func greet(person name: String) { --- -source_file - statement: - function_declaration - body: - block - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: simple_identifier "name" - name: simple_identifier "greet" - parameter: - function_parameter - parameter: - parameter - external_name: simple_identifier "person" - name: simple_identifier "name" - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "String" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + functionDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + declReferenceExpr + baseName: identifier "name" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + name: identifier "greet" + modifiers: + signature: + functionSignature + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + functionParameter + colon: : + attributes: + modifiers: + type: + identifierType + name: identifier "String" + firstName: identifier "person" + secondName: identifier "name" + funcKeyword: func --- diff --git a/unified/extractor/tests/corpus/swift/functions/function-with-no-parameters.output b/unified/extractor/tests/corpus/swift/functions/function-with-no-parameters.output index b59ed702f296..4ddc26ae94d6 100644 --- a/unified/extractor/tests/corpus/swift/functions/function-with-no-parameters.output +++ b/unified/extractor/tests/corpus/swift/functions/function-with-no-parameters.output @@ -4,24 +4,46 @@ func greet() { --- -source_file - statement: - function_declaration - body: - block - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: - line_string_literal - text: line_str_text "hello" - name: simple_identifier "greet" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + functionDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment "hello" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + name: identifier "greet" + modifiers: + signature: + functionSignature + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + funcKeyword: func --- diff --git a/unified/extractor/tests/corpus/swift/functions/function-with-parameters-and-return-type.output b/unified/extractor/tests/corpus/swift/functions/function-with-parameters-and-return-type.output index eca072fed022..1ffb391dbc5a 100644 --- a/unified/extractor/tests/corpus/swift/functions/function-with-parameters-and-return-type.output +++ b/unified/extractor/tests/corpus/swift/functions/function-with-parameters-and-return-type.output @@ -4,52 +4,68 @@ func add(_ a: Int, _ b: Int) -> Int { --- -source_file - statement: - function_declaration - body: - block - statement: - control_transfer_statement - kind: return - result: - additive_expression - lhs: simple_identifier "a" - op: + - rhs: simple_identifier "b" - name: simple_identifier "add" - parameter: - function_parameter - parameter: - parameter - external_name: simple_identifier "_" - name: simple_identifier "a" - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" - function_parameter - parameter: - parameter - external_name: simple_identifier "_" - name: simple_identifier "b" - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" - return_type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + functionDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + returnStmt + expression: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "+" + leftOperand: + declReferenceExpr + baseName: identifier "a" + rightOperand: + declReferenceExpr + baseName: identifier "b" + returnKeyword: return + name: identifier "add" + modifiers: + signature: + functionSignature + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + functionParameter + colon: : + attributes: + modifiers: + trailingComma: , + type: + identifierType + name: identifier "Int" + firstName: _ + secondName: identifier "a" + functionParameter + colon: : + attributes: + modifiers: + type: + identifierType + name: identifier "Int" + firstName: _ + secondName: identifier "b" + returnClause: + returnClause + arrow: -> + type: + identifierType + name: identifier "Int" + funcKeyword: func --- diff --git a/unified/extractor/tests/corpus/swift/functions/generic-function.output b/unified/extractor/tests/corpus/swift/functions/generic-function.output index 5fb2d4b03899..1652f7f47414 100644 --- a/unified/extractor/tests/corpus/swift/functions/generic-function.output +++ b/unified/extractor/tests/corpus/swift/functions/generic-function.output @@ -4,41 +4,58 @@ func identity(_ x: T) -> T { --- -source_file - statement: - function_declaration - body: - block - statement: - control_transfer_statement - kind: return - result: simple_identifier "x" - name: simple_identifier "identity" - parameter: - function_parameter - parameter: - parameter - external_name: simple_identifier "_" - name: simple_identifier "x" - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "T" - return_type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "T" - type_parameters: - type_parameters - parameter: - type_parameter - name: type_identifier "T" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + functionDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + returnStmt + expression: + declReferenceExpr + baseName: identifier "x" + returnKeyword: return + name: identifier "identity" + genericParameterClause: + genericParameterClause + parameters: + genericParameter + attributes: + name: identifier "T" + leftAngle: < + rightAngle: > + modifiers: + signature: + functionSignature + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + functionParameter + colon: : + attributes: + modifiers: + type: + identifierType + name: identifier "T" + firstName: _ + secondName: identifier "x" + returnClause: + returnClause + arrow: -> + type: + identifierType + name: identifier "T" + funcKeyword: func --- diff --git a/unified/extractor/tests/corpus/swift/functions/leading-dot-expression-call.output b/unified/extractor/tests/corpus/swift/functions/leading-dot-expression-call.output index 75fa887f25ac..d0a844d02afa 100644 --- a/unified/extractor/tests/corpus/swift/functions/leading-dot-expression-call.output +++ b/unified/extractor/tests/corpus/swift/functions/leading-dot-expression-call.output @@ -2,30 +2,39 @@ let y = .some(1) --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "y" - value: - call_expression - function: - prefix_expression - operation: . - target: simple_identifier "some" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: integer_literal "1" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + integerLiteralExpr + literal: integerLiteral "1" + additionalTrailingClosures: + calledExpression: + memberAccessExpr + period: . + declName: + declReferenceExpr + baseName: identifier "some" + pattern: + identifierPattern + identifier: identifier "y" --- diff --git a/unified/extractor/tests/corpus/swift/functions/leading-dot-expression-value.output b/unified/extractor/tests/corpus/swift/functions/leading-dot-expression-value.output index 85aeeffde6eb..bec014593d91 100644 --- a/unified/extractor/tests/corpus/swift/functions/leading-dot-expression-value.output +++ b/unified/extractor/tests/corpus/swift/functions/leading-dot-expression-value.output @@ -2,21 +2,29 @@ let x = .foo --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "x" - value: - prefix_expression - operation: . - target: simple_identifier "foo" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + memberAccessExpr + period: . + declName: + declReferenceExpr + baseName: identifier "foo" + pattern: + identifierPattern + identifier: identifier "x" --- diff --git a/unified/extractor/tests/corpus/swift/functions/method-call.output b/unified/extractor/tests/corpus/swift/functions/method-call.output index 76d6d3206d19..3c0b150b8235 100644 --- a/unified/extractor/tests/corpus/swift/functions/method-call.output +++ b/unified/extractor/tests/corpus/swift/functions/method-call.output @@ -2,22 +2,29 @@ list.append(1) --- -source_file - statement: - call_expression - function: - navigation_expression - suffix: - navigation_suffix - suffix: simple_identifier "append" - target: simple_identifier "list" - suffix: - call_suffix +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) arguments: - value_arguments - argument: - value_argument - value: integer_literal "1" + labeledExpr + expression: + integerLiteralExpr + literal: integerLiteral "1" + additionalTrailingClosures: + calledExpression: + memberAccessExpr + period: . + declName: + declReferenceExpr + baseName: identifier "append" + base: + declReferenceExpr + baseName: identifier "list" --- diff --git a/unified/extractor/tests/corpus/swift/functions/variadic-function.output b/unified/extractor/tests/corpus/swift/functions/variadic-function.output index da8d4afd4d7c..571f07c35e0c 100644 --- a/unified/extractor/tests/corpus/swift/functions/variadic-function.output +++ b/unified/extractor/tests/corpus/swift/functions/variadic-function.output @@ -4,54 +4,72 @@ func sum(_ values: Int...) -> Int { --- -source_file - statement: - function_declaration - body: - block - statement: - control_transfer_statement - kind: return - result: - call_expression - function: - navigation_expression - suffix: - navigation_suffix - suffix: simple_identifier "reduce" - target: simple_identifier "values" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: integer_literal "0" - value_argument - value: - referenceable_operator - operator: + - name: simple_identifier "sum" - parameter: - function_parameter - parameter: - parameter - external_name: simple_identifier "_" - name: simple_identifier "values" - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" - return_type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + functionDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + returnStmt + expression: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + integerLiteralExpr + literal: integerLiteral "0" + trailingComma: , + labeledExpr + expression: + declReferenceExpr + baseName: binaryOperator "+" + additionalTrailingClosures: + calledExpression: + memberAccessExpr + period: . + declName: + declReferenceExpr + baseName: identifier "reduce" + base: + declReferenceExpr + baseName: identifier "values" + returnKeyword: return + name: identifier "sum" + modifiers: + signature: + functionSignature + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + functionParameter + colon: : + attributes: + modifiers: + type: + identifierType + name: identifier "Int" + ellipsis: ... + firstName: _ + secondName: identifier "values" + returnClause: + returnClause + arrow: -> + type: + identifierType + name: identifier "Int" + funcKeyword: func --- diff --git a/unified/extractor/tests/corpus/swift/literals/boolean-literals.output b/unified/extractor/tests/corpus/swift/literals/boolean-literals.output index d31893de0522..34b394712a35 100644 --- a/unified/extractor/tests/corpus/swift/literals/boolean-literals.output +++ b/unified/extractor/tests/corpus/swift/literals/boolean-literals.output @@ -3,10 +3,17 @@ false --- -source_file - statement: - boolean_literal - boolean_literal +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + booleanLiteralExpr + literal: true + codeBlockItem + item: + booleanLiteralExpr + literal: false --- diff --git a/unified/extractor/tests/corpus/swift/literals/floating-point-literal.output b/unified/extractor/tests/corpus/swift/literals/floating-point-literal.output index 0c374dc4452c..19fa40aac776 100644 --- a/unified/extractor/tests/corpus/swift/literals/floating-point-literal.output +++ b/unified/extractor/tests/corpus/swift/literals/floating-point-literal.output @@ -2,8 +2,13 @@ --- -source_file - statement: real_literal "3.14" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + floatLiteralExpr + literal: floatLiteral "3.14" --- diff --git a/unified/extractor/tests/corpus/swift/literals/integer-literal.output b/unified/extractor/tests/corpus/swift/literals/integer-literal.output index 018c57983948..9df79925753c 100644 --- a/unified/extractor/tests/corpus/swift/literals/integer-literal.output +++ b/unified/extractor/tests/corpus/swift/literals/integer-literal.output @@ -2,8 +2,13 @@ --- -source_file - statement: integer_literal "42" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + integerLiteralExpr + literal: integerLiteral "42" --- diff --git a/unified/extractor/tests/corpus/swift/literals/negative-integer-literal.output b/unified/extractor/tests/corpus/swift/literals/negative-integer-literal.output index e1ca11e070ab..907944054782 100644 --- a/unified/extractor/tests/corpus/swift/literals/negative-integer-literal.output +++ b/unified/extractor/tests/corpus/swift/literals/negative-integer-literal.output @@ -2,11 +2,16 @@ --- -source_file - statement: - prefix_expression - operation: - - target: integer_literal "7" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + prefixOperatorExpr + expression: + integerLiteralExpr + literal: integerLiteral "7" + operator: prefixOperator "-" --- diff --git a/unified/extractor/tests/corpus/swift/literals/nil-literal.output b/unified/extractor/tests/corpus/swift/literals/nil-literal.output index 6c826cabe7db..c7da232131fd 100644 --- a/unified/extractor/tests/corpus/swift/literals/nil-literal.output +++ b/unified/extractor/tests/corpus/swift/literals/nil-literal.output @@ -2,8 +2,13 @@ nil --- -source_file - statement: nil +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + nilLiteralExpr + nilKeyword: nil --- diff --git a/unified/extractor/tests/corpus/swift/literals/string-literal.output b/unified/extractor/tests/corpus/swift/literals/string-literal.output index ca2ac6df325d..8d3ea8e796c0 100644 --- a/unified/extractor/tests/corpus/swift/literals/string-literal.output +++ b/unified/extractor/tests/corpus/swift/literals/string-literal.output @@ -2,10 +2,17 @@ --- -source_file - statement: - line_string_literal - text: line_str_text "hello" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment "hello" --- diff --git a/unified/extractor/tests/corpus/swift/literals/string-with-interpolation.output b/unified/extractor/tests/corpus/swift/literals/string-with-interpolation.output index eb56fbbbb03f..5207085d174c 100644 --- a/unified/extractor/tests/corpus/swift/literals/string-with-interpolation.output +++ b/unified/extractor/tests/corpus/swift/literals/string-with-interpolation.output @@ -2,13 +2,28 @@ --- -source_file - statement: - line_string_literal - interpolation: - interpolated_expression - value: simple_identifier "name" - text: line_str_text "hello " +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment "hello " + expressionSegment + leftParen: ( + rightParen: ) + backslash: \ + expressions: + labeledExpr + expression: + declReferenceExpr + baseName: identifier "name" + stringSegment + content: stringSegment --- diff --git a/unified/extractor/tests/corpus/swift/loops/break-and-continue.output b/unified/extractor/tests/corpus/swift/loops/break-and-continue.output index 76b2c77b968d..7ce869998272 100644 --- a/unified/extractor/tests/corpus/swift/loops/break-and-continue.output +++ b/unified/extractor/tests/corpus/swift/loops/break-and-continue.output @@ -6,51 +6,95 @@ for x in xs { --- -source_file - statement: - for_statement - body: - block - statement: - if_statement - body: - block - statement: - control_transfer_statement - kind: continue - condition: - if_condition - kind: - comparison_expression - lhs: simple_identifier "x" - op: < - rhs: integer_literal "0" - if_statement - body: - block - statement: - control_transfer_statement - kind: break - condition: - if_condition - kind: - comparison_expression - lhs: simple_identifier "x" - op: > - rhs: integer_literal "100" - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: simple_identifier "x" - collection: simple_identifier "xs" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem item: - pattern - bound_identifier: simple_identifier "x" + forStmt + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + expressionStmt + expression: + ifExpr + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + continueStmt + continueKeyword: continue + conditions: + conditionElement + condition: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "<" + leftOperand: + declReferenceExpr + baseName: identifier "x" + rightOperand: + integerLiteralExpr + literal: integerLiteral "0" + ifKeyword: if + codeBlockItem + item: + expressionStmt + expression: + ifExpr + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + breakStmt + breakKeyword: break + conditions: + conditionElement + condition: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator ">" + leftOperand: + declReferenceExpr + baseName: identifier "x" + rightOperand: + integerLiteralExpr + literal: integerLiteral "100" + ifKeyword: if + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + declReferenceExpr + baseName: identifier "x" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + pattern: + identifierPattern + identifier: identifier "x" + inKeyword: in + forKeyword: for + sequence: + declReferenceExpr + baseName: identifier "xs" --- diff --git a/unified/extractor/tests/corpus/swift/loops/for-in-over-array-literal.output b/unified/extractor/tests/corpus/swift/loops/for-in-over-array-literal.output index cd1e6d8baab1..2d8db27bfe85 100644 --- a/unified/extractor/tests/corpus/swift/loops/for-in-over-array-literal.output +++ b/unified/extractor/tests/corpus/swift/loops/for-in-over-array-literal.output @@ -4,30 +4,55 @@ for x in [1, 2, 3] { --- -source_file - statement: - for_statement - body: - block - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: simple_identifier "x" - collection: - array_literal - element: - integer_literal "1" - integer_literal "2" - integer_literal "3" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem item: - pattern - bound_identifier: simple_identifier "x" + forStmt + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + declReferenceExpr + baseName: identifier "x" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + pattern: + identifierPattern + identifier: identifier "x" + inKeyword: in + forKeyword: for + sequence: + arrayExpr + elements: + arrayElement + expression: + integerLiteralExpr + literal: integerLiteral "1" + trailingComma: , + arrayElement + expression: + integerLiteralExpr + literal: integerLiteral "2" + trailingComma: , + arrayElement + expression: + integerLiteralExpr + literal: integerLiteral "3" + leftSquare: [ + rightSquare: ] --- diff --git a/unified/extractor/tests/corpus/swift/loops/for-in-over-range.output b/unified/extractor/tests/corpus/swift/loops/for-in-over-range.output index eb65a677d45b..cb8b4e67b68d 100644 --- a/unified/extractor/tests/corpus/swift/loops/for-in-over-range.output +++ b/unified/extractor/tests/corpus/swift/loops/for-in-over-range.output @@ -4,29 +4,47 @@ for i in 0..<10 { --- -source_file - statement: - for_statement - body: - block - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: simple_identifier "i" - collection: - range_expression - end: integer_literal "10" - op: ..< - start: integer_literal "0" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem item: - pattern - bound_identifier: simple_identifier "i" + forStmt + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + declReferenceExpr + baseName: identifier "i" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + pattern: + identifierPattern + identifier: identifier "i" + inKeyword: in + forKeyword: for + sequence: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "..<" + leftOperand: + integerLiteralExpr + literal: integerLiteral "0" + rightOperand: + integerLiteralExpr + literal: integerLiteral "10" --- diff --git a/unified/extractor/tests/corpus/swift/loops/for-in-with-where-clause.output b/unified/extractor/tests/corpus/swift/loops/for-in-with-where-clause.output index be538bde4473..6659039029f3 100644 --- a/unified/extractor/tests/corpus/swift/loops/for-in-with-where-clause.output +++ b/unified/extractor/tests/corpus/swift/loops/for-in-with-where-clause.output @@ -4,33 +4,53 @@ for x in xs where x > 0 { --- -source_file - statement: - for_statement - body: - block - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: simple_identifier "x" - collection: simple_identifier "xs" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem item: - pattern - bound_identifier: simple_identifier "x" - where: - where_clause - expr: - comparison_expression - lhs: simple_identifier "x" - op: > - rhs: integer_literal "0" - keyword: where_keyword "where" + forStmt + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + declReferenceExpr + baseName: identifier "x" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + pattern: + identifierPattern + identifier: identifier "x" + whereClause: + whereClause + condition: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator ">" + leftOperand: + declReferenceExpr + baseName: identifier "x" + rightOperand: + integerLiteralExpr + literal: integerLiteral "0" + whereKeyword: where + inKeyword: in + forKeyword: for + sequence: + declReferenceExpr + baseName: identifier "xs" --- diff --git a/unified/extractor/tests/corpus/swift/loops/repeat-while-loop.output b/unified/extractor/tests/corpus/swift/loops/repeat-while-loop.output index 547a50de735b..71c49fd2cd10 100644 --- a/unified/extractor/tests/corpus/swift/loops/repeat-while-loop.output +++ b/unified/extractor/tests/corpus/swift/loops/repeat-while-loop.output @@ -4,25 +4,42 @@ repeat { --- -source_file - statement: - repeat_while_statement - body: - block - statement: - assignment - operator: -= - result: integer_literal "1" - target: - directly_assignable_expression - expr: simple_identifier "x" - condition: - if_condition - kind: - comparison_expression - lhs: simple_identifier "x" - op: > - rhs: integer_literal "0" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + repeatStmt + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "-=" + leftOperand: + declReferenceExpr + baseName: identifier "x" + rightOperand: + integerLiteralExpr + literal: integerLiteral "1" + condition: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator ">" + leftOperand: + declReferenceExpr + baseName: identifier "x" + rightOperand: + integerLiteralExpr + literal: integerLiteral "0" + repeatKeyword: repeat + whileKeyword: while --- diff --git a/unified/extractor/tests/corpus/swift/loops/while-loop.output b/unified/extractor/tests/corpus/swift/loops/while-loop.output index 7a57bb42068f..1132c6f9f819 100644 --- a/unified/extractor/tests/corpus/swift/loops/while-loop.output +++ b/unified/extractor/tests/corpus/swift/loops/while-loop.output @@ -4,25 +4,43 @@ while x > 0 { --- -source_file - statement: - while_statement - body: - block - statement: - assignment - operator: -= - result: integer_literal "1" - target: - directly_assignable_expression - expr: simple_identifier "x" - condition: - if_condition - kind: - comparison_expression - lhs: simple_identifier "x" - op: > - rhs: integer_literal "0" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + whileStmt + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "-=" + leftOperand: + declReferenceExpr + baseName: identifier "x" + rightOperand: + integerLiteralExpr + literal: integerLiteral "1" + conditions: + conditionElement + condition: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator ">" + leftOperand: + declReferenceExpr + baseName: identifier "x" + rightOperand: + integerLiteralExpr + literal: integerLiteral "0" + whileKeyword: while --- diff --git a/unified/extractor/tests/corpus/swift/operators/addition.output b/unified/extractor/tests/corpus/swift/operators/addition.output index 072682f6f381..9ba0f4de4770 100644 --- a/unified/extractor/tests/corpus/swift/operators/addition.output +++ b/unified/extractor/tests/corpus/swift/operators/addition.output @@ -2,12 +2,21 @@ a + b --- -source_file - statement: - additive_expression - lhs: simple_identifier "a" - op: + - rhs: simple_identifier "b" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "+" + leftOperand: + declReferenceExpr + baseName: identifier "a" + rightOperand: + declReferenceExpr + baseName: identifier "b" --- diff --git a/unified/extractor/tests/corpus/swift/operators/comparison.output b/unified/extractor/tests/corpus/swift/operators/comparison.output index aeee98ecd535..49bb8c996f2c 100644 --- a/unified/extractor/tests/corpus/swift/operators/comparison.output +++ b/unified/extractor/tests/corpus/swift/operators/comparison.output @@ -2,12 +2,21 @@ a < b --- -source_file - statement: - comparison_expression - lhs: simple_identifier "a" - op: < - rhs: simple_identifier "b" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "<" + leftOperand: + declReferenceExpr + baseName: identifier "a" + rightOperand: + declReferenceExpr + baseName: identifier "b" --- diff --git a/unified/extractor/tests/corpus/swift/operators/division.output b/unified/extractor/tests/corpus/swift/operators/division.output index c2a0a03a23f3..f15dce8e8ea5 100644 --- a/unified/extractor/tests/corpus/swift/operators/division.output +++ b/unified/extractor/tests/corpus/swift/operators/division.output @@ -2,12 +2,21 @@ a / b --- -source_file - statement: - multiplicative_expression - lhs: simple_identifier "a" - op: / - rhs: simple_identifier "b" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "/" + leftOperand: + declReferenceExpr + baseName: identifier "a" + rightOperand: + declReferenceExpr + baseName: identifier "b" --- diff --git a/unified/extractor/tests/corpus/swift/operators/equality.output b/unified/extractor/tests/corpus/swift/operators/equality.output index 64c2fb78b178..7cf139ffa18d 100644 --- a/unified/extractor/tests/corpus/swift/operators/equality.output +++ b/unified/extractor/tests/corpus/swift/operators/equality.output @@ -2,12 +2,21 @@ a == b --- -source_file - statement: - equality_expression - lhs: simple_identifier "a" - op: == - rhs: simple_identifier "b" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "==" + leftOperand: + declReferenceExpr + baseName: identifier "a" + rightOperand: + declReferenceExpr + baseName: identifier "b" --- diff --git a/unified/extractor/tests/corpus/swift/operators/logical-and.output b/unified/extractor/tests/corpus/swift/operators/logical-and.output index fbdbd904eafe..32a71ed1088c 100644 --- a/unified/extractor/tests/corpus/swift/operators/logical-and.output +++ b/unified/extractor/tests/corpus/swift/operators/logical-and.output @@ -2,12 +2,21 @@ a && b --- -source_file - statement: - conjunction_expression - lhs: simple_identifier "a" - op: && - rhs: simple_identifier "b" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "&&" + leftOperand: + declReferenceExpr + baseName: identifier "a" + rightOperand: + declReferenceExpr + baseName: identifier "b" --- diff --git a/unified/extractor/tests/corpus/swift/operators/logical-not.output b/unified/extractor/tests/corpus/swift/operators/logical-not.output index d07e357620fd..1e80aa2ca71e 100644 --- a/unified/extractor/tests/corpus/swift/operators/logical-not.output +++ b/unified/extractor/tests/corpus/swift/operators/logical-not.output @@ -2,11 +2,16 @@ --- -source_file - statement: - prefix_expression - operation: bang "!" - target: simple_identifier "a" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + prefixOperatorExpr + expression: + declReferenceExpr + baseName: identifier "a" + operator: prefixOperator "!" --- diff --git a/unified/extractor/tests/corpus/swift/operators/logical-or.output b/unified/extractor/tests/corpus/swift/operators/logical-or.output index 5d15828065cf..b75d018dea71 100644 --- a/unified/extractor/tests/corpus/swift/operators/logical-or.output +++ b/unified/extractor/tests/corpus/swift/operators/logical-or.output @@ -2,12 +2,21 @@ a || b --- -source_file - statement: - disjunction_expression - lhs: simple_identifier "a" - op: || - rhs: simple_identifier "b" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "||" + leftOperand: + declReferenceExpr + baseName: identifier "a" + rightOperand: + declReferenceExpr + baseName: identifier "b" --- diff --git a/unified/extractor/tests/corpus/swift/operators/multiplication.output b/unified/extractor/tests/corpus/swift/operators/multiplication.output index 77ce11a659e4..387c16439c48 100644 --- a/unified/extractor/tests/corpus/swift/operators/multiplication.output +++ b/unified/extractor/tests/corpus/swift/operators/multiplication.output @@ -2,12 +2,21 @@ a * b --- -source_file - statement: - multiplicative_expression - lhs: simple_identifier "a" - op: * - rhs: simple_identifier "b" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "*" + leftOperand: + declReferenceExpr + baseName: identifier "a" + rightOperand: + declReferenceExpr + baseName: identifier "b" --- diff --git a/unified/extractor/tests/corpus/swift/operators/operator-precedence-addition-and-multiplication.output b/unified/extractor/tests/corpus/swift/operators/operator-precedence-addition-and-multiplication.output index 2c89c306a6d0..f458c3ef847c 100644 --- a/unified/extractor/tests/corpus/swift/operators/operator-precedence-addition-and-multiplication.output +++ b/unified/extractor/tests/corpus/swift/operators/operator-precedence-addition-and-multiplication.output @@ -2,16 +2,29 @@ a + b * c --- -source_file - statement: - additive_expression - lhs: simple_identifier "a" - op: + - rhs: - multiplicative_expression - lhs: simple_identifier "b" - op: * - rhs: simple_identifier "c" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "+" + leftOperand: + declReferenceExpr + baseName: identifier "a" + rightOperand: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "*" + leftOperand: + declReferenceExpr + baseName: identifier "b" + rightOperand: + declReferenceExpr + baseName: identifier "c" --- diff --git a/unified/extractor/tests/corpus/swift/operators/parenthesised-expression.output b/unified/extractor/tests/corpus/swift/operators/parenthesised-expression.output index 36216b4201f4..0324476ce994 100644 --- a/unified/extractor/tests/corpus/swift/operators/parenthesised-expression.output +++ b/unified/extractor/tests/corpus/swift/operators/parenthesised-expression.output @@ -2,20 +2,35 @@ --- -source_file - statement: - multiplicative_expression - lhs: - tuple_expression - element: - tuple_expression_item - value: - additive_expression - lhs: simple_identifier "a" - op: + - rhs: simple_identifier "b" - op: * - rhs: simple_identifier "c" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "*" + leftOperand: + tupleExpr + leftParen: ( + rightParen: ) + elements: + labeledExpr + expression: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "+" + leftOperand: + declReferenceExpr + baseName: identifier "a" + rightOperand: + declReferenceExpr + baseName: identifier "b" + rightOperand: + declReferenceExpr + baseName: identifier "c" --- diff --git a/unified/extractor/tests/corpus/swift/operators/range-operator.output b/unified/extractor/tests/corpus/swift/operators/range-operator.output index 574eccd9795e..55ed3ab971a7 100644 --- a/unified/extractor/tests/corpus/swift/operators/range-operator.output +++ b/unified/extractor/tests/corpus/swift/operators/range-operator.output @@ -2,12 +2,21 @@ --- -source_file - statement: - range_expression - end: integer_literal "10" - op: ... - start: integer_literal "1" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "..." + leftOperand: + integerLiteralExpr + literal: integerLiteral "1" + rightOperand: + integerLiteralExpr + literal: integerLiteral "10" --- diff --git a/unified/extractor/tests/corpus/swift/operators/subtraction.output b/unified/extractor/tests/corpus/swift/operators/subtraction.output index 993a6c3b6838..5c6fd51a2d38 100644 --- a/unified/extractor/tests/corpus/swift/operators/subtraction.output +++ b/unified/extractor/tests/corpus/swift/operators/subtraction.output @@ -2,12 +2,21 @@ a - b --- -source_file - statement: - additive_expression - lhs: simple_identifier "a" - op: - - rhs: simple_identifier "b" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "-" + leftOperand: + declReferenceExpr + baseName: identifier "a" + rightOperand: + declReferenceExpr + baseName: identifier "b" --- diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/do-catch.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/do-catch.output index 1178570e5117..81491b295fc1 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors/do-catch.output +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/do-catch.output @@ -6,37 +6,54 @@ do { --- -source_file - statement: - do_statement - body: - block - statement: - try_expression - expr: - call_expression - function: simple_identifier "foo" - suffix: - call_suffix - arguments: - value_arguments - operator: - try_operator - catch: - catch_block +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + doStmt body: - block - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: simple_identifier "error" - keyword: catch_keyword "catch" + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + tryExpr + expression: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "foo" + tryKeyword: try + catchClauses: + catchClause + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + declReferenceExpr + baseName: identifier "error" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + catchItems: + catchKeyword: catch + doKeyword: do --- diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/force-unwrap.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/force-unwrap.output index 96fb627e18b1..2c6fd1a6f763 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors/force-unwrap.output +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/force-unwrap.output @@ -2,21 +2,29 @@ let n = opt! --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "n" - value: - postfix_expression - operation: bang "!" - target: simple_identifier "opt" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + forceUnwrapExpr + expression: + declReferenceExpr + baseName: identifier "opt" + exclamationMark: ! + pattern: + identifierPattern + identifier: identifier "n" --- diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/nil-coalescing.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/nil-coalescing.output index c0b3a3a9783a..31a039ad0065 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors/nil-coalescing.output +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/nil-coalescing.output @@ -2,21 +2,34 @@ let n = opt ?? 0 --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "n" - value: - nil_coalescing_expression - if_nil: integer_literal "0" - value: simple_identifier "opt" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "??" + leftOperand: + declReferenceExpr + baseName: identifier "opt" + rightOperand: + integerLiteralExpr + literal: integerLiteral "0" + pattern: + identifierPattern + identifier: identifier "n" --- diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/optional-chaining.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/optional-chaining.output index 6c5b27a64fe2..b69b0ae47d50 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors/optional-chaining.output +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/optional-chaining.output @@ -2,32 +2,44 @@ let n = obj?.foo?.bar --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "n" - value: - navigation_expression - suffix: - navigation_suffix - suffix: simple_identifier "bar" - target: - optional_chain_marker - expr: - navigation_expression - suffix: - navigation_suffix - suffix: simple_identifier "foo" - target: - optional_chain_marker - expr: simple_identifier "obj" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + memberAccessExpr + period: . + declName: + declReferenceExpr + baseName: identifier "bar" + base: + optionalChainingExpr + expression: + memberAccessExpr + period: . + declName: + declReferenceExpr + baseName: identifier "foo" + base: + optionalChainingExpr + expression: + declReferenceExpr + baseName: identifier "obj" + questionMark: ? + questionMark: ? + pattern: + identifierPattern + identifier: identifier "n" --- diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/optional-type-annotation.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/optional-type-annotation.output index 06191891496e..1927b494ef9a 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors/optional-type-annotation.output +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/optional-type-annotation.output @@ -2,29 +2,35 @@ let x: Int? = nil --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "x" - type: - type_annotation - type: - type - name: - optional_type - wrapped: - user_type - part: - simple_user_type - name: type_identifier "Int" - value: nil +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + nilLiteralExpr + nilKeyword: nil + pattern: + identifierPattern + identifier: identifier "x" + typeAnnotation: + typeAnnotation + colon: : + type: + optionalType + wrappedType: + identifierType + name: identifier "Int" + questionMark: ? --- diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/throwing-function.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/throwing-function.output index 880128cd372f..e68b4c3c57ac 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors/throwing-function.output +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/throwing-function.output @@ -4,25 +4,50 @@ func read() throws -> String { --- -source_file - statement: - function_declaration - body: - block - statement: - control_transfer_statement - kind: return - result: - line_string_literal - name: simple_identifier "read" - return_type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "String" - throws: throws "throws" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + functionDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + returnStmt + expression: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment + returnKeyword: return + name: identifier "read" + modifiers: + signature: + functionSignature + effectSpecifiers: + functionEffectSpecifiers + throwsClause: + throwsClause + throwsSpecifier: throws + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + returnClause: + returnClause + arrow: -> + type: + identifierType + name: identifier "String" + funcKeyword: func --- diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/try-expression-2.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/try-expression-2.output index 9d5ff032d75c..aafc0c67c217 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors/try-expression-2.output +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/try-expression-2.output @@ -2,28 +2,36 @@ let result = try! foo() --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "result" - value: - try_expression - expr: - call_expression - function: simple_identifier "foo" - suffix: - call_suffix - arguments: - value_arguments - operator: - try_operator +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + tryExpr + expression: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "foo" + questionOrExclamationMark: ! + tryKeyword: try + pattern: + identifierPattern + identifier: identifier "result" --- diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/try-expression.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/try-expression.output index e6a7bfef3444..5b1b0b24d0fa 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors/try-expression.output +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/try-expression.output @@ -2,28 +2,36 @@ let result = try? foo() --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "result" - value: - try_expression - expr: - call_expression - function: simple_identifier "foo" - suffix: - call_suffix - arguments: - value_arguments - operator: - try_operator +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + tryExpr + expression: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "foo" + questionOrExclamationMark: ? + tryKeyword: try + pattern: + identifierPattern + identifier: identifier "result" --- diff --git a/unified/extractor/tests/corpus/swift/types/binding-modifier-does-not-leak-into-accessor-body.output b/unified/extractor/tests/corpus/swift/types/binding-modifier-does-not-leak-into-accessor-body.output index dc137a3e621f..c05bc7794437 100644 --- a/unified/extractor/tests/corpus/swift/types/binding-modifier-does-not-leak-into-accessor-body.output +++ b/unified/extractor/tests/corpus/swift/types/binding-modifier-does-not-leak-into-accessor-body.output @@ -11,54 +11,84 @@ var p: Int { --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: var - declarator: - property_binding - computed_value: - computed_property - accessor: - computed_getter - body: - block - statement: - switch_statement - entry: - switch_entry - pattern: - switch_pattern - pattern: - pattern - kind: simple_identifier "someConstant" - statement: - control_transfer_statement - kind: return - result: integer_literal "1" - switch_entry - default: default_keyword "default" - statement: - control_transfer_statement - kind: return - result: integer_literal "2" - expr: simple_identifier "y" - specifier: - getter_specifier - name: - pattern - bound_identifier: simple_identifier "p" - type: - type_annotation - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: var + bindings: + patternBinding + pattern: + identifierPattern + identifier: identifier "p" + typeAnnotation: + typeAnnotation + colon: : + type: + identifierType + name: identifier "Int" + accessorBlock: + accessorBlock + accessors: + accessorDecl + accessorSpecifier: get + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + expressionStmt + expression: + switchExpr + leftBrace: { + rightBrace: } + cases: + switchCase + label: + switchCaseLabel + colon: : + caseKeyword: case + caseItems: + switchCaseItem + pattern: + expressionPattern + expression: + declReferenceExpr + baseName: identifier "someConstant" + statements: + codeBlockItem + item: + returnStmt + expression: + integerLiteralExpr + literal: integerLiteral "1" + returnKeyword: return + switchCase + label: + switchDefaultLabel + colon: : + defaultKeyword: default + statements: + codeBlockItem + item: + returnStmt + expression: + integerLiteralExpr + literal: integerLiteral "2" + returnKeyword: return + subject: + declReferenceExpr + baseName: identifier "y" + switchKeyword: switch + leftBrace: { + rightBrace: } --- diff --git a/unified/extractor/tests/corpus/swift/types/class-inheritance.output b/unified/extractor/tests/corpus/swift/types/class-inheritance.output index e90cccc4a8b6..62a0a43414d0 100644 --- a/unified/extractor/tests/corpus/swift/types/class-inheritance.output +++ b/unified/extractor/tests/corpus/swift/types/class-inheritance.output @@ -2,20 +2,29 @@ class Dog: Animal {} --- -source_file - statement: - class_declaration - body: - class_body - declaration_kind: class - inherits: - inheritance_specifier - inherits_from: - user_type - part: - simple_user_type - name: type_identifier "Animal" - name: type_identifier "Dog" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + classDecl + attributes: + name: identifier "Dog" + inheritanceClause: + inheritanceClause + colon: : + inheritedTypes: + inheritedType + type: + identifierType + name: identifier "Animal" + memberBlock: + memberBlock + leftBrace: { + rightBrace: } + members: + modifiers: + classKeyword: class --- diff --git a/unified/extractor/tests/corpus/swift/types/class-with-initializer.output b/unified/extractor/tests/corpus/swift/types/class-with-initializer.output index 77cfa70ac351..5e712d739e5f 100644 --- a/unified/extractor/tests/corpus/swift/types/class-with-initializer.output +++ b/unified/extractor/tests/corpus/swift/types/class-with-initializer.output @@ -7,60 +7,82 @@ class Point { --- -source_file - statement: - class_declaration - body: - class_body - member: - property_declaration - binding: - value_binding_pattern - mutability: var - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "x" - type: - type_annotation - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" - init_declaration - body: - block - statement: - assignment - operator: = - result: simple_identifier "x" - target: - directly_assignable_expression - expr: - navigation_expression - suffix: - navigation_suffix - suffix: simple_identifier "x" - target: - self_expression - parameter: - function_parameter - parameter: - parameter - name: simple_identifier "x" - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" - declaration_kind: class - name: type_identifier "Point" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + classDecl + attributes: + name: identifier "Point" + memberBlock: + memberBlock + leftBrace: { + rightBrace: } + members: + memberBlockItem + decl: + variableDecl + attributes: + modifiers: + bindingSpecifier: var + bindings: + patternBinding + pattern: + identifierPattern + identifier: identifier "x" + typeAnnotation: + typeAnnotation + colon: : + type: + identifierType + name: identifier "Int" + memberBlockItem + decl: + initializerDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + assignmentExpr + equal: = + leftOperand: + memberAccessExpr + period: . + declName: + declReferenceExpr + baseName: identifier "x" + base: + declReferenceExpr + baseName: self + rightOperand: + declReferenceExpr + baseName: identifier "x" + modifiers: + signature: + functionSignature + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + functionParameter + colon: : + attributes: + modifiers: + type: + identifierType + name: identifier "Int" + firstName: identifier "x" + initKeyword: init + modifiers: + classKeyword: class --- diff --git a/unified/extractor/tests/corpus/swift/types/class-with-method.output b/unified/extractor/tests/corpus/swift/types/class-with-method.output index 20152cd26c8e..f45cb31e53ad 100644 --- a/unified/extractor/tests/corpus/swift/types/class-with-method.output +++ b/unified/extractor/tests/corpus/swift/types/class-with-method.output @@ -7,35 +7,69 @@ class Counter { --- -source_file - statement: - class_declaration - body: - class_body - member: - property_declaration - binding: - value_binding_pattern - mutability: var - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "n" - value: integer_literal "0" - function_declaration - body: - block - statement: - assignment - operator: += - result: integer_literal "1" - target: - directly_assignable_expression - expr: simple_identifier "n" - name: simple_identifier "bump" - declaration_kind: class - name: type_identifier "Counter" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + classDecl + attributes: + name: identifier "Counter" + memberBlock: + memberBlock + leftBrace: { + rightBrace: } + members: + memberBlockItem + decl: + variableDecl + attributes: + modifiers: + bindingSpecifier: var + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + integerLiteralExpr + literal: integerLiteral "0" + pattern: + identifierPattern + identifier: identifier "n" + memberBlockItem + decl: + functionDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "+=" + leftOperand: + declReferenceExpr + baseName: identifier "n" + rightOperand: + integerLiteralExpr + literal: integerLiteral "1" + name: identifier "bump" + modifiers: + signature: + functionSignature + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + funcKeyword: func + modifiers: + classKeyword: class --- diff --git a/unified/extractor/tests/corpus/swift/types/class-with-stored-properties.output b/unified/extractor/tests/corpus/swift/types/class-with-stored-properties.output index c2ae82ea3dae..e184426eb755 100644 --- a/unified/extractor/tests/corpus/swift/types/class-with-stored-properties.output +++ b/unified/extractor/tests/corpus/swift/types/class-with-stored-properties.output @@ -5,50 +5,55 @@ class Point { --- -source_file - statement: - class_declaration - body: - class_body - member: - property_declaration - binding: - value_binding_pattern - mutability: var - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "x" - type: - type_annotation - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" - property_declaration - binding: - value_binding_pattern - mutability: var - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "y" - type: - type_annotation - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" - declaration_kind: class - name: type_identifier "Point" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + classDecl + attributes: + name: identifier "Point" + memberBlock: + memberBlock + leftBrace: { + rightBrace: } + members: + memberBlockItem + decl: + variableDecl + attributes: + modifiers: + bindingSpecifier: var + bindings: + patternBinding + pattern: + identifierPattern + identifier: identifier "x" + typeAnnotation: + typeAnnotation + colon: : + type: + identifierType + name: identifier "Int" + memberBlockItem + decl: + variableDecl + attributes: + modifiers: + bindingSpecifier: var + bindings: + patternBinding + pattern: + identifierPattern + identifier: identifier "y" + typeAnnotation: + typeAnnotation + colon: : + type: + identifierType + name: identifier "Int" + modifiers: + classKeyword: class --- diff --git a/unified/extractor/tests/corpus/swift/types/computed-property.output b/unified/extractor/tests/corpus/swift/types/computed-property.output index 287f75956330..24e816be0091 100644 --- a/unified/extractor/tests/corpus/swift/types/computed-property.output +++ b/unified/extractor/tests/corpus/swift/types/computed-property.output @@ -8,78 +8,92 @@ class Rect { --- -source_file - statement: - class_declaration - body: - class_body - member: - property_declaration - binding: - value_binding_pattern - mutability: var - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "w" - type: - type_annotation - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Double" - property_declaration - binding: - value_binding_pattern - mutability: var - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "h" - type: - type_annotation - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Double" - property_declaration - binding: - value_binding_pattern - mutability: var - declarator: - property_binding - computed_value: - computed_property - statement: - control_transfer_statement - kind: return - result: - multiplicative_expression - lhs: simple_identifier "w" - op: * - rhs: simple_identifier "h" - name: - pattern - bound_identifier: simple_identifier "area" - type: - type_annotation - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Double" - declaration_kind: class - name: type_identifier "Rect" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + classDecl + attributes: + name: identifier "Rect" + memberBlock: + memberBlock + leftBrace: { + rightBrace: } + members: + memberBlockItem + decl: + variableDecl + attributes: + modifiers: + bindingSpecifier: var + bindings: + patternBinding + pattern: + identifierPattern + identifier: identifier "w" + typeAnnotation: + typeAnnotation + colon: : + type: + identifierType + name: identifier "Double" + memberBlockItem + decl: + variableDecl + attributes: + modifiers: + bindingSpecifier: var + bindings: + patternBinding + pattern: + identifierPattern + identifier: identifier "h" + typeAnnotation: + typeAnnotation + colon: : + type: + identifierType + name: identifier "Double" + memberBlockItem + decl: + variableDecl + attributes: + modifiers: + bindingSpecifier: var + bindings: + patternBinding + pattern: + identifierPattern + identifier: identifier "area" + typeAnnotation: + typeAnnotation + colon: : + type: + identifierType + name: identifier "Double" + accessorBlock: + accessorBlock + accessors: + codeBlockItem + item: + returnStmt + expression: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "*" + leftOperand: + declReferenceExpr + baseName: identifier "w" + rightOperand: + declReferenceExpr + baseName: identifier "h" + returnKeyword: return + leftBrace: { + rightBrace: } + modifiers: + classKeyword: class --- diff --git a/unified/extractor/tests/corpus/swift/types/empty-class.output b/unified/extractor/tests/corpus/swift/types/empty-class.output index 761de778543d..6693744c9b43 100644 --- a/unified/extractor/tests/corpus/swift/types/empty-class.output +++ b/unified/extractor/tests/corpus/swift/types/empty-class.output @@ -2,13 +2,21 @@ class Foo {} --- -source_file - statement: - class_declaration - body: - class_body - declaration_kind: class - name: type_identifier "Foo" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + classDecl + attributes: + name: identifier "Foo" + memberBlock: + memberBlock + leftBrace: { + rightBrace: } + members: + modifiers: + classKeyword: class --- diff --git a/unified/extractor/tests/corpus/swift/types/enum-with-associated-values.output b/unified/extractor/tests/corpus/swift/types/enum-with-associated-values.output index f520b649095a..399239bbea30 100644 --- a/unified/extractor/tests/corpus/swift/types/enum-with-associated-values.output +++ b/unified/extractor/tests/corpus/swift/types/enum-with-associated-values.output @@ -5,46 +5,63 @@ enum Shape { --- -source_file - statement: - class_declaration - body: - enum_class_body - member: - enum_entry - case: - enum_case_entry - data_contents: - enum_type_parameters - parameter: - enum_type_parameter - name: simple_identifier "radius" - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Double" - name: simple_identifier "circle" - enum_entry - case: - enum_case_entry - data_contents: - enum_type_parameters - parameter: - enum_type_parameter - name: simple_identifier "side" - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Double" - name: simple_identifier "square" - declaration_kind: enum - name: type_identifier "Shape" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + enumDecl + attributes: + name: identifier "Shape" + memberBlock: + memberBlock + leftBrace: { + rightBrace: } + members: + memberBlockItem + decl: + enumCaseDecl + attributes: + modifiers: + elements: + enumCaseElement + name: identifier "circle" + parameterClause: + enumCaseParameterClause + leftParen: ( + rightParen: ) + parameters: + enumCaseParameter + colon: : + modifiers: + type: + identifierType + name: identifier "Double" + firstName: identifier "radius" + caseKeyword: case + memberBlockItem + decl: + enumCaseDecl + attributes: + modifiers: + elements: + enumCaseElement + name: identifier "square" + parameterClause: + enumCaseParameterClause + leftParen: ( + rightParen: ) + parameters: + enumCaseParameter + colon: : + modifiers: + type: + identifierType + name: identifier "Double" + firstName: identifier "side" + caseKeyword: case + modifiers: + enumKeyword: enum --- diff --git a/unified/extractor/tests/corpus/swift/types/enum-with-cases.output b/unified/extractor/tests/corpus/swift/types/enum-with-cases.output index f70f43bfb8ec..f081c2a82046 100644 --- a/unified/extractor/tests/corpus/swift/types/enum-with-cases.output +++ b/unified/extractor/tests/corpus/swift/types/enum-with-cases.output @@ -7,30 +7,57 @@ enum Direction { --- -source_file - statement: - class_declaration - body: - enum_class_body - member: - enum_entry - case: - enum_case_entry - name: simple_identifier "north" - enum_entry - case: - enum_case_entry - name: simple_identifier "south" - enum_entry - case: - enum_case_entry - name: simple_identifier "east" - enum_entry - case: - enum_case_entry - name: simple_identifier "west" - declaration_kind: enum - name: type_identifier "Direction" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + enumDecl + attributes: + name: identifier "Direction" + memberBlock: + memberBlock + leftBrace: { + rightBrace: } + members: + memberBlockItem + decl: + enumCaseDecl + attributes: + modifiers: + elements: + enumCaseElement + name: identifier "north" + caseKeyword: case + memberBlockItem + decl: + enumCaseDecl + attributes: + modifiers: + elements: + enumCaseElement + name: identifier "south" + caseKeyword: case + memberBlockItem + decl: + enumCaseDecl + attributes: + modifiers: + elements: + enumCaseElement + name: identifier "east" + caseKeyword: case + memberBlockItem + decl: + enumCaseDecl + attributes: + modifiers: + elements: + enumCaseElement + name: identifier "west" + caseKeyword: case + modifiers: + enumKeyword: enum --- diff --git a/unified/extractor/tests/corpus/swift/types/enum-with-comma-separated-cases-chained-declaration.output b/unified/extractor/tests/corpus/swift/types/enum-with-comma-separated-cases-chained-declaration.output index 56e793247bbf..6a4ea95e9a62 100644 --- a/unified/extractor/tests/corpus/swift/types/enum-with-comma-separated-cases-chained-declaration.output +++ b/unified/extractor/tests/corpus/swift/types/enum-with-comma-separated-cases-chained-declaration.output @@ -4,24 +4,39 @@ enum Suit { --- -source_file - statement: - class_declaration - body: - enum_class_body - member: - enum_entry - case: - enum_case_entry - name: simple_identifier "clubs" - enum_case_entry - name: simple_identifier "diamonds" - enum_case_entry - name: simple_identifier "hearts" - enum_case_entry - name: simple_identifier "spades" - declaration_kind: enum - name: type_identifier "Suit" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + enumDecl + attributes: + name: identifier "Suit" + memberBlock: + memberBlock + leftBrace: { + rightBrace: } + members: + memberBlockItem + decl: + enumCaseDecl + attributes: + modifiers: + elements: + enumCaseElement + name: identifier "clubs" + trailingComma: , + enumCaseElement + name: identifier "diamonds" + trailingComma: , + enumCaseElement + name: identifier "hearts" + trailingComma: , + enumCaseElement + name: identifier "spades" + caseKeyword: case + modifiers: + enumKeyword: enum --- diff --git a/unified/extractor/tests/corpus/swift/types/extension.output b/unified/extractor/tests/corpus/swift/types/extension.output index 894b8c530c81..1b1d02ebddad 100644 --- a/unified/extractor/tests/corpus/swift/types/extension.output +++ b/unified/extractor/tests/corpus/swift/types/extension.output @@ -4,39 +4,63 @@ extension Int { --- -source_file - statement: - class_declaration - body: - class_body - member: - function_declaration - body: - block - statement: - control_transfer_statement - kind: return - result: - multiplicative_expression - lhs: - self_expression - op: * - rhs: - self_expression - name: simple_identifier "squared" - return_type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" - declaration_kind: extension - name: - user_type - part: - simple_user_type - name: type_identifier "Int" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + extensionDecl + attributes: + memberBlock: + memberBlock + leftBrace: { + rightBrace: } + members: + memberBlockItem + decl: + functionDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + returnStmt + expression: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "*" + leftOperand: + declReferenceExpr + baseName: self + rightOperand: + declReferenceExpr + baseName: self + returnKeyword: return + name: identifier "squared" + modifiers: + signature: + functionSignature + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + returnClause: + returnClause + arrow: -> + type: + identifierType + name: identifier "Int" + funcKeyword: func + modifiers: + extendedType: + identifierType + name: identifier "Int" + extensionKeyword: extension --- diff --git a/unified/extractor/tests/corpus/swift/types/protocol-declaration.output b/unified/extractor/tests/corpus/swift/types/protocol-declaration.output index 628b58e979f6..e848fb23eb3f 100644 --- a/unified/extractor/tests/corpus/swift/types/protocol-declaration.output +++ b/unified/extractor/tests/corpus/swift/types/protocol-declaration.output @@ -4,15 +4,35 @@ protocol Drawable { --- -source_file - statement: - protocol_declaration - body: - protocol_body - member: - protocol_function_declaration - name: simple_identifier "draw" - name: type_identifier "Drawable" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + protocolDecl + attributes: + name: identifier "Drawable" + memberBlock: + memberBlock + leftBrace: { + rightBrace: } + members: + memberBlockItem + decl: + functionDecl + attributes: + name: identifier "draw" + modifiers: + signature: + functionSignature + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + funcKeyword: func + modifiers: + protocolKeyword: protocol --- diff --git a/unified/extractor/tests/corpus/swift/types/protocol-with-read-only-and-read-write-property-requirements.output b/unified/extractor/tests/corpus/swift/types/protocol-with-read-only-and-read-write-property-requirements.output index 11296b02e005..83362740bb1e 100644 --- a/unified/extractor/tests/corpus/swift/types/protocol-with-read-only-and-read-write-property-requirements.output +++ b/unified/extractor/tests/corpus/swift/types/protocol-with-read-only-and-read-write-property-requirements.output @@ -5,54 +5,74 @@ protocol P { --- -source_file - statement: - protocol_declaration - body: - protocol_body - member: - protocol_property_declaration - name: - pattern - binding: - value_binding_pattern - mutability: var - bound_identifier: simple_identifier "foo" - requirements: - protocol_property_requirements - accessor: - getter_specifier - type: - type_annotation - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" - protocol_property_declaration - name: - pattern - binding: - value_binding_pattern - mutability: var - bound_identifier: simple_identifier "bar" - requirements: - protocol_property_requirements - accessor: - getter_specifier - setter_specifier - type: - type_annotation - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "String" - name: type_identifier "P" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + protocolDecl + attributes: + name: identifier "P" + memberBlock: + memberBlock + leftBrace: { + rightBrace: } + members: + memberBlockItem + decl: + variableDecl + attributes: + modifiers: + bindingSpecifier: var + bindings: + patternBinding + pattern: + identifierPattern + identifier: identifier "foo" + typeAnnotation: + typeAnnotation + colon: : + type: + identifierType + name: identifier "Int" + accessorBlock: + accessorBlock + accessors: + accessorDecl + accessorSpecifier: get + attributes: + leftBrace: { + rightBrace: } + memberBlockItem + decl: + variableDecl + attributes: + modifiers: + bindingSpecifier: var + bindings: + patternBinding + pattern: + identifierPattern + identifier: identifier "bar" + typeAnnotation: + typeAnnotation + colon: : + type: + identifierType + name: identifier "String" + accessorBlock: + accessorBlock + accessors: + accessorDecl + accessorSpecifier: get + attributes: + accessorDecl + accessorSpecifier: set + attributes: + leftBrace: { + rightBrace: } + modifiers: + protocolKeyword: protocol --- diff --git a/unified/extractor/tests/corpus/swift/types/struct.output b/unified/extractor/tests/corpus/swift/types/struct.output index 7de3a4f5fde5..57fb25c9e193 100644 --- a/unified/extractor/tests/corpus/swift/types/struct.output +++ b/unified/extractor/tests/corpus/swift/types/struct.output @@ -5,50 +5,55 @@ struct Point { --- -source_file - statement: - class_declaration - body: - class_body - member: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "x" - type: - type_annotation - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "y" - type: - type_annotation - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" - declaration_kind: struct - name: type_identifier "Point" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + structDecl + attributes: + name: identifier "Point" + memberBlock: + memberBlock + leftBrace: { + rightBrace: } + members: + memberBlockItem + decl: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + pattern: + identifierPattern + identifier: identifier "x" + typeAnnotation: + typeAnnotation + colon: : + type: + identifierType + name: identifier "Int" + memberBlockItem + decl: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + pattern: + identifierPattern + identifier: identifier "y" + typeAnnotation: + typeAnnotation + colon: : + type: + identifierType + name: identifier "Int" + modifiers: + structKeyword: struct --- diff --git a/unified/extractor/tests/corpus/swift/variables/assignment.output b/unified/extractor/tests/corpus/swift/variables/assignment.output index 9d1a61e89a82..a011eb76cafc 100644 --- a/unified/extractor/tests/corpus/swift/variables/assignment.output +++ b/unified/extractor/tests/corpus/swift/variables/assignment.output @@ -2,14 +2,21 @@ x = 1 --- -source_file - statement: - assignment - operator: = - result: integer_literal "1" - target: - directly_assignable_expression - expr: simple_identifier "x" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + assignmentExpr + equal: = + leftOperand: + declReferenceExpr + baseName: identifier "x" + rightOperand: + integerLiteralExpr + literal: integerLiteral "1" --- diff --git a/unified/extractor/tests/corpus/swift/variables/binding-modifier-does-not-leak-into-initializer.output b/unified/extractor/tests/corpus/swift/variables/binding-modifier-does-not-leak-into-initializer.output index a6d554ca8370..d159cd6b37cb 100644 --- a/unified/extractor/tests/corpus/swift/variables/binding-modifier-does-not-leak-into-initializer.output +++ b/unified/extractor/tests/corpus/swift/variables/binding-modifier-does-not-leak-into-initializer.output @@ -5,31 +5,59 @@ default: 2 --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "x" - value: - switch_statement - entry: - switch_entry - pattern: - switch_pattern - pattern: - pattern - kind: simple_identifier "someConstant" - statement: integer_literal "1" - switch_entry - default: default_keyword "default" - statement: integer_literal "2" - expr: simple_identifier "y" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + switchExpr + leftBrace: { + rightBrace: } + cases: + switchCase + label: + switchCaseLabel + colon: : + caseKeyword: case + caseItems: + switchCaseItem + pattern: + expressionPattern + expression: + declReferenceExpr + baseName: identifier "someConstant" + statements: + codeBlockItem + item: + integerLiteralExpr + literal: integerLiteral "1" + switchCase + label: + switchDefaultLabel + colon: : + defaultKeyword: default + statements: + codeBlockItem + item: + integerLiteralExpr + literal: integerLiteral "2" + subject: + declReferenceExpr + baseName: identifier "y" + switchKeyword: switch + pattern: + identifierPattern + identifier: identifier "x" --- diff --git a/unified/extractor/tests/corpus/swift/variables/compound-assignment.output b/unified/extractor/tests/corpus/swift/variables/compound-assignment.output index 5385e0ae46be..485b5044ad69 100644 --- a/unified/extractor/tests/corpus/swift/variables/compound-assignment.output +++ b/unified/extractor/tests/corpus/swift/variables/compound-assignment.output @@ -2,14 +2,21 @@ x += 1 --- -source_file - statement: - assignment - operator: += - result: integer_literal "1" - target: - directly_assignable_expression - expr: simple_identifier "x" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "+=" + leftOperand: + declReferenceExpr + baseName: identifier "x" + rightOperand: + integerLiteralExpr + literal: integerLiteral "1" --- diff --git a/unified/extractor/tests/corpus/swift/variables/let-binding.output b/unified/extractor/tests/corpus/swift/variables/let-binding.output index b8b16dc80144..4774eb3eeca8 100644 --- a/unified/extractor/tests/corpus/swift/variables/let-binding.output +++ b/unified/extractor/tests/corpus/swift/variables/let-binding.output @@ -2,18 +2,26 @@ let x = 1 --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "x" - value: integer_literal "1" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + integerLiteralExpr + literal: integerLiteral "1" + pattern: + identifierPattern + identifier: identifier "x" --- diff --git a/unified/extractor/tests/corpus/swift/variables/let-with-type-annotation.output b/unified/extractor/tests/corpus/swift/variables/let-with-type-annotation.output index 3fd78d09fa42..a56feb445ace 100644 --- a/unified/extractor/tests/corpus/swift/variables/let-with-type-annotation.output +++ b/unified/extractor/tests/corpus/swift/variables/let-with-type-annotation.output @@ -2,27 +2,32 @@ let x: Int = 1 --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "x" - type: - type_annotation - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" - value: integer_literal "1" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + integerLiteralExpr + literal: integerLiteral "1" + pattern: + identifierPattern + identifier: identifier "x" + typeAnnotation: + typeAnnotation + colon: : + type: + identifierType + name: identifier "Int" --- diff --git a/unified/extractor/tests/corpus/swift/variables/multiple-bindings-on-one-line.output b/unified/extractor/tests/corpus/swift/variables/multiple-bindings-on-one-line.output index 7f202885b9be..9470a578ad62 100644 --- a/unified/extractor/tests/corpus/swift/variables/multiple-bindings-on-one-line.output +++ b/unified/extractor/tests/corpus/swift/variables/multiple-bindings-on-one-line.output @@ -2,23 +2,37 @@ let x = 1, y = 2 --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "x" - value: integer_literal "1" - property_binding - name: - pattern - bound_identifier: simple_identifier "y" - value: integer_literal "2" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + trailingComma: , + initializer: + initializerClause + equal: = + value: + integerLiteralExpr + literal: integerLiteral "1" + pattern: + identifierPattern + identifier: identifier "x" + patternBinding + initializer: + initializerClause + equal: = + value: + integerLiteralExpr + literal: integerLiteral "2" + pattern: + identifierPattern + identifier: identifier "y" --- diff --git a/unified/extractor/tests/corpus/swift/variables/property-with-willset-and-didset-observers.output b/unified/extractor/tests/corpus/swift/variables/property-with-willset-and-didset-observers.output index 5bf4b48efbcc..8071d5d52900 100644 --- a/unified/extractor/tests/corpus/swift/variables/property-with-willset-and-didset-observers.output +++ b/unified/extractor/tests/corpus/swift/variables/property-with-willset-and-didset-observers.output @@ -7,63 +7,93 @@ class C { --- -source_file - statement: - class_declaration - body: - class_body - member: - property_declaration - binding: - value_binding_pattern - mutability: var - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "x" - observers: - willset_didset_block - didset: - didset_clause - body: - block - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: simple_identifier "oldValue" - willset: - willset_clause - body: - block - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: simple_identifier "newValue" - type: - type_annotation - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" - value: integer_literal "0" - declaration_kind: class - name: type_identifier "C" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + classDecl + attributes: + name: identifier "C" + memberBlock: + memberBlock + leftBrace: { + rightBrace: } + members: + memberBlockItem + decl: + variableDecl + attributes: + modifiers: + bindingSpecifier: var + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + integerLiteralExpr + literal: integerLiteral "0" + pattern: + identifierPattern + identifier: identifier "x" + typeAnnotation: + typeAnnotation + colon: : + type: + identifierType + name: identifier "Int" + accessorBlock: + accessorBlock + accessors: + accessorDecl + accessorSpecifier: willSet + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + declReferenceExpr + baseName: identifier "newValue" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + accessorDecl + accessorSpecifier: didSet + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + declReferenceExpr + baseName: identifier "oldValue" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + leftBrace: { + rightBrace: } + modifiers: + classKeyword: class --- diff --git a/unified/extractor/tests/corpus/swift/variables/tuple-destructuring-binding.output b/unified/extractor/tests/corpus/swift/variables/tuple-destructuring-binding.output index 5709911171c1..6b6bd81115ed 100644 --- a/unified/extractor/tests/corpus/swift/variables/tuple-destructuring-binding.output +++ b/unified/extractor/tests/corpus/swift/variables/tuple-destructuring-binding.output @@ -2,28 +2,37 @@ let (a, b) = pair --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - kind: - tuple_pattern - item: - tuple_pattern_item +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + declReferenceExpr + baseName: identifier "pair" + pattern: + tuplePattern + leftParen: ( + rightParen: ) + elements: + tuplePatternElement + trailingComma: , pattern: - pattern - kind: simple_identifier "a" - tuple_pattern_item + identifierPattern + identifier: identifier "a" + tuplePatternElement pattern: - pattern - kind: simple_identifier "b" - value: simple_identifier "pair" + identifierPattern + identifier: identifier "b" --- diff --git a/unified/extractor/tests/corpus/swift/variables/var-binding.output b/unified/extractor/tests/corpus/swift/variables/var-binding.output index b7dc8e772700..63498105dc75 100644 --- a/unified/extractor/tests/corpus/swift/variables/var-binding.output +++ b/unified/extractor/tests/corpus/swift/variables/var-binding.output @@ -2,18 +2,26 @@ var x = 1 --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: var - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "x" - value: integer_literal "1" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: var + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + integerLiteralExpr + literal: integerLiteral "1" + pattern: + identifierPattern + identifier: identifier "x" --- diff --git a/unified/extractor/tests/corpus/swift/variables/var-without-initialiser.output b/unified/extractor/tests/corpus/swift/variables/var-without-initialiser.output index 692befea8553..d841ce2bb583 100644 --- a/unified/extractor/tests/corpus/swift/variables/var-without-initialiser.output +++ b/unified/extractor/tests/corpus/swift/variables/var-without-initialiser.output @@ -2,26 +2,26 @@ var x: Int --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: var - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "x" - type: - type_annotation - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: var + bindings: + patternBinding + pattern: + identifierPattern + identifier: identifier "x" + typeAnnotation: + typeAnnotation + colon: : + type: + identifierType + name: identifier "Int" --- From 046c88a329eaa4fd2d444a1b3470cd5f92cb0925 Mon Sep 17 00:00:00 2001 From: Taus Date: Thu, 23 Jul 2026 12:53:57 +0000 Subject: [PATCH 045/188] unified: Regenerate the enhanced getter/setter property corpus case Regenerate `types/property-with-getter-and-setter`, whose mapped AST now differs from the tree-sitter output: the backing `private var _v` retains its `private` modifier (`modifier "var"` + `modifier "private"`), whereas the tree-sitter path dropped it (its `visibility_modifier` node carried no text). The swift-syntax front-end preserves the modifier, so the mapped AST is strictly richer here. The raw (second) section is regenerated to the swift-syntax AST like the other cases; the mapped (third) section gains the retained `private` modifier. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../property-with-getter-and-setter.output | 159 +++++++++++------- 1 file changed, 94 insertions(+), 65 deletions(-) diff --git a/unified/extractor/tests/corpus/swift/types/property-with-getter-and-setter.output b/unified/extractor/tests/corpus/swift/types/property-with-getter-and-setter.output index a44c6fc3c127..951768cd8444 100644 --- a/unified/extractor/tests/corpus/swift/types/property-with-getter-and-setter.output +++ b/unified/extractor/tests/corpus/swift/types/property-with-getter-and-setter.output @@ -8,70 +8,97 @@ class Box { --- -source_file - statement: - class_declaration - body: - class_body - member: - property_declaration - binding: - value_binding_pattern - mutability: var - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "_v" - value: integer_literal "0" - modifiers: - modifiers - modifier: - visibility_modifier - property_declaration - binding: - value_binding_pattern - mutability: var - declarator: - property_binding - computed_value: - computed_property - accessor: - computed_getter - body: - block - statement: - control_transfer_statement - kind: return - result: simple_identifier "_v" - specifier: - getter_specifier - computed_setter - body: - block - statement: - assignment - operator: = - result: simple_identifier "newValue" - target: - directly_assignable_expression - expr: simple_identifier "_v" - specifier: - setter_specifier - name: - pattern - bound_identifier: simple_identifier "v" - type: - type_annotation - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" - declaration_kind: class - name: type_identifier "Box" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + classDecl + attributes: + name: identifier "Box" + memberBlock: + memberBlock + leftBrace: { + rightBrace: } + members: + memberBlockItem + decl: + variableDecl + attributes: + modifiers: + declModifier + name: private + bindingSpecifier: var + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + integerLiteralExpr + literal: integerLiteral "0" + pattern: + identifierPattern + identifier: identifier "_v" + memberBlockItem + decl: + variableDecl + attributes: + modifiers: + bindingSpecifier: var + bindings: + patternBinding + pattern: + identifierPattern + identifier: identifier "v" + typeAnnotation: + typeAnnotation + colon: : + type: + identifierType + name: identifier "Int" + accessorBlock: + accessorBlock + accessors: + accessorDecl + accessorSpecifier: get + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + returnStmt + expression: + declReferenceExpr + baseName: identifier "_v" + returnKeyword: return + accessorDecl + accessorSpecifier: set + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + assignmentExpr + equal: = + leftOperand: + declReferenceExpr + baseName: identifier "_v" + rightOperand: + declReferenceExpr + baseName: identifier "newValue" + leftBrace: { + rightBrace: } + modifiers: + classKeyword: class --- @@ -84,7 +111,9 @@ top_level name: identifier "Box" member: variable_declaration - modifier: modifier "var" + modifier: + modifier "var" + modifier "private" pattern: name_pattern identifier: identifier "_v" From c50bcbacc06b937b38dfb56d92593449158dc514 Mon Sep 17 00:00:00 2001 From: Taus Date: Thu, 23 Jul 2026 14:03:43 +0000 Subject: [PATCH 046/188] swift-syntax-rs: Degrade gracefully without a Swift toolchain MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `swift-syntax-rs` is a workspace member, so its build script runs on a plain `cargo check`/`fmt`/`clippy` at the repo root. Previously it panicked when `swift build` could not be run, breaking those Swift-free workflows for anyone without a Swift toolchain. Instead, when `swift build` cannot be spawned, emit a `cargo:warning` and skip the link directives rather than panicking. `cargo check`/`fmt`/`clippy` don't link, so they keep working; only `cargo build`/`cargo test` then fail, at link time — which is fair, since those genuinely need Swift (and CI builds go through Bazel). A Swift toolchain that is present but whose build fails is still surfaced as a hard error. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- unified/swift-syntax-rs/build.rs | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/unified/swift-syntax-rs/build.rs b/unified/swift-syntax-rs/build.rs index c599cdf4e70b..6a58ddb4d8da 100644 --- a/unified/swift-syntax-rs/build.rs +++ b/unified/swift-syntax-rs/build.rs @@ -24,20 +24,34 @@ fn main() { println!("cargo:rerun-if-env-changed=SWIFTC"); // Build the Swift FFI package as a release dynamic library. + // + // Degrade gracefully when there is no runnable Swift toolchain. This crate + // is a workspace member, so a plain `cargo check`/`fmt`/`clippy` at the repo + // root runs this build script; if `swift build` cannot even be spawned we + // emit a warning and skip the link directives rather than panicking, so + // those Swift-free workflows keep working. Only `cargo build`/`cargo test` + // then fail — at link time, which is fair: they genuinely need Swift (and CI + // builds go through Bazel anyway). A Swift toolchain that *is* present but + // whose build fails is still surfaced as a hard error below. let mut command = Command::new(swift_bin()); command .args(["build", "-c", "release"]) .current_dir(&swift_dir); apply_bare_repository_workaround(&mut command); - let status = command.status().unwrap_or_else(|e| { - panic!( - "failed to run `{swift} build`: {e}\n\ - Install a Swift toolchain (see https://www.swift.org/install/, e.g. via \ - swiftly) and ensure `swift` is on PATH, or set the `SWIFT` environment \ - variable to the `swift` executable. The pinned version is in `.swift-version`.", - swift = swift_bin(), - ) - }); + let status = match command.status() { + Ok(status) => status, + Err(e) => { + println!( + "cargo:warning=skipping the Swift FFI build: failed to run `{swift} build`: {e}. \ + Install a Swift toolchain (see https://www.swift.org/install/, e.g. via swiftly) \ + and ensure `swift` is on PATH, or set the `SWIFT` environment variable, to build \ + or test this crate. `cargo check`/`fmt`/`clippy` work without it. The pinned \ + version is in `.swift-version`.", + swift = swift_bin(), + ); + return; + } + }; assert!(status.success(), "`swift build` failed"); // Link against the freshly built dynamic library. From 17cbb4eb6b66115eefadd7134b2ca64b31d3d3c2 Mon Sep 17 00:00:00 2001 From: Taus Date: Fri, 24 Jul 2026 13:18:13 +0000 Subject: [PATCH 047/188] unified: Harden the external Swift parser integration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two fixes prompted by review of the swift-syntax switch-over. Parser resolution (`parse.rs`): `parse_bin` now resolves the `swift-syntax-parse` executable in priority order — the `CODEQL_EXTRACTOR_UNIFIED_SWIFT_SYNTAX_PARSE` override, then a copy next to the extractor executable (as a shipped extractor pack lays it out: `tools//{extractor,swift-syntax-parse}`), then a bare `PATH` lookup. This lets a packaged extractor find its parser with no environment setup. (Bundling the binary into the pack, together with its Swift runtime, is a separate follow-up.) Corpus test guard (`corpus_tests.rs`): `parser_available` previously treated *any* parser error as "unavailable" and skipped the entire corpus suite, so a parser that was present but crashed or emitted invalid JSON would silently skip the exact regressions the suite exists to catch. It now uses the new `binary_available`, which reports whether the *executable* can be launched (false only when it cannot be found, e.g. no Swift toolchain); a launchable-but-failing parser makes the suite run and fail. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../extractor/src/languages/swift/parse.rs | 54 +++++++++++++++++-- unified/extractor/tests/corpus_tests.rs | 16 ++++-- 2 files changed, 62 insertions(+), 8 deletions(-) diff --git a/unified/extractor/src/languages/swift/parse.rs b/unified/extractor/src/languages/swift/parse.rs index 21ef1b9ad215..c8633f1a27a5 100644 --- a/unified/extractor/src/languages/swift/parse.rs +++ b/unified/extractor/src/languages/swift/parse.rs @@ -16,9 +16,12 @@ use codeql_extractor::extractor::ParsedTree; use super::swift_adapter; /// Environment variable naming the `swift-syntax-parse` executable. When unset, -/// `swift-syntax-parse` is looked up on `PATH`. +/// the parser is resolved next to the extractor executable, then on `PATH`. const PARSE_BIN_ENV: &str = "CODEQL_EXTRACTOR_UNIFIED_SWIFT_SYNTAX_PARSE"; +/// Base name of the `swift-syntax-parse` executable as shipped / looked up. +const PARSE_BIN_NAME: &str = "swift-syntax-parse"; + /// Parse Swift `source` into a [`ParsedTree`] (a raw `yeast::Ast` plus /// side-channel `extra` tokens), ready to be desugared via `run_from_ast`. pub fn parse(source: &[u8]) -> Result { @@ -33,9 +36,54 @@ pub fn parse(source: &[u8]) -> Result { }) } -/// The `swift-syntax-parse` executable to invoke. +/// The `swift-syntax-parse` executable to invoke, resolved in priority order: +/// +/// 1. the `CODEQL_EXTRACTOR_UNIFIED_SWIFT_SYNTAX_PARSE` override, if set; +/// 2. a copy shipped next to the extractor executable — this is how the CodeQL +/// extractor pack lays it out (`tools//{extractor, +/// swift-syntax-parse}`), so a packaged extractor is self-contained with no +/// environment setup; +/// 3. a bare `swift-syntax-parse`, looked up on `PATH`. fn parse_bin() -> String { - std::env::var(PARSE_BIN_ENV).unwrap_or_else(|_| "swift-syntax-parse".to_string()) + if let Ok(bin) = std::env::var(PARSE_BIN_ENV) { + if !bin.is_empty() { + return bin; + } + } + if let Ok(exe) = std::env::current_exe() { + if let Some(sibling) = exe.parent().map(|dir| dir.join(PARSE_BIN_NAME)) { + if sibling.is_file() { + return sibling.to_string_lossy().into_owned(); + } + } + } + PARSE_BIN_NAME.to_string() +} + +/// Whether the `swift-syntax-parse` executable can be launched at all. +/// +/// This reports availability of the *executable*, deliberately not whether +/// parsing succeeds: a binary that launches but then crashes or emits invalid +/// JSON is still "available", so callers run and surface the failure rather +/// than silently skipping. Only a genuinely missing/unlaunchable binary (e.g. +/// no Swift toolchain is installed) reports `false`. +pub fn binary_available() -> bool { + match Command::new(parse_bin()) + .stdin(Stdio::null()) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .spawn() + { + Ok(mut child) => { + let _ = child.wait(); + true + } + Err(e) if e.kind() == std::io::ErrorKind::NotFound => false, + // Any other spawn failure (e.g. a permissions problem) is a genuine + // issue worth surfacing, so treat the parser as available and let the + // caller fail rather than masking it as "unavailable". + Err(_) => true, + } } /// Run the external parser, feeding `source` on stdin and returning its JSON diff --git a/unified/extractor/tests/corpus_tests.rs b/unified/extractor/tests/corpus_tests.rs index 66374e56526e..b2700b999b7c 100644 --- a/unified/extractor/tests/corpus_tests.rs +++ b/unified/extractor/tests/corpus_tests.rs @@ -20,12 +20,18 @@ fn update_mode_enabled() -> bool { .unwrap_or(false) } -/// Whether the external swift-syntax parser is available. When it is not (e.g. -/// no Swift toolchain / the `swift-syntax-parse` binary is not on `PATH` and -/// `CODEQL_EXTRACTOR_UNIFIED_SWIFT_SYNTAX_PARSE` is unset), the corpus test is -/// skipped rather than failed — it cannot run without the Swift-backed parser. +/// Whether the external swift-syntax parser is available. When the parser +/// binary genuinely cannot be found/launched (e.g. no Swift toolchain, and +/// neither `CODEQL_EXTRACTOR_UNIFIED_SWIFT_SYNTAX_PARSE` nor a `swift-syntax-parse` +/// on `PATH`), the corpus test is skipped rather than failed — it cannot run +/// without the Swift-backed parser. +/// +/// Crucially this checks only that the executable *launches*: a parser that is +/// present but crashes, emits invalid JSON, or otherwise regresses is +/// considered available, so the suite runs and fails (rather than silently +/// skipping the very failures CI needs to catch). fn parser_available() -> bool { - languages::swift_parse::parse(b"").is_ok() + languages::swift_parse::binary_available() } /// Parse a corpus `.output` file. The file holds a single test case made of From 7721ce2eba9612d50feb987e1f95729c3cc5fa18 Mon Sep 17 00:00:00 2001 From: Taus Date: Fri, 24 Jul 2026 15:47:34 +0000 Subject: [PATCH 048/188] unified: Add swift_node_types.yml to the extractor's compile_data `languages::swift::adapter` embeds the swift-syntax node-types schema with `include_str!("../../../swift_node_types.yml")`, but the file was never listed in the extractor's Bazel `compile_data`. The `cargo` build finds it on disk, so this went unnoticed, but the sandboxed Bazel build cannot see it and fails to compile the extractor. List it alongside `ast_types.yml`. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- unified/extractor/BUILD.bazel | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/unified/extractor/BUILD.bazel b/unified/extractor/BUILD.bazel index 0ef7f1b68b0e..13a3b6b287bc 100644 --- a/unified/extractor/BUILD.bazel +++ b/unified/extractor/BUILD.bazel @@ -7,7 +7,10 @@ codeql_rust_binary( name = "extractor", srcs = glob(["src/**/*.rs"]), aliases = aliases(), - compile_data = ["ast_types.yml"], + compile_data = [ + "ast_types.yml", + "swift_node_types.yml", + ], proc_macro_deps = all_crate_deps( proc_macro = True, ), From e3a0822248e31f675bcc962a22e63c837c351e70 Mon Sep 17 00:00:00 2001 From: Taus Date: Fri, 24 Jul 2026 15:48:00 +0000 Subject: [PATCH 049/188] unified: Package the swift-syntax parser in the extractor pack MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The extractor shells out to a separate `swift-syntax-parse` binary, but nothing placed it in the extractor pack, so a shipped Swift extraction failed at the first spawn. Package it next to the extractor, the same way `//swift/extractor` ships its Swift-linked binary: a small wrapper points the dynamic loader at its own directory and execs the real binary, whose Swift runtime libraries travel alongside it. - `swift-syntax-parse.sh`: wrapper that sets `LD_LIBRARY_PATH` / `DYLD_LIBRARY_PATH` to its directory and execs `swift-syntax-parse.real` (mirrors `swift/extractor/extractor.sh`). - `runtime.bzl`: a `swift_runtime_libs` rule that selects just the Linux Swift runtime shared objects (`usr/lib/swift/linux/*.so`) out of the full toolchain, so only they — not the whole toolchain — travel with the binary. - `swift-syntax-rs/BUILD.bazel`: the `rust_binary` becomes `swift-syntax-parse.real` and carries the runtime libraries as runfiles on Linux; a `sh_binary` (`swift-syntax-parse`) is the wrapper; `codeql_pkg_runfiles` flattens the three (wrapper, real binary, runtime) into one directory. - `BUILD.bazel`: ship that group under `tools/{CODEQL_PLATFORM}` next to the extractor, on the platforms where swift-syntax builds (Linux/macOS). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- unified/BUILD.bazel | 15 +++++++ unified/swift-syntax-rs/BUILD.bazel | 40 ++++++++++++++++--- unified/swift-syntax-rs/swift-syntax-parse.sh | 12 ++++++ 3 files changed, 62 insertions(+), 5 deletions(-) create mode 100755 unified/swift-syntax-rs/swift-syntax-parse.sh diff --git a/unified/BUILD.bazel b/unified/BUILD.bazel index e702fd251594..a54080b0542d 100644 --- a/unified/BUILD.bazel +++ b/unified/BUILD.bazel @@ -1,5 +1,6 @@ load("@rules_pkg//pkg:mappings.bzl", "pkg_filegroup") load("//misc/bazel:pkg.bzl", "codeql_pack", "codeql_pkg_files") +load("//misc/bazel:utils.bzl", "select_os") package(default_visibility = ["//visibility:public"]) @@ -46,12 +47,26 @@ codeql_pkg_files( prefix = "tools/{CODEQL_PLATFORM}", ) +# The Swift front-end parser (wrapper + real binary + bundled Swift runtime), +# shipped next to the extractor. Only on platforms where swift-syntax builds +# (Linux/macOS); elsewhere the group is empty so the pack still builds (Swift +# extraction is simply unavailable there). +pkg_filegroup( + name = "swift-syntax-parse-arch", + srcs = select_os( + posix = ["//unified/swift-syntax-rs:swift-syntax-parse-pkg"], + otherwise = [], + ), + prefix = "tools/{CODEQL_PLATFORM}", +) + codeql_pack( name = "unified", srcs = [ ":codeql-extractor-yml", ":dbscheme-group", ":extractor-arch", + ":swift-syntax-parse-arch", "//unified/tools", ], ) diff --git a/unified/swift-syntax-rs/BUILD.bazel b/unified/swift-syntax-rs/BUILD.bazel index 11484736ca8f..651cb09531e3 100644 --- a/unified/swift-syntax-rs/BUILD.bazel +++ b/unified/swift-syntax-rs/BUILD.bazel @@ -1,4 +1,6 @@ load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_library", "rust_test") +load("@rules_shell//shell:sh_binary.bzl", "sh_binary") +load("//misc/bazel:pkg.bzl", "codeql_pkg_runfiles") load(":swift_runtime.bzl", "swift_runtime_libs") load(":xcode_transition.bzl", "xcode_transition_swift_library") @@ -48,13 +50,19 @@ rust_library( ], ) +# The Swift front-end parser. We ship it like `//swift/extractor`: a small shell +# wrapper (`swift-syntax-parse`) sets `LD_LIBRARY_PATH`/`DYLD_LIBRARY_PATH` to its +# own directory and execs the real binary (`swift-syntax-parse.real`); the Swift +# runtime shared libraries are packaged alongside them. `parse.rs` resolves the +# wrapper as a sibling of the extractor executable. rust_binary( - name = "swift-syntax-parse", + name = "swift-syntax-parse.real", srcs = ["src/main.rs"], - # `rust_binary` doesn't copy the Swift runtime into runfiles the way - # `swift_binary` does. On Linux, ship the standalone toolchain's runtime; - # on macOS the OS provides it at `/usr/lib/swift` (rpath'd by - # `xcode_swift_toolchain`). + # Target name carries `.real` (invalid in a crate name), so set it explicitly. + crate_name = "swift_syntax_parse", + # On Linux, carry the toolchain's runtime shared libraries as runfiles so + # they get packaged next to the binary. On macOS the OS provides the Swift + # runtime, so nothing extra is bundled. data = select({ "@platforms//os:macos": [], "@platforms//os:linux": [":swift_runtime_libs"], @@ -64,6 +72,28 @@ rust_binary( deps = [":swift_syntax_rs"], ) +# `swift-syntax-parse` wrapper (see `swift-syntax-parse.sh`). Its runfiles carry +# the real binary and the runtime libraries; packaging flattens them into one +# directory. +sh_binary( + name = "swift-syntax-parse", + srcs = ["swift-syntax-parse.sh"], + data = [":swift-syntax-parse.real"], + target_compatible_with = _SWIFT_SUPPORTED_PLATFORMS, +) + +# Packaged form for the extractor pack: the wrapper (as `swift-syntax-parse`), +# the real binary, and the runtime libraries, flattened into one directory. +codeql_pkg_runfiles( + name = "swift-syntax-parse-pkg", + exes = [":swift-syntax-parse"], + # The `.sh` source is shipped as `swift-syntax-parse` (the wrapper); drop the + # original filename. + excludes = ["swift-syntax-parse.sh"], + target_compatible_with = _SWIFT_SUPPORTED_PLATFORMS, + visibility = ["//unified:__pkg__"], +) + rust_test( name = "swift_syntax_rs_test", size = "small", diff --git a/unified/swift-syntax-rs/swift-syntax-parse.sh b/unified/swift-syntax-rs/swift-syntax-parse.sh new file mode 100755 index 000000000000..811697c820c6 --- /dev/null +++ b/unified/swift-syntax-rs/swift-syntax-parse.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +# Wrapper that lets the shipped `swift-syntax-parse` find its Swift runtime +# libraries, which are packaged in the same directory as this script (and the +# real binary). Mirrors `swift/extractor/extractor.sh`. +if [[ "$(uname)" == Darwin ]]; then + export DYLD_LIBRARY_PATH=$(dirname "$0") +else + export LD_LIBRARY_PATH=$(dirname "$0") +fi + +exec -a "$0" "$0.real" "$@" From 2b871e92bb6d15d0138c2c7e49c85d3c440921e7 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Mon, 27 Jul 2026 12:55:04 +0200 Subject: [PATCH 050/188] Swift: Recurse calng submodules when computing extension indexes Fixes: https://github.com/github/codeql/issues/22224 --- swift/extractor/mangler/SwiftMangler.cpp | 23 +++++++++++++++-------- swift/extractor/mangler/SwiftMangler.h | 3 +++ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/swift/extractor/mangler/SwiftMangler.cpp b/swift/extractor/mangler/SwiftMangler.cpp index e7dbda6ba914..986cce695103 100644 --- a/swift/extractor/mangler/SwiftMangler.cpp +++ b/swift/extractor/mangler/SwiftMangler.cpp @@ -1,6 +1,5 @@ #include "swift/extractor/mangler/SwiftMangler.h" #include "swift/extractor/infra/SwiftDispatcher.h" -#include "swift/extractor/trap/generated/decl/TrapClasses.h" #include "swift/logging/SwiftLogging.h" #include @@ -170,15 +169,12 @@ void SwiftMangler::indexExtensionsAndFilePrivateValues(llvm::ArrayRefsubmodules()) { + index = indexClangSubmoduleExtensionsAndFilePrivateValues(submodule, moduleLoader, index); if (auto* swiftSubmodule = moduleLoader->getWrapperForModule(submodule)) { llvm::SmallVector children; swiftSubmodule->getTopLevelDecls(children); @@ -191,6 +187,17 @@ void SwiftMangler::indexClangExtensionsAndFilePrivateValues( } } } + return index; +} + +void SwiftMangler::indexClangExtensionsAndFilePrivateValues( + const clang::Module* clangModule, + swift::ClangModuleLoader* moduleLoader) { + if (!moduleLoader) { + return; + } + + indexClangSubmoduleExtensionsAndFilePrivateValues(clangModule, moduleLoader, 0u); } SwiftMangledName SwiftMangler::visitGenericTypeParamDecl(const swift::GenericTypeParamDecl* decl) { diff --git a/swift/extractor/mangler/SwiftMangler.h b/swift/extractor/mangler/SwiftMangler.h index 92175b5887b3..6b835348f14b 100644 --- a/swift/extractor/mangler/SwiftMangler.h +++ b/swift/extractor/mangler/SwiftMangler.h @@ -126,6 +126,9 @@ class SwiftMangler : private swift::TypeVisitor, bool isExtensionOrFilePrivateValue(const swift::Decl* decl); void indexExtensionsAndFilePrivateValues(llvm::ArrayRef siblings); + uint32_t indexClangSubmoduleExtensionsAndFilePrivateValues(const clang::Module* clangModule, + swift::ClangModuleLoader* moduleLoader, + uint32_t index); void indexClangExtensionsAndFilePrivateValues(const clang::Module* clangModule, swift::ClangModuleLoader* moduleLoader); ExtensionOrFilePrivateValueIndex getExtensionOrFilePrivateValueIndex(const swift::Decl* decl, From aa5a74fc442a06bbb2f97757d7f02126612d6184 Mon Sep 17 00:00:00 2001 From: JarLob Date: Sat, 25 Jul 2026 20:55:13 +0300 Subject: [PATCH 051/188] Fix merge_group event source mapping Map merge_group event payloads to their GitHub context so modeled untrusted fields are recognized, and add code-injection regression coverage. --- .../2026-07-27-merge-group-event-source.md | 4 ++++ actions/ql/lib/ext/config/context_event_map.yml | 1 + .../.github/workflows/merge_group_code_injection.yml | 10 ++++++++++ .../Security/CWE-094/CodeInjectionCritical.expected | 1 + .../Security/CWE-094/CodeInjectionMedium.expected | 2 ++ 5 files changed, 18 insertions(+) create mode 100644 actions/ql/lib/change-notes/2026-07-27-merge-group-event-source.md create mode 100644 actions/ql/test/query-tests/Security/CWE-094/.github/workflows/merge_group_code_injection.yml diff --git a/actions/ql/lib/change-notes/2026-07-27-merge-group-event-source.md b/actions/ql/lib/change-notes/2026-07-27-merge-group-event-source.md new file mode 100644 index 000000000000..41b39b6c452f --- /dev/null +++ b/actions/ql/lib/change-notes/2026-07-27-merge-group-event-source.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* GitHub Actions analysis now recognizes untrusted data in `github.event.merge_group` for workflows triggered by the `merge_group` event. \ No newline at end of file diff --git a/actions/ql/lib/ext/config/context_event_map.yml b/actions/ql/lib/ext/config/context_event_map.yml index 541ac8b9a8f6..311ea7cf5481 100644 --- a/actions/ql/lib/ext/config/context_event_map.yml +++ b/actions/ql/lib/ext/config/context_event_map.yml @@ -19,6 +19,7 @@ extensions: - ["gollum", "github.event.changes"] - ["pull_request_comment", "github.event.comment"] - ["pull_request_comment", "github.event.pull_request"] + - ["merge_group", "github.event.merge_group"] - ["pull_request_comment", "github.head_ref"] - ["pull_request_comment", "github.event.changes"] - ["pull_request_review", "github.event.pull_request"] diff --git a/actions/ql/test/query-tests/Security/CWE-094/.github/workflows/merge_group_code_injection.yml b/actions/ql/test/query-tests/Security/CWE-094/.github/workflows/merge_group_code_injection.yml new file mode 100644 index 000000000000..0ee85ed45e8a --- /dev/null +++ b/actions/ql/test/query-tests/Security/CWE-094/.github/workflows/merge_group_code_injection.yml @@ -0,0 +1,10 @@ +on: + merge_group: + types: [checks_requested] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Use merge group payload + run: echo '${{ toJSON(github.event) }}' \ No newline at end of file diff --git a/actions/ql/test/query-tests/Security/CWE-094/CodeInjectionCritical.expected b/actions/ql/test/query-tests/Security/CWE-094/CodeInjectionCritical.expected index 9bf7e9aa56db..bf1b6dec7fd5 100644 --- a/actions/ql/test/query-tests/Security/CWE-094/CodeInjectionCritical.expected +++ b/actions/ql/test/query-tests/Security/CWE-094/CodeInjectionCritical.expected @@ -400,6 +400,7 @@ nodes | .github/workflows/level0.yml:44:20:44:49 | github.event.issue.body | semmle.label | github.event.issue.body | | .github/workflows/level0.yml:69:35:69:66 | github.event.comment.body | semmle.label | github.event.comment.body | | .github/workflows/level1.yml:37:38:37:81 | github.event.workflow_run.head_branch | semmle.label | github.event.workflow_run.head_branch | +| .github/workflows/merge_group_code_injection.yml:10:21:10:47 | toJSON(github.event) | semmle.label | toJSON(github.event) | | .github/workflows/priv_pull_request.yml:14:21:14:57 | github.event.pull_request.body | semmle.label | github.event.pull_request.body | | .github/workflows/pull_request_review.yml:7:19:7:56 | github.event.pull_request.title | semmle.label | github.event.pull_request.title | | .github/workflows/pull_request_review.yml:8:19:8:55 | github.event.pull_request.body | semmle.label | github.event.pull_request.body | diff --git a/actions/ql/test/query-tests/Security/CWE-094/CodeInjectionMedium.expected b/actions/ql/test/query-tests/Security/CWE-094/CodeInjectionMedium.expected index 4bbe7da0aaf3..c3a79774aac3 100644 --- a/actions/ql/test/query-tests/Security/CWE-094/CodeInjectionMedium.expected +++ b/actions/ql/test/query-tests/Security/CWE-094/CodeInjectionMedium.expected @@ -400,6 +400,7 @@ nodes | .github/workflows/level0.yml:44:20:44:49 | github.event.issue.body | semmle.label | github.event.issue.body | | .github/workflows/level0.yml:69:35:69:66 | github.event.comment.body | semmle.label | github.event.comment.body | | .github/workflows/level1.yml:37:38:37:81 | github.event.workflow_run.head_branch | semmle.label | github.event.workflow_run.head_branch | +| .github/workflows/merge_group_code_injection.yml:10:21:10:47 | toJSON(github.event) | semmle.label | toJSON(github.event) | | .github/workflows/priv_pull_request.yml:14:21:14:57 | github.event.pull_request.body | semmle.label | github.event.pull_request.body | | .github/workflows/pull_request_review.yml:7:19:7:56 | github.event.pull_request.title | semmle.label | github.event.pull_request.title | | .github/workflows/pull_request_review.yml:8:19:8:55 | github.event.pull_request.body | semmle.label | github.event.pull_request.body | @@ -718,6 +719,7 @@ subpaths | .github/workflows/inter-job2.yml:45:20:45:53 | needs.job1.outputs.job_output | .github/workflows/inter-job2.yml:22:9:26:6 | Uses Step: source | .github/workflows/inter-job2.yml:45:20:45:53 | needs.job1.outputs.job_output | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/inter-job2.yml:45:20:45:53 | needs.job1.outputs.job_output | ${{needs.job1.outputs.job_output}} | | .github/workflows/inter-job4.yml:44:20:44:53 | needs.job1.outputs.job_output | .github/workflows/inter-job4.yml:22:9:26:6 | Uses Step: source | .github/workflows/inter-job4.yml:44:20:44:53 | needs.job1.outputs.job_output | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/inter-job4.yml:44:20:44:53 | needs.job1.outputs.job_output | ${{needs.job1.outputs.job_output}} | | .github/workflows/inter-job5.yml:45:20:45:53 | needs.job1.outputs.job_output | .github/workflows/inter-job5.yml:45:20:45:53 | needs.job1.outputs.job_output | .github/workflows/inter-job5.yml:45:20:45:53 | needs.job1.outputs.job_output | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/inter-job5.yml:45:20:45:53 | needs.job1.outputs.job_output | ${{needs.job1.outputs.job_output}} | +| .github/workflows/merge_group_code_injection.yml:10:21:10:47 | toJSON(github.event) | .github/workflows/merge_group_code_injection.yml:10:21:10:47 | toJSON(github.event) | .github/workflows/merge_group_code_injection.yml:10:21:10:47 | toJSON(github.event) | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/merge_group_code_injection.yml:10:21:10:47 | toJSON(github.event) | ${{ toJSON(github.event) }} | | .github/workflows/priv_pull_request.yml:14:21:14:57 | github.event.pull_request.body | .github/workflows/priv_pull_request.yml:14:21:14:57 | github.event.pull_request.body | .github/workflows/priv_pull_request.yml:14:21:14:57 | github.event.pull_request.body | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/priv_pull_request.yml:14:21:14:57 | github.event.pull_request.body | ${{ github.event.pull_request.body }} | | .github/workflows/push.yml:7:19:7:57 | github.event.commits[11].message | .github/workflows/push.yml:7:19:7:57 | github.event.commits[11].message | .github/workflows/push.yml:7:19:7:57 | github.event.commits[11].message | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/push.yml:7:19:7:57 | github.event.commits[11].message | ${{ github.event.commits[11].message }} | | .github/workflows/push.yml:8:19:8:62 | github.event.commits[11].author.email | .github/workflows/push.yml:8:19:8:62 | github.event.commits[11].author.email | .github/workflows/push.yml:8:19:8:62 | github.event.commits[11].author.email | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/push.yml:8:19:8:62 | github.event.commits[11].author.email | ${{ github.event.commits[11].author.email }} | From 148d9ccc58e2c6822461b55673e9d19065f0e77b Mon Sep 17 00:00:00 2001 From: Adrien Pessu <7055334+adrienpessu@users.noreply.github.com> Date: Mon, 27 Jul 2026 13:57:59 +0200 Subject: [PATCH 052/188] Update change-notes/1.26/analysis-javascript.md Co-authored-by: Asger F --- change-notes/1.26/analysis-javascript.md | 1 - 1 file changed, 1 deletion(-) diff --git a/change-notes/1.26/analysis-javascript.md b/change-notes/1.26/analysis-javascript.md index ef3a8e23ffd0..15edb607c70a 100644 --- a/change-notes/1.26/analysis-javascript.md +++ b/change-notes/1.26/analysis-javascript.md @@ -42,7 +42,6 @@ - [styled-components](https://www.npmjs.com/package/styled-components) - [throttle-debounce](https://www.npmjs.com/package/throttle-debounce) - [underscore](https://www.npmjs.com/package/underscore) - - [vue-router](https://www.npmjs.com/package/vue-router) * Analyzing files with the ".cjs" extension is now supported. * ES2021 features are now supported. From 4f30042b10ef8520e7a654ed6d1a04123b82321c Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Mon, 6 Jul 2026 17:59:55 +0200 Subject: [PATCH 053/188] Update expected test results after CLI/extractor changes --- .../integration-tests/windows/subst/file.expected | 14 +++++++------- go/ql/integration-tests/subst/file.expected | 2 +- java/ql/integration-tests/java/subst/file.expected | 6 +++--- .../ql/integration-tests/subst/file.expected | 4 ++-- python/ql/integration-tests/subst/file.expected | 2 +- ruby/ql/integration-tests/subst/file.expected | 2 +- rust/ql/integration-tests/subst/file.expected | 2 +- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/csharp/ql/integration-tests/windows/subst/file.expected b/csharp/ql/integration-tests/windows/subst/file.expected index 6421dce41212..d14faca364be 100644 --- a/csharp/ql/integration-tests/windows/subst/file.expected +++ b/csharp/ql/integration-tests/windows/subst/file.expected @@ -1,8 +1,8 @@ -| code/Program.cs:0:0:0:0 | code/Program.cs | | -| code/obj/Debug/net9.0/.NETCoreApp,Version=v9.0.AssemblyAttributes.cs:0:0:0:0 | code/obj/Debug/net9.0/.NETCoreApp,Version=v9.0.AssemblyAttributes.cs | | -| code/obj/Debug/net9.0/dotnet_build.AssemblyInfo.cs:0:0:0:0 | code/obj/Debug/net9.0/dotnet_build.AssemblyInfo.cs | | -| code/obj/Debug/net9.0/dotnet_build.GlobalUsings.g.cs:0:0:0:0 | code/obj/Debug/net9.0/dotnet_build.GlobalUsings.g.cs | | -| code/obj/Debug/net9.0/dotnet_build.dll:0:0:0:0 | code/obj/Debug/net9.0/dotnet_build.dll | | +| code/Program.cs:0:0:0:0 | code/Program.cs | relative | +| code/dotnet_build.csproj:0:0:0:0 | code/dotnet_build.csproj | relative | +| code/obj/Debug/net9.0/.NETCoreApp,Version=v9.0.AssemblyAttributes.cs:0:0:0:0 | code/obj/Debug/net9.0/.NETCoreApp,Version=v9.0.AssemblyAttributes.cs | relative | +| code/obj/Debug/net9.0/dotnet_build.AssemblyInfo.cs:0:0:0:0 | code/obj/Debug/net9.0/dotnet_build.AssemblyInfo.cs | relative | +| code/obj/Debug/net9.0/dotnet_build.GlobalUsings.g.cs:0:0:0:0 | code/obj/Debug/net9.0/dotnet_build.GlobalUsings.g.cs | relative | +| code/obj/Debug/net9.0/dotnet_build.dll:0:0:0:0 | code/obj/Debug/net9.0/dotnet_build.dll | relative | +| code/obj/dotnet_build.csproj.nuget.g.props:0:0:0:0 | code/obj/dotnet_build.csproj.nuget.g.props | relative | | file://:0:0:0:0 | | | -| file://Z:/dotnet_build.csproj:0:0:0:0 | Z:/dotnet_build.csproj | relative | -| file://Z:/obj/dotnet_build.csproj.nuget.g.props:0:0:0:0 | Z:/obj/dotnet_build.csproj.nuget.g.props | relative | diff --git a/go/ql/integration-tests/subst/file.expected b/go/ql/integration-tests/subst/file.expected index b86b34681e44..03c7e2c7feca 100644 --- a/go/ql/integration-tests/subst/file.expected +++ b/go/ql/integration-tests/subst/file.expected @@ -1 +1 @@ -| file://Z:/main.go:0:0:0:0 | Z:/main.go | relative | +| file://Z:/main.go:0:0:0:0 | Z:/main.go | | diff --git a/java/ql/integration-tests/java/subst/file.expected b/java/ql/integration-tests/java/subst/file.expected index 467876a74450..de0596287124 100644 --- a/java/ql/integration-tests/java/subst/file.expected +++ b/java/ql/integration-tests/java/subst/file.expected @@ -1,5 +1,5 @@ +| code/Test.class:0:0:0:0 | Test | relative | +| code/test1.java:0:0:0:0 | test1 | relative | | file://:0:0:0:0 | | | | file://:0:0:0:0 | | | -| file://Z:/Test.class:0:0:0:0 | Test | relative | -| file://Z:/test1.java:0:0:0:0 | test1 | relative | -| file://Z:/test2.kt:0:0:0:0 | test2 | relative | +| file://Z:/test2.kt:0:0:0:0 | test2 | | diff --git a/javascript/ql/integration-tests/subst/file.expected b/javascript/ql/integration-tests/subst/file.expected index 10416eb5e733..6d3663acac81 100644 --- a/javascript/ql/integration-tests/subst/file.expected +++ b/javascript/ql/integration-tests/subst/file.expected @@ -1,2 +1,2 @@ -| file://Z:/main.js:0:0:0:0 | Z:/main.js | relative | -| file://Z:/test.ts:0:0:0:0 | Z:/test.ts | relative | +| code/main.js:0:0:0:0 | code/main.js | relative | +| code/test.ts:0:0:0:0 | code/test.ts | relative | diff --git a/python/ql/integration-tests/subst/file.expected b/python/ql/integration-tests/subst/file.expected index 1bc4d03914a1..e001d4959bb5 100644 --- a/python/ql/integration-tests/subst/file.expected +++ b/python/ql/integration-tests/subst/file.expected @@ -1 +1 @@ -| code/main.py:0:0:0:0 | code/main.py | | +| code/main.py:0:0:0:0 | code/main.py | relative | diff --git a/ruby/ql/integration-tests/subst/file.expected b/ruby/ql/integration-tests/subst/file.expected index 47b324fea9e9..2962c283b484 100644 --- a/ruby/ql/integration-tests/subst/file.expected +++ b/ruby/ql/integration-tests/subst/file.expected @@ -1,2 +1,2 @@ -| code/test.rb:0:0:0:0 | code/test.rb | | +| code/test.rb:0:0:0:0 | code/test.rb | relative | | file://:0:0:0:0 | | | diff --git a/rust/ql/integration-tests/subst/file.expected b/rust/ql/integration-tests/subst/file.expected index c1ff73337f2a..407f50b5c0ea 100644 --- a/rust/ql/integration-tests/subst/file.expected +++ b/rust/ql/integration-tests/subst/file.expected @@ -1,2 +1,2 @@ -| code/test.rs:0:0:0:0 | code/test.rs | | +| code/test.rs:0:0:0:0 | code/test.rs | relative | | file://:0:0:0:0 | | | From 75ee4afec9dbab835e21f0ad3394899ff58030c1 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Tue, 7 Jul 2026 10:45:29 +0200 Subject: [PATCH 054/188] Kotlin: Resolve `subst`ed drives on Windows --- .../java/com/semmle/util/files/FileUtil.java | 7 +- .../com/semmle/util/files/SubstResolver.java | 77 +++++++++++++++++++ 2 files changed, 81 insertions(+), 3 deletions(-) create mode 100644 java/kotlin-extractor/src/main/java/com/semmle/util/files/SubstResolver.java diff --git a/java/kotlin-extractor/src/main/java/com/semmle/util/files/FileUtil.java b/java/kotlin-extractor/src/main/java/com/semmle/util/files/FileUtil.java index 79ce2d8d8d3d..19bdc786c5e2 100644 --- a/java/kotlin-extractor/src/main/java/com/semmle/util/files/FileUtil.java +++ b/java/kotlin-extractor/src/main/java/com/semmle/util/files/FileUtil.java @@ -1237,13 +1237,14 @@ public static String relativePathLink (File f, File base) /** * Try to convert a file into a canonical file. Handles the possible IO exception by just making - * the path absolute. + * the path absolute. Also resolves subst drives on Windows. */ public static File tryMakeCanonical (File f) { try { - return f.getCanonicalFile(); - } + // getCanonicalFile does not canonicalize subst drives on Windows, so do this separately. This + // is a no-op on non-Windows platforms. + return SubstResolver.resolve(f.getCanonicalFile()); } catch (IOException ignored) { Exceptions.ignore(ignored, "Can't log error: Could be too verbose."); return new File(simplifyPath(f)); diff --git a/java/kotlin-extractor/src/main/java/com/semmle/util/files/SubstResolver.java b/java/kotlin-extractor/src/main/java/com/semmle/util/files/SubstResolver.java new file mode 100644 index 000000000000..3d93c45234dc --- /dev/null +++ b/java/kotlin-extractor/src/main/java/com/semmle/util/files/SubstResolver.java @@ -0,0 +1,77 @@ +package com.semmle.util.files; + +import java.io.File; +import java.net.URISyntaxException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; + +/** + * Resolves Windows {@code subst}ed drive letters to their underlying paths. On non-Windows + * platforms, or when the native library failed to load, resolving will be a no-op. + */ +public class SubstResolver { + private static final boolean available; + + static { + boolean loaded = false; + if (File.separatorChar == '\\') { + String dist = System.getenv("CODEQL_DIST"); + if (dist != null && !dist.isEmpty()) { + try { + Path library = Paths.get(dist).resolve("tools") + .resolve("win64").resolve("canonicalize.dll").toAbsolutePath(); + System.load(library.toString()); + loaded = true; + } catch (RuntimeException | UnsatisfiedLinkError ignored) { + } + } + } + available = loaded; + } + + private SubstResolver() {} + + /** + * Given a drive root like {@code "X:\\"} (or {@code "X:/"}), returns the path that drive is + * {@code subst}ed to, or {@code null} if the drive root was not subst drive or if an internal + * error occurred. + */ + private static native String nativeResolveSubst(String driveRoot); + + /** + * If {@code f} is an absolute path starting with a {@code subst}ed drive letter, return an + * equivalent path with the drive letter replaced by its target. Otherwise return {@code f} + * unchanged. + */ + public static File resolve(File f) { + if (!available) { + return f; + } + String path = f.getPath(); + if (path.length() < 3 || path.charAt(1) != ':') { + return f; + } + char sep = path.charAt(2); + if (sep != '\\' && sep != '/') { + return f; + } + if (!isDriveLetter(path.charAt(0))) { + return f; + } + + String resolved = nativeResolveSubst(path.substring(0, 3)); + if (resolved == null) { + return f; + } + + // Append the remainder of the original path. The native side strips away + // any trailing separator. + return new File(resolved + path.substring(2)); + } + + private static boolean isDriveLetter(char c) { + return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); + } +} From 009ed608e0b40de6a3f1384d1601f8bd04f0cdbf Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Tue, 7 Jul 2026 11:33:48 +0200 Subject: [PATCH 055/188] Java: Update expected test results --- java/ql/integration-tests/java/subst/file.expected | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/integration-tests/java/subst/file.expected b/java/ql/integration-tests/java/subst/file.expected index de0596287124..02d4543cfcae 100644 --- a/java/ql/integration-tests/java/subst/file.expected +++ b/java/ql/integration-tests/java/subst/file.expected @@ -1,5 +1,5 @@ | code/Test.class:0:0:0:0 | Test | relative | | code/test1.java:0:0:0:0 | test1 | relative | +| code/test2.kt:0:0:0:0 | test2 | relative | | file://:0:0:0:0 | | | | file://:0:0:0:0 | | | -| file://Z:/test2.kt:0:0:0:0 | test2 | | From e06ce00d6068872d8f962cd53df8cf8c510c4517 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Tue, 7 Jul 2026 14:20:55 +0200 Subject: [PATCH 056/188] Go: Resolve `subst`ed drives on Windows --- MODULE.bazel | 2 +- go/extractor/extractor.go | 2 +- go/extractor/go.mod | 5 +- go/extractor/go.sum | 2 + go/extractor/util/BUILD.bazel | 11 +++- go/extractor/util/subst_other.go | 6 +++ go/extractor/util/subst_windows.go | 86 ++++++++++++++++++++++++++++++ 7 files changed, 110 insertions(+), 4 deletions(-) create mode 100644 go/extractor/util/subst_other.go create mode 100644 go/extractor/util/subst_windows.go diff --git a/MODULE.bazel b/MODULE.bazel index 8dd50d33c3f8..a5140fbd27c7 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -280,7 +280,7 @@ go_sdk.download(version = "1.26.5") go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps") go_deps.from_file(go_mod = "//go/extractor:go.mod") -use_repo(go_deps, "com_github_stretchr_testify", "org_golang_x_mod", "org_golang_x_tools") +use_repo(go_deps, "com_github_stretchr_testify", "org_golang_x_mod", "org_golang_x_sys", "org_golang_x_tools") ripunzip_archive = use_repo_rule("//misc/ripunzip:ripunzip.bzl", "ripunzip_archive") diff --git a/go/extractor/extractor.go b/go/extractor/extractor.go index 8c2178376141..4efa1daac569 100644 --- a/go/extractor/extractor.go +++ b/go/extractor/extractor.go @@ -770,7 +770,7 @@ func normalizedPath(ast *ast.File, fset *token.FileSet) string { if err != nil { return file } - return path + return util.ResolvePath(path) } // extractFile extracts AST information for the given file diff --git a/go/extractor/go.mod b/go/extractor/go.mod index b45815abbc95..c92b654c8c6c 100644 --- a/go/extractor/go.mod +++ b/go/extractor/go.mod @@ -13,7 +13,10 @@ require ( golang.org/x/tools v0.48.0 ) -require github.com/stretchr/testify v1.11.1 +require ( + github.com/stretchr/testify v1.11.1 + golang.org/x/sys v0.47.0 +) require ( github.com/davecgh/go-spew v1.1.1 // indirect diff --git a/go/extractor/go.sum b/go/extractor/go.sum index 76fbec137b47..b57649cbb351 100644 --- a/go/extractor/go.sum +++ b/go/extractor/go.sum @@ -10,6 +10,8 @@ golang.org/x/mod v0.38.0 h1:MECBjubtXD7yj4HrhIUcywNaGeNVUdfVnxmPajOk4yk= golang.org/x/mod v0.38.0/go.mod h1:V6Xz0pq8TQ3dGqVQ1FVHuelZpAL0uNhSkk9ogYP3c40= golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek= golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs= +golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/tools v0.48.0 h1:3+hClM1aLL5mjMKm5ovokw9epgRXPuu2tILgismM6RE= golang.org/x/tools v0.48.0/go.mod h1:08xX0orndb/F7jJxGDicx061tyd5pcMto75YMAXr6lk= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= diff --git a/go/extractor/util/BUILD.bazel b/go/extractor/util/BUILD.bazel index ccebf5ebd865..6d6c6c7a9933 100644 --- a/go/extractor/util/BUILD.bazel +++ b/go/extractor/util/BUILD.bazel @@ -9,11 +9,20 @@ go_library( "logging.go", "overlays.go", "semver.go", + "subst_other.go", + "subst_windows.go", "util.go", ], importpath = "github.com/github/codeql-go/extractor/util", visibility = ["//visibility:public"], - deps = ["@org_golang_x_mod//semver"], + deps = [ + "@org_golang_x_mod//semver", + ] + select({ + "@rules_go//go/platform:windows": [ + "@org_golang_x_sys//windows", + ], + "//conditions:default": [], + }), ) go_test( diff --git a/go/extractor/util/subst_other.go b/go/extractor/util/subst_other.go new file mode 100644 index 000000000000..b32420a7746e --- /dev/null +++ b/go/extractor/util/subst_other.go @@ -0,0 +1,6 @@ +//go:build !windows + +package util + +// ResolvePath is a no-op on non-Windows platforms. +func ResolvePath(path string) string { return path } diff --git a/go/extractor/util/subst_windows.go b/go/extractor/util/subst_windows.go new file mode 100644 index 000000000000..b31ee08dc225 --- /dev/null +++ b/go/extractor/util/subst_windows.go @@ -0,0 +1,86 @@ +//go:build windows + +package util + +import ( + "os" + "path/filepath" + "syscall" + "unsafe" + + "golang.org/x/sys/windows" +) + +var ( + dll *syscall.DLL + procResolve *syscall.Proc + procFree *syscall.Proc + available bool +) + +func init() { + dist := os.Getenv("CODEQL_DIST") + if dist == "" { + return + } + dllPath := filepath.Join(dist, "tools", "win64", "canonicalize.dll") + d, err := syscall.LoadDLL(dllPath) + if err != nil { + return + } + p, err := d.FindProc("resolve_subst") + if err != nil { + return + } + f, _ := d.FindProc("resolve_subst_free") + dll = d + procResolve = p + procFree = f + available = true +} + +// If "path" is an absolute path starting with a "subst"ed drive letter, return an +// equivalent path with the drive letter replaced by its target. Otherwise return +// "path" unchanged. +func ResolvePath(path string) string { + if len(path) < 3 { + return path + } + if path[1] != ':' { + return path + } + if path[2] != '\\' && path[2] != '/' { + return path + } + c := path[0] + if !((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) { + return path + } + + resolved, ok := resolveDrive(path[:3]) + if !ok { + return path + } + return resolved + path[2:] +} + +// Given a drive root like "X:\" (or "X:/"), returns the path that drive is +// "subst"ed to. Returns false if the drive is not "subst"ed or an error occurred. +func resolveDrive(driveRoot string) (string, bool) { + if !available { + return "", false + } + driveBytes, err := windows.ByteSliceFromString(driveRoot) + if err != nil { + return "", false + } + ret, _, _ := procResolve.Call(uintptr(unsafe.Pointer(&driveBytes[0]))) + if ret == 0 { + return "", false + } + result := windows.BytePtrToString((*byte)(unsafe.Pointer(ret))) + if procFree != nil { + procFree.Call(ret) + } + return result, true +} From c95a8ab9d22618b30d51fe84026ee662b76211c5 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Tue, 7 Jul 2026 16:07:00 +0200 Subject: [PATCH 057/188] Go: Update expected test results --- go/ql/integration-tests/subst/file.expected | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/ql/integration-tests/subst/file.expected b/go/ql/integration-tests/subst/file.expected index 03c7e2c7feca..96cce26cff5e 100644 --- a/go/ql/integration-tests/subst/file.expected +++ b/go/ql/integration-tests/subst/file.expected @@ -1 +1 @@ -| file://Z:/main.go:0:0:0:0 | Z:/main.go | | +| code/main.go:0:0:0:0 | code/main.go | relative | From 9976a7a3acdd05607112ea4e46268c1e1f6200b8 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Thu, 23 Jul 2026 13:22:43 +0200 Subject: [PATCH 058/188] Address review comments --- go/extractor/util/subst_windows.go | 7 ++++++- .../main/java/com/semmle/util/files/SubstResolver.java | 9 +++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/go/extractor/util/subst_windows.go b/go/extractor/util/subst_windows.go index b31ee08dc225..a64f21576fd9 100644 --- a/go/extractor/util/subst_windows.go +++ b/go/extractor/util/subst_windows.go @@ -30,9 +30,14 @@ func init() { } p, err := d.FindProc("resolve_subst") if err != nil { + d.Release() + return + } + f, err := d.FindProc("resolve_subst_free") + if err != nil { + d.Release() return } - f, _ := d.FindProc("resolve_subst_free") dll = d procResolve = p procFree = f diff --git a/java/kotlin-extractor/src/main/java/com/semmle/util/files/SubstResolver.java b/java/kotlin-extractor/src/main/java/com/semmle/util/files/SubstResolver.java index 3d93c45234dc..4d3975f19b34 100644 --- a/java/kotlin-extractor/src/main/java/com/semmle/util/files/SubstResolver.java +++ b/java/kotlin-extractor/src/main/java/com/semmle/util/files/SubstResolver.java @@ -18,7 +18,7 @@ public class SubstResolver { boolean loaded = false; if (File.separatorChar == '\\') { String dist = System.getenv("CODEQL_DIST"); - if (dist != null && !dist.isEmpty()) { + if (dist != null && !dist.isEmpty()) { try { Path library = Paths.get(dist).resolve("tools") .resolve("win64").resolve("canonicalize.dll").toAbsolutePath(); @@ -61,7 +61,12 @@ public static File resolve(File f) { return f; } - String resolved = nativeResolveSubst(path.substring(0, 3)); + String resolved; + try { + resolved = nativeResolveSubst(path.substring(0, 3)); + } catch (UnsatisfiedLinkError ignored) { + return f; + } if (resolved == null) { return f; } From 726705b7311301018d23eb42eba4af6ce3dc9761 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Mon, 27 Jul 2026 13:59:40 +0200 Subject: [PATCH 059/188] Address review comments --- .../src/main/java/com/semmle/util/files/SubstResolver.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/java/kotlin-extractor/src/main/java/com/semmle/util/files/SubstResolver.java b/java/kotlin-extractor/src/main/java/com/semmle/util/files/SubstResolver.java index 4d3975f19b34..017d4fb8399f 100644 --- a/java/kotlin-extractor/src/main/java/com/semmle/util/files/SubstResolver.java +++ b/java/kotlin-extractor/src/main/java/com/semmle/util/files/SubstResolver.java @@ -1,5 +1,6 @@ package com.semmle.util.files; +import com.semmle.util.exception.Exceptions; import java.io.File; import java.net.URISyntaxException; import java.nio.file.Path; @@ -16,6 +17,7 @@ public class SubstResolver { static { boolean loaded = false; + // Cheap check to see that we are on Windows. Avoids static initialization of {@code Env}. if (File.separatorChar == '\\') { String dist = System.getenv("CODEQL_DIST"); if (dist != null && !dist.isEmpty()) { @@ -25,6 +27,7 @@ public class SubstResolver { System.load(library.toString()); loaded = true; } catch (RuntimeException | UnsatisfiedLinkError ignored) { + Exceptions.ignore(ignored, "Fall back to resolution being a no-op."); } } } @@ -64,7 +67,9 @@ public static File resolve(File f) { String resolved; try { resolved = nativeResolveSubst(path.substring(0, 3)); - } catch (UnsatisfiedLinkError ignored) { + } catch (RuntimeException | UnsatisfiedLinkError ignored) { + Exceptions.ignore(ignored, "Fall back to resolution being a no-op."); + return f; } if (resolved == null) { From 147f67964cd9a52b40e6d4d0170e33416f353a68 Mon Sep 17 00:00:00 2001 From: JarLob Date: Mon, 27 Jul 2026 15:03:03 +0300 Subject: [PATCH 060/188] Test direct merge_group event source mapping --- .../CWE-094/.github/workflows/merge_group_code_injection.yml | 4 +++- .../Security/CWE-094/CodeInjectionCritical.expected | 1 + .../query-tests/Security/CWE-094/CodeInjectionMedium.expected | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/actions/ql/test/query-tests/Security/CWE-094/.github/workflows/merge_group_code_injection.yml b/actions/ql/test/query-tests/Security/CWE-094/.github/workflows/merge_group_code_injection.yml index 0ee85ed45e8a..02c9864bb7bf 100644 --- a/actions/ql/test/query-tests/Security/CWE-094/.github/workflows/merge_group_code_injection.yml +++ b/actions/ql/test/query-tests/Security/CWE-094/.github/workflows/merge_group_code_injection.yml @@ -7,4 +7,6 @@ jobs: runs-on: ubuntu-latest steps: - name: Use merge group payload - run: echo '${{ toJSON(github.event) }}' \ No newline at end of file + run: echo '${{ toJSON(github.event) }}' + - name: Use merge group head ref + run: echo '${{ github.event.merge_group.head_ref }}' \ No newline at end of file diff --git a/actions/ql/test/query-tests/Security/CWE-094/CodeInjectionCritical.expected b/actions/ql/test/query-tests/Security/CWE-094/CodeInjectionCritical.expected index bf1b6dec7fd5..26f1046ed04f 100644 --- a/actions/ql/test/query-tests/Security/CWE-094/CodeInjectionCritical.expected +++ b/actions/ql/test/query-tests/Security/CWE-094/CodeInjectionCritical.expected @@ -401,6 +401,7 @@ nodes | .github/workflows/level0.yml:69:35:69:66 | github.event.comment.body | semmle.label | github.event.comment.body | | .github/workflows/level1.yml:37:38:37:81 | github.event.workflow_run.head_branch | semmle.label | github.event.workflow_run.head_branch | | .github/workflows/merge_group_code_injection.yml:10:21:10:47 | toJSON(github.event) | semmle.label | toJSON(github.event) | +| .github/workflows/merge_group_code_injection.yml:12:21:12:60 | github.event.merge_group.head_ref | semmle.label | github.event.merge_group.head_ref | | .github/workflows/priv_pull_request.yml:14:21:14:57 | github.event.pull_request.body | semmle.label | github.event.pull_request.body | | .github/workflows/pull_request_review.yml:7:19:7:56 | github.event.pull_request.title | semmle.label | github.event.pull_request.title | | .github/workflows/pull_request_review.yml:8:19:8:55 | github.event.pull_request.body | semmle.label | github.event.pull_request.body | diff --git a/actions/ql/test/query-tests/Security/CWE-094/CodeInjectionMedium.expected b/actions/ql/test/query-tests/Security/CWE-094/CodeInjectionMedium.expected index c3a79774aac3..020edd104b3b 100644 --- a/actions/ql/test/query-tests/Security/CWE-094/CodeInjectionMedium.expected +++ b/actions/ql/test/query-tests/Security/CWE-094/CodeInjectionMedium.expected @@ -401,6 +401,7 @@ nodes | .github/workflows/level0.yml:69:35:69:66 | github.event.comment.body | semmle.label | github.event.comment.body | | .github/workflows/level1.yml:37:38:37:81 | github.event.workflow_run.head_branch | semmle.label | github.event.workflow_run.head_branch | | .github/workflows/merge_group_code_injection.yml:10:21:10:47 | toJSON(github.event) | semmle.label | toJSON(github.event) | +| .github/workflows/merge_group_code_injection.yml:12:21:12:60 | github.event.merge_group.head_ref | semmle.label | github.event.merge_group.head_ref | | .github/workflows/priv_pull_request.yml:14:21:14:57 | github.event.pull_request.body | semmle.label | github.event.pull_request.body | | .github/workflows/pull_request_review.yml:7:19:7:56 | github.event.pull_request.title | semmle.label | github.event.pull_request.title | | .github/workflows/pull_request_review.yml:8:19:8:55 | github.event.pull_request.body | semmle.label | github.event.pull_request.body | @@ -720,6 +721,7 @@ subpaths | .github/workflows/inter-job4.yml:44:20:44:53 | needs.job1.outputs.job_output | .github/workflows/inter-job4.yml:22:9:26:6 | Uses Step: source | .github/workflows/inter-job4.yml:44:20:44:53 | needs.job1.outputs.job_output | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/inter-job4.yml:44:20:44:53 | needs.job1.outputs.job_output | ${{needs.job1.outputs.job_output}} | | .github/workflows/inter-job5.yml:45:20:45:53 | needs.job1.outputs.job_output | .github/workflows/inter-job5.yml:45:20:45:53 | needs.job1.outputs.job_output | .github/workflows/inter-job5.yml:45:20:45:53 | needs.job1.outputs.job_output | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/inter-job5.yml:45:20:45:53 | needs.job1.outputs.job_output | ${{needs.job1.outputs.job_output}} | | .github/workflows/merge_group_code_injection.yml:10:21:10:47 | toJSON(github.event) | .github/workflows/merge_group_code_injection.yml:10:21:10:47 | toJSON(github.event) | .github/workflows/merge_group_code_injection.yml:10:21:10:47 | toJSON(github.event) | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/merge_group_code_injection.yml:10:21:10:47 | toJSON(github.event) | ${{ toJSON(github.event) }} | +| .github/workflows/merge_group_code_injection.yml:12:21:12:60 | github.event.merge_group.head_ref | .github/workflows/merge_group_code_injection.yml:12:21:12:60 | github.event.merge_group.head_ref | .github/workflows/merge_group_code_injection.yml:12:21:12:60 | github.event.merge_group.head_ref | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/merge_group_code_injection.yml:12:21:12:60 | github.event.merge_group.head_ref | ${{ github.event.merge_group.head_ref }} | | .github/workflows/priv_pull_request.yml:14:21:14:57 | github.event.pull_request.body | .github/workflows/priv_pull_request.yml:14:21:14:57 | github.event.pull_request.body | .github/workflows/priv_pull_request.yml:14:21:14:57 | github.event.pull_request.body | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/priv_pull_request.yml:14:21:14:57 | github.event.pull_request.body | ${{ github.event.pull_request.body }} | | .github/workflows/push.yml:7:19:7:57 | github.event.commits[11].message | .github/workflows/push.yml:7:19:7:57 | github.event.commits[11].message | .github/workflows/push.yml:7:19:7:57 | github.event.commits[11].message | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/push.yml:7:19:7:57 | github.event.commits[11].message | ${{ github.event.commits[11].message }} | | .github/workflows/push.yml:8:19:8:62 | github.event.commits[11].author.email | .github/workflows/push.yml:8:19:8:62 | github.event.commits[11].author.email | .github/workflows/push.yml:8:19:8:62 | github.event.commits[11].author.email | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/push.yml:8:19:8:62 | github.event.commits[11].author.email | ${{ github.event.commits[11].author.email }} | From 90c1ddfd497d7397679edec95338f410999a6583 Mon Sep 17 00:00:00 2001 From: yoff Date: Mon, 27 Jul 2026 16:24:46 +0200 Subject: [PATCH 061/188] Update python/ql/lib/ide-contextual-queries/printCfg.ql Co-authored-by: Tom Hvitved --- python/ql/lib/ide-contextual-queries/printCfg.ql | 1 - 1 file changed, 1 deletion(-) diff --git a/python/ql/lib/ide-contextual-queries/printCfg.ql b/python/ql/lib/ide-contextual-queries/printCfg.ql index 6e325e84bb7b..819022c750c9 100644 --- a/python/ql/lib/ide-contextual-queries/printCfg.ql +++ b/python/ql/lib/ide-contextual-queries/printCfg.ql @@ -8,7 +8,6 @@ */ import semmle.python.Files as Files -// import semmle.python.Scope import semmle.python.controlflow.internal.AstNodeImpl external string selectedSourceFile(); From 1068add0ed97454bb72e980cd4b21d742a3a55c2 Mon Sep 17 00:00:00 2001 From: yoff Date: Tue, 21 Jul 2026 13:39:48 +0200 Subject: [PATCH 062/188] Split tests with disjoint concerns --- .../ql/test/library-tests/ControlFlow/bindings/starred.py | 4 ++++ .../ControlFlow/bindings/{walrus_starred.py => walrus.py} | 7 +------ 2 files changed, 5 insertions(+), 6 deletions(-) create mode 100644 python/ql/test/library-tests/ControlFlow/bindings/starred.py rename python/ql/test/library-tests/ControlFlow/bindings/{walrus_starred.py => walrus.py} (62%) diff --git a/python/ql/test/library-tests/ControlFlow/bindings/starred.py b/python/ql/test/library-tests/ControlFlow/bindings/starred.py new file mode 100644 index 000000000000..ac38c74ef122 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/starred.py @@ -0,0 +1,4 @@ +# Starred-target edge cases — wired in the new CFG. + +# Starred target in a Tuple LHS. +*head, tail = [1, 2, 3] # $ cfgdefines=head cfgdefines=tail diff --git a/python/ql/test/library-tests/ControlFlow/bindings/walrus_starred.py b/python/ql/test/library-tests/ControlFlow/bindings/walrus.py similarity index 62% rename from python/ql/test/library-tests/ControlFlow/bindings/walrus_starred.py rename to python/ql/test/library-tests/ControlFlow/bindings/walrus.py index 5c0c1bd83191..d370fd342dcd 100644 --- a/python/ql/test/library-tests/ControlFlow/bindings/walrus_starred.py +++ b/python/ql/test/library-tests/ControlFlow/bindings/walrus.py @@ -1,4 +1,4 @@ -# Walrus and starred-target edge cases — wired in the new CFG. +# Walrus edge cases — wired in the new CFG. # Walrus in expression context. if (y := 5) > 0: # $ cfgdefines=y @@ -7,8 +7,3 @@ # Walrus in a comprehension. The comprehension introduces a synthetic # `.0` parameter bound to the iterable. _ = [w for _ in range(3) if (w := 1)] # $ cfgdefines=_ cfgdefines=w cfgdefines=.0 - -# Starred target in a Tuple LHS. -*head, tail = [1, 2, 3] # $ cfgdefines=head cfgdefines=tail - - From 2c0ed98cb2a3fa90a1e31612d3795cfb829460c7 Mon Sep 17 00:00:00 2001 From: yoff Date: Tue, 21 Jul 2026 13:41:29 +0200 Subject: [PATCH 063/188] python: remove uninformative headers --- .../evaluation-order/NewCfgBasicBlockAnnotationGap.ql | 1 - .../ControlFlow/evaluation-order/NewCfgBasicBlockOrdering.ql | 1 - .../ControlFlow/evaluation-order/NewCfgConsecutiveTimestamps.ql | 1 - .../ControlFlow/evaluation-order/NewCfgNeverReachable.ql | 1 - .../ControlFlow/evaluation-order/NewCfgNoBackwardFlow.ql | 1 - .../ControlFlow/evaluation-order/NewCfgNoSharedReachable.ql | 1 - .../ControlFlow/evaluation-order/NewCfgStrictForward.ql | 1 - 7 files changed, 7 deletions(-) diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockAnnotationGap.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockAnnotationGap.ql index 80dd759a3651..52fbda8cfaa3 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockAnnotationGap.ql +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockAnnotationGap.ql @@ -1,7 +1,6 @@ /** * New-CFG version of BasicBlockAnnotationGap. * - * Original: * Checks that within a basic block, if a node is annotated then its * successor is also annotated (or excluded). A gap in annotations * within a basic block indicates a missing annotation, since there diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockOrdering.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockOrdering.ql index f06d08d937e3..27288dcaa67b 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockOrdering.ql +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockOrdering.ql @@ -1,7 +1,6 @@ /** * New-CFG version of BasicBlockOrdering. * - * Original: * Checks that within a single basic block, annotations appear in * increasing minimum-timestamp order. */ diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutiveTimestamps.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutiveTimestamps.ql index 8e52663d6eaf..657fc80437cd 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutiveTimestamps.ql +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutiveTimestamps.ql @@ -1,7 +1,6 @@ /** * New-CFG version of ConsecutiveTimestamps. * - * Original: * Checks that consecutive annotated nodes have consecutive timestamps: * for each annotation with timestamp `a`, some CFG node for that annotation * must have a next annotation containing `a + 1`. diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNeverReachable.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNeverReachable.ql index 6949b2cc6e9b..f10df59c34e0 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNeverReachable.ql +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNeverReachable.ql @@ -1,7 +1,6 @@ /** * New-CFG version of NeverReachable. * - * Original: * Checks that expressions annotated with `t.never` either have no CFG * node, or if they do, that the node is not reachable from its scope's * entry (including within the same basic block). diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBackwardFlow.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBackwardFlow.ql index 442ca5f5456c..a45e01b30c15 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBackwardFlow.ql +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBackwardFlow.ql @@ -1,7 +1,6 @@ /** * New-CFG version of NoBackwardFlow. * - * Original: * Checks that time never flows backward between consecutive timer annotations * in the CFG. For each pair of consecutive annotated nodes (A -> B), there must * exist timestamps a in A and b in B with a < b. diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoSharedReachable.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoSharedReachable.ql index 5a1a1aba2a7a..30d250d32abe 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoSharedReachable.ql +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoSharedReachable.ql @@ -1,7 +1,6 @@ /** * New-CFG version of NoSharedReachable. * - * Original: * Checks that two annotations sharing a timestamp value are on * mutually exclusive CFG paths (neither can reach the other). */ diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgStrictForward.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgStrictForward.ql index ebbc60346db0..c93d181d8529 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgStrictForward.ql +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgStrictForward.ql @@ -1,7 +1,6 @@ /** * New-CFG version of StrictForward. * - * Original: * Stronger version of NoBackwardFlow: for consecutive annotated nodes * A -> B that both have a single timestamp (non-loop code) and B does * NOT dominate A (forward edge), requires max(A) < min(B). From aa305c20b12e835820e751c874159ba91b0110e2 Mon Sep 17 00:00:00 2001 From: yoff Date: Thu, 23 Jul 2026 18:52:24 +0200 Subject: [PATCH 064/188] Python: mark definition of type ascription as `SPURIOUS` --- .../ql/test/library-tests/ControlFlow/bindings/type_params.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/test/library-tests/ControlFlow/bindings/type_params.py b/python/ql/test/library-tests/ControlFlow/bindings/type_params.py index 2bd34dc3f0ee..ae48ccf130b1 100644 --- a/python/ql/test/library-tests/ControlFlow/bindings/type_params.py +++ b/python/ql/test/library-tests/ControlFlow/bindings/type_params.py @@ -8,7 +8,7 @@ def func[T](x: T) -> T: # $ cfgdefines=func cfgdefines=x class Box[T]: # $ cfgdefines=Box - item: T # $ cfgdefines=item + item: T # $ SPURIOUS: cfgdefines=item # Multi-parameter, with bound and variadics. From 05aa8debc442151180fefd7c1daf4a99258e09a4 Mon Sep 17 00:00:00 2001 From: yoff Date: Mon, 27 Jul 2026 16:23:30 +0200 Subject: [PATCH 065/188] python: make `LoopStmt` final --- .../python/controlflow/internal/AstNodeImpl.qll | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll b/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll index 8199008e88c9..891ba8c1318b 100644 --- a/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll +++ b/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll @@ -593,8 +593,10 @@ module Ast implements AstSig { } /** A loop statement. */ - class LoopStmt extends Stmt { - LoopStmt() { + final class LoopStmt = LoopStmtImpl; + + abstract private class LoopStmtImpl extends Stmt { + LoopStmtImpl() { this = TPyStmt(any(Py::While w)) or this = TPyStmt(any(Py::For f)) @@ -605,7 +607,7 @@ module Ast implements AstSig { } /** A `while` loop statement. */ - class WhileStmt extends LoopStmt { + class WhileStmt extends LoopStmtImpl { private Py::While whileStmt; WhileStmt() { this = TPyStmt(whileStmt) } @@ -630,21 +632,21 @@ module Ast implements AstSig { /** * A `do-while` loop statement. Python has no do-while construct. */ - class DoStmt extends LoopStmt { + class DoStmt extends LoopStmtImpl { DoStmt() { none() } Expr getCondition() { none() } } /** An `until` loop. Python has no `until` loop. */ - class UntilStmt extends LoopStmt { + class UntilStmt extends LoopStmtImpl { UntilStmt() { none() } Expr getCondition() { none() } } /** A C-style `for` loop. Python has no C-style for loop. */ - class ForStmt extends LoopStmt { + class ForStmt extends LoopStmtImpl { ForStmt() { none() } AstNode getInit(int index) { none() } @@ -655,7 +657,7 @@ module Ast implements AstSig { } /** A for-each loop (`for x in iterable:`). */ - class ForeachStmt extends LoopStmt { + class ForeachStmt extends LoopStmtImpl { private Py::For forStmt; ForeachStmt() { this = TPyStmt(forStmt) } From fa94dc9a329d593c8f8069b551138d3219ba7e5b Mon Sep 17 00:00:00 2001 From: yoff Date: Mon, 27 Jul 2026 16:31:41 +0200 Subject: [PATCH 066/188] Python: remove reference to line numbers --- .../ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll b/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll index 891ba8c1318b..31bcf19b4346 100644 --- a/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll +++ b/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll @@ -156,7 +156,7 @@ module Ast implements AstSig { /** * A parameter of a callable. * - * Modelled per the C# template (`csharp/.../ControlFlowGraph.qll:147-156`): + * Modelled per the C# template (`csharp/.../ControlFlowGraph.qll`): * each Python parameter (the `Py::Parameter` AST node, which is a `Name` * or — Python 2 only — a `Tuple` in store context) becomes a CFG node * at a stable position in the enclosing callable's entry sequence. From 665e046ae6d505e4e0d2ce80c1530815c91d258f Mon Sep 17 00:00:00 2001 From: yoff Date: Mon, 27 Jul 2026 17:00:35 +0200 Subject: [PATCH 067/188] Python: add overlay annotations to inlined predicates --- python/ql/lib/semmle/python/controlflow/internal/Cfg.qll | 2 ++ 1 file changed, 2 insertions(+) diff --git a/python/ql/lib/semmle/python/controlflow/internal/Cfg.qll b/python/ql/lib/semmle/python/controlflow/internal/Cfg.qll index ec8b44d5a821..4dc6ac20d042 100644 --- a/python/ql/lib/semmle/python/controlflow/internal/Cfg.qll +++ b/python/ql/lib/semmle/python/controlflow/internal/Cfg.qll @@ -85,10 +85,12 @@ class ControlFlowNode extends CfgImpl::ControlFlowNode { } /** Holds if this strictly dominates `other`. */ + overlay[caller?] pragma[inline] predicate strictlyDominates(ControlFlowNode other) { super.strictlyDominates(other) } /** Holds if this dominates `other` (reflexively). */ + overlay[caller?] pragma[inline] predicate dominates(ControlFlowNode other) { super.dominates(other) } From 3206ab0be19038c6d91bc34493d6c3c4101067c2 Mon Sep 17 00:00:00 2001 From: yoff Date: Mon, 27 Jul 2026 17:37:36 +0200 Subject: [PATCH 068/188] Python: address CodeQL alerts --- .../controlflow/internal/AstNodeImpl.qll | 18 +++++++++--------- .../semmle/python/controlflow/internal/Cfg.qll | 2 +- .../evaluation-order/NewCfgAllLiveReachable.ql | 1 - .../NewCfgAnnotationHasCfgNode.ql | 1 - .../NewCfgBasicBlockAnnotationGap.ql | 1 - .../NewCfgBasicBlockOrdering.ql | 1 - .../evaluation-order/NewCfgBranchTimestamps.ql | 3 +-- .../NewCfgConsecutivePredecessorTimestamps.ql | 1 - .../NewCfgConsecutiveTimestamps.ql | 1 - .../evaluation-order/NewCfgImpl.qll | 4 +--- .../evaluation-order/NewCfgNeverReachable.ql | 1 - .../evaluation-order/NewCfgNoBackwardFlow.ql | 1 - .../evaluation-order/NewCfgNoBasicBlock.ql | 1 - .../NewCfgNoSharedReachable.ql | 1 - .../evaluation-order/NewCfgStrictForward.ql | 1 - .../evaluation-order/OldCfgImpl.qll | 8 ++++---- 16 files changed, 16 insertions(+), 30 deletions(-) diff --git a/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll b/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll index 31bcf19b4346..21dbad68b814 100644 --- a/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll +++ b/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll @@ -156,7 +156,7 @@ module Ast implements AstSig { /** * A parameter of a callable. * - * Modelled per the C# template (`csharp/.../ControlFlowGraph.qll`): + * modeled per the C# template (`csharp/.../ControlFlowGraph.qll`): * each Python parameter (the `Py::Parameter` AST node, which is a `Name` * or — Python 2 only — a `Tuple` in store context) becomes a CFG node * at a stable position in the enclosing callable's entry sequence. @@ -766,7 +766,7 @@ module Ast implements AstSig { /** * A `from m import *` statement. Evaluates the module expression but * binds no name (the bindings happen by side-effect at runtime, which - * is not modelled at the CFG level). + * is not modeled at the CFG level). */ additional class ImportStarStmt extends Stmt { private Py::ImportStar imp; @@ -921,7 +921,7 @@ module Ast implements AstSig { * latter flattens a tuple of exception types (`except (A, B):`) into * its individual elements, which would yield several patterns for one * handler and violate the shared CFG's single-pattern-per-catch - * contract. The raw child is the one tuple node, modelling the + * contract. The raw child is the one tuple node, modeling the * runtime's single `isinstance(exc, (A, B))` test. */ AstNode getPattern() { @@ -1231,7 +1231,7 @@ module Ast implements AstSig { } /** - * An `import x.y` module expression. Modelled as a leaf — the dotted + * An `import x.y` module expression. modeled as a leaf — the dotted * name is just a string. */ additional class ImportExpression extends Expr { @@ -1629,9 +1629,9 @@ private module Input implements InputSig1, InputSig2 { private string assertThrowTag() { result = "[assert-throw]" } /** - * Holds if the AST node `n` may raise an exception at runtime as part of + * Holds if the expression node `e` may raise an exception at runtime as part of * its normal evaluation (not via an explicit `raise`/`assert`, which are - * modelled separately). + * modeled separately). * * The set mirrors what the legacy CFG used to flag implicitly: function * calls (anything can raise), attribute access (`AttributeError`), @@ -1640,7 +1640,7 @@ private module Input implements InputSig1, InputSig2 { * (`ImportError`/`ModuleNotFoundError`), and generator/coroutine * suspension points (`await`/`yield`/`yield from`). * - * Bare `Name` reads are intentionally excluded — modelling every name + * Bare `Name` reads are intentionally excluded — modeling every name * read as `mayThrow` would explode CFG edge count for negligible * analysis value. `BoolExpr`/`IfExp` containers are also excluded; the * operands they evaluate contribute their own exception edges. @@ -1677,7 +1677,7 @@ private module Input implements InputSig1, InputSig2 { private predicate stmtMayThrow(Py::Stmt s) { s instanceof Py::ImportStar } /** - * Holds if `n` is syntactically inside the body, handlers, `else`, or + * Holds if `py` is syntactically inside the body, handlers, `else`, or * `finally` of a `try` statement (or the body of a `with` statement, * which compiles to an implicit try/finally for `__exit__`) in the * same scope. @@ -1701,7 +1701,7 @@ private module Input implements InputSig1, InputSig2 { * `exprMayThrow` and `stmtMayThrow` for the included AST classes. * * Restricted to nodes inside a `try`/`with` statement: matches Java's - * approach of only modelling exception flow where it can be observed + * approach of only modeling exception flow where it can be observed * by local handling. */ private predicate mayThrow(Ast::AstNode n) { diff --git a/python/ql/lib/semmle/python/controlflow/internal/Cfg.qll b/python/ql/lib/semmle/python/controlflow/internal/Cfg.qll index 4dc6ac20d042..b102c71391fe 100644 --- a/python/ql/lib/semmle/python/controlflow/internal/Cfg.qll +++ b/python/ql/lib/semmle/python/controlflow/internal/Cfg.qll @@ -859,7 +859,7 @@ class ExceptGroupFlowNode extends ControlFlowNode { ControlFlowNode getName() { result = this } } -/** Abstract base class for sequence nodes (tuple, list). */ +/** A control flow node corresponding to a sequence (tuple, list). */ abstract class SequenceNode extends ControlFlowNode { /** Gets the `n`th element of this sequence. */ abstract ControlFlowNode getElement(int n); diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAllLiveReachable.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAllLiveReachable.ql index 75f02d14a9cb..883b266c82eb 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAllLiveReachable.ql +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAllLiveReachable.ql @@ -1,7 +1,6 @@ /** New-CFG version of AllLiveReachable. */ import python -import TimerUtils import NewCfgImpl private module Utils = EvalOrderCfgUtils; diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAnnotationHasCfgNode.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAnnotationHasCfgNode.ql index 4b1d82e27e67..bf97a0793222 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAnnotationHasCfgNode.ql +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAnnotationHasCfgNode.ql @@ -5,7 +5,6 @@ */ import python -import TimerUtils import NewCfgImpl private module Utils = EvalOrderCfgUtils; diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockAnnotationGap.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockAnnotationGap.ql index 52fbda8cfaa3..e12ab8ff5ef6 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockAnnotationGap.ql +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockAnnotationGap.ql @@ -11,7 +11,6 @@ */ import python -import TimerUtils import NewCfgImpl private module Utils = EvalOrderCfgUtils; diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockOrdering.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockOrdering.ql index 27288dcaa67b..b8254a8e8646 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockOrdering.ql +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockOrdering.ql @@ -6,7 +6,6 @@ */ import python -import TimerUtils import NewCfgImpl private module Utils = EvalOrderCfgUtils; diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBranchTimestamps.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBranchTimestamps.ql index cfd8ffb4e4bd..2dc8ae144dcd 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBranchTimestamps.ql +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBranchTimestamps.ql @@ -16,7 +16,7 @@ * * `match` statements: each `case` body is a syntactically distinct * sub-tree, and the branches don't reconverge through a common * annotation point in the timeline; - * * `try` / `with` and `raise` / `assert`: exception edges are modelled + * * `try` / `with` and `raise` / `assert`: exception edges are modeled * as true/false but flow to syntactically distinct handlers, with no * reconvergence in the linear annotation order; * * short-circuit `and` / `or` (`BoolExpr`): the branches reconverge at @@ -33,7 +33,6 @@ */ import python -import TimerUtils import NewCfgImpl private module Utils = EvalOrderCfgUtils; diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutivePredecessorTimestamps.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutivePredecessorTimestamps.ql index 3feacae264e5..0eb8ad5a414e 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutivePredecessorTimestamps.ql +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutivePredecessorTimestamps.ql @@ -8,7 +8,6 @@ */ import python -import TimerUtils import NewCfgImpl private module Utils = EvalOrderCfgUtils; diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutiveTimestamps.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutiveTimestamps.ql index 657fc80437cd..8fc13c9acba9 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutiveTimestamps.ql +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutiveTimestamps.ql @@ -14,7 +14,6 @@ */ import python -import TimerUtils import NewCfgImpl private module Utils = EvalOrderCfgUtils; diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgImpl.qll b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgImpl.qll index cbecb2da19d9..ae27e8f16a0e 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgImpl.qll +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgImpl.qll @@ -74,9 +74,7 @@ module NewCfg implements EvalOrderCfgSig { Py::Scope getScope() { result = NewControlFlowNode.super.getEnclosingCallable().asScope() } - BasicBlock getBasicBlock() { - exists(NewBasicBlock bb, int i | bb.getNode(i) = this and result = bb) - } + BasicBlock getBasicBlock() { exists(NewBasicBlock bb | bb.getNode(_) = this and result = bb) } } /** diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNeverReachable.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNeverReachable.ql index f10df59c34e0..db324e6ee76b 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNeverReachable.ql +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNeverReachable.ql @@ -7,7 +7,6 @@ */ import python -import TimerUtils import NewCfgImpl private module Utils = EvalOrderCfgUtils; diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBackwardFlow.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBackwardFlow.ql index a45e01b30c15..8cb0dfb143b0 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBackwardFlow.ql +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBackwardFlow.ql @@ -7,7 +7,6 @@ */ import python -import TimerUtils import NewCfgImpl private module Utils = EvalOrderCfgUtils; diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBasicBlock.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBasicBlock.ql index e07890f72502..c0fc86b5130b 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBasicBlock.ql +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBasicBlock.ql @@ -5,7 +5,6 @@ */ import python -import TimerUtils import NewCfgImpl private module Utils = EvalOrderCfgUtils; diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoSharedReachable.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoSharedReachable.ql index 30d250d32abe..dd174d6d913c 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoSharedReachable.ql +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoSharedReachable.ql @@ -6,7 +6,6 @@ */ import python -import TimerUtils import NewCfgImpl private module Utils = EvalOrderCfgUtils; diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgStrictForward.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgStrictForward.ql index c93d181d8529..e7f4a12ff813 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgStrictForward.ql +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgStrictForward.ql @@ -7,7 +7,6 @@ */ import python -import TimerUtils import NewCfgImpl private module Utils = EvalOrderCfgUtils; diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/OldCfgImpl.qll b/python/ql/test/library-tests/ControlFlow/evaluation-order/OldCfgImpl.qll index fc52c8dd3ed1..cb7bbb495b87 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/OldCfgImpl.qll +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/OldCfgImpl.qll @@ -3,14 +3,14 @@ * Python control flow graph. */ -private import python as Py +private import python as PY import TimerUtils /** Existing Python CFG implementation of the evaluation-order signature. */ module OldCfg implements EvalOrderCfgSig { - class CfgNode = Py::ControlFlowNode; + class CfgNode = PY::ControlFlowNode; - class BasicBlock = Py::BasicBlock; + class BasicBlock = PY::BasicBlock; - CfgNode scopeGetEntryNode(Py::Scope s) { result = s.getEntryNode() } + CfgNode scopeGetEntryNode(PY::Scope s) { result = s.getEntryNode() } } From ba26e1d02988497cac75d48a5c905d08b0bbc270 Mon Sep 17 00:00:00 2001 From: Taus Date: Mon, 27 Jul 2026 15:48:06 +0000 Subject: [PATCH 069/188] unified: Add corpus tests for nested types Adds a few tests that validate that higher-order functions are parsed correctly into the commonAST representation. Also removes a redundant assignment to `ctx.in_function_type` that happend after all translations had taken place (and so nothing would actually read this field). --- .../extractor/src/languages/swift/swift.rs | 1 - .../functions/nested-function-type.output | 156 ++++++++++++++++++ .../functions/nested-function-type.swift | 3 + 3 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 unified/extractor/tests/corpus/swift/functions/nested-function-type.output create mode 100644 unified/extractor/tests/corpus/swift/functions/nested-function-type.swift diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index 32252f8a0228..ef3672e1b91c 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -1007,7 +1007,6 @@ fn translation_rules() -> Vec> { for p in params { out.extend(ctx.translate(p)?); } - ctx.in_function_type = false; tree!((function_type_expr parameter: {out} return_type: {ret})) } ), diff --git a/unified/extractor/tests/corpus/swift/functions/nested-function-type.output b/unified/extractor/tests/corpus/swift/functions/nested-function-type.output new file mode 100644 index 000000000000..d9ce0cd7a976 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/functions/nested-function-type.output @@ -0,0 +1,156 @@ +typealias NestedFunction = ((Int) -> Bool) -> Bool + +typealias MixedParametersAndTuples = ((Int) -> Bool, String) -> (Bool, Int) + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + typeAliasDecl + attributes: + name: identifier "NestedFunction" + modifiers: + initializer: + typeInitializerClause + equal: = + value: + functionType + leftParen: ( + rightParen: ) + parameters: + tupleTypeElement + type: + functionType + leftParen: ( + rightParen: ) + parameters: + tupleTypeElement + type: + identifierType + name: identifier "Int" + returnClause: + returnClause + arrow: -> + type: + identifierType + name: identifier "Bool" + returnClause: + returnClause + arrow: -> + type: + identifierType + name: identifier "Bool" + typealiasKeyword: typealias + codeBlockItem + item: + typeAliasDecl + attributes: + name: identifier "MixedParametersAndTuples" + modifiers: + initializer: + typeInitializerClause + equal: = + value: + functionType + leftParen: ( + rightParen: ) + parameters: + tupleTypeElement + trailingComma: , + type: + functionType + leftParen: ( + rightParen: ) + parameters: + tupleTypeElement + type: + identifierType + name: identifier "Int" + returnClause: + returnClause + arrow: -> + type: + identifierType + name: identifier "Bool" + tupleTypeElement + type: + identifierType + name: identifier "String" + returnClause: + returnClause + arrow: -> + type: + tupleType + leftParen: ( + rightParen: ) + elements: + tupleTypeElement + trailingComma: , + type: + identifierType + name: identifier "Bool" + tupleTypeElement + type: + identifierType + name: identifier "Int" + typealiasKeyword: typealias + +--- + +top_level + body: + block + stmt: + type_alias_declaration + name: identifier "NestedFunction" + type: + function_type_expr + parameter: + parameter + type: + function_type_expr + parameter: + parameter + type: + named_type_expr + name: identifier "Int" + return_type: + named_type_expr + name: identifier "Bool" + return_type: + named_type_expr + name: identifier "Bool" + type_alias_declaration + name: identifier "MixedParametersAndTuples" + type: + function_type_expr + parameter: + parameter + type: + function_type_expr + parameter: + parameter + type: + named_type_expr + name: identifier "Int" + return_type: + named_type_expr + name: identifier "Bool" + parameter + type: + named_type_expr + name: identifier "String" + return_type: + tuple_type_expr + element: + tuple_type_element + type: + named_type_expr + name: identifier "Bool" + tuple_type_element + type: + named_type_expr + name: identifier "Int" diff --git a/unified/extractor/tests/corpus/swift/functions/nested-function-type.swift b/unified/extractor/tests/corpus/swift/functions/nested-function-type.swift new file mode 100644 index 000000000000..b19128965f34 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/functions/nested-function-type.swift @@ -0,0 +1,3 @@ +typealias NestedFunction = ((Int) -> Bool) -> Bool + +typealias MixedParametersAndTuples = ((Int) -> Bool, String) -> (Bool, Int) From 9b4de2bfb693688c81b55a088b6cb733f4641449 Mon Sep 17 00:00:00 2001 From: yoff Date: Mon, 27 Jul 2026 17:52:24 +0200 Subject: [PATCH 070/188] Python: add tests for short-circuiting comparisons - Both the old and new CFG model this incorrectly right now. - Added ConsecutivePredecessorTimestamps.ql for the old CFG for symmetry. --- .../ConsecutivePredecessorTimestamps.expected | 13 +++++++ .../ConsecutivePredecessorTimestamps.ql | 22 +++++++++++ .../ConsecutiveTimestamps.expected | 1 + ...gConsecutivePredecessorTimestamps.expected | 2 +- .../NewCfgConsecutiveTimestamps.expected | 1 + .../evaluation-order/test_comparison.py | 37 +++++++++++++++++++ 6 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 python/ql/test/library-tests/ControlFlow/evaluation-order/ConsecutivePredecessorTimestamps.expected create mode 100644 python/ql/test/library-tests/ControlFlow/evaluation-order/ConsecutivePredecessorTimestamps.ql create mode 100644 python/ql/test/library-tests/ControlFlow/evaluation-order/test_comparison.py diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/ConsecutivePredecessorTimestamps.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/ConsecutivePredecessorTimestamps.expected new file mode 100644 index 000000000000..9dc286490613 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/ConsecutivePredecessorTimestamps.expected @@ -0,0 +1,13 @@ +| test_boolean.py:9:10:9:43 | BoolExpr | $@ in $@ has no consecutive predecessor (expected 1) | test_boolean.py:9:59:9:59 | IntegerLiteral | Timestamp 2 | test_boolean.py:7:1:7:27 | Function test_and_both_sides | test_and_both_sides | +| test_boolean.py:15:10:15:43 | BoolExpr | $@ in $@ has no consecutive predecessor (expected 0) | test_boolean.py:15:50:15:50 | IntegerLiteral | Timestamp 1 | test_boolean.py:13:1:13:30 | Function test_and_short_circuit | test_and_short_circuit | +| test_boolean.py:21:10:21:42 | BoolExpr | $@ in $@ has no consecutive predecessor (expected 0) | test_boolean.py:21:49:21:49 | IntegerLiteral | Timestamp 1 | test_boolean.py:19:1:19:29 | Function test_or_short_circuit | test_or_short_circuit | +| test_boolean.py:27:10:27:34 | BoolExpr | $@ in $@ has no consecutive predecessor (expected 1) | test_boolean.py:27:50:27:50 | IntegerLiteral | Timestamp 2 | test_boolean.py:25:1:25:26 | Function test_or_both_sides | test_or_both_sides | +| test_boolean.py:40:10:40:61 | BoolExpr | $@ in $@ has no consecutive predecessor (expected 2) | test_boolean.py:40:86:40:86 | IntegerLiteral | Timestamp 3 | test_boolean.py:38:1:38:24 | Function test_chained_and | test_chained_and | +| test_boolean.py:46:10:46:61 | BoolExpr | $@ in $@ has no consecutive predecessor (expected 2) | test_boolean.py:46:86:46:86 | IntegerLiteral | Timestamp 3 | test_boolean.py:44:1:44:23 | Function test_chained_or | test_chained_or | +| test_boolean.py:52:10:52:95 | BoolExpr | $@ in $@ has no consecutive predecessor (expected 3) | test_boolean.py:52:120:52:120 | IntegerLiteral | Timestamp 4 | test_boolean.py:50:1:50:25 | Function test_mixed_and_or | test_mixed_and_or | +| test_boolean.py:52:11:52:47 | BoolExpr | $@ in $@ has no consecutive predecessor (expected 1) | test_boolean.py:52:63:52:63 | IntegerLiteral | Timestamp 2 | test_boolean.py:50:1:50:25 | Function test_mixed_and_or | test_mixed_and_or | +| test_boolean.py:52:78:52:79 | IntegerLiteral | $@ in $@ has no consecutive predecessor (expected 2) | test_boolean.py:52:85:52:85 | IntegerLiteral | Timestamp 3 | test_boolean.py:50:1:50:25 | Function test_mixed_and_or | test_mixed_and_or | +| test_comparison.py:37:6:37:41 | Compare | $@ in $@ has no consecutive predecessor (expected 1) | test_comparison.py:37:48:37:48 | IntegerLiteral | Timestamp 2 | test_comparison.py:32:1:32:32 | Function test_three_short_circuit | test_three_short_circuit | +| test_if.py:96:9:96:9 | x | $@ in $@ has no consecutive predecessor (expected 1) | test_if.py:96:15:96:15 | IntegerLiteral | Timestamp 2 | test_if.py:93:1:93:34 | Function test_if_compound_condition | test_if_compound_condition | +| test_if.py:96:9:96:29 | BoolExpr | $@ in $@ has no consecutive predecessor (expected 3) | test_if.py:96:36:96:36 | IntegerLiteral | Timestamp 4 | test_if.py:93:1:93:34 | Function test_if_compound_condition | test_if_compound_condition | +| test_if.py:99:13:99:13 | IntegerLiteral | $@ in $@ has no consecutive predecessor (expected 4) | test_if.py:99:19:99:19 | IntegerLiteral | Timestamp 5 | test_if.py:93:1:93:34 | Function test_if_compound_condition | test_if_compound_condition | diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/ConsecutivePredecessorTimestamps.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/ConsecutivePredecessorTimestamps.ql new file mode 100644 index 000000000000..6d90605d685f --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/ConsecutivePredecessorTimestamps.ql @@ -0,0 +1,22 @@ +/** + * Checks that each annotated node (except the minimum timestamp) has a + * predecessor annotation with timestamp `a - 1`. This is the reverse of + * ConsecutiveTimestamps: it catches nodes that are reachable but arrived + * at from the wrong place (skipping an intermediate node). + * + * Only applies to functions where all annotations are in the function's + * own scope (excludes tests with generators, async, comprehensions, or + * lambdas that have annotations in nested scopes). + */ + +import OldCfgImpl + +private module Utils = EvalOrderCfgUtils; + +private import Utils +private import Utils::CfgTests + +from TimerAnnotation ann, int a +where consecutivePredecessorTimestamps(ann, a) +select ann, "$@ in $@ has no consecutive predecessor (expected " + (a - 1) + ")", + ann.getTimestampExpr(a), "Timestamp " + a, ann.getTestFunction(), ann.getTestFunction().getName() diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/ConsecutiveTimestamps.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/ConsecutiveTimestamps.expected index ed22c971ecbc..c354396586e7 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/ConsecutiveTimestamps.expected +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/ConsecutiveTimestamps.expected @@ -7,6 +7,7 @@ | test_boolean.py:52:11:52:47 | BoolExpr | $@ in $@ has no consecutive successor (expected 3) | test_boolean.py:52:63:52:63 | IntegerLiteral | Timestamp 2 | test_boolean.py:50:1:50:25 | Function test_mixed_and_or | test_mixed_and_or | | test_boolean.py:52:27:52:31 | False | $@ in $@ has no consecutive successor (expected 2) | test_boolean.py:52:37:52:37 | IntegerLiteral | Timestamp 1 | test_boolean.py:50:1:50:25 | Function test_mixed_and_or | test_mixed_and_or | | test_boolean.py:52:78:52:79 | IntegerLiteral | $@ in $@ has no consecutive successor (expected 4) | test_boolean.py:52:85:52:85 | IntegerLiteral | Timestamp 3 | test_boolean.py:50:1:50:25 | Function test_mixed_and_or | test_mixed_and_or | +| test_comparison.py:37:17:37:17 | IntegerLiteral | $@ in $@ has no consecutive successor (expected 2) | test_comparison.py:37:23:37:23 | IntegerLiteral | Timestamp 1 | test_comparison.py:32:1:32:32 | Function test_three_short_circuit | test_three_short_circuit | | test_if.py:95:9:95:13 | False | $@ in $@ has no consecutive successor (expected 2) | test_if.py:95:19:95:19 | IntegerLiteral | Timestamp 1 | test_if.py:93:1:93:34 | Function test_if_compound_condition | test_if_compound_condition | | test_if.py:96:9:96:29 | BoolExpr | $@ in $@ has no consecutive successor (expected 5) | test_if.py:96:36:96:36 | IntegerLiteral | Timestamp 4 | test_if.py:93:1:93:34 | Function test_if_compound_condition | test_if_compound_condition | | test_if.py:96:22:96:22 | y | $@ in $@ has no consecutive successor (expected 4) | test_if.py:96:28:96:28 | IntegerLiteral | Timestamp 3 | test_if.py:93:1:93:34 | Function test_if_compound_condition | test_if_compound_condition | diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutivePredecessorTimestamps.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutivePredecessorTimestamps.expected index 8b137891791f..0c9e31f37713 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutivePredecessorTimestamps.expected +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutivePredecessorTimestamps.expected @@ -1 +1 @@ - +| test_comparison.py:37:6:37:41 | Compare | $@ in $@ has no consecutive predecessor (expected 1) | test_comparison.py:37:48:37:48 | IntegerLiteral | Timestamp 2 | test_comparison.py:32:1:32:32 | Function test_three_short_circuit | test_three_short_circuit | diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutiveTimestamps.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutiveTimestamps.expected index e69de29bb2d1..6fdcfc40c4a5 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutiveTimestamps.expected +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutiveTimestamps.expected @@ -0,0 +1 @@ +| test_comparison.py:37:17:37:17 | IntegerLiteral | $@ in $@ has no consecutive successor (expected 2) | test_comparison.py:37:23:37:23 | IntegerLiteral | Timestamp 1 | test_comparison.py:32:1:32:32 | Function test_three_short_circuit | test_three_short_circuit | diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/test_comparison.py b/python/ql/test/library-tests/ControlFlow/evaluation-order/test_comparison.py new file mode 100644 index 000000000000..978663171663 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/test_comparison.py @@ -0,0 +1,37 @@ +"""Comparisons and evaluation order. + +Comparison operands are evaluated left-to-right, followed by the comparison +node itself. Annotations record the *run-time* evaluation order, so this file +self-validates under CPython (``python3 test_comparison.py``). + +Python short-circuits *chained* comparisons (in ``a < b < c`` the operand ``c`` +is skipped once ``a < b`` is false), whereas the control-flow graph +conservatively evaluates every operand. That divergence cannot be expressed in +a single annotation, so the affected CFG queries report it (captured in the +ConsecutiveTimestamps and NewCfgConsecutivePredecessorTimestamps .expected +files). +""" + +from timer import test, dead + + +@test +def test_two(t): + # Both operands, then the comparison. + (1 @ t[0] < 0 @ t[1]) @ t[2] + + +@test +def test_three(t): + # Chained comparison, all comparisons hold: operands left-to-right, then + # the comparison. Run time and CFG agree. + (1 @ t[0] < 2 @ t[1] < 3 @ t[2]) @ t[3] + + +@test +def test_three_short_circuit(t): + # ``1 > 2`` is false, so at run time Python short-circuits and never + # evaluates ``3``; the comparison is reached at timestamp 2. The CFG still + # evaluates ``3`` (dead at run time), which is why the CFG queries report a + # gap around this comparison. + (1 @ t[0] > 2 @ t[1] < 3 @ t[dead(2)]) @ t[2] From b5136b6fa3ecccfbe06334071bcd37d1aaaee99b Mon Sep 17 00:00:00 2001 From: Adrien Pessu <7055334+adrienpessu@users.noreply.github.com> Date: Mon, 27 Jul 2026 18:03:56 +0200 Subject: [PATCH 071/188] JS: Move Vue Composition API and useRoute source config to data extensions Move the Vue Composition API flow summaries (ref, shallowRef, toRef, reactive) and the vue-router useRoute() remote-source modeling out of Vue.qll and into the vue.model.yml data extension as summaryModel and sourceModel rows. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 928b6965-7da7-4da8-b6e6-debb96036108 --- .../2026-07-16-vue-router-useRoute-query.md | 2 +- javascript/ql/lib/ext/vue.model.yml | 13 +++++++ .../lib/semmle/javascript/frameworks/Vue.qll | 36 ------------------- .../frameworks/Vue/tests.expected | 1 + 4 files changed, 15 insertions(+), 37 deletions(-) diff --git a/javascript/ql/lib/change-notes/2026-07-16-vue-router-useRoute-query.md b/javascript/ql/lib/change-notes/2026-07-16-vue-router-useRoute-query.md index 91f8d0a204d4..973af15aae03 100644 --- a/javascript/ql/lib/change-notes/2026-07-16-vue-router-useRoute-query.md +++ b/javascript/ql/lib/change-notes/2026-07-16-vue-router-useRoute-query.md @@ -1,5 +1,5 @@ --- category: minorAnalysis --- -* The query parameter of Vue Router's `useRoute()` Composition API is now recognized as a client-side remote flow source. +* The route object returned by Vue Router's `useRoute()` Composition API is now recognized as a client-side remote flow source, covering its `query`, `params`, `path`, `fullPath`, and `hash` members. These members are additionally reported under the corresponding `browser-url-query`, `browser-url-path`, and `browser-url-fragment` threat models. * Added flow models for Vue's `ref`, `shallowRef`, `toRef`, `reactive`, and `computed` Composition API helpers. diff --git a/javascript/ql/lib/ext/vue.model.yml b/javascript/ql/lib/ext/vue.model.yml index 9ff24265a8d4..17d473210335 100644 --- a/javascript/ql/lib/ext/vue.model.yml +++ b/javascript/ql/lib/ext/vue.model.yml @@ -1,8 +1,21 @@ extensions: + - addsTo: + pack: codeql/javascript-all + extensible: sourceModel + data: + # `useRoute()` — Vue Router's Composition API returns a route object whose URL-derived + # members are client-side remote flow sources. + - ["vue-router", "Member[useRoute].ReturnValue.Member[params,path,fullPath]", "browser-url-path"] + - ["vue-router", "Member[useRoute].ReturnValue.Member[query]", "browser-url-query"] + - ["vue-router", "Member[useRoute].ReturnValue.Member[hash]", "browser-url-fragment"] - addsTo: pack: codeql/javascript-all extensible: summaryModel data: + # `ref`, `shallowRef`, `toRef` — the wrapped argument flows to `.value`. + - ["vue", "Member[ref,shallowRef,toRef]", "Argument[0]", "ReturnValue.Member[value]", "value"] + # `reactive` — the wrapped argument taints the returned reactive object. + - ["vue", "Member[reactive]", "Argument[0]", "ReturnValue", "taint"] # `computed(() => ...)` — function overload: the getter's return value flows to `.value`. - ["vue", "Member[computed]", "Argument[0].ReturnValue", "ReturnValue.Member[value]", "value"] # `computed({ get() { ... } })` — object overload: the `get` getter's return value flows to `.value`. diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Vue.qll b/javascript/ql/lib/semmle/javascript/frameworks/Vue.qll index 35a66debf4f1..59490a2d5c65 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Vue.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Vue.qll @@ -35,40 +35,6 @@ module Vue { result = any(GlobalVueEntryPoint e).getANode() } - /** - * Models data flow through Vue Composition API helpers. - * - * Note that `computed` is not modeled here but in the `vue.model.yml` data - * extension, because its object overload (`computed({ get() { ... } })`) - * requires callback flow synthesis that data extensions support but a - * hand-written `SummarizedCallable` does not. - */ - overlay[local?] - private class VueCompositionApiSummary extends DataFlow::SummarizedCallable::Range { - string name; - - VueCompositionApiSummary() { - name = ["ref", "shallowRef", "toRef", "reactive"] and - this = "vue." + name - } - - override predicate propagatesFlow(string input, string output, boolean preservesValue) { - name = ["ref", "shallowRef", "toRef"] and - input = "Argument[0]" and - output = "ReturnValue.Member[value]" and - preservesValue = true - or - name = "reactive" and - input = "Argument[0]" and - output = "ReturnValue" and - preservesValue = false - } - - override DataFlow::InvokeNode getACall() { - result = API::moduleImport("vue").getMember(name).getACall() - } - } - /** * Gets a reference to the 'Vue' object. */ @@ -686,8 +652,6 @@ module Vue { t.start() and ( exists(API::Node router | router = API::moduleImport("vue-router") | - result = router.getMember("useRoute").getACall() - or result = router.getInstance().getMember("currentRoute").asSource() or result = diff --git a/javascript/ql/test/library-tests/frameworks/Vue/tests.expected b/javascript/ql/test/library-tests/frameworks/Vue/tests.expected index 01ff68751781..4ba7ba338637 100644 --- a/javascript/ql/test/library-tests/frameworks/Vue/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/Vue/tests.expected @@ -240,6 +240,7 @@ threatModelSource | router.js:39:5:39:14 | from.query | remote | | router.js:43:5:43:12 | to.query | remote | | router.js:44:5:44:14 | from.query | remote | +| router.js:47:1:47:16 | useRoute().query | browser-url-query | | router.js:47:1:47:16 | useRoute().query | remote | | single-component-file-1.vue:7:45:7:54 | this.input | view-component-input | | single-file-component-3-script.js:5:42:5:51 | this.input | view-component-input | From 0dd3ad64d5e13f9d84fa99dc6ac19e5d27729b38 Mon Sep 17 00:00:00 2001 From: JarLob Date: Sat, 25 Jul 2026 17:58:09 +0300 Subject: [PATCH 072/188] Fixed `Schedule` event mapping --- .../config/externally_triggereable_events.yml | 2 +- .../2026-07-28-schedule-event-mapping.md | 4 ++++ .../schedule_remote_code_injection.yml | 19 +++++++++++++++++++ .../CWE-094/CodeInjectionCritical.expected | 4 ++++ .../CWE-094/CodeInjectionMedium.expected | 3 +++ 5 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 actions/ql/src/change-notes/2026-07-28-schedule-event-mapping.md create mode 100644 actions/ql/test/query-tests/Security/CWE-094/.github/workflows/schedule_remote_code_injection.yml diff --git a/actions/ql/lib/ext/config/externally_triggereable_events.yml b/actions/ql/lib/ext/config/externally_triggereable_events.yml index ae47c684095d..2a73f4f0a6db 100644 --- a/actions/ql/lib/ext/config/externally_triggereable_events.yml +++ b/actions/ql/lib/ext/config/externally_triggereable_events.yml @@ -17,4 +17,4 @@ extensions: - ["workflow_run"] # depending on branch filter - ["workflow_call"] # depending on caller - ["workflow_dispatch"] - - ["scheduled"] + - ["schedule"] diff --git a/actions/ql/src/change-notes/2026-07-28-schedule-event-mapping.md b/actions/ql/src/change-notes/2026-07-28-schedule-event-mapping.md new file mode 100644 index 000000000000..ff949c266d08 --- /dev/null +++ b/actions/ql/src/change-notes/2026-07-28-schedule-event-mapping.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* GitHub Actions queries now correctly classify the `schedule` event when determining whether a workflow is externally triggerable. diff --git a/actions/ql/test/query-tests/Security/CWE-094/.github/workflows/schedule_remote_code_injection.yml b/actions/ql/test/query-tests/Security/CWE-094/.github/workflows/schedule_remote_code_injection.yml new file mode 100644 index 000000000000..004a50f18e4d --- /dev/null +++ b/actions/ql/test/query-tests/Security/CWE-094/.github/workflows/schedule_remote_code_injection.yml @@ -0,0 +1,19 @@ +on: + schedule: + - cron: "0 0 * * *" + +permissions: + contents: write + +jobs: + fetch-issues: + runs-on: ubuntu-latest + steps: + - name: Fetch open issues + id: issues + uses: octokit/request-action@v2.x + with: + route: GET /repos/foo/bar/issues?state=open + + - name: Write issues to file + run: echo '${{ steps.issues.outputs.data }}' > issues.json \ No newline at end of file diff --git a/actions/ql/test/query-tests/Security/CWE-094/CodeInjectionCritical.expected b/actions/ql/test/query-tests/Security/CWE-094/CodeInjectionCritical.expected index 9bf7e9aa56db..8807d1ebe57b 100644 --- a/actions/ql/test/query-tests/Security/CWE-094/CodeInjectionCritical.expected +++ b/actions/ql/test/query-tests/Security/CWE-094/CodeInjectionCritical.expected @@ -100,6 +100,7 @@ edges | .github/workflows/reusable-workflow-caller-1.yml:11:15:11:52 | github.event.pull_request.title | .github/workflows/reusable-workflow-1.yml:6:7:6:11 | input taint | provenance | | | .github/workflows/reusable-workflow-caller-2.yml:10:15:10:52 | github.event.pull_request.title | .github/workflows/reusable-workflow-2.yml:6:7:6:11 | input taint | provenance | | | .github/workflows/reusable-workflow-caller-3.yml:10:15:10:52 | github.event.pull_request.title | .github/workflows/external/TestOrg/TestRepo/.github/workflows/reusable-workflow.yml:6:7:6:11 | input taint | provenance | | +| .github/workflows/schedule_remote_code_injection.yml:12:9:18:6 | Uses Step: issues | .github/workflows/schedule_remote_code_injection.yml:19:21:19:52 | steps.issues.outputs.data | provenance | | | .github/workflows/self_needs.yml:11:7:12:4 | Job outputs node [job_output] | .github/workflows/self_needs.yml:20:15:20:51 | needs.test1.outputs.job_output | provenance | | | .github/workflows/self_needs.yml:11:20:11:52 | steps.source.outputs.value | .github/workflows/self_needs.yml:11:7:12:4 | Job outputs node [job_output] | provenance | | | .github/workflows/self_needs.yml:13:9:19:6 | Uses Step: source [value] | .github/workflows/self_needs.yml:11:20:11:52 | steps.source.outputs.value | provenance | | @@ -460,6 +461,8 @@ nodes | .github/workflows/reusable-workflow-caller-1.yml:11:15:11:52 | github.event.pull_request.title | semmle.label | github.event.pull_request.title | | .github/workflows/reusable-workflow-caller-2.yml:10:15:10:52 | github.event.pull_request.title | semmle.label | github.event.pull_request.title | | .github/workflows/reusable-workflow-caller-3.yml:10:15:10:52 | github.event.pull_request.title | semmle.label | github.event.pull_request.title | +| .github/workflows/schedule_remote_code_injection.yml:12:9:18:6 | Uses Step: issues | semmle.label | Uses Step: issues | +| .github/workflows/schedule_remote_code_injection.yml:19:21:19:52 | steps.issues.outputs.data | semmle.label | steps.issues.outputs.data | | .github/workflows/self_needs.yml:11:7:12:4 | Job outputs node [job_output] | semmle.label | Job outputs node [job_output] | | .github/workflows/self_needs.yml:11:20:11:52 | steps.source.outputs.value | semmle.label | steps.source.outputs.value | | .github/workflows/self_needs.yml:13:9:19:6 | Uses Step: source [value] | semmle.label | Uses Step: source [value] | @@ -777,6 +780,7 @@ subpaths | .github/workflows/reusable-workflow-2.yml:36:21:36:39 | inputs.taint | .github/workflows/reusable-workflow-caller-2.yml:10:15:10:52 | github.event.pull_request.title | .github/workflows/reusable-workflow-2.yml:36:21:36:39 | inputs.taint | Potential code injection in $@, which may be controlled by an external user ($@). | .github/workflows/reusable-workflow-2.yml:36:21:36:39 | inputs.taint | ${{ inputs.taint }} | .github/workflows/reusable-workflow-caller-2.yml:4:3:4:21 | pull_request_target | pull_request_target | | .github/workflows/reusable-workflow-2.yml:53:26:53:39 | env.log | .github/workflows/reusable-workflow-2.yml:44:19:44:56 | github.event.pull_request.title | .github/workflows/reusable-workflow-2.yml:53:26:53:39 | env.log | Potential code injection in $@, which may be controlled by an external user ($@). | .github/workflows/reusable-workflow-2.yml:53:26:53:39 | env.log | ${{ env.log }} | .github/workflows/reusable-workflow-caller-2.yml:4:3:4:21 | pull_request_target | pull_request_target | | .github/workflows/reusable-workflow-2.yml:66:34:66:52 | env.prev_log | .github/workflows/reusable-workflow-2.yml:45:24:45:61 | github.event.changes.title.from | .github/workflows/reusable-workflow-2.yml:66:34:66:52 | env.prev_log | Potential code injection in $@, which may be controlled by an external user ($@). | .github/workflows/reusable-workflow-2.yml:66:34:66:52 | env.prev_log | ${{ env.prev_log }} | .github/workflows/reusable-workflow-caller-2.yml:4:3:4:21 | pull_request_target | pull_request_target | +| .github/workflows/schedule_remote_code_injection.yml:19:21:19:52 | steps.issues.outputs.data | .github/workflows/schedule_remote_code_injection.yml:12:9:18:6 | Uses Step: issues | .github/workflows/schedule_remote_code_injection.yml:19:21:19:52 | steps.issues.outputs.data | Potential code injection in $@, which may be controlled by an external user ($@). | .github/workflows/schedule_remote_code_injection.yml:19:21:19:52 | steps.issues.outputs.data | ${{ steps.issues.outputs.data }} | .github/workflows/schedule_remote_code_injection.yml:2:3:2:10 | schedule | schedule | | .github/workflows/self_needs.yml:19:15:19:47 | steps.source.outputs.value | .github/workflows/self_needs.yml:16:20:16:57 | github.event['comment']['body'] | .github/workflows/self_needs.yml:19:15:19:47 | steps.source.outputs.value | Potential code injection in $@, which may be controlled by an external user ($@). | .github/workflows/self_needs.yml:19:15:19:47 | steps.source.outputs.value | ${{ steps.source.outputs.value }} | .github/workflows/self_needs.yml:4:3:4:15 | issue_comment | issue_comment | | .github/workflows/self_needs.yml:20:15:20:51 | needs.test1.outputs.job_output | .github/workflows/self_needs.yml:16:20:16:57 | github.event['comment']['body'] | .github/workflows/self_needs.yml:20:15:20:51 | needs.test1.outputs.job_output | Potential code injection in $@, which may be controlled by an external user ($@). | .github/workflows/self_needs.yml:20:15:20:51 | needs.test1.outputs.job_output | ${{ needs.test1.outputs.job_output }} | .github/workflows/self_needs.yml:4:3:4:15 | issue_comment | issue_comment | | .github/workflows/simple2.yml:29:24:29:54 | steps.step.outputs.value | .github/workflows/simple2.yml:14:9:18:6 | Uses Step: source | .github/workflows/simple2.yml:29:24:29:54 | steps.step.outputs.value | Potential code injection in $@, which may be controlled by an external user ($@). | .github/workflows/simple2.yml:29:24:29:54 | steps.step.outputs.value | ${{ steps.step.outputs.value }} | .github/workflows/simple2.yml:3:6:3:24 | pull_request_target | pull_request_target | diff --git a/actions/ql/test/query-tests/Security/CWE-094/CodeInjectionMedium.expected b/actions/ql/test/query-tests/Security/CWE-094/CodeInjectionMedium.expected index 4bbe7da0aaf3..bbf8b0dec557 100644 --- a/actions/ql/test/query-tests/Security/CWE-094/CodeInjectionMedium.expected +++ b/actions/ql/test/query-tests/Security/CWE-094/CodeInjectionMedium.expected @@ -100,6 +100,7 @@ edges | .github/workflows/reusable-workflow-caller-1.yml:11:15:11:52 | github.event.pull_request.title | .github/workflows/reusable-workflow-1.yml:6:7:6:11 | input taint | provenance | | | .github/workflows/reusable-workflow-caller-2.yml:10:15:10:52 | github.event.pull_request.title | .github/workflows/reusable-workflow-2.yml:6:7:6:11 | input taint | provenance | | | .github/workflows/reusable-workflow-caller-3.yml:10:15:10:52 | github.event.pull_request.title | .github/workflows/external/TestOrg/TestRepo/.github/workflows/reusable-workflow.yml:6:7:6:11 | input taint | provenance | | +| .github/workflows/schedule_remote_code_injection.yml:12:9:18:6 | Uses Step: issues | .github/workflows/schedule_remote_code_injection.yml:19:21:19:52 | steps.issues.outputs.data | provenance | | | .github/workflows/self_needs.yml:11:7:12:4 | Job outputs node [job_output] | .github/workflows/self_needs.yml:20:15:20:51 | needs.test1.outputs.job_output | provenance | | | .github/workflows/self_needs.yml:11:20:11:52 | steps.source.outputs.value | .github/workflows/self_needs.yml:11:7:12:4 | Job outputs node [job_output] | provenance | | | .github/workflows/self_needs.yml:13:9:19:6 | Uses Step: source [value] | .github/workflows/self_needs.yml:11:20:11:52 | steps.source.outputs.value | provenance | | @@ -460,6 +461,8 @@ nodes | .github/workflows/reusable-workflow-caller-1.yml:11:15:11:52 | github.event.pull_request.title | semmle.label | github.event.pull_request.title | | .github/workflows/reusable-workflow-caller-2.yml:10:15:10:52 | github.event.pull_request.title | semmle.label | github.event.pull_request.title | | .github/workflows/reusable-workflow-caller-3.yml:10:15:10:52 | github.event.pull_request.title | semmle.label | github.event.pull_request.title | +| .github/workflows/schedule_remote_code_injection.yml:12:9:18:6 | Uses Step: issues | semmle.label | Uses Step: issues | +| .github/workflows/schedule_remote_code_injection.yml:19:21:19:52 | steps.issues.outputs.data | semmle.label | steps.issues.outputs.data | | .github/workflows/self_needs.yml:11:7:12:4 | Job outputs node [job_output] | semmle.label | Job outputs node [job_output] | | .github/workflows/self_needs.yml:11:20:11:52 | steps.source.outputs.value | semmle.label | steps.source.outputs.value | | .github/workflows/self_needs.yml:13:9:19:6 | Uses Step: source [value] | semmle.label | Uses Step: source [value] | From 68410fd4a8f55a979af3dfb93c49329c76a35fb5 Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 28 Jul 2026 09:31:35 +0200 Subject: [PATCH 073/188] JS: Do not warn about browser-specific source kinds in MaD --- shared/mad/codeql/mad/ModelValidation.qll | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/shared/mad/codeql/mad/ModelValidation.qll b/shared/mad/codeql/mad/ModelValidation.qll index 58e13dc96008..47a3c24adce1 100644 --- a/shared/mad/codeql/mad/ModelValidation.qll +++ b/shared/mad/codeql/mad/ModelValidation.qll @@ -132,7 +132,9 @@ module KindValidation { // C# "file-write", "windows-registry", // JavaScript - "database-access-result", "response", "request" + "database-access-result", "response", "request", "browser", "browser-url-query", + "browser-url-fragment", "browser-url-path", "browser-url", "browser-window-name", + "browser-message-event" ] or this.matches([ From b5cb703f2e623edbbbb6dffd7dca99074064dd5c Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 28 Jul 2026 12:19:15 +0100 Subject: [PATCH 074/188] C++: Add tests with missing flow sources. --- .../dataflow/external-models/windows.cpp | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp b/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp index f098f7344e43..19ee57cd58b8 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp +++ b/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp @@ -940,4 +940,93 @@ void test_http_server_api(HANDLE hRequestQueue) { sink(certInfo.pCertEncoded); sink(*certInfo.pCertEncoded); // $ ir } +} + +using HKEY = void*; +using BYTE = unsigned char; +using LPBYTE = BYTE*; +using PLONG = LONG*; + +typedef struct value_entA { + LPSTR ve_valuename; + DWORD ve_valuelen; + DWORD_PTR ve_valueptr; + DWORD ve_type; +} VALENTA, *PVALENTA; + +typedef struct value_entW { + LPWSTR ve_valuename; + DWORD ve_valuelen; + DWORD_PTR ve_valueptr; + DWORD ve_type; +} VALENTW, *PVALENTW; + +LONG RegQueryValueA(HKEY hKey, LPCSTR lpSubKey, LPSTR lpData, PLONG lpcbData); +LONG RegQueryValueW(HKEY hKey, LPCWSTR lpSubKey, LPWSTR lpData, PLONG lpcbData); + +LONG RegQueryValueExA( + HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, + LPDWORD lpcbData +); + +LONG RegQueryValueExW( + HKEY hKey, LPCWSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, + LPDWORD lpcbData +); + +LONG RegQueryMultipleValuesA( + HKEY hKey, PVALENTA valList, DWORD numVals, LPSTR valueBuffer, LPDWORD totalSize +); + +LONG RegQueryMultipleValuesW( + HKEY hKey, PVALENTW valList, DWORD numVals, LPWSTR valueBuffer, LPDWORD totalSize +); + +void test_registry_queries(HKEY hKey) { + { + char data[256]; + LONG dataSize = sizeof(data); + RegQueryValueA(hKey, "value", data, &dataSize); + sink(data); // clean + sink(*data); // $ MISSING: ir + } + { + wchar_t data[256]; + LONG dataSize = sizeof(data); + RegQueryValueW(hKey, L"value", data, &dataSize); + sink(data); // clean + sink(*data); // $ MISSING: ir + } + { + BYTE data[256]; + DWORD dataSize = sizeof(data); + DWORD type; + RegQueryValueExA(hKey, "value", nullptr, &type, data, &dataSize); + sink(data); // clean + sink(*data); // $ MISSING: ir + } + { + BYTE data[256]; + DWORD dataSize = sizeof(data); + DWORD type; + RegQueryValueExW(hKey, L"value", nullptr, &type, data, &dataSize); + sink(data); // clean + sink(*data); // $ MISSING: ir + } + { + VALENTA values[1]; + char data[256]; + DWORD dataSize = sizeof(data); + RegQueryMultipleValuesA(hKey, values, 1, data, &dataSize); + sink(data); // clean + sink(*data); // $ MISSING: ir + } + { + VALENTW values[1]; + wchar_t data[256]; + DWORD dataSize = sizeof(data); + RegQueryMultipleValuesW(hKey, values, 1, data, &dataSize); + sink(data); // clean + sink(*data); // $ MISSING: ir + } } \ No newline at end of file From 16ad0a3c31cfb301b75bf281fd6fc7d396e14e87 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 28 Jul 2026 12:20:14 +0100 Subject: [PATCH 075/188] C++: Add flow sources for 'winreg.h'. --- cpp/ql/lib/ext/Windows.model.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cpp/ql/lib/ext/Windows.model.yml b/cpp/ql/lib/ext/Windows.model.yml index 6794e9a86641..3e7ef1fb4fe6 100644 --- a/cpp/ql/lib/ext/Windows.model.yml +++ b/cpp/ql/lib/ext/Windows.model.yml @@ -34,6 +34,15 @@ extensions: - ["", "", False, "HttpReceiveHttpRequest", "", "", "Argument[*3]", "remote", "manual"] - ["", "", False, "HttpReceiveRequestEntityBody", "", "", "Argument[*3]", "remote", "manual"] - ["", "", False, "HttpReceiveClientCertificate", "", "", "Argument[*3]", "remote", "manual"] + # winreg.h + - ["", "", False, "RegQueryValueA", "", "", "Argument[*2]", "local", "manual"] + - ["", "", False, "RegQueryValueExA", "", "", "Argument[*4]", "local", "manual"] + - ["", "", False, "RegQueryValueW", "", "", "Argument[*2]", "local", "manual"] + - ["", "", False, "RegQueryValueExW", "", "", "Argument[*4]", "local", "manual"] + # TODO: Once we support access paths at sources we should also mark Argument[*1].Field[*ve_valueptr] + - ["", "", False, "RegQueryMultipleValuesA", "", "", "Argument[*3]", "local", "manual"] + # TODO: Once we support access paths at sources we should also mark Argument[*1].Field[*ve_valueptr] + - ["", "", False, "RegQueryMultipleValuesW", "", "", "Argument[*3]", "local", "manual"] - addsTo: pack: codeql/cpp-all extensible: summaryModel From 154b3b1f6cc3d704a4896259ebf6fa81e800742d Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 28 Jul 2026 12:20:34 +0100 Subject: [PATCH 076/188] C++: Accept test changes. --- .../dataflow/external-models/flow.expected | 250 ++++++++++-------- .../dataflow/external-models/sources.expected | 6 + .../dataflow/external-models/windows.cpp | 12 +- 3 files changed, 149 insertions(+), 119 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/external-models/flow.expected b/cpp/ql/test/library-tests/dataflow/external-models/flow.expected index 641804364501..49740545f77a 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/flow.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/flow.expected @@ -17,104 +17,110 @@ models | 16 | Source: ; ; false; NtReadFile; ; ; Argument[*5]; local; manual | | 17 | Source: ; ; false; ReadFile; ; ; Argument[*1]; local; manual | | 18 | Source: ; ; false; ReadFileEx; ; ; Argument[*1]; local; manual | -| 19 | Source: ; ; false; WinHttpQueryHeaders; ; ; Argument[*3]; remote; manual | -| 20 | Source: ; ; false; WinHttpQueryHeadersEx; ; ; Argument[**8]; remote; manual | -| 21 | Source: ; ; false; WinHttpQueryHeadersEx; ; ; Argument[*5]; remote; manual | -| 22 | Source: ; ; false; WinHttpQueryHeadersEx; ; ; Argument[*6]; remote; manual | -| 23 | Source: ; ; false; WinHttpReadData; ; ; Argument[*1]; remote; manual | -| 24 | Source: ; ; false; WinHttpReadDataEx; ; ; Argument[*1]; remote; manual | -| 25 | Source: ; ; false; ymlSource; ; ; ReturnValue; local; manual | -| 26 | Source: Azure::Core::Http; RawResponse; true; ExtractBodyStream; ; ; ReturnValue[*]; remote; manual | -| 27 | Source: Azure::Core::Http; RawResponse; true; GetBody; ; ; ReturnValue[*]; remote; manual | -| 28 | Source: Azure::Core::Http; RawResponse; true; GetHeaders; ; ; ReturnValue[*]; remote; manual | -| 29 | Source: Azure::Core::Http; Request; true; GetBodyStream; ; ; ReturnValue[*]; remote; manual | -| 30 | Source: Azure::Core::Http; Request; true; GetHeader; ; ; ReturnValue; remote; manual | -| 31 | Source: Azure::Core::Http; Request; true; GetHeaders; ; ; ReturnValue; remote; manual | -| 32 | Source: boost::asio; ; false; read_until; ; ; Argument[*1]; remote; manual | -| 33 | Summary: ; ; false; CommandLineToArgvA; ; ; Argument[*0]; ReturnValue[**]; taint; manual | -| 34 | Summary: ; ; false; CreateRemoteThread; ; ; Argument[@4]; Argument[3].Parameter[@0]; value; manual | -| 35 | Summary: ; ; false; CreateRemoteThreadEx; ; ; Argument[@4]; Argument[3].Parameter[@0]; value; manual | -| 36 | Summary: ; ; false; CreateThread; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual | -| 37 | Summary: ; ; false; ReadFileEx; ; ; Argument[*3].Field[@hEvent]; Argument[4].Parameter[*2].Field[@hEvent]; value; manual | -| 38 | Summary: ; ; false; RtlCopyDeviceMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | -| 39 | Summary: ; ; false; RtlCopyMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | -| 40 | Summary: ; ; false; RtlCopyMemoryNonTemporal; ; ; Argument[*@1]; Argument[*@0]; value; manual | -| 41 | Summary: ; ; false; RtlCopyUnicodeString; ; ; Argument[*1].Field[*Buffer]; Argument[*0].Field[*Buffer]; value; manual | -| 42 | Summary: ; ; false; RtlCopyVolatileMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | -| 43 | Summary: ; ; false; RtlInitUnicodeString; ; ; Argument[*1]; Argument[*0].Field[*Buffer]; value; manual | -| 44 | Summary: ; ; false; RtlMoveMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | -| 45 | Summary: ; ; false; RtlMoveVolatileMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | -| 46 | Summary: ; ; false; WinHttpCrackUrl; ; ; Argument[*0]; Argument[*3]; taint; manual | -| 47 | Summary: ; ; false; callWithArgument; ; ; Argument[1]; Argument[0].Parameter[0]; value; manual | -| 48 | Summary: ; ; false; callWithNonTypeTemplate; (const T &); ; Argument[*0]; ReturnValue; value; manual | -| 49 | Summary: ; ; false; pthread_create; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual | -| 50 | Summary: ; ; false; read_field_from_struct; ; ; Argument[*0].Field[MyNamespace::MyStructInNamespace::myField]; ReturnValue; value; manual | -| 51 | Summary: ; ; false; read_field_from_struct_2; ; ; Argument[*0].Field[MyGlobalStruct::myField]; ReturnValue; value; manual | -| 52 | Summary: ; ; false; ymlStepGenerated; ; ; Argument[0]; ReturnValue; taint; df-generated | -| 53 | Summary: ; ; false; ymlStepManual; ; ; Argument[0]; ReturnValue; taint; manual | -| 54 | Summary: ; ; false; ymlStepManual_with_body; ; ; Argument[0]; ReturnValue; taint; manual | -| 55 | Summary: ; MyString; true; operator[]; ; ; Argument[-1]; ReturnValue[*]; taint; manual | -| 56 | Summary: ; MyString; true; operator[]; ; ; ReturnValue[*]; Argument[-1]; taint; manual | -| 57 | Summary: ; ReverseFlow; true; get_ptr; ; ; ReturnValue[*]; Argument[-1].Field[ReverseFlow::value]; value; manual | -| 58 | Summary: ; TemplateClass1; true; templateFunction2; (U,V); ; Argument[1]; ReturnValue; value; manual | -| 59 | Summary: ; TemplateClass1; false; templateFunction; (T,U); ; Argument[0]; ReturnValue; value; manual | -| 60 | Summary: ; TemplateClass2; true; function; (U,T); ; Argument[1]; ReturnValue; value; manual | -| 61 | Summary: Azure::Core::IO; BodyStream; true; Read; ; ; Argument[-1]; Argument[*0]; taint; manual | -| 62 | Summary: Azure::Core::IO; BodyStream; true; ReadToCount; ; ; Argument[-1]; Argument[*0]; taint; manual | -| 63 | Summary: Azure::Core::IO; BodyStream; true; ReadToEnd; ; ; Argument[-1]; ReturnValue.Element; taint; manual | -| 64 | Summary: Azure; Nullable; true; Value; ; ; Argument[-1]; ReturnValue[*]; taint; manual | -| 65 | Summary: boost::asio; ; false; buffer; ; ; Argument[*0]; ReturnValue; taint; manual | +| 19 | Source: ; ; false; RegQueryMultipleValuesA; ; ; Argument[*3]; local; manual | +| 20 | Source: ; ; false; RegQueryMultipleValuesW; ; ; Argument[*3]; local; manual | +| 21 | Source: ; ; false; RegQueryValueA; ; ; Argument[*2]; local; manual | +| 22 | Source: ; ; false; RegQueryValueExA; ; ; Argument[*4]; local; manual | +| 23 | Source: ; ; false; RegQueryValueExW; ; ; Argument[*4]; local; manual | +| 24 | Source: ; ; false; RegQueryValueW; ; ; Argument[*2]; local; manual | +| 25 | Source: ; ; false; WinHttpQueryHeaders; ; ; Argument[*3]; remote; manual | +| 26 | Source: ; ; false; WinHttpQueryHeadersEx; ; ; Argument[**8]; remote; manual | +| 27 | Source: ; ; false; WinHttpQueryHeadersEx; ; ; Argument[*5]; remote; manual | +| 28 | Source: ; ; false; WinHttpQueryHeadersEx; ; ; Argument[*6]; remote; manual | +| 29 | Source: ; ; false; WinHttpReadData; ; ; Argument[*1]; remote; manual | +| 30 | Source: ; ; false; WinHttpReadDataEx; ; ; Argument[*1]; remote; manual | +| 31 | Source: ; ; false; ymlSource; ; ; ReturnValue; local; manual | +| 32 | Source: Azure::Core::Http; RawResponse; true; ExtractBodyStream; ; ; ReturnValue[*]; remote; manual | +| 33 | Source: Azure::Core::Http; RawResponse; true; GetBody; ; ; ReturnValue[*]; remote; manual | +| 34 | Source: Azure::Core::Http; RawResponse; true; GetHeaders; ; ; ReturnValue[*]; remote; manual | +| 35 | Source: Azure::Core::Http; Request; true; GetBodyStream; ; ; ReturnValue[*]; remote; manual | +| 36 | Source: Azure::Core::Http; Request; true; GetHeader; ; ; ReturnValue; remote; manual | +| 37 | Source: Azure::Core::Http; Request; true; GetHeaders; ; ; ReturnValue; remote; manual | +| 38 | Source: boost::asio; ; false; read_until; ; ; Argument[*1]; remote; manual | +| 39 | Summary: ; ; false; CommandLineToArgvA; ; ; Argument[*0]; ReturnValue[**]; taint; manual | +| 40 | Summary: ; ; false; CreateRemoteThread; ; ; Argument[@4]; Argument[3].Parameter[@0]; value; manual | +| 41 | Summary: ; ; false; CreateRemoteThreadEx; ; ; Argument[@4]; Argument[3].Parameter[@0]; value; manual | +| 42 | Summary: ; ; false; CreateThread; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual | +| 43 | Summary: ; ; false; ReadFileEx; ; ; Argument[*3].Field[@hEvent]; Argument[4].Parameter[*2].Field[@hEvent]; value; manual | +| 44 | Summary: ; ; false; RtlCopyDeviceMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | +| 45 | Summary: ; ; false; RtlCopyMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | +| 46 | Summary: ; ; false; RtlCopyMemoryNonTemporal; ; ; Argument[*@1]; Argument[*@0]; value; manual | +| 47 | Summary: ; ; false; RtlCopyUnicodeString; ; ; Argument[*1].Field[*Buffer]; Argument[*0].Field[*Buffer]; value; manual | +| 48 | Summary: ; ; false; RtlCopyVolatileMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | +| 49 | Summary: ; ; false; RtlInitUnicodeString; ; ; Argument[*1]; Argument[*0].Field[*Buffer]; value; manual | +| 50 | Summary: ; ; false; RtlMoveMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | +| 51 | Summary: ; ; false; RtlMoveVolatileMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | +| 52 | Summary: ; ; false; WinHttpCrackUrl; ; ; Argument[*0]; Argument[*3]; taint; manual | +| 53 | Summary: ; ; false; callWithArgument; ; ; Argument[1]; Argument[0].Parameter[0]; value; manual | +| 54 | Summary: ; ; false; callWithNonTypeTemplate; (const T &); ; Argument[*0]; ReturnValue; value; manual | +| 55 | Summary: ; ; false; pthread_create; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual | +| 56 | Summary: ; ; false; read_field_from_struct; ; ; Argument[*0].Field[MyNamespace::MyStructInNamespace::myField]; ReturnValue; value; manual | +| 57 | Summary: ; ; false; read_field_from_struct_2; ; ; Argument[*0].Field[MyGlobalStruct::myField]; ReturnValue; value; manual | +| 58 | Summary: ; ; false; ymlStepGenerated; ; ; Argument[0]; ReturnValue; taint; df-generated | +| 59 | Summary: ; ; false; ymlStepManual; ; ; Argument[0]; ReturnValue; taint; manual | +| 60 | Summary: ; ; false; ymlStepManual_with_body; ; ; Argument[0]; ReturnValue; taint; manual | +| 61 | Summary: ; MyString; true; operator[]; ; ; Argument[-1]; ReturnValue[*]; taint; manual | +| 62 | Summary: ; MyString; true; operator[]; ; ; ReturnValue[*]; Argument[-1]; taint; manual | +| 63 | Summary: ; ReverseFlow; true; get_ptr; ; ; ReturnValue[*]; Argument[-1].Field[ReverseFlow::value]; value; manual | +| 64 | Summary: ; TemplateClass1; true; templateFunction2; (U,V); ; Argument[1]; ReturnValue; value; manual | +| 65 | Summary: ; TemplateClass1; false; templateFunction; (T,U); ; Argument[0]; ReturnValue; value; manual | +| 66 | Summary: ; TemplateClass2; true; function; (U,T); ; Argument[1]; ReturnValue; value; manual | +| 67 | Summary: Azure::Core::IO; BodyStream; true; Read; ; ; Argument[-1]; Argument[*0]; taint; manual | +| 68 | Summary: Azure::Core::IO; BodyStream; true; ReadToCount; ; ; Argument[-1]; Argument[*0]; taint; manual | +| 69 | Summary: Azure::Core::IO; BodyStream; true; ReadToEnd; ; ; Argument[-1]; ReturnValue.Element; taint; manual | +| 70 | Summary: Azure; Nullable; true; Value; ; ; Argument[-1]; ReturnValue[*]; taint; manual | +| 71 | Summary: boost::asio; ; false; buffer; ; ; Argument[*0]; ReturnValue; taint; manual | edges -| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:91:7:91:17 | recv_buffer | provenance | Src:MaD:32 | -| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:93:29:93:39 | *recv_buffer | provenance | Src:MaD:32 Sink:MaD:2 | +| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:91:7:91:17 | recv_buffer | provenance | Src:MaD:38 | +| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:93:29:93:39 | *recv_buffer | provenance | Src:MaD:38 Sink:MaD:2 | | asio_streams.cpp:97:37:97:44 | call to source | asio_streams.cpp:98:7:98:14 | send_str | provenance | TaintFunction | | asio_streams.cpp:97:37:97:44 | call to source | asio_streams.cpp:100:64:100:71 | *send_str | provenance | TaintFunction | | asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | | | asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:101:7:101:17 | send_buffer | provenance | | | asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:103:29:103:39 | *send_buffer | provenance | Sink:MaD:2 | -| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:65 | -| azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:253:48:253:60 | *call to GetBodyStream | provenance | Src:MaD:29 | +| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:71 | +| azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:253:48:253:60 | *call to GetBodyStream | provenance | Src:MaD:35 | | azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:257:5:257:8 | *resp | provenance | | | azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:262:5:262:8 | *resp | provenance | | | azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:266:38:266:41 | *resp | provenance | | -| azure.cpp:257:5:257:8 | *resp | azure.cpp:257:16:257:21 | Read output argument | provenance | MaD:61 | +| azure.cpp:257:5:257:8 | *resp | azure.cpp:257:16:257:21 | Read output argument | provenance | MaD:67 | | azure.cpp:257:16:257:21 | Read output argument | azure.cpp:258:10:258:16 | * ... | provenance | | -| azure.cpp:262:5:262:8 | *resp | azure.cpp:262:23:262:28 | ReadToCount output argument | provenance | MaD:62 | +| azure.cpp:262:5:262:8 | *resp | azure.cpp:262:23:262:28 | ReadToCount output argument | provenance | MaD:68 | | azure.cpp:262:23:262:28 | ReadToCount output argument | azure.cpp:263:10:263:16 | * ... | provenance | | -| azure.cpp:266:38:266:41 | *resp | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | provenance | MaD:63 | +| azure.cpp:266:38:266:41 | *resp | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | provenance | MaD:69 | | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | provenance | | | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | azure.cpp:267:10:267:12 | vec [element] | provenance | | | azure.cpp:267:10:267:12 | vec [element] | azure.cpp:267:10:267:12 | vec | provenance | | -| azure.cpp:273:62:273:64 | call to GetHeaders | azure.cpp:273:62:273:64 | call to GetHeaders | provenance | Src:MaD:28 | +| azure.cpp:273:62:273:64 | call to GetHeaders | azure.cpp:273:62:273:64 | call to GetHeaders | provenance | Src:MaD:34 | | azure.cpp:273:62:273:64 | call to GetHeaders | azure.cpp:274:14:274:29 | call to operator[] | provenance | TaintFunction | | azure.cpp:273:62:273:64 | call to GetHeaders | azure.cpp:274:14:274:29 | call to operator[] | provenance | TaintFunction | | azure.cpp:273:62:273:64 | call to GetHeaders | azure.cpp:274:14:274:29 | call to operator[] | provenance | TaintFunction | | azure.cpp:274:14:274:29 | call to operator[] | azure.cpp:274:10:274:29 | call to operator[] | provenance | | | azure.cpp:274:14:274:29 | call to operator[] | azure.cpp:274:14:274:29 | call to operator[] | provenance | | -| azure.cpp:277:45:277:47 | call to GetBody | azure.cpp:277:45:277:47 | call to GetBody | provenance | Src:MaD:27 | +| azure.cpp:277:45:277:47 | call to GetBody | azure.cpp:277:45:277:47 | call to GetBody | provenance | Src:MaD:33 | | azure.cpp:277:45:277:47 | call to GetBody | azure.cpp:278:10:278:13 | body | provenance | | | azure.cpp:277:45:277:47 | call to GetBody | azure.cpp:278:10:278:13 | body | provenance | | | azure.cpp:278:10:278:13 | body | azure.cpp:278:10:278:13 | body | provenance | | -| azure.cpp:281:68:281:84 | *call to ExtractBodyStream | azure.cpp:281:68:281:84 | *call to ExtractBodyStream | provenance | Src:MaD:26 | +| azure.cpp:281:68:281:84 | *call to ExtractBodyStream | azure.cpp:281:68:281:84 | *call to ExtractBodyStream | provenance | Src:MaD:32 | | azure.cpp:281:68:281:84 | *call to ExtractBodyStream | azure.cpp:282:21:282:23 | *call to get | provenance | | -| azure.cpp:282:21:282:23 | *call to get | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | provenance | MaD:63 | +| azure.cpp:282:21:282:23 | *call to get | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | provenance | MaD:69 | | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | azure.cpp:282:10:282:38 | call to ReadToEnd | provenance | | | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | provenance | | -| azure.cpp:289:24:289:56 | call to GetHeader | azure.cpp:289:63:289:65 | call to Value | provenance | MaD:64 | +| azure.cpp:289:24:289:56 | call to GetHeader | azure.cpp:289:63:289:65 | call to Value | provenance | MaD:70 | | azure.cpp:289:32:289:40 | call to GetHeader | azure.cpp:289:24:289:56 | call to GetHeader | provenance | | -| azure.cpp:289:32:289:40 | call to GetHeader | azure.cpp:289:32:289:40 | call to GetHeader | provenance | Src:MaD:30 | +| azure.cpp:289:32:289:40 | call to GetHeader | azure.cpp:289:32:289:40 | call to GetHeader | provenance | Src:MaD:36 | | azure.cpp:289:63:289:65 | call to Value | azure.cpp:289:63:289:65 | call to Value | provenance | | | azure.cpp:289:63:289:65 | call to Value | azure.cpp:290:10:290:20 | headerValue | provenance | | | azure.cpp:289:63:289:65 | call to Value | azure.cpp:290:10:290:20 | headerValue | provenance | | | azure.cpp:290:10:290:20 | headerValue | azure.cpp:290:10:290:20 | headerValue | provenance | | -| azure.cpp:293:58:293:67 | call to GetHeaders | azure.cpp:293:58:293:67 | call to GetHeaders | provenance | Src:MaD:31 | +| azure.cpp:293:58:293:67 | call to GetHeaders | azure.cpp:293:58:293:67 | call to GetHeaders | provenance | Src:MaD:37 | | azure.cpp:293:58:293:67 | call to GetHeaders | azure.cpp:294:38:294:53 | call to operator[] | provenance | TaintFunction | | azure.cpp:294:38:294:53 | call to operator[] | azure.cpp:295:10:295:20 | contentType | provenance | | | azure.cpp:294:38:294:53 | call to operator[] | azure.cpp:295:10:295:20 | contentType | provenance | | | azure.cpp:295:10:295:20 | contentType | azure.cpp:295:10:295:20 | contentType | provenance | | | test.cpp:7:47:7:52 | value2 | test.cpp:7:64:7:69 | value2 | provenance | | | test.cpp:7:64:7:69 | value2 | test.cpp:7:5:7:30 | *ymlStepGenerated_with_body | provenance | | -| test.cpp:10:10:10:18 | call to ymlSource | test.cpp:10:10:10:18 | call to ymlSource | provenance | Src:MaD:25 | +| test.cpp:10:10:10:18 | call to ymlSource | test.cpp:10:10:10:18 | call to ymlSource | provenance | Src:MaD:31 | | test.cpp:10:10:10:18 | call to ymlSource | test.cpp:14:10:14:10 | x | provenance | Sink:MaD:1 | | test.cpp:10:10:10:18 | call to ymlSource | test.cpp:17:24:17:24 | x | provenance | | | test.cpp:10:10:10:18 | call to ymlSource | test.cpp:21:27:21:27 | x | provenance | | @@ -122,13 +128,13 @@ edges | test.cpp:10:10:10:18 | call to ymlSource | test.cpp:32:41:32:41 | x | provenance | | | test.cpp:17:10:17:22 | call to ymlStepManual | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | | | test.cpp:17:10:17:22 | call to ymlStepManual | test.cpp:18:10:18:10 | y | provenance | Sink:MaD:1 | -| test.cpp:17:24:17:24 | x | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | MaD:53 | +| test.cpp:17:24:17:24 | x | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | MaD:59 | | test.cpp:21:10:21:25 | call to ymlStepGenerated | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | | | test.cpp:21:10:21:25 | call to ymlStepGenerated | test.cpp:22:10:22:10 | z | provenance | Sink:MaD:1 | -| test.cpp:21:27:21:27 | x | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | MaD:52 | +| test.cpp:21:27:21:27 | x | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | MaD:58 | | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | | | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | test.cpp:26:10:26:11 | y2 | provenance | Sink:MaD:1 | -| test.cpp:25:35:25:35 | x | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | MaD:54 | +| test.cpp:25:35:25:35 | x | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | MaD:60 | | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | provenance | | | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | test.cpp:33:10:33:11 | z2 | provenance | Sink:MaD:1 | | test.cpp:32:41:32:41 | x | test.cpp:7:47:7:52 | value2 | provenance | | @@ -138,73 +144,73 @@ edges | test.cpp:48:13:48:13 | *s [x] | test.cpp:48:16:48:16 | x | provenance | Sink:MaD:1 | | test.cpp:56:2:56:2 | *s [post update] [x] | test.cpp:59:55:59:64 | *& ... [x] | provenance | | | test.cpp:56:2:56:18 | ... = ... | test.cpp:56:2:56:2 | *s [post update] [x] | provenance | | -| test.cpp:56:8:56:16 | call to ymlSource | test.cpp:56:2:56:18 | ... = ... | provenance | Src:MaD:25 | -| test.cpp:59:55:59:64 | *& ... [x] | test.cpp:46:30:46:32 | *arg [x] | provenance | MaD:49 | +| test.cpp:56:8:56:16 | call to ymlSource | test.cpp:56:2:56:18 | ... = ... | provenance | Src:MaD:31 | +| test.cpp:59:55:59:64 | *& ... [x] | test.cpp:46:30:46:32 | *arg [x] | provenance | MaD:55 | | test.cpp:68:22:68:22 | y | test.cpp:69:11:69:11 | y | provenance | Sink:MaD:1 | | test.cpp:74:22:74:22 | y | test.cpp:75:11:75:11 | y | provenance | Sink:MaD:1 | | test.cpp:82:22:82:22 | y | test.cpp:83:11:83:11 | y | provenance | Sink:MaD:1 | | test.cpp:88:22:88:22 | y | test.cpp:89:11:89:11 | y | provenance | Sink:MaD:1 | -| test.cpp:94:10:94:18 | call to ymlSource | test.cpp:94:10:94:18 | call to ymlSource | provenance | Src:MaD:25 | +| test.cpp:94:10:94:18 | call to ymlSource | test.cpp:94:10:94:18 | call to ymlSource | provenance | Src:MaD:31 | | test.cpp:94:10:94:18 | call to ymlSource | test.cpp:97:26:97:26 | x | provenance | | | test.cpp:94:10:94:18 | call to ymlSource | test.cpp:101:26:101:26 | x | provenance | | | test.cpp:94:10:94:18 | call to ymlSource | test.cpp:103:63:103:63 | x | provenance | | | test.cpp:94:10:94:18 | call to ymlSource | test.cpp:104:62:104:62 | x | provenance | | -| test.cpp:97:26:97:26 | x | test.cpp:68:22:68:22 | y | provenance | MaD:47 | -| test.cpp:101:26:101:26 | x | test.cpp:74:22:74:22 | y | provenance | MaD:47 | -| test.cpp:103:63:103:63 | x | test.cpp:82:22:82:22 | y | provenance | MaD:47 | -| test.cpp:104:62:104:62 | x | test.cpp:88:22:88:22 | y | provenance | MaD:47 | -| test.cpp:114:10:114:18 | call to ymlSource | test.cpp:114:10:114:18 | call to ymlSource | provenance | Src:MaD:25 | +| test.cpp:97:26:97:26 | x | test.cpp:68:22:68:22 | y | provenance | MaD:53 | +| test.cpp:101:26:101:26 | x | test.cpp:74:22:74:22 | y | provenance | MaD:53 | +| test.cpp:103:63:103:63 | x | test.cpp:82:22:82:22 | y | provenance | MaD:53 | +| test.cpp:104:62:104:62 | x | test.cpp:88:22:88:22 | y | provenance | MaD:53 | +| test.cpp:114:10:114:18 | call to ymlSource | test.cpp:114:10:114:18 | call to ymlSource | provenance | Src:MaD:31 | | test.cpp:114:10:114:18 | call to ymlSource | test.cpp:118:44:118:44 | *x | provenance | | | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | provenance | | | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | test.cpp:119:10:119:11 | y2 | provenance | Sink:MaD:1 | -| test.cpp:118:44:118:44 | *x | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | provenance | MaD:48 | -| test.cpp:133:10:133:18 | call to ymlSource | test.cpp:133:10:133:18 | call to ymlSource | provenance | Src:MaD:25 | +| test.cpp:118:44:118:44 | *x | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | provenance | MaD:54 | +| test.cpp:133:10:133:18 | call to ymlSource | test.cpp:133:10:133:18 | call to ymlSource | provenance | Src:MaD:31 | | test.cpp:133:10:133:18 | call to ymlSource | test.cpp:134:45:134:45 | x | provenance | | | test.cpp:134:13:134:43 | call to templateFunction | test.cpp:134:13:134:43 | call to templateFunction | provenance | | | test.cpp:134:13:134:43 | call to templateFunction | test.cpp:135:10:135:10 | y | provenance | Sink:MaD:1 | -| test.cpp:134:45:134:45 | x | test.cpp:134:13:134:43 | call to templateFunction | provenance | MaD:59 | -| test.cpp:146:10:146:18 | call to ymlSource | test.cpp:146:10:146:18 | call to ymlSource | provenance | Src:MaD:25 | +| test.cpp:134:45:134:45 | x | test.cpp:134:13:134:43 | call to templateFunction | provenance | MaD:65 | +| test.cpp:146:10:146:18 | call to ymlSource | test.cpp:146:10:146:18 | call to ymlSource | provenance | Src:MaD:31 | | test.cpp:146:10:146:18 | call to ymlSource | test.cpp:148:26:148:26 | x | provenance | | | test.cpp:148:10:148:27 | call to function | test.cpp:148:10:148:27 | call to function | provenance | | | test.cpp:148:10:148:27 | call to function | test.cpp:149:10:149:10 | z | provenance | Sink:MaD:1 | -| test.cpp:148:26:148:26 | x | test.cpp:148:10:148:27 | call to function | provenance | MaD:60 | -| test.cpp:155:10:155:18 | call to ymlSource | test.cpp:155:10:155:18 | call to ymlSource | provenance | Src:MaD:25 | +| test.cpp:148:26:148:26 | x | test.cpp:148:10:148:27 | call to function | provenance | MaD:66 | +| test.cpp:155:10:155:18 | call to ymlSource | test.cpp:155:10:155:18 | call to ymlSource | provenance | Src:MaD:31 | | test.cpp:155:10:155:18 | call to ymlSource | test.cpp:157:26:157:26 | x | provenance | | | test.cpp:157:13:157:20 | call to function | test.cpp:157:13:157:20 | call to function | provenance | | | test.cpp:157:13:157:20 | call to function | test.cpp:158:10:158:10 | z | provenance | Sink:MaD:1 | -| test.cpp:157:26:157:26 | x | test.cpp:157:13:157:20 | call to function | provenance | MaD:60 | +| test.cpp:157:26:157:26 | x | test.cpp:157:13:157:20 | call to function | provenance | MaD:66 | | test.cpp:164:34:164:34 | x | test.cpp:165:69:165:69 | x | provenance | | | test.cpp:165:12:165:64 | call to templateFunction2 | test.cpp:164:7:164:7 | *templateFunction3 | provenance | | | test.cpp:165:12:165:64 | call to templateFunction2 | test.cpp:165:12:165:64 | call to templateFunction2 | provenance | | -| test.cpp:165:69:165:69 | x | test.cpp:165:12:165:64 | call to templateFunction2 | provenance | MaD:58 | -| test.cpp:170:10:170:18 | call to ymlSource | test.cpp:170:10:170:18 | call to ymlSource | provenance | Src:MaD:25 | +| test.cpp:165:69:165:69 | x | test.cpp:165:12:165:64 | call to templateFunction2 | provenance | MaD:64 | +| test.cpp:170:10:170:18 | call to ymlSource | test.cpp:170:10:170:18 | call to ymlSource | provenance | Src:MaD:31 | | test.cpp:170:10:170:18 | call to ymlSource | test.cpp:172:51:172:51 | x | provenance | | | test.cpp:172:13:172:44 | call to templateFunction3 | test.cpp:172:13:172:44 | call to templateFunction3 | provenance | | | test.cpp:172:13:172:44 | call to templateFunction3 | test.cpp:173:10:173:10 | y | provenance | Sink:MaD:1 | | test.cpp:172:51:172:51 | x | test.cpp:164:34:164:34 | x | provenance | | -| test.cpp:172:51:172:51 | x | test.cpp:172:13:172:44 | call to templateFunction3 | provenance | MaD:58 | +| test.cpp:172:51:172:51 | x | test.cpp:172:13:172:44 | call to templateFunction3 | provenance | MaD:64 | | test.cpp:186:2:186:2 | *s [post update] [myField] | test.cpp:187:33:187:34 | *& ... [myField] | provenance | | | test.cpp:186:2:186:24 | ... = ... | test.cpp:186:2:186:2 | *s [post update] [myField] | provenance | | -| test.cpp:186:14:186:22 | call to ymlSource | test.cpp:186:2:186:24 | ... = ... | provenance | Src:MaD:25 | +| test.cpp:186:14:186:22 | call to ymlSource | test.cpp:186:2:186:24 | ... = ... | provenance | Src:MaD:31 | | test.cpp:187:10:187:31 | call to read_field_from_struct | test.cpp:187:10:187:31 | call to read_field_from_struct | provenance | | | test.cpp:187:10:187:31 | call to read_field_from_struct | test.cpp:188:10:188:10 | x | provenance | Sink:MaD:1 | -| test.cpp:187:33:187:34 | *& ... [myField] | test.cpp:187:10:187:31 | call to read_field_from_struct | provenance | MaD:50 | +| test.cpp:187:33:187:34 | *& ... [myField] | test.cpp:187:10:187:31 | call to read_field_from_struct | provenance | MaD:56 | | test.cpp:199:2:199:2 | *s [post update] [myField] | test.cpp:200:35:200:36 | *& ... [myField] | provenance | | | test.cpp:199:2:199:24 | ... = ... | test.cpp:199:2:199:2 | *s [post update] [myField] | provenance | | -| test.cpp:199:14:199:22 | call to ymlSource | test.cpp:199:2:199:24 | ... = ... | provenance | Src:MaD:25 | +| test.cpp:199:14:199:22 | call to ymlSource | test.cpp:199:2:199:24 | ... = ... | provenance | Src:MaD:31 | | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | provenance | | | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | test.cpp:201:10:201:10 | x | provenance | Sink:MaD:1 | -| test.cpp:200:35:200:36 | *& ... [myField] | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | provenance | MaD:51 | +| test.cpp:200:35:200:36 | *& ... [myField] | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | provenance | MaD:57 | | test.cpp:216:3:216:4 | get_ptr output argument [value] | test.cpp:217:11:217:12 | *rf [value] | provenance | | -| test.cpp:216:3:216:28 | ... = ... | test.cpp:216:3:216:4 | get_ptr output argument [value] | provenance | MaD:57 | -| test.cpp:216:18:216:26 | call to ymlSource | test.cpp:216:3:216:28 | ... = ... | provenance | Src:MaD:25 | +| test.cpp:216:3:216:28 | ... = ... | test.cpp:216:3:216:4 | get_ptr output argument [value] | provenance | MaD:63 | +| test.cpp:216:18:216:26 | call to ymlSource | test.cpp:216:3:216:28 | ... = ... | provenance | Src:MaD:31 | | test.cpp:217:11:217:12 | *rf [value] | test.cpp:217:14:217:18 | value | provenance | | | test.cpp:217:14:217:18 | value | test.cpp:217:14:217:18 | value | provenance | | | test.cpp:217:14:217:18 | value | test.cpp:218:11:218:11 | x | provenance | Sink:MaD:1 | | test.cpp:222:3:222:3 | operator[] output argument | test.cpp:223:12:223:12 | *s | provenance | | -| test.cpp:222:3:222:20 | ... = ... | test.cpp:222:3:222:3 | operator[] output argument | provenance | MaD:56 | -| test.cpp:222:10:222:20 | call to ymlSource | test.cpp:222:3:222:20 | ... = ... | provenance | Src:MaD:25 | -| test.cpp:223:12:223:12 | *s | test.cpp:223:13:223:15 | call to operator[] | provenance | MaD:55 | +| test.cpp:222:3:222:20 | ... = ... | test.cpp:222:3:222:3 | operator[] output argument | provenance | MaD:62 | +| test.cpp:222:10:222:20 | call to ymlSource | test.cpp:222:3:222:20 | ... = ... | provenance | Src:MaD:31 | +| test.cpp:223:12:223:12 | *s | test.cpp:223:13:223:15 | call to operator[] | provenance | MaD:61 | | test.cpp:223:13:223:15 | call to operator[] | test.cpp:223:13:223:15 | call to operator[] | provenance | | | test.cpp:223:13:223:15 | call to operator[] | test.cpp:224:11:224:11 | c | provenance | Sink:MaD:1 | | windows.cpp:22:15:22:29 | *call to GetCommandLineA | windows.cpp:22:15:22:29 | *call to GetCommandLineA | provenance | Src:MaD:3 | @@ -212,7 +218,7 @@ edges | windows.cpp:22:15:22:29 | *call to GetCommandLineA | windows.cpp:27:36:27:38 | *cmd | provenance | | | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | provenance | | | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | windows.cpp:30:8:30:15 | * ... | provenance | | -| windows.cpp:27:36:27:38 | *cmd | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | provenance | MaD:33 | +| windows.cpp:27:36:27:38 | *cmd | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | provenance | MaD:39 | | windows.cpp:34:17:34:38 | *call to GetEnvironmentStringsA | windows.cpp:34:17:34:38 | *call to GetEnvironmentStringsA | provenance | Src:MaD:4 | | windows.cpp:34:17:34:38 | *call to GetEnvironmentStringsA | windows.cpp:36:10:36:13 | * ... | provenance | | | windows.cpp:39:36:39:38 | GetEnvironmentVariableA output argument | windows.cpp:41:10:41:13 | * ... | provenance | Src:MaD:5 | @@ -232,11 +238,11 @@ edges | windows.cpp:189:21:189:26 | ReadFile output argument | windows.cpp:190:5:190:56 | *... = ... | provenance | Src:MaD:17 | | windows.cpp:190:5:190:14 | *overlapped [post update] [*hEvent] | windows.cpp:192:53:192:63 | *& ... [*hEvent] | provenance | | | windows.cpp:190:5:190:56 | *... = ... | windows.cpp:190:5:190:14 | *overlapped [post update] [*hEvent] | provenance | | -| windows.cpp:192:53:192:63 | *& ... [*hEvent] | windows.cpp:147:16:147:27 | *lpOverlapped [*hEvent] | provenance | MaD:37 | +| windows.cpp:192:53:192:63 | *& ... [*hEvent] | windows.cpp:147:16:147:27 | *lpOverlapped [*hEvent] | provenance | MaD:43 | | windows.cpp:198:21:198:26 | ReadFile output argument | windows.cpp:199:5:199:57 | ... = ... | provenance | Src:MaD:17 | | windows.cpp:199:5:199:14 | *overlapped [post update] [hEvent] | windows.cpp:201:53:201:63 | *& ... [hEvent] | provenance | | | windows.cpp:199:5:199:57 | ... = ... | windows.cpp:199:5:199:14 | *overlapped [post update] [hEvent] | provenance | | -| windows.cpp:201:53:201:63 | *& ... [hEvent] | windows.cpp:157:16:157:27 | *lpOverlapped [hEvent] | provenance | MaD:37 | +| windows.cpp:201:53:201:63 | *& ... [hEvent] | windows.cpp:157:16:157:27 | *lpOverlapped [hEvent] | provenance | MaD:43 | | windows.cpp:209:84:209:89 | NtReadFile output argument | windows.cpp:211:10:211:16 | * ... | provenance | Src:MaD:16 | | windows.cpp:286:23:286:35 | *call to MapViewOfFile | windows.cpp:286:23:286:35 | *call to MapViewOfFile | provenance | Src:MaD:12 | | windows.cpp:286:23:286:35 | *call to MapViewOfFile | windows.cpp:287:20:287:52 | *pMapView | provenance | | @@ -273,9 +279,9 @@ edges | windows.cpp:431:3:431:3 | *s [post update] [x] | windows.cpp:464:7:464:8 | *& ... [x] | provenance | | | windows.cpp:431:3:431:16 | ... = ... | windows.cpp:431:3:431:3 | *s [post update] [x] | provenance | | | windows.cpp:431:9:431:14 | call to source | windows.cpp:431:3:431:16 | ... = ... | provenance | | -| windows.cpp:439:7:439:8 | *& ... [x] | windows.cpp:403:26:403:36 | *lpParameter [x] | provenance | MaD:36 | -| windows.cpp:451:7:451:8 | *& ... [x] | windows.cpp:410:26:410:36 | *lpParameter [x] | provenance | MaD:34 | -| windows.cpp:464:7:464:8 | *& ... [x] | windows.cpp:417:26:417:36 | *lpParameter [x] | provenance | MaD:35 | +| windows.cpp:439:7:439:8 | *& ... [x] | windows.cpp:403:26:403:36 | *lpParameter [x] | provenance | MaD:42 | +| windows.cpp:451:7:451:8 | *& ... [x] | windows.cpp:410:26:410:36 | *lpParameter [x] | provenance | MaD:40 | +| windows.cpp:464:7:464:8 | *& ... [x] | windows.cpp:417:26:417:36 | *lpParameter [x] | provenance | MaD:41 | | windows.cpp:533:11:533:16 | call to source | windows.cpp:533:11:533:16 | call to source | provenance | | | windows.cpp:533:11:533:16 | call to source | windows.cpp:537:40:537:41 | *& ... | provenance | | | windows.cpp:533:11:533:16 | call to source | windows.cpp:542:38:542:39 | *& ... | provenance | | @@ -284,39 +290,39 @@ edges | windows.cpp:533:11:533:16 | call to source | windows.cpp:568:32:568:33 | *& ... | provenance | | | windows.cpp:533:11:533:16 | call to source | windows.cpp:573:40:573:41 | *& ... | provenance | | | windows.cpp:537:27:537:37 | RtlCopyVolatileMemory output argument | windows.cpp:538:10:538:23 | access to array | provenance | | -| windows.cpp:537:40:537:41 | *& ... | windows.cpp:537:27:537:37 | RtlCopyVolatileMemory output argument | provenance | MaD:42 | +| windows.cpp:537:40:537:41 | *& ... | windows.cpp:537:27:537:37 | RtlCopyVolatileMemory output argument | provenance | MaD:48 | | windows.cpp:542:25:542:35 | RtlCopyDeviceMemory output argument | windows.cpp:543:10:543:23 | access to array | provenance | | -| windows.cpp:542:38:542:39 | *& ... | windows.cpp:542:25:542:35 | RtlCopyDeviceMemory output argument | provenance | MaD:38 | +| windows.cpp:542:38:542:39 | *& ... | windows.cpp:542:25:542:35 | RtlCopyDeviceMemory output argument | provenance | MaD:44 | | windows.cpp:547:19:547:29 | RtlCopyMemory output argument | windows.cpp:548:10:548:23 | access to array | provenance | | -| windows.cpp:547:32:547:33 | *& ... | windows.cpp:547:19:547:29 | RtlCopyMemory output argument | provenance | MaD:39 | +| windows.cpp:547:32:547:33 | *& ... | windows.cpp:547:19:547:29 | RtlCopyMemory output argument | provenance | MaD:45 | | windows.cpp:552:30:552:40 | RtlCopyMemoryNonTemporal output argument | windows.cpp:553:10:553:23 | access to array | provenance | | -| windows.cpp:552:43:552:44 | *& ... | windows.cpp:552:30:552:40 | RtlCopyMemoryNonTemporal output argument | provenance | MaD:40 | +| windows.cpp:552:43:552:44 | *& ... | windows.cpp:552:30:552:40 | RtlCopyMemoryNonTemporal output argument | provenance | MaD:46 | | windows.cpp:559:5:559:24 | ... = ... | windows.cpp:561:39:561:44 | *buffer | provenance | | | windows.cpp:559:17:559:24 | call to source | windows.cpp:559:5:559:24 | ... = ... | provenance | | | windows.cpp:561:26:561:36 | RtlInitUnicodeString output argument [*Buffer] | windows.cpp:562:10:562:19 | *src_string [*Buffer] | provenance | | | windows.cpp:561:26:561:36 | RtlInitUnicodeString output argument [*Buffer] | windows.cpp:563:40:563:50 | *& ... [*Buffer] | provenance | | -| windows.cpp:561:39:561:44 | *buffer | windows.cpp:561:26:561:36 | RtlInitUnicodeString output argument [*Buffer] | provenance | MaD:43 | +| windows.cpp:561:39:561:44 | *buffer | windows.cpp:561:26:561:36 | RtlInitUnicodeString output argument [*Buffer] | provenance | MaD:49 | | windows.cpp:562:10:562:19 | *src_string [*Buffer] | windows.cpp:562:10:562:29 | access to array | provenance | | | windows.cpp:562:10:562:19 | *src_string [*Buffer] | windows.cpp:562:21:562:26 | *Buffer | provenance | | | windows.cpp:562:21:562:26 | *Buffer | windows.cpp:562:10:562:29 | access to array | provenance | | | windows.cpp:563:26:563:37 | RtlCopyUnicodeString output argument [*Buffer] | windows.cpp:564:10:564:20 | *dest_string [*Buffer] | provenance | | -| windows.cpp:563:40:563:50 | *& ... [*Buffer] | windows.cpp:563:26:563:37 | RtlCopyUnicodeString output argument [*Buffer] | provenance | MaD:41 | +| windows.cpp:563:40:563:50 | *& ... [*Buffer] | windows.cpp:563:26:563:37 | RtlCopyUnicodeString output argument [*Buffer] | provenance | MaD:47 | | windows.cpp:564:10:564:20 | *dest_string [*Buffer] | windows.cpp:564:10:564:30 | access to array | provenance | | | windows.cpp:564:10:564:20 | *dest_string [*Buffer] | windows.cpp:564:22:564:27 | *Buffer | provenance | | | windows.cpp:564:22:564:27 | *Buffer | windows.cpp:564:10:564:30 | access to array | provenance | | | windows.cpp:568:19:568:29 | RtlMoveMemory output argument | windows.cpp:569:10:569:23 | access to array | provenance | | -| windows.cpp:568:32:568:33 | *& ... | windows.cpp:568:19:568:29 | RtlMoveMemory output argument | provenance | MaD:44 | +| windows.cpp:568:32:568:33 | *& ... | windows.cpp:568:19:568:29 | RtlMoveMemory output argument | provenance | MaD:50 | | windows.cpp:573:27:573:37 | RtlMoveVolatileMemory output argument | windows.cpp:574:10:574:23 | access to array | provenance | | -| windows.cpp:573:40:573:41 | *& ... | windows.cpp:573:27:573:37 | RtlMoveVolatileMemory output argument | provenance | MaD:45 | -| windows.cpp:645:45:645:50 | WinHttpReadData output argument | windows.cpp:647:10:647:16 | * ... | provenance | Src:MaD:23 | -| windows.cpp:652:48:652:53 | WinHttpReadDataEx output argument | windows.cpp:654:10:654:16 | * ... | provenance | Src:MaD:24 | -| windows.cpp:659:47:659:52 | WinHttpQueryHeaders output argument | windows.cpp:661:10:661:16 | * ... | provenance | Src:MaD:19 | -| windows.cpp:669:70:669:79 | WinHttpQueryHeadersEx output argument | windows.cpp:673:10:673:29 | * ... | provenance | Src:MaD:21 | -| windows.cpp:669:82:669:87 | WinHttpQueryHeadersEx output argument | windows.cpp:671:10:671:16 | * ... | provenance | Src:MaD:22 | -| windows.cpp:669:105:669:112 | WinHttpQueryHeadersEx output argument | windows.cpp:675:10:675:27 | * ... | provenance | Src:MaD:20 | +| windows.cpp:573:40:573:41 | *& ... | windows.cpp:573:27:573:37 | RtlMoveVolatileMemory output argument | provenance | MaD:51 | +| windows.cpp:645:45:645:50 | WinHttpReadData output argument | windows.cpp:647:10:647:16 | * ... | provenance | Src:MaD:29 | +| windows.cpp:652:48:652:53 | WinHttpReadDataEx output argument | windows.cpp:654:10:654:16 | * ... | provenance | Src:MaD:30 | +| windows.cpp:659:47:659:52 | WinHttpQueryHeaders output argument | windows.cpp:661:10:661:16 | * ... | provenance | Src:MaD:25 | +| windows.cpp:669:70:669:79 | WinHttpQueryHeadersEx output argument | windows.cpp:673:10:673:29 | * ... | provenance | Src:MaD:27 | +| windows.cpp:669:82:669:87 | WinHttpQueryHeadersEx output argument | windows.cpp:671:10:671:16 | * ... | provenance | Src:MaD:28 | +| windows.cpp:669:105:669:112 | WinHttpQueryHeadersEx output argument | windows.cpp:675:10:675:27 | * ... | provenance | Src:MaD:26 | | windows.cpp:728:5:728:28 | ... = ... | windows.cpp:729:35:729:35 | *x | provenance | | | windows.cpp:728:12:728:28 | call to source | windows.cpp:728:5:728:28 | ... = ... | provenance | | -| windows.cpp:729:35:729:35 | *x | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | provenance | MaD:46 | +| windows.cpp:729:35:729:35 | *x | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | provenance | MaD:52 | | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | windows.cpp:731:10:731:36 | * ... | provenance | | | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | windows.cpp:733:10:733:35 | * ... | provenance | | | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | windows.cpp:735:10:735:37 | * ... | provenance | | @@ -337,6 +343,12 @@ edges | windows.cpp:936:70:936:78 | HttpReceiveClientCertificate output argument | windows.cpp:937:15:937:48 | *& ... | provenance | Src:MaD:6 | | windows.cpp:936:70:936:78 | HttpReceiveClientCertificate output argument | windows.cpp:941:10:941:31 | * ... | provenance | Src:MaD:6 | | windows.cpp:937:15:937:48 | *& ... | windows.cpp:939:10:939:11 | * ... | provenance | | +| windows.cpp:989:35:989:38 | RegQueryValueA output argument | windows.cpp:991:10:991:14 | * ... | provenance | Src:MaD:21 | +| windows.cpp:996:36:996:39 | RegQueryValueW output argument | windows.cpp:998:10:998:14 | * ... | provenance | Src:MaD:24 | +| windows.cpp:1004:53:1004:56 | RegQueryValueExA output argument | windows.cpp:1006:10:1006:14 | * ... | provenance | Src:MaD:22 | +| windows.cpp:1012:54:1012:57 | RegQueryValueExW output argument | windows.cpp:1014:10:1014:14 | * ... | provenance | Src:MaD:23 | +| windows.cpp:1020:46:1020:49 | RegQueryMultipleValuesA output argument | windows.cpp:1022:10:1022:14 | * ... | provenance | Src:MaD:19 | +| windows.cpp:1028:46:1028:49 | RegQueryMultipleValuesW output argument | windows.cpp:1030:10:1030:14 | * ... | provenance | Src:MaD:20 | nodes | asio_streams.cpp:87:34:87:44 | read_until output argument | semmle.label | read_until output argument | | asio_streams.cpp:91:7:91:17 | recv_buffer | semmle.label | recv_buffer | @@ -653,6 +665,18 @@ nodes | windows.cpp:937:15:937:48 | *& ... | semmle.label | *& ... | | windows.cpp:939:10:939:11 | * ... | semmle.label | * ... | | windows.cpp:941:10:941:31 | * ... | semmle.label | * ... | +| windows.cpp:989:35:989:38 | RegQueryValueA output argument | semmle.label | RegQueryValueA output argument | +| windows.cpp:991:10:991:14 | * ... | semmle.label | * ... | +| windows.cpp:996:36:996:39 | RegQueryValueW output argument | semmle.label | RegQueryValueW output argument | +| windows.cpp:998:10:998:14 | * ... | semmle.label | * ... | +| windows.cpp:1004:53:1004:56 | RegQueryValueExA output argument | semmle.label | RegQueryValueExA output argument | +| windows.cpp:1006:10:1006:14 | * ... | semmle.label | * ... | +| windows.cpp:1012:54:1012:57 | RegQueryValueExW output argument | semmle.label | RegQueryValueExW output argument | +| windows.cpp:1014:10:1014:14 | * ... | semmle.label | * ... | +| windows.cpp:1020:46:1020:49 | RegQueryMultipleValuesA output argument | semmle.label | RegQueryMultipleValuesA output argument | +| windows.cpp:1022:10:1022:14 | * ... | semmle.label | * ... | +| windows.cpp:1028:46:1028:49 | RegQueryMultipleValuesW output argument | semmle.label | RegQueryMultipleValuesW output argument | +| windows.cpp:1030:10:1030:14 | * ... | semmle.label | * ... | subpaths | test.cpp:32:41:32:41 | x | test.cpp:7:47:7:52 | value2 | test.cpp:7:5:7:30 | *ymlStepGenerated_with_body | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | | test.cpp:172:51:172:51 | x | test.cpp:164:34:164:34 | x | test.cpp:164:7:164:7 | *templateFunction3 | test.cpp:172:13:172:44 | call to templateFunction3 | diff --git a/cpp/ql/test/library-tests/dataflow/external-models/sources.expected b/cpp/ql/test/library-tests/dataflow/external-models/sources.expected index 6585c88dc6dd..37162a09c189 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/sources.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/sources.expected @@ -43,3 +43,9 @@ | windows.cpp:900:64:900:77 | HttpReceiveHttpRequest output argument | remote | | windows.cpp:929:70:929:75 | HttpReceiveRequestEntityBody output argument | remote | | windows.cpp:936:70:936:78 | HttpReceiveClientCertificate output argument | remote | +| windows.cpp:989:35:989:38 | RegQueryValueA output argument | local | +| windows.cpp:996:36:996:39 | RegQueryValueW output argument | local | +| windows.cpp:1004:53:1004:56 | RegQueryValueExA output argument | local | +| windows.cpp:1012:54:1012:57 | RegQueryValueExW output argument | local | +| windows.cpp:1020:46:1020:49 | RegQueryMultipleValuesA output argument | local | +| windows.cpp:1028:46:1028:49 | RegQueryMultipleValuesW output argument | local | diff --git a/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp b/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp index 19ee57cd58b8..2fe55480ca13 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp +++ b/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp @@ -988,14 +988,14 @@ void test_registry_queries(HKEY hKey) { LONG dataSize = sizeof(data); RegQueryValueA(hKey, "value", data, &dataSize); sink(data); // clean - sink(*data); // $ MISSING: ir + sink(*data); // $ ir } { wchar_t data[256]; LONG dataSize = sizeof(data); RegQueryValueW(hKey, L"value", data, &dataSize); sink(data); // clean - sink(*data); // $ MISSING: ir + sink(*data); // $ ir } { BYTE data[256]; @@ -1003,7 +1003,7 @@ void test_registry_queries(HKEY hKey) { DWORD type; RegQueryValueExA(hKey, "value", nullptr, &type, data, &dataSize); sink(data); // clean - sink(*data); // $ MISSING: ir + sink(*data); // $ ir } { BYTE data[256]; @@ -1011,7 +1011,7 @@ void test_registry_queries(HKEY hKey) { DWORD type; RegQueryValueExW(hKey, L"value", nullptr, &type, data, &dataSize); sink(data); // clean - sink(*data); // $ MISSING: ir + sink(*data); // $ ir } { VALENTA values[1]; @@ -1019,7 +1019,7 @@ void test_registry_queries(HKEY hKey) { DWORD dataSize = sizeof(data); RegQueryMultipleValuesA(hKey, values, 1, data, &dataSize); sink(data); // clean - sink(*data); // $ MISSING: ir + sink(*data); // $ ir } { VALENTW values[1]; @@ -1027,6 +1027,6 @@ void test_registry_queries(HKEY hKey) { DWORD dataSize = sizeof(data); RegQueryMultipleValuesW(hKey, values, 1, data, &dataSize); sink(data); // clean - sink(*data); // $ MISSING: ir + sink(*data); // $ ir } } \ No newline at end of file From 7bd322a3c7b26797a545f2839b2847244d6237c5 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 28 Jul 2026 12:26:18 +0100 Subject: [PATCH 077/188] C++: Add change note. --- cpp/ql/lib/change-notes/2026-07-28-winreg-sources.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 cpp/ql/lib/change-notes/2026-07-28-winreg-sources.md diff --git a/cpp/ql/lib/change-notes/2026-07-28-winreg-sources.md b/cpp/ql/lib/change-notes/2026-07-28-winreg-sources.md new file mode 100644 index 000000000000..9a70926b9984 --- /dev/null +++ b/cpp/ql/lib/change-notes/2026-07-28-winreg-sources.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Added flow source models for `RegQueryValue` and related functions from the `winreg.h` Windows header. \ No newline at end of file From a2ff35a72df1761606c0abffbf0b7405f0ce85c9 Mon Sep 17 00:00:00 2001 From: Taus Date: Tue, 28 Jul 2026 11:45:53 +0000 Subject: [PATCH 078/188] unified: Fix Bazel formatting errors --- unified/BUILD.bazel | 2 +- unified/swift-syntax-rs/BUILD.bazel | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/unified/BUILD.bazel b/unified/BUILD.bazel index a54080b0542d..405500d7d407 100644 --- a/unified/BUILD.bazel +++ b/unified/BUILD.bazel @@ -54,8 +54,8 @@ codeql_pkg_files( pkg_filegroup( name = "swift-syntax-parse-arch", srcs = select_os( - posix = ["//unified/swift-syntax-rs:swift-syntax-parse-pkg"], otherwise = [], + posix = ["//unified/swift-syntax-rs:swift-syntax-parse-pkg"], ), prefix = "tools/{CODEQL_PLATFORM}", ) diff --git a/unified/swift-syntax-rs/BUILD.bazel b/unified/swift-syntax-rs/BUILD.bazel index 651cb09531e3..db451e5b7b9a 100644 --- a/unified/swift-syntax-rs/BUILD.bazel +++ b/unified/swift-syntax-rs/BUILD.bazel @@ -86,10 +86,10 @@ sh_binary( # the real binary, and the runtime libraries, flattened into one directory. codeql_pkg_runfiles( name = "swift-syntax-parse-pkg", - exes = [":swift-syntax-parse"], # The `.sh` source is shipped as `swift-syntax-parse` (the wrapper); drop the # original filename. excludes = ["swift-syntax-parse.sh"], + exes = [":swift-syntax-parse"], target_compatible_with = _SWIFT_SUPPORTED_PLATFORMS, visibility = ["//unified:__pkg__"], ) From ceffe40a54849056069d2f5c33cf403486a168e0 Mon Sep 17 00:00:00 2001 From: Taus Date: Tue, 28 Jul 2026 11:55:11 +0000 Subject: [PATCH 079/188] unified: Remove references to Swift input schema generation --- unified/extractor/src/languages/swift/adapter.rs | 8 ++++---- unified/extractor/swift_node_types.yml | 1 - 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/unified/extractor/src/languages/swift/adapter.rs b/unified/extractor/src/languages/swift/adapter.rs index 696fce889708..4ae4040d043d 100644 --- a/unified/extractor/src/languages/swift/adapter.rs +++ b/unified/extractor/src/languages/swift/adapter.rs @@ -262,10 +262,10 @@ fn parse_range(node: &Value) -> Option { }) } -/// The authoritative swift-syntax input node-types schema, generated from -/// swift-syntax (see the schemagen tool). [`json_to_ast`] seeds every parse -/// with the schema built from this, pre-registering every input kind and field -/// so rule matching never references a name absent from a given file's tree. +/// The authoritative swift-syntax input node-types schema. +/// [`json_to_ast`] seeds every parse with the schema built from this, +/// pre-registering every input kind and field so rule matching never references +/// a name absent from a given file's tree. const SWIFT_NODE_TYPES: &str = include_str!("../../../swift_node_types.yml"); /// Convert a swift-syntax JSON tree (as produced by [`crate::parse_to_json`]) diff --git a/unified/extractor/swift_node_types.yml b/unified/extractor/swift_node_types.yml index d8793acce2ca..c98dd1d33b23 100644 --- a/unified/extractor/swift_node_types.yml +++ b/unified/extractor/swift_node_types.yml @@ -1,4 +1,3 @@ -# GENERATED from swift-syntax by the one-off schemagen tool. Do not edit. supertypes: decl: - accessorDecl From c11b4914e93bd6742dd3bc26d1565691e3586df4 Mon Sep 17 00:00:00 2001 From: yoff Date: Tue, 28 Jul 2026 14:42:04 +0200 Subject: [PATCH 080/188] Update python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll Co-authored-by: Anders Schack-Mulligen --- python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll | 1 - 1 file changed, 1 deletion(-) diff --git a/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll b/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll index 21dbad68b814..bfbd6e29bdd7 100644 --- a/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll +++ b/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll @@ -1755,7 +1755,6 @@ private module Input implements InputSig1, InputSig2 { } } -import CfgCachedStage import Public /** From c516d1f0b951aa973686ed3383066c1057f12d57 Mon Sep 17 00:00:00 2001 From: yoff Date: Tue, 28 Jul 2026 14:49:18 +0200 Subject: [PATCH 081/188] python: forward rather implement subtle predicates --- .../python/controlflow/internal/Cfg.qll | 26 ++----------------- 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/python/ql/lib/semmle/python/controlflow/internal/Cfg.qll b/python/ql/lib/semmle/python/controlflow/internal/Cfg.qll index b102c71391fe..3441ad0203c1 100644 --- a/python/ql/lib/semmle/python/controlflow/internal/Cfg.qll +++ b/python/ql/lib/semmle/python/controlflow/internal/Cfg.qll @@ -280,14 +280,7 @@ class BasicBlock extends CfgImpl::BasicBlock { * doesn't currently expose a `dominanceFrontier` predicate at this * level. */ - predicate inDominanceFrontier(BasicBlock df) { - this = df.getAPredecessor() and not this = df.getImmediateDominator() - or - exists(BasicBlock prev | prev.inDominanceFrontier(df) | - this = prev.getImmediateDominator() and - not this = df.getImmediateDominator() - ) - } + predicate inDominanceFrontier(BasicBlock df) { super.inDominanceFrontier(df) } /** Holds if this basic block strictly reaches `other`. */ predicate strictlyReaches(BasicBlock other) { super.getASuccessor+() = other } @@ -326,22 +319,7 @@ class BasicBlock extends CfgImpl::BasicBlock { * This mirrors the legacy `ConditionBlock.controls(BB, branch)`. */ predicate controls(BasicBlock other, boolean branch) { - exists(BasicBlock succ | - branch = true and succ = this.getATrueSuccessor() - or - branch = false and succ = this.getAFalseSuccessor() - | - succ.dominates(other) and - // The other branch must not also reach `other` — otherwise - // `other` is not actually controlled by `branch`. - not exists(BasicBlock otherSucc | - branch = true and otherSucc = this.getAFalseSuccessor() - or - branch = false and otherSucc = this.getATrueSuccessor() - | - otherSucc.reaches(other) - ) - ) + super.edgeDominates(other, any(BooleanSuccessor t | t.getValue() = branch)) } } From b0f345a1ad4a3d79e5f512beeb6ff7764f668d5c Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 28 Jul 2026 13:48:59 +0100 Subject: [PATCH 082/188] C++: Add a test for 'RegGetValueA'. --- .../dataflow/external-models/flow.expected | 36 +++++++++---------- .../dataflow/external-models/sources.expected | 12 +++---- .../dataflow/external-models/windows.cpp | 13 +++++++ 3 files changed, 37 insertions(+), 24 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/external-models/flow.expected b/cpp/ql/test/library-tests/dataflow/external-models/flow.expected index 49740545f77a..581d152023cd 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/flow.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/flow.expected @@ -343,12 +343,12 @@ edges | windows.cpp:936:70:936:78 | HttpReceiveClientCertificate output argument | windows.cpp:937:15:937:48 | *& ... | provenance | Src:MaD:6 | | windows.cpp:936:70:936:78 | HttpReceiveClientCertificate output argument | windows.cpp:941:10:941:31 | * ... | provenance | Src:MaD:6 | | windows.cpp:937:15:937:48 | *& ... | windows.cpp:939:10:939:11 | * ... | provenance | | -| windows.cpp:989:35:989:38 | RegQueryValueA output argument | windows.cpp:991:10:991:14 | * ... | provenance | Src:MaD:21 | -| windows.cpp:996:36:996:39 | RegQueryValueW output argument | windows.cpp:998:10:998:14 | * ... | provenance | Src:MaD:24 | -| windows.cpp:1004:53:1004:56 | RegQueryValueExA output argument | windows.cpp:1006:10:1006:14 | * ... | provenance | Src:MaD:22 | -| windows.cpp:1012:54:1012:57 | RegQueryValueExW output argument | windows.cpp:1014:10:1014:14 | * ... | provenance | Src:MaD:23 | -| windows.cpp:1020:46:1020:49 | RegQueryMultipleValuesA output argument | windows.cpp:1022:10:1022:14 | * ... | provenance | Src:MaD:19 | -| windows.cpp:1028:46:1028:49 | RegQueryMultipleValuesW output argument | windows.cpp:1030:10:1030:14 | * ... | provenance | Src:MaD:20 | +| windows.cpp:994:35:994:38 | RegQueryValueA output argument | windows.cpp:996:10:996:14 | * ... | provenance | Src:MaD:21 | +| windows.cpp:1001:36:1001:39 | RegQueryValueW output argument | windows.cpp:1003:10:1003:14 | * ... | provenance | Src:MaD:24 | +| windows.cpp:1009:53:1009:56 | RegQueryValueExA output argument | windows.cpp:1011:10:1011:14 | * ... | provenance | Src:MaD:22 | +| windows.cpp:1017:54:1017:57 | RegQueryValueExW output argument | windows.cpp:1019:10:1019:14 | * ... | provenance | Src:MaD:23 | +| windows.cpp:1025:46:1025:49 | RegQueryMultipleValuesA output argument | windows.cpp:1027:10:1027:14 | * ... | provenance | Src:MaD:19 | +| windows.cpp:1033:46:1033:49 | RegQueryMultipleValuesW output argument | windows.cpp:1035:10:1035:14 | * ... | provenance | Src:MaD:20 | nodes | asio_streams.cpp:87:34:87:44 | read_until output argument | semmle.label | read_until output argument | | asio_streams.cpp:91:7:91:17 | recv_buffer | semmle.label | recv_buffer | @@ -665,18 +665,18 @@ nodes | windows.cpp:937:15:937:48 | *& ... | semmle.label | *& ... | | windows.cpp:939:10:939:11 | * ... | semmle.label | * ... | | windows.cpp:941:10:941:31 | * ... | semmle.label | * ... | -| windows.cpp:989:35:989:38 | RegQueryValueA output argument | semmle.label | RegQueryValueA output argument | -| windows.cpp:991:10:991:14 | * ... | semmle.label | * ... | -| windows.cpp:996:36:996:39 | RegQueryValueW output argument | semmle.label | RegQueryValueW output argument | -| windows.cpp:998:10:998:14 | * ... | semmle.label | * ... | -| windows.cpp:1004:53:1004:56 | RegQueryValueExA output argument | semmle.label | RegQueryValueExA output argument | -| windows.cpp:1006:10:1006:14 | * ... | semmle.label | * ... | -| windows.cpp:1012:54:1012:57 | RegQueryValueExW output argument | semmle.label | RegQueryValueExW output argument | -| windows.cpp:1014:10:1014:14 | * ... | semmle.label | * ... | -| windows.cpp:1020:46:1020:49 | RegQueryMultipleValuesA output argument | semmle.label | RegQueryMultipleValuesA output argument | -| windows.cpp:1022:10:1022:14 | * ... | semmle.label | * ... | -| windows.cpp:1028:46:1028:49 | RegQueryMultipleValuesW output argument | semmle.label | RegQueryMultipleValuesW output argument | -| windows.cpp:1030:10:1030:14 | * ... | semmle.label | * ... | +| windows.cpp:994:35:994:38 | RegQueryValueA output argument | semmle.label | RegQueryValueA output argument | +| windows.cpp:996:10:996:14 | * ... | semmle.label | * ... | +| windows.cpp:1001:36:1001:39 | RegQueryValueW output argument | semmle.label | RegQueryValueW output argument | +| windows.cpp:1003:10:1003:14 | * ... | semmle.label | * ... | +| windows.cpp:1009:53:1009:56 | RegQueryValueExA output argument | semmle.label | RegQueryValueExA output argument | +| windows.cpp:1011:10:1011:14 | * ... | semmle.label | * ... | +| windows.cpp:1017:54:1017:57 | RegQueryValueExW output argument | semmle.label | RegQueryValueExW output argument | +| windows.cpp:1019:10:1019:14 | * ... | semmle.label | * ... | +| windows.cpp:1025:46:1025:49 | RegQueryMultipleValuesA output argument | semmle.label | RegQueryMultipleValuesA output argument | +| windows.cpp:1027:10:1027:14 | * ... | semmle.label | * ... | +| windows.cpp:1033:46:1033:49 | RegQueryMultipleValuesW output argument | semmle.label | RegQueryMultipleValuesW output argument | +| windows.cpp:1035:10:1035:14 | * ... | semmle.label | * ... | subpaths | test.cpp:32:41:32:41 | x | test.cpp:7:47:7:52 | value2 | test.cpp:7:5:7:30 | *ymlStepGenerated_with_body | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | | test.cpp:172:51:172:51 | x | test.cpp:164:34:164:34 | x | test.cpp:164:7:164:7 | *templateFunction3 | test.cpp:172:13:172:44 | call to templateFunction3 | diff --git a/cpp/ql/test/library-tests/dataflow/external-models/sources.expected b/cpp/ql/test/library-tests/dataflow/external-models/sources.expected index 37162a09c189..7adf091e962e 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/sources.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/sources.expected @@ -43,9 +43,9 @@ | windows.cpp:900:64:900:77 | HttpReceiveHttpRequest output argument | remote | | windows.cpp:929:70:929:75 | HttpReceiveRequestEntityBody output argument | remote | | windows.cpp:936:70:936:78 | HttpReceiveClientCertificate output argument | remote | -| windows.cpp:989:35:989:38 | RegQueryValueA output argument | local | -| windows.cpp:996:36:996:39 | RegQueryValueW output argument | local | -| windows.cpp:1004:53:1004:56 | RegQueryValueExA output argument | local | -| windows.cpp:1012:54:1012:57 | RegQueryValueExW output argument | local | -| windows.cpp:1020:46:1020:49 | RegQueryMultipleValuesA output argument | local | -| windows.cpp:1028:46:1028:49 | RegQueryMultipleValuesW output argument | local | +| windows.cpp:994:35:994:38 | RegQueryValueA output argument | local | +| windows.cpp:1001:36:1001:39 | RegQueryValueW output argument | local | +| windows.cpp:1009:53:1009:56 | RegQueryValueExA output argument | local | +| windows.cpp:1017:54:1017:57 | RegQueryValueExW output argument | local | +| windows.cpp:1025:46:1025:49 | RegQueryMultipleValuesA output argument | local | +| windows.cpp:1033:46:1033:49 | RegQueryMultipleValuesW output argument | local | diff --git a/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp b/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp index 2fe55480ca13..03854a6965a5 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp +++ b/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp @@ -974,6 +974,11 @@ LONG RegQueryValueExW( LPDWORD lpcbData ); +LONG RegGetValueA( + HKEY hKey, LPCSTR lpSubKey, LPCSTR lpValue, DWORD flags, LPDWORD lpType, PVOID lpData, + LPDWORD lpcbData +); + LONG RegQueryMultipleValuesA( HKEY hKey, PVALENTA valList, DWORD numVals, LPSTR valueBuffer, LPDWORD totalSize ); @@ -1029,4 +1034,12 @@ void test_registry_queries(HKEY hKey) { sink(data); // clean sink(*data); // $ ir } + { + BYTE data[256]; + DWORD dataSize = sizeof(data); + DWORD type; + RegGetValueA(hKey, "subkey", "value", 0, &type, data, &dataSize); + sink(data); // clean + sink(*data); // $ MISSING: ir + } } \ No newline at end of file From daefacfcc90d73cccf90b55d818247ead1239887 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 28 Jul 2026 13:52:09 +0100 Subject: [PATCH 083/188] C++: Add models for 'RegGetValue' and friends. --- cpp/ql/lib/ext/Windows.model.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cpp/ql/lib/ext/Windows.model.yml b/cpp/ql/lib/ext/Windows.model.yml index 3e7ef1fb4fe6..e9f6dfd7fbfd 100644 --- a/cpp/ql/lib/ext/Windows.model.yml +++ b/cpp/ql/lib/ext/Windows.model.yml @@ -39,6 +39,8 @@ extensions: - ["", "", False, "RegQueryValueExA", "", "", "Argument[*4]", "local", "manual"] - ["", "", False, "RegQueryValueW", "", "", "Argument[*2]", "local", "manual"] - ["", "", False, "RegQueryValueExW", "", "", "Argument[*4]", "local", "manual"] + - ["", "", False, "RegGetValueA", "", "", "Argument[*5]", "local", "manual"] + - ["", "", False, "RegGetValueW", "", "", "Argument[*5]", "local", "manual"] # TODO: Once we support access paths at sources we should also mark Argument[*1].Field[*ve_valueptr] - ["", "", False, "RegQueryMultipleValuesA", "", "", "Argument[*3]", "local", "manual"] # TODO: Once we support access paths at sources we should also mark Argument[*1].Field[*ve_valueptr] From 034a90bf2a33d86b42837a8d47e8aaa3ae187cba Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 28 Jul 2026 13:53:06 +0100 Subject: [PATCH 084/188] C++: Accept test changes. --- .../dataflow/external-models/flow.expected | 254 +++++++++--------- .../dataflow/external-models/sources.expected | 1 + .../dataflow/external-models/windows.cpp | 2 +- 3 files changed, 131 insertions(+), 126 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/external-models/flow.expected b/cpp/ql/test/library-tests/dataflow/external-models/flow.expected index 581d152023cd..df453de8e1d3 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/flow.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/flow.expected @@ -17,110 +17,111 @@ models | 16 | Source: ; ; false; NtReadFile; ; ; Argument[*5]; local; manual | | 17 | Source: ; ; false; ReadFile; ; ; Argument[*1]; local; manual | | 18 | Source: ; ; false; ReadFileEx; ; ; Argument[*1]; local; manual | -| 19 | Source: ; ; false; RegQueryMultipleValuesA; ; ; Argument[*3]; local; manual | -| 20 | Source: ; ; false; RegQueryMultipleValuesW; ; ; Argument[*3]; local; manual | -| 21 | Source: ; ; false; RegQueryValueA; ; ; Argument[*2]; local; manual | -| 22 | Source: ; ; false; RegQueryValueExA; ; ; Argument[*4]; local; manual | -| 23 | Source: ; ; false; RegQueryValueExW; ; ; Argument[*4]; local; manual | -| 24 | Source: ; ; false; RegQueryValueW; ; ; Argument[*2]; local; manual | -| 25 | Source: ; ; false; WinHttpQueryHeaders; ; ; Argument[*3]; remote; manual | -| 26 | Source: ; ; false; WinHttpQueryHeadersEx; ; ; Argument[**8]; remote; manual | -| 27 | Source: ; ; false; WinHttpQueryHeadersEx; ; ; Argument[*5]; remote; manual | -| 28 | Source: ; ; false; WinHttpQueryHeadersEx; ; ; Argument[*6]; remote; manual | -| 29 | Source: ; ; false; WinHttpReadData; ; ; Argument[*1]; remote; manual | -| 30 | Source: ; ; false; WinHttpReadDataEx; ; ; Argument[*1]; remote; manual | -| 31 | Source: ; ; false; ymlSource; ; ; ReturnValue; local; manual | -| 32 | Source: Azure::Core::Http; RawResponse; true; ExtractBodyStream; ; ; ReturnValue[*]; remote; manual | -| 33 | Source: Azure::Core::Http; RawResponse; true; GetBody; ; ; ReturnValue[*]; remote; manual | -| 34 | Source: Azure::Core::Http; RawResponse; true; GetHeaders; ; ; ReturnValue[*]; remote; manual | -| 35 | Source: Azure::Core::Http; Request; true; GetBodyStream; ; ; ReturnValue[*]; remote; manual | -| 36 | Source: Azure::Core::Http; Request; true; GetHeader; ; ; ReturnValue; remote; manual | -| 37 | Source: Azure::Core::Http; Request; true; GetHeaders; ; ; ReturnValue; remote; manual | -| 38 | Source: boost::asio; ; false; read_until; ; ; Argument[*1]; remote; manual | -| 39 | Summary: ; ; false; CommandLineToArgvA; ; ; Argument[*0]; ReturnValue[**]; taint; manual | -| 40 | Summary: ; ; false; CreateRemoteThread; ; ; Argument[@4]; Argument[3].Parameter[@0]; value; manual | -| 41 | Summary: ; ; false; CreateRemoteThreadEx; ; ; Argument[@4]; Argument[3].Parameter[@0]; value; manual | -| 42 | Summary: ; ; false; CreateThread; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual | -| 43 | Summary: ; ; false; ReadFileEx; ; ; Argument[*3].Field[@hEvent]; Argument[4].Parameter[*2].Field[@hEvent]; value; manual | -| 44 | Summary: ; ; false; RtlCopyDeviceMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | -| 45 | Summary: ; ; false; RtlCopyMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | -| 46 | Summary: ; ; false; RtlCopyMemoryNonTemporal; ; ; Argument[*@1]; Argument[*@0]; value; manual | -| 47 | Summary: ; ; false; RtlCopyUnicodeString; ; ; Argument[*1].Field[*Buffer]; Argument[*0].Field[*Buffer]; value; manual | -| 48 | Summary: ; ; false; RtlCopyVolatileMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | -| 49 | Summary: ; ; false; RtlInitUnicodeString; ; ; Argument[*1]; Argument[*0].Field[*Buffer]; value; manual | -| 50 | Summary: ; ; false; RtlMoveMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | -| 51 | Summary: ; ; false; RtlMoveVolatileMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | -| 52 | Summary: ; ; false; WinHttpCrackUrl; ; ; Argument[*0]; Argument[*3]; taint; manual | -| 53 | Summary: ; ; false; callWithArgument; ; ; Argument[1]; Argument[0].Parameter[0]; value; manual | -| 54 | Summary: ; ; false; callWithNonTypeTemplate; (const T &); ; Argument[*0]; ReturnValue; value; manual | -| 55 | Summary: ; ; false; pthread_create; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual | -| 56 | Summary: ; ; false; read_field_from_struct; ; ; Argument[*0].Field[MyNamespace::MyStructInNamespace::myField]; ReturnValue; value; manual | -| 57 | Summary: ; ; false; read_field_from_struct_2; ; ; Argument[*0].Field[MyGlobalStruct::myField]; ReturnValue; value; manual | -| 58 | Summary: ; ; false; ymlStepGenerated; ; ; Argument[0]; ReturnValue; taint; df-generated | -| 59 | Summary: ; ; false; ymlStepManual; ; ; Argument[0]; ReturnValue; taint; manual | -| 60 | Summary: ; ; false; ymlStepManual_with_body; ; ; Argument[0]; ReturnValue; taint; manual | -| 61 | Summary: ; MyString; true; operator[]; ; ; Argument[-1]; ReturnValue[*]; taint; manual | -| 62 | Summary: ; MyString; true; operator[]; ; ; ReturnValue[*]; Argument[-1]; taint; manual | -| 63 | Summary: ; ReverseFlow; true; get_ptr; ; ; ReturnValue[*]; Argument[-1].Field[ReverseFlow::value]; value; manual | -| 64 | Summary: ; TemplateClass1; true; templateFunction2; (U,V); ; Argument[1]; ReturnValue; value; manual | -| 65 | Summary: ; TemplateClass1; false; templateFunction; (T,U); ; Argument[0]; ReturnValue; value; manual | -| 66 | Summary: ; TemplateClass2; true; function; (U,T); ; Argument[1]; ReturnValue; value; manual | -| 67 | Summary: Azure::Core::IO; BodyStream; true; Read; ; ; Argument[-1]; Argument[*0]; taint; manual | -| 68 | Summary: Azure::Core::IO; BodyStream; true; ReadToCount; ; ; Argument[-1]; Argument[*0]; taint; manual | -| 69 | Summary: Azure::Core::IO; BodyStream; true; ReadToEnd; ; ; Argument[-1]; ReturnValue.Element; taint; manual | -| 70 | Summary: Azure; Nullable; true; Value; ; ; Argument[-1]; ReturnValue[*]; taint; manual | -| 71 | Summary: boost::asio; ; false; buffer; ; ; Argument[*0]; ReturnValue; taint; manual | +| 19 | Source: ; ; false; RegGetValueA; ; ; Argument[*5]; local; manual | +| 20 | Source: ; ; false; RegQueryMultipleValuesA; ; ; Argument[*3]; local; manual | +| 21 | Source: ; ; false; RegQueryMultipleValuesW; ; ; Argument[*3]; local; manual | +| 22 | Source: ; ; false; RegQueryValueA; ; ; Argument[*2]; local; manual | +| 23 | Source: ; ; false; RegQueryValueExA; ; ; Argument[*4]; local; manual | +| 24 | Source: ; ; false; RegQueryValueExW; ; ; Argument[*4]; local; manual | +| 25 | Source: ; ; false; RegQueryValueW; ; ; Argument[*2]; local; manual | +| 26 | Source: ; ; false; WinHttpQueryHeaders; ; ; Argument[*3]; remote; manual | +| 27 | Source: ; ; false; WinHttpQueryHeadersEx; ; ; Argument[**8]; remote; manual | +| 28 | Source: ; ; false; WinHttpQueryHeadersEx; ; ; Argument[*5]; remote; manual | +| 29 | Source: ; ; false; WinHttpQueryHeadersEx; ; ; Argument[*6]; remote; manual | +| 30 | Source: ; ; false; WinHttpReadData; ; ; Argument[*1]; remote; manual | +| 31 | Source: ; ; false; WinHttpReadDataEx; ; ; Argument[*1]; remote; manual | +| 32 | Source: ; ; false; ymlSource; ; ; ReturnValue; local; manual | +| 33 | Source: Azure::Core::Http; RawResponse; true; ExtractBodyStream; ; ; ReturnValue[*]; remote; manual | +| 34 | Source: Azure::Core::Http; RawResponse; true; GetBody; ; ; ReturnValue[*]; remote; manual | +| 35 | Source: Azure::Core::Http; RawResponse; true; GetHeaders; ; ; ReturnValue[*]; remote; manual | +| 36 | Source: Azure::Core::Http; Request; true; GetBodyStream; ; ; ReturnValue[*]; remote; manual | +| 37 | Source: Azure::Core::Http; Request; true; GetHeader; ; ; ReturnValue; remote; manual | +| 38 | Source: Azure::Core::Http; Request; true; GetHeaders; ; ; ReturnValue; remote; manual | +| 39 | Source: boost::asio; ; false; read_until; ; ; Argument[*1]; remote; manual | +| 40 | Summary: ; ; false; CommandLineToArgvA; ; ; Argument[*0]; ReturnValue[**]; taint; manual | +| 41 | Summary: ; ; false; CreateRemoteThread; ; ; Argument[@4]; Argument[3].Parameter[@0]; value; manual | +| 42 | Summary: ; ; false; CreateRemoteThreadEx; ; ; Argument[@4]; Argument[3].Parameter[@0]; value; manual | +| 43 | Summary: ; ; false; CreateThread; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual | +| 44 | Summary: ; ; false; ReadFileEx; ; ; Argument[*3].Field[@hEvent]; Argument[4].Parameter[*2].Field[@hEvent]; value; manual | +| 45 | Summary: ; ; false; RtlCopyDeviceMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | +| 46 | Summary: ; ; false; RtlCopyMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | +| 47 | Summary: ; ; false; RtlCopyMemoryNonTemporal; ; ; Argument[*@1]; Argument[*@0]; value; manual | +| 48 | Summary: ; ; false; RtlCopyUnicodeString; ; ; Argument[*1].Field[*Buffer]; Argument[*0].Field[*Buffer]; value; manual | +| 49 | Summary: ; ; false; RtlCopyVolatileMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | +| 50 | Summary: ; ; false; RtlInitUnicodeString; ; ; Argument[*1]; Argument[*0].Field[*Buffer]; value; manual | +| 51 | Summary: ; ; false; RtlMoveMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | +| 52 | Summary: ; ; false; RtlMoveVolatileMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | +| 53 | Summary: ; ; false; WinHttpCrackUrl; ; ; Argument[*0]; Argument[*3]; taint; manual | +| 54 | Summary: ; ; false; callWithArgument; ; ; Argument[1]; Argument[0].Parameter[0]; value; manual | +| 55 | Summary: ; ; false; callWithNonTypeTemplate; (const T &); ; Argument[*0]; ReturnValue; value; manual | +| 56 | Summary: ; ; false; pthread_create; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual | +| 57 | Summary: ; ; false; read_field_from_struct; ; ; Argument[*0].Field[MyNamespace::MyStructInNamespace::myField]; ReturnValue; value; manual | +| 58 | Summary: ; ; false; read_field_from_struct_2; ; ; Argument[*0].Field[MyGlobalStruct::myField]; ReturnValue; value; manual | +| 59 | Summary: ; ; false; ymlStepGenerated; ; ; Argument[0]; ReturnValue; taint; df-generated | +| 60 | Summary: ; ; false; ymlStepManual; ; ; Argument[0]; ReturnValue; taint; manual | +| 61 | Summary: ; ; false; ymlStepManual_with_body; ; ; Argument[0]; ReturnValue; taint; manual | +| 62 | Summary: ; MyString; true; operator[]; ; ; Argument[-1]; ReturnValue[*]; taint; manual | +| 63 | Summary: ; MyString; true; operator[]; ; ; ReturnValue[*]; Argument[-1]; taint; manual | +| 64 | Summary: ; ReverseFlow; true; get_ptr; ; ; ReturnValue[*]; Argument[-1].Field[ReverseFlow::value]; value; manual | +| 65 | Summary: ; TemplateClass1; true; templateFunction2; (U,V); ; Argument[1]; ReturnValue; value; manual | +| 66 | Summary: ; TemplateClass1; false; templateFunction; (T,U); ; Argument[0]; ReturnValue; value; manual | +| 67 | Summary: ; TemplateClass2; true; function; (U,T); ; Argument[1]; ReturnValue; value; manual | +| 68 | Summary: Azure::Core::IO; BodyStream; true; Read; ; ; Argument[-1]; Argument[*0]; taint; manual | +| 69 | Summary: Azure::Core::IO; BodyStream; true; ReadToCount; ; ; Argument[-1]; Argument[*0]; taint; manual | +| 70 | Summary: Azure::Core::IO; BodyStream; true; ReadToEnd; ; ; Argument[-1]; ReturnValue.Element; taint; manual | +| 71 | Summary: Azure; Nullable; true; Value; ; ; Argument[-1]; ReturnValue[*]; taint; manual | +| 72 | Summary: boost::asio; ; false; buffer; ; ; Argument[*0]; ReturnValue; taint; manual | edges -| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:91:7:91:17 | recv_buffer | provenance | Src:MaD:38 | -| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:93:29:93:39 | *recv_buffer | provenance | Src:MaD:38 Sink:MaD:2 | +| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:91:7:91:17 | recv_buffer | provenance | Src:MaD:39 | +| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:93:29:93:39 | *recv_buffer | provenance | Src:MaD:39 Sink:MaD:2 | | asio_streams.cpp:97:37:97:44 | call to source | asio_streams.cpp:98:7:98:14 | send_str | provenance | TaintFunction | | asio_streams.cpp:97:37:97:44 | call to source | asio_streams.cpp:100:64:100:71 | *send_str | provenance | TaintFunction | | asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | | | asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:101:7:101:17 | send_buffer | provenance | | | asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:103:29:103:39 | *send_buffer | provenance | Sink:MaD:2 | -| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:71 | -| azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:253:48:253:60 | *call to GetBodyStream | provenance | Src:MaD:35 | +| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:72 | +| azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:253:48:253:60 | *call to GetBodyStream | provenance | Src:MaD:36 | | azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:257:5:257:8 | *resp | provenance | | | azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:262:5:262:8 | *resp | provenance | | | azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:266:38:266:41 | *resp | provenance | | -| azure.cpp:257:5:257:8 | *resp | azure.cpp:257:16:257:21 | Read output argument | provenance | MaD:67 | +| azure.cpp:257:5:257:8 | *resp | azure.cpp:257:16:257:21 | Read output argument | provenance | MaD:68 | | azure.cpp:257:16:257:21 | Read output argument | azure.cpp:258:10:258:16 | * ... | provenance | | -| azure.cpp:262:5:262:8 | *resp | azure.cpp:262:23:262:28 | ReadToCount output argument | provenance | MaD:68 | +| azure.cpp:262:5:262:8 | *resp | azure.cpp:262:23:262:28 | ReadToCount output argument | provenance | MaD:69 | | azure.cpp:262:23:262:28 | ReadToCount output argument | azure.cpp:263:10:263:16 | * ... | provenance | | -| azure.cpp:266:38:266:41 | *resp | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | provenance | MaD:69 | +| azure.cpp:266:38:266:41 | *resp | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | provenance | MaD:70 | | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | provenance | | | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | azure.cpp:267:10:267:12 | vec [element] | provenance | | | azure.cpp:267:10:267:12 | vec [element] | azure.cpp:267:10:267:12 | vec | provenance | | -| azure.cpp:273:62:273:64 | call to GetHeaders | azure.cpp:273:62:273:64 | call to GetHeaders | provenance | Src:MaD:34 | +| azure.cpp:273:62:273:64 | call to GetHeaders | azure.cpp:273:62:273:64 | call to GetHeaders | provenance | Src:MaD:35 | | azure.cpp:273:62:273:64 | call to GetHeaders | azure.cpp:274:14:274:29 | call to operator[] | provenance | TaintFunction | | azure.cpp:273:62:273:64 | call to GetHeaders | azure.cpp:274:14:274:29 | call to operator[] | provenance | TaintFunction | | azure.cpp:273:62:273:64 | call to GetHeaders | azure.cpp:274:14:274:29 | call to operator[] | provenance | TaintFunction | | azure.cpp:274:14:274:29 | call to operator[] | azure.cpp:274:10:274:29 | call to operator[] | provenance | | | azure.cpp:274:14:274:29 | call to operator[] | azure.cpp:274:14:274:29 | call to operator[] | provenance | | -| azure.cpp:277:45:277:47 | call to GetBody | azure.cpp:277:45:277:47 | call to GetBody | provenance | Src:MaD:33 | +| azure.cpp:277:45:277:47 | call to GetBody | azure.cpp:277:45:277:47 | call to GetBody | provenance | Src:MaD:34 | | azure.cpp:277:45:277:47 | call to GetBody | azure.cpp:278:10:278:13 | body | provenance | | | azure.cpp:277:45:277:47 | call to GetBody | azure.cpp:278:10:278:13 | body | provenance | | | azure.cpp:278:10:278:13 | body | azure.cpp:278:10:278:13 | body | provenance | | -| azure.cpp:281:68:281:84 | *call to ExtractBodyStream | azure.cpp:281:68:281:84 | *call to ExtractBodyStream | provenance | Src:MaD:32 | +| azure.cpp:281:68:281:84 | *call to ExtractBodyStream | azure.cpp:281:68:281:84 | *call to ExtractBodyStream | provenance | Src:MaD:33 | | azure.cpp:281:68:281:84 | *call to ExtractBodyStream | azure.cpp:282:21:282:23 | *call to get | provenance | | -| azure.cpp:282:21:282:23 | *call to get | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | provenance | MaD:69 | +| azure.cpp:282:21:282:23 | *call to get | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | provenance | MaD:70 | | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | azure.cpp:282:10:282:38 | call to ReadToEnd | provenance | | | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | provenance | | -| azure.cpp:289:24:289:56 | call to GetHeader | azure.cpp:289:63:289:65 | call to Value | provenance | MaD:70 | +| azure.cpp:289:24:289:56 | call to GetHeader | azure.cpp:289:63:289:65 | call to Value | provenance | MaD:71 | | azure.cpp:289:32:289:40 | call to GetHeader | azure.cpp:289:24:289:56 | call to GetHeader | provenance | | -| azure.cpp:289:32:289:40 | call to GetHeader | azure.cpp:289:32:289:40 | call to GetHeader | provenance | Src:MaD:36 | +| azure.cpp:289:32:289:40 | call to GetHeader | azure.cpp:289:32:289:40 | call to GetHeader | provenance | Src:MaD:37 | | azure.cpp:289:63:289:65 | call to Value | azure.cpp:289:63:289:65 | call to Value | provenance | | | azure.cpp:289:63:289:65 | call to Value | azure.cpp:290:10:290:20 | headerValue | provenance | | | azure.cpp:289:63:289:65 | call to Value | azure.cpp:290:10:290:20 | headerValue | provenance | | | azure.cpp:290:10:290:20 | headerValue | azure.cpp:290:10:290:20 | headerValue | provenance | | -| azure.cpp:293:58:293:67 | call to GetHeaders | azure.cpp:293:58:293:67 | call to GetHeaders | provenance | Src:MaD:37 | +| azure.cpp:293:58:293:67 | call to GetHeaders | azure.cpp:293:58:293:67 | call to GetHeaders | provenance | Src:MaD:38 | | azure.cpp:293:58:293:67 | call to GetHeaders | azure.cpp:294:38:294:53 | call to operator[] | provenance | TaintFunction | | azure.cpp:294:38:294:53 | call to operator[] | azure.cpp:295:10:295:20 | contentType | provenance | | | azure.cpp:294:38:294:53 | call to operator[] | azure.cpp:295:10:295:20 | contentType | provenance | | | azure.cpp:295:10:295:20 | contentType | azure.cpp:295:10:295:20 | contentType | provenance | | | test.cpp:7:47:7:52 | value2 | test.cpp:7:64:7:69 | value2 | provenance | | | test.cpp:7:64:7:69 | value2 | test.cpp:7:5:7:30 | *ymlStepGenerated_with_body | provenance | | -| test.cpp:10:10:10:18 | call to ymlSource | test.cpp:10:10:10:18 | call to ymlSource | provenance | Src:MaD:31 | +| test.cpp:10:10:10:18 | call to ymlSource | test.cpp:10:10:10:18 | call to ymlSource | provenance | Src:MaD:32 | | test.cpp:10:10:10:18 | call to ymlSource | test.cpp:14:10:14:10 | x | provenance | Sink:MaD:1 | | test.cpp:10:10:10:18 | call to ymlSource | test.cpp:17:24:17:24 | x | provenance | | | test.cpp:10:10:10:18 | call to ymlSource | test.cpp:21:27:21:27 | x | provenance | | @@ -128,13 +129,13 @@ edges | test.cpp:10:10:10:18 | call to ymlSource | test.cpp:32:41:32:41 | x | provenance | | | test.cpp:17:10:17:22 | call to ymlStepManual | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | | | test.cpp:17:10:17:22 | call to ymlStepManual | test.cpp:18:10:18:10 | y | provenance | Sink:MaD:1 | -| test.cpp:17:24:17:24 | x | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | MaD:59 | +| test.cpp:17:24:17:24 | x | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | MaD:60 | | test.cpp:21:10:21:25 | call to ymlStepGenerated | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | | | test.cpp:21:10:21:25 | call to ymlStepGenerated | test.cpp:22:10:22:10 | z | provenance | Sink:MaD:1 | -| test.cpp:21:27:21:27 | x | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | MaD:58 | +| test.cpp:21:27:21:27 | x | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | MaD:59 | | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | | | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | test.cpp:26:10:26:11 | y2 | provenance | Sink:MaD:1 | -| test.cpp:25:35:25:35 | x | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | MaD:60 | +| test.cpp:25:35:25:35 | x | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | MaD:61 | | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | provenance | | | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | test.cpp:33:10:33:11 | z2 | provenance | Sink:MaD:1 | | test.cpp:32:41:32:41 | x | test.cpp:7:47:7:52 | value2 | provenance | | @@ -144,73 +145,73 @@ edges | test.cpp:48:13:48:13 | *s [x] | test.cpp:48:16:48:16 | x | provenance | Sink:MaD:1 | | test.cpp:56:2:56:2 | *s [post update] [x] | test.cpp:59:55:59:64 | *& ... [x] | provenance | | | test.cpp:56:2:56:18 | ... = ... | test.cpp:56:2:56:2 | *s [post update] [x] | provenance | | -| test.cpp:56:8:56:16 | call to ymlSource | test.cpp:56:2:56:18 | ... = ... | provenance | Src:MaD:31 | -| test.cpp:59:55:59:64 | *& ... [x] | test.cpp:46:30:46:32 | *arg [x] | provenance | MaD:55 | +| test.cpp:56:8:56:16 | call to ymlSource | test.cpp:56:2:56:18 | ... = ... | provenance | Src:MaD:32 | +| test.cpp:59:55:59:64 | *& ... [x] | test.cpp:46:30:46:32 | *arg [x] | provenance | MaD:56 | | test.cpp:68:22:68:22 | y | test.cpp:69:11:69:11 | y | provenance | Sink:MaD:1 | | test.cpp:74:22:74:22 | y | test.cpp:75:11:75:11 | y | provenance | Sink:MaD:1 | | test.cpp:82:22:82:22 | y | test.cpp:83:11:83:11 | y | provenance | Sink:MaD:1 | | test.cpp:88:22:88:22 | y | test.cpp:89:11:89:11 | y | provenance | Sink:MaD:1 | -| test.cpp:94:10:94:18 | call to ymlSource | test.cpp:94:10:94:18 | call to ymlSource | provenance | Src:MaD:31 | +| test.cpp:94:10:94:18 | call to ymlSource | test.cpp:94:10:94:18 | call to ymlSource | provenance | Src:MaD:32 | | test.cpp:94:10:94:18 | call to ymlSource | test.cpp:97:26:97:26 | x | provenance | | | test.cpp:94:10:94:18 | call to ymlSource | test.cpp:101:26:101:26 | x | provenance | | | test.cpp:94:10:94:18 | call to ymlSource | test.cpp:103:63:103:63 | x | provenance | | | test.cpp:94:10:94:18 | call to ymlSource | test.cpp:104:62:104:62 | x | provenance | | -| test.cpp:97:26:97:26 | x | test.cpp:68:22:68:22 | y | provenance | MaD:53 | -| test.cpp:101:26:101:26 | x | test.cpp:74:22:74:22 | y | provenance | MaD:53 | -| test.cpp:103:63:103:63 | x | test.cpp:82:22:82:22 | y | provenance | MaD:53 | -| test.cpp:104:62:104:62 | x | test.cpp:88:22:88:22 | y | provenance | MaD:53 | -| test.cpp:114:10:114:18 | call to ymlSource | test.cpp:114:10:114:18 | call to ymlSource | provenance | Src:MaD:31 | +| test.cpp:97:26:97:26 | x | test.cpp:68:22:68:22 | y | provenance | MaD:54 | +| test.cpp:101:26:101:26 | x | test.cpp:74:22:74:22 | y | provenance | MaD:54 | +| test.cpp:103:63:103:63 | x | test.cpp:82:22:82:22 | y | provenance | MaD:54 | +| test.cpp:104:62:104:62 | x | test.cpp:88:22:88:22 | y | provenance | MaD:54 | +| test.cpp:114:10:114:18 | call to ymlSource | test.cpp:114:10:114:18 | call to ymlSource | provenance | Src:MaD:32 | | test.cpp:114:10:114:18 | call to ymlSource | test.cpp:118:44:118:44 | *x | provenance | | | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | provenance | | | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | test.cpp:119:10:119:11 | y2 | provenance | Sink:MaD:1 | -| test.cpp:118:44:118:44 | *x | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | provenance | MaD:54 | -| test.cpp:133:10:133:18 | call to ymlSource | test.cpp:133:10:133:18 | call to ymlSource | provenance | Src:MaD:31 | +| test.cpp:118:44:118:44 | *x | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | provenance | MaD:55 | +| test.cpp:133:10:133:18 | call to ymlSource | test.cpp:133:10:133:18 | call to ymlSource | provenance | Src:MaD:32 | | test.cpp:133:10:133:18 | call to ymlSource | test.cpp:134:45:134:45 | x | provenance | | | test.cpp:134:13:134:43 | call to templateFunction | test.cpp:134:13:134:43 | call to templateFunction | provenance | | | test.cpp:134:13:134:43 | call to templateFunction | test.cpp:135:10:135:10 | y | provenance | Sink:MaD:1 | -| test.cpp:134:45:134:45 | x | test.cpp:134:13:134:43 | call to templateFunction | provenance | MaD:65 | -| test.cpp:146:10:146:18 | call to ymlSource | test.cpp:146:10:146:18 | call to ymlSource | provenance | Src:MaD:31 | +| test.cpp:134:45:134:45 | x | test.cpp:134:13:134:43 | call to templateFunction | provenance | MaD:66 | +| test.cpp:146:10:146:18 | call to ymlSource | test.cpp:146:10:146:18 | call to ymlSource | provenance | Src:MaD:32 | | test.cpp:146:10:146:18 | call to ymlSource | test.cpp:148:26:148:26 | x | provenance | | | test.cpp:148:10:148:27 | call to function | test.cpp:148:10:148:27 | call to function | provenance | | | test.cpp:148:10:148:27 | call to function | test.cpp:149:10:149:10 | z | provenance | Sink:MaD:1 | -| test.cpp:148:26:148:26 | x | test.cpp:148:10:148:27 | call to function | provenance | MaD:66 | -| test.cpp:155:10:155:18 | call to ymlSource | test.cpp:155:10:155:18 | call to ymlSource | provenance | Src:MaD:31 | +| test.cpp:148:26:148:26 | x | test.cpp:148:10:148:27 | call to function | provenance | MaD:67 | +| test.cpp:155:10:155:18 | call to ymlSource | test.cpp:155:10:155:18 | call to ymlSource | provenance | Src:MaD:32 | | test.cpp:155:10:155:18 | call to ymlSource | test.cpp:157:26:157:26 | x | provenance | | | test.cpp:157:13:157:20 | call to function | test.cpp:157:13:157:20 | call to function | provenance | | | test.cpp:157:13:157:20 | call to function | test.cpp:158:10:158:10 | z | provenance | Sink:MaD:1 | -| test.cpp:157:26:157:26 | x | test.cpp:157:13:157:20 | call to function | provenance | MaD:66 | +| test.cpp:157:26:157:26 | x | test.cpp:157:13:157:20 | call to function | provenance | MaD:67 | | test.cpp:164:34:164:34 | x | test.cpp:165:69:165:69 | x | provenance | | | test.cpp:165:12:165:64 | call to templateFunction2 | test.cpp:164:7:164:7 | *templateFunction3 | provenance | | | test.cpp:165:12:165:64 | call to templateFunction2 | test.cpp:165:12:165:64 | call to templateFunction2 | provenance | | -| test.cpp:165:69:165:69 | x | test.cpp:165:12:165:64 | call to templateFunction2 | provenance | MaD:64 | -| test.cpp:170:10:170:18 | call to ymlSource | test.cpp:170:10:170:18 | call to ymlSource | provenance | Src:MaD:31 | +| test.cpp:165:69:165:69 | x | test.cpp:165:12:165:64 | call to templateFunction2 | provenance | MaD:65 | +| test.cpp:170:10:170:18 | call to ymlSource | test.cpp:170:10:170:18 | call to ymlSource | provenance | Src:MaD:32 | | test.cpp:170:10:170:18 | call to ymlSource | test.cpp:172:51:172:51 | x | provenance | | | test.cpp:172:13:172:44 | call to templateFunction3 | test.cpp:172:13:172:44 | call to templateFunction3 | provenance | | | test.cpp:172:13:172:44 | call to templateFunction3 | test.cpp:173:10:173:10 | y | provenance | Sink:MaD:1 | | test.cpp:172:51:172:51 | x | test.cpp:164:34:164:34 | x | provenance | | -| test.cpp:172:51:172:51 | x | test.cpp:172:13:172:44 | call to templateFunction3 | provenance | MaD:64 | +| test.cpp:172:51:172:51 | x | test.cpp:172:13:172:44 | call to templateFunction3 | provenance | MaD:65 | | test.cpp:186:2:186:2 | *s [post update] [myField] | test.cpp:187:33:187:34 | *& ... [myField] | provenance | | | test.cpp:186:2:186:24 | ... = ... | test.cpp:186:2:186:2 | *s [post update] [myField] | provenance | | -| test.cpp:186:14:186:22 | call to ymlSource | test.cpp:186:2:186:24 | ... = ... | provenance | Src:MaD:31 | +| test.cpp:186:14:186:22 | call to ymlSource | test.cpp:186:2:186:24 | ... = ... | provenance | Src:MaD:32 | | test.cpp:187:10:187:31 | call to read_field_from_struct | test.cpp:187:10:187:31 | call to read_field_from_struct | provenance | | | test.cpp:187:10:187:31 | call to read_field_from_struct | test.cpp:188:10:188:10 | x | provenance | Sink:MaD:1 | -| test.cpp:187:33:187:34 | *& ... [myField] | test.cpp:187:10:187:31 | call to read_field_from_struct | provenance | MaD:56 | +| test.cpp:187:33:187:34 | *& ... [myField] | test.cpp:187:10:187:31 | call to read_field_from_struct | provenance | MaD:57 | | test.cpp:199:2:199:2 | *s [post update] [myField] | test.cpp:200:35:200:36 | *& ... [myField] | provenance | | | test.cpp:199:2:199:24 | ... = ... | test.cpp:199:2:199:2 | *s [post update] [myField] | provenance | | -| test.cpp:199:14:199:22 | call to ymlSource | test.cpp:199:2:199:24 | ... = ... | provenance | Src:MaD:31 | +| test.cpp:199:14:199:22 | call to ymlSource | test.cpp:199:2:199:24 | ... = ... | provenance | Src:MaD:32 | | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | provenance | | | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | test.cpp:201:10:201:10 | x | provenance | Sink:MaD:1 | -| test.cpp:200:35:200:36 | *& ... [myField] | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | provenance | MaD:57 | +| test.cpp:200:35:200:36 | *& ... [myField] | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | provenance | MaD:58 | | test.cpp:216:3:216:4 | get_ptr output argument [value] | test.cpp:217:11:217:12 | *rf [value] | provenance | | -| test.cpp:216:3:216:28 | ... = ... | test.cpp:216:3:216:4 | get_ptr output argument [value] | provenance | MaD:63 | -| test.cpp:216:18:216:26 | call to ymlSource | test.cpp:216:3:216:28 | ... = ... | provenance | Src:MaD:31 | +| test.cpp:216:3:216:28 | ... = ... | test.cpp:216:3:216:4 | get_ptr output argument [value] | provenance | MaD:64 | +| test.cpp:216:18:216:26 | call to ymlSource | test.cpp:216:3:216:28 | ... = ... | provenance | Src:MaD:32 | | test.cpp:217:11:217:12 | *rf [value] | test.cpp:217:14:217:18 | value | provenance | | | test.cpp:217:14:217:18 | value | test.cpp:217:14:217:18 | value | provenance | | | test.cpp:217:14:217:18 | value | test.cpp:218:11:218:11 | x | provenance | Sink:MaD:1 | | test.cpp:222:3:222:3 | operator[] output argument | test.cpp:223:12:223:12 | *s | provenance | | -| test.cpp:222:3:222:20 | ... = ... | test.cpp:222:3:222:3 | operator[] output argument | provenance | MaD:62 | -| test.cpp:222:10:222:20 | call to ymlSource | test.cpp:222:3:222:20 | ... = ... | provenance | Src:MaD:31 | -| test.cpp:223:12:223:12 | *s | test.cpp:223:13:223:15 | call to operator[] | provenance | MaD:61 | +| test.cpp:222:3:222:20 | ... = ... | test.cpp:222:3:222:3 | operator[] output argument | provenance | MaD:63 | +| test.cpp:222:10:222:20 | call to ymlSource | test.cpp:222:3:222:20 | ... = ... | provenance | Src:MaD:32 | +| test.cpp:223:12:223:12 | *s | test.cpp:223:13:223:15 | call to operator[] | provenance | MaD:62 | | test.cpp:223:13:223:15 | call to operator[] | test.cpp:223:13:223:15 | call to operator[] | provenance | | | test.cpp:223:13:223:15 | call to operator[] | test.cpp:224:11:224:11 | c | provenance | Sink:MaD:1 | | windows.cpp:22:15:22:29 | *call to GetCommandLineA | windows.cpp:22:15:22:29 | *call to GetCommandLineA | provenance | Src:MaD:3 | @@ -218,7 +219,7 @@ edges | windows.cpp:22:15:22:29 | *call to GetCommandLineA | windows.cpp:27:36:27:38 | *cmd | provenance | | | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | provenance | | | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | windows.cpp:30:8:30:15 | * ... | provenance | | -| windows.cpp:27:36:27:38 | *cmd | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | provenance | MaD:39 | +| windows.cpp:27:36:27:38 | *cmd | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | provenance | MaD:40 | | windows.cpp:34:17:34:38 | *call to GetEnvironmentStringsA | windows.cpp:34:17:34:38 | *call to GetEnvironmentStringsA | provenance | Src:MaD:4 | | windows.cpp:34:17:34:38 | *call to GetEnvironmentStringsA | windows.cpp:36:10:36:13 | * ... | provenance | | | windows.cpp:39:36:39:38 | GetEnvironmentVariableA output argument | windows.cpp:41:10:41:13 | * ... | provenance | Src:MaD:5 | @@ -238,11 +239,11 @@ edges | windows.cpp:189:21:189:26 | ReadFile output argument | windows.cpp:190:5:190:56 | *... = ... | provenance | Src:MaD:17 | | windows.cpp:190:5:190:14 | *overlapped [post update] [*hEvent] | windows.cpp:192:53:192:63 | *& ... [*hEvent] | provenance | | | windows.cpp:190:5:190:56 | *... = ... | windows.cpp:190:5:190:14 | *overlapped [post update] [*hEvent] | provenance | | -| windows.cpp:192:53:192:63 | *& ... [*hEvent] | windows.cpp:147:16:147:27 | *lpOverlapped [*hEvent] | provenance | MaD:43 | +| windows.cpp:192:53:192:63 | *& ... [*hEvent] | windows.cpp:147:16:147:27 | *lpOverlapped [*hEvent] | provenance | MaD:44 | | windows.cpp:198:21:198:26 | ReadFile output argument | windows.cpp:199:5:199:57 | ... = ... | provenance | Src:MaD:17 | | windows.cpp:199:5:199:14 | *overlapped [post update] [hEvent] | windows.cpp:201:53:201:63 | *& ... [hEvent] | provenance | | | windows.cpp:199:5:199:57 | ... = ... | windows.cpp:199:5:199:14 | *overlapped [post update] [hEvent] | provenance | | -| windows.cpp:201:53:201:63 | *& ... [hEvent] | windows.cpp:157:16:157:27 | *lpOverlapped [hEvent] | provenance | MaD:43 | +| windows.cpp:201:53:201:63 | *& ... [hEvent] | windows.cpp:157:16:157:27 | *lpOverlapped [hEvent] | provenance | MaD:44 | | windows.cpp:209:84:209:89 | NtReadFile output argument | windows.cpp:211:10:211:16 | * ... | provenance | Src:MaD:16 | | windows.cpp:286:23:286:35 | *call to MapViewOfFile | windows.cpp:286:23:286:35 | *call to MapViewOfFile | provenance | Src:MaD:12 | | windows.cpp:286:23:286:35 | *call to MapViewOfFile | windows.cpp:287:20:287:52 | *pMapView | provenance | | @@ -279,9 +280,9 @@ edges | windows.cpp:431:3:431:3 | *s [post update] [x] | windows.cpp:464:7:464:8 | *& ... [x] | provenance | | | windows.cpp:431:3:431:16 | ... = ... | windows.cpp:431:3:431:3 | *s [post update] [x] | provenance | | | windows.cpp:431:9:431:14 | call to source | windows.cpp:431:3:431:16 | ... = ... | provenance | | -| windows.cpp:439:7:439:8 | *& ... [x] | windows.cpp:403:26:403:36 | *lpParameter [x] | provenance | MaD:42 | -| windows.cpp:451:7:451:8 | *& ... [x] | windows.cpp:410:26:410:36 | *lpParameter [x] | provenance | MaD:40 | -| windows.cpp:464:7:464:8 | *& ... [x] | windows.cpp:417:26:417:36 | *lpParameter [x] | provenance | MaD:41 | +| windows.cpp:439:7:439:8 | *& ... [x] | windows.cpp:403:26:403:36 | *lpParameter [x] | provenance | MaD:43 | +| windows.cpp:451:7:451:8 | *& ... [x] | windows.cpp:410:26:410:36 | *lpParameter [x] | provenance | MaD:41 | +| windows.cpp:464:7:464:8 | *& ... [x] | windows.cpp:417:26:417:36 | *lpParameter [x] | provenance | MaD:42 | | windows.cpp:533:11:533:16 | call to source | windows.cpp:533:11:533:16 | call to source | provenance | | | windows.cpp:533:11:533:16 | call to source | windows.cpp:537:40:537:41 | *& ... | provenance | | | windows.cpp:533:11:533:16 | call to source | windows.cpp:542:38:542:39 | *& ... | provenance | | @@ -290,39 +291,39 @@ edges | windows.cpp:533:11:533:16 | call to source | windows.cpp:568:32:568:33 | *& ... | provenance | | | windows.cpp:533:11:533:16 | call to source | windows.cpp:573:40:573:41 | *& ... | provenance | | | windows.cpp:537:27:537:37 | RtlCopyVolatileMemory output argument | windows.cpp:538:10:538:23 | access to array | provenance | | -| windows.cpp:537:40:537:41 | *& ... | windows.cpp:537:27:537:37 | RtlCopyVolatileMemory output argument | provenance | MaD:48 | +| windows.cpp:537:40:537:41 | *& ... | windows.cpp:537:27:537:37 | RtlCopyVolatileMemory output argument | provenance | MaD:49 | | windows.cpp:542:25:542:35 | RtlCopyDeviceMemory output argument | windows.cpp:543:10:543:23 | access to array | provenance | | -| windows.cpp:542:38:542:39 | *& ... | windows.cpp:542:25:542:35 | RtlCopyDeviceMemory output argument | provenance | MaD:44 | +| windows.cpp:542:38:542:39 | *& ... | windows.cpp:542:25:542:35 | RtlCopyDeviceMemory output argument | provenance | MaD:45 | | windows.cpp:547:19:547:29 | RtlCopyMemory output argument | windows.cpp:548:10:548:23 | access to array | provenance | | -| windows.cpp:547:32:547:33 | *& ... | windows.cpp:547:19:547:29 | RtlCopyMemory output argument | provenance | MaD:45 | +| windows.cpp:547:32:547:33 | *& ... | windows.cpp:547:19:547:29 | RtlCopyMemory output argument | provenance | MaD:46 | | windows.cpp:552:30:552:40 | RtlCopyMemoryNonTemporal output argument | windows.cpp:553:10:553:23 | access to array | provenance | | -| windows.cpp:552:43:552:44 | *& ... | windows.cpp:552:30:552:40 | RtlCopyMemoryNonTemporal output argument | provenance | MaD:46 | +| windows.cpp:552:43:552:44 | *& ... | windows.cpp:552:30:552:40 | RtlCopyMemoryNonTemporal output argument | provenance | MaD:47 | | windows.cpp:559:5:559:24 | ... = ... | windows.cpp:561:39:561:44 | *buffer | provenance | | | windows.cpp:559:17:559:24 | call to source | windows.cpp:559:5:559:24 | ... = ... | provenance | | | windows.cpp:561:26:561:36 | RtlInitUnicodeString output argument [*Buffer] | windows.cpp:562:10:562:19 | *src_string [*Buffer] | provenance | | | windows.cpp:561:26:561:36 | RtlInitUnicodeString output argument [*Buffer] | windows.cpp:563:40:563:50 | *& ... [*Buffer] | provenance | | -| windows.cpp:561:39:561:44 | *buffer | windows.cpp:561:26:561:36 | RtlInitUnicodeString output argument [*Buffer] | provenance | MaD:49 | +| windows.cpp:561:39:561:44 | *buffer | windows.cpp:561:26:561:36 | RtlInitUnicodeString output argument [*Buffer] | provenance | MaD:50 | | windows.cpp:562:10:562:19 | *src_string [*Buffer] | windows.cpp:562:10:562:29 | access to array | provenance | | | windows.cpp:562:10:562:19 | *src_string [*Buffer] | windows.cpp:562:21:562:26 | *Buffer | provenance | | | windows.cpp:562:21:562:26 | *Buffer | windows.cpp:562:10:562:29 | access to array | provenance | | | windows.cpp:563:26:563:37 | RtlCopyUnicodeString output argument [*Buffer] | windows.cpp:564:10:564:20 | *dest_string [*Buffer] | provenance | | -| windows.cpp:563:40:563:50 | *& ... [*Buffer] | windows.cpp:563:26:563:37 | RtlCopyUnicodeString output argument [*Buffer] | provenance | MaD:47 | +| windows.cpp:563:40:563:50 | *& ... [*Buffer] | windows.cpp:563:26:563:37 | RtlCopyUnicodeString output argument [*Buffer] | provenance | MaD:48 | | windows.cpp:564:10:564:20 | *dest_string [*Buffer] | windows.cpp:564:10:564:30 | access to array | provenance | | | windows.cpp:564:10:564:20 | *dest_string [*Buffer] | windows.cpp:564:22:564:27 | *Buffer | provenance | | | windows.cpp:564:22:564:27 | *Buffer | windows.cpp:564:10:564:30 | access to array | provenance | | | windows.cpp:568:19:568:29 | RtlMoveMemory output argument | windows.cpp:569:10:569:23 | access to array | provenance | | -| windows.cpp:568:32:568:33 | *& ... | windows.cpp:568:19:568:29 | RtlMoveMemory output argument | provenance | MaD:50 | +| windows.cpp:568:32:568:33 | *& ... | windows.cpp:568:19:568:29 | RtlMoveMemory output argument | provenance | MaD:51 | | windows.cpp:573:27:573:37 | RtlMoveVolatileMemory output argument | windows.cpp:574:10:574:23 | access to array | provenance | | -| windows.cpp:573:40:573:41 | *& ... | windows.cpp:573:27:573:37 | RtlMoveVolatileMemory output argument | provenance | MaD:51 | -| windows.cpp:645:45:645:50 | WinHttpReadData output argument | windows.cpp:647:10:647:16 | * ... | provenance | Src:MaD:29 | -| windows.cpp:652:48:652:53 | WinHttpReadDataEx output argument | windows.cpp:654:10:654:16 | * ... | provenance | Src:MaD:30 | -| windows.cpp:659:47:659:52 | WinHttpQueryHeaders output argument | windows.cpp:661:10:661:16 | * ... | provenance | Src:MaD:25 | -| windows.cpp:669:70:669:79 | WinHttpQueryHeadersEx output argument | windows.cpp:673:10:673:29 | * ... | provenance | Src:MaD:27 | -| windows.cpp:669:82:669:87 | WinHttpQueryHeadersEx output argument | windows.cpp:671:10:671:16 | * ... | provenance | Src:MaD:28 | -| windows.cpp:669:105:669:112 | WinHttpQueryHeadersEx output argument | windows.cpp:675:10:675:27 | * ... | provenance | Src:MaD:26 | +| windows.cpp:573:40:573:41 | *& ... | windows.cpp:573:27:573:37 | RtlMoveVolatileMemory output argument | provenance | MaD:52 | +| windows.cpp:645:45:645:50 | WinHttpReadData output argument | windows.cpp:647:10:647:16 | * ... | provenance | Src:MaD:30 | +| windows.cpp:652:48:652:53 | WinHttpReadDataEx output argument | windows.cpp:654:10:654:16 | * ... | provenance | Src:MaD:31 | +| windows.cpp:659:47:659:52 | WinHttpQueryHeaders output argument | windows.cpp:661:10:661:16 | * ... | provenance | Src:MaD:26 | +| windows.cpp:669:70:669:79 | WinHttpQueryHeadersEx output argument | windows.cpp:673:10:673:29 | * ... | provenance | Src:MaD:28 | +| windows.cpp:669:82:669:87 | WinHttpQueryHeadersEx output argument | windows.cpp:671:10:671:16 | * ... | provenance | Src:MaD:29 | +| windows.cpp:669:105:669:112 | WinHttpQueryHeadersEx output argument | windows.cpp:675:10:675:27 | * ... | provenance | Src:MaD:27 | | windows.cpp:728:5:728:28 | ... = ... | windows.cpp:729:35:729:35 | *x | provenance | | | windows.cpp:728:12:728:28 | call to source | windows.cpp:728:5:728:28 | ... = ... | provenance | | -| windows.cpp:729:35:729:35 | *x | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | provenance | MaD:52 | +| windows.cpp:729:35:729:35 | *x | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | provenance | MaD:53 | | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | windows.cpp:731:10:731:36 | * ... | provenance | | | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | windows.cpp:733:10:733:35 | * ... | provenance | | | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | windows.cpp:735:10:735:37 | * ... | provenance | | @@ -343,12 +344,13 @@ edges | windows.cpp:936:70:936:78 | HttpReceiveClientCertificate output argument | windows.cpp:937:15:937:48 | *& ... | provenance | Src:MaD:6 | | windows.cpp:936:70:936:78 | HttpReceiveClientCertificate output argument | windows.cpp:941:10:941:31 | * ... | provenance | Src:MaD:6 | | windows.cpp:937:15:937:48 | *& ... | windows.cpp:939:10:939:11 | * ... | provenance | | -| windows.cpp:994:35:994:38 | RegQueryValueA output argument | windows.cpp:996:10:996:14 | * ... | provenance | Src:MaD:21 | -| windows.cpp:1001:36:1001:39 | RegQueryValueW output argument | windows.cpp:1003:10:1003:14 | * ... | provenance | Src:MaD:24 | -| windows.cpp:1009:53:1009:56 | RegQueryValueExA output argument | windows.cpp:1011:10:1011:14 | * ... | provenance | Src:MaD:22 | -| windows.cpp:1017:54:1017:57 | RegQueryValueExW output argument | windows.cpp:1019:10:1019:14 | * ... | provenance | Src:MaD:23 | -| windows.cpp:1025:46:1025:49 | RegQueryMultipleValuesA output argument | windows.cpp:1027:10:1027:14 | * ... | provenance | Src:MaD:19 | -| windows.cpp:1033:46:1033:49 | RegQueryMultipleValuesW output argument | windows.cpp:1035:10:1035:14 | * ... | provenance | Src:MaD:20 | +| windows.cpp:994:35:994:38 | RegQueryValueA output argument | windows.cpp:996:10:996:14 | * ... | provenance | Src:MaD:22 | +| windows.cpp:1001:36:1001:39 | RegQueryValueW output argument | windows.cpp:1003:10:1003:14 | * ... | provenance | Src:MaD:25 | +| windows.cpp:1009:53:1009:56 | RegQueryValueExA output argument | windows.cpp:1011:10:1011:14 | * ... | provenance | Src:MaD:23 | +| windows.cpp:1017:54:1017:57 | RegQueryValueExW output argument | windows.cpp:1019:10:1019:14 | * ... | provenance | Src:MaD:24 | +| windows.cpp:1025:46:1025:49 | RegQueryMultipleValuesA output argument | windows.cpp:1027:10:1027:14 | * ... | provenance | Src:MaD:20 | +| windows.cpp:1033:46:1033:49 | RegQueryMultipleValuesW output argument | windows.cpp:1035:10:1035:14 | * ... | provenance | Src:MaD:21 | +| windows.cpp:1041:53:1041:56 | RegGetValueA output argument | windows.cpp:1043:10:1043:14 | * ... | provenance | Src:MaD:19 | nodes | asio_streams.cpp:87:34:87:44 | read_until output argument | semmle.label | read_until output argument | | asio_streams.cpp:91:7:91:17 | recv_buffer | semmle.label | recv_buffer | @@ -677,6 +679,8 @@ nodes | windows.cpp:1027:10:1027:14 | * ... | semmle.label | * ... | | windows.cpp:1033:46:1033:49 | RegQueryMultipleValuesW output argument | semmle.label | RegQueryMultipleValuesW output argument | | windows.cpp:1035:10:1035:14 | * ... | semmle.label | * ... | +| windows.cpp:1041:53:1041:56 | RegGetValueA output argument | semmle.label | RegGetValueA output argument | +| windows.cpp:1043:10:1043:14 | * ... | semmle.label | * ... | subpaths | test.cpp:32:41:32:41 | x | test.cpp:7:47:7:52 | value2 | test.cpp:7:5:7:30 | *ymlStepGenerated_with_body | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | | test.cpp:172:51:172:51 | x | test.cpp:164:34:164:34 | x | test.cpp:164:7:164:7 | *templateFunction3 | test.cpp:172:13:172:44 | call to templateFunction3 | diff --git a/cpp/ql/test/library-tests/dataflow/external-models/sources.expected b/cpp/ql/test/library-tests/dataflow/external-models/sources.expected index 7adf091e962e..54320be20331 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/sources.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/sources.expected @@ -49,3 +49,4 @@ | windows.cpp:1017:54:1017:57 | RegQueryValueExW output argument | local | | windows.cpp:1025:46:1025:49 | RegQueryMultipleValuesA output argument | local | | windows.cpp:1033:46:1033:49 | RegQueryMultipleValuesW output argument | local | +| windows.cpp:1041:53:1041:56 | RegGetValueA output argument | local | diff --git a/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp b/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp index 03854a6965a5..5afa72723d64 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp +++ b/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp @@ -1040,6 +1040,6 @@ void test_registry_queries(HKEY hKey) { DWORD type; RegGetValueA(hKey, "subkey", "value", 0, &type, data, &dataSize); sink(data); // clean - sink(*data); // $ MISSING: ir + sink(*data); // $ ir } } \ No newline at end of file From 3ad48615a7cd2aa70513b49d56883c13fb54b024 Mon Sep 17 00:00:00 2001 From: yoff Date: Tue, 28 Jul 2026 14:54:09 +0200 Subject: [PATCH 085/188] Python: fix replace of upper-case characters --- .../ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll b/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll index bfbd6e29bdd7..78218f489215 100644 --- a/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll +++ b/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll @@ -156,7 +156,7 @@ module Ast implements AstSig { /** * A parameter of a callable. * - * modeled per the C# template (`csharp/.../ControlFlowGraph.qll`): + * Modeled per the C# template (`csharp/.../ControlFlowGraph.qll`): * each Python parameter (the `Py::Parameter` AST node, which is a `Name` * or — Python 2 only — a `Tuple` in store context) becomes a CFG node * at a stable position in the enclosing callable's entry sequence. @@ -1231,7 +1231,7 @@ module Ast implements AstSig { } /** - * An `import x.y` module expression. modeled as a leaf — the dotted + * An `import x.y` module expression. Modeled as a leaf — the dotted * name is just a string. */ additional class ImportExpression extends Expr { From a6d696a01333051cf5490dd2689ab14dad8db0f0 Mon Sep 17 00:00:00 2001 From: Keshav Malik Date: Tue, 28 Jul 2026 19:01:44 +0530 Subject: [PATCH 086/188] Update javascript/ql/lib/semmle/javascript/frameworks/Sails.qll Co-authored-by: Asger F --- javascript/ql/lib/semmle/javascript/frameworks/Sails.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Sails.qll b/javascript/ql/lib/semmle/javascript/frameworks/Sails.qll index 5c4b62ab99ac..eae9d8927f1c 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Sails.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Sails.qll @@ -2,8 +2,8 @@ * Provides classes for working with [Sails](https://sailsjs.com/) applications. */ -import javascript -import semmle.javascript.frameworks.HTTP +private import javascript +private import semmle.javascript.frameworks.HTTP private import DataFlow /** From b2641e10ad7a7d2a509786e239022d748f5ab7ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20Loba=C4=8Devski?= Date: Sun, 19 Jul 2026 11:14:56 +0000 Subject: [PATCH 087/188] Add named related locations for cache poisoning query --- .../CachePoisoningViaPoisonableStep.ql | 65 +++++++++++++++++-- .../CachePoisoningViaPoisonableStep.expected | 14 ++-- 2 files changed, 65 insertions(+), 14 deletions(-) diff --git a/actions/ql/src/Security/CWE-349/CachePoisoningViaPoisonableStep.ql b/actions/ql/src/Security/CWE-349/CachePoisoningViaPoisonableStep.ql index 95adcfaf78ec..ad961623ae82 100644 --- a/actions/ql/src/Security/CWE-349/CachePoisoningViaPoisonableStep.ql +++ b/actions/ql/src/Security/CWE-349/CachePoisoningViaPoisonableStep.ql @@ -20,18 +20,69 @@ import codeql.actions.security.ControlChecks query predicate edges(Step a, Step b) { a.getNextStep() = b } -from LocalJob job, Event event, Step source, Step step, string message, string path +private predicate isRunCheckoutReference( + PRHeadCheckoutStep checkout, Expression reference, string variable +) { + checkout instanceof Run and + reference = checkout.(Run).getInScopeEnvVarExpr(variable) and + ( + checkout instanceof SHACheckoutStep and containsHeadSHA(reference.getExpression()) + or + checkout instanceof MutableRefCheckoutStep and + ( + containsHeadRef(reference.getExpression()) or + containsPullRequestNumber(reference.getExpression()) + ) + ) and + exists(string command | + checkout.(Run).getScript().getACommand() = command and + exists(command.regexpFind(variable, _, _)) + ) +} + +private AstNode getCheckoutReference(PRHeadCheckoutStep checkout) { + exists(UsesStep uses | + checkout = uses and + ( + result = uses.getArgumentExpr("ref") + or + not exists(uses.getArgumentExpr("ref")) and result = uses.getArgumentExpr("repository") + ) + ) + or + exists(string variable | isRunCheckoutReference(checkout, result, variable)) + or + checkout instanceof Run and + result = checkout and + not exists(Expression reference, string variable | + isRunCheckoutReference(checkout, reference, variable) + ) +} + +private string getCheckoutReferenceText(AstNode reference) { + result = reference.(Expression).getExpression() + or + not reference instanceof Expression and result = "the checkout command" +} + +from + LocalJob job, Event event, Step source, Step step, string message, string path, + AstNode untrustedInput, string untrustedInputText where // the job checkouts untrusted code from a pull request or downloads an untrusted artifact job.getAStep() = source and ( source instanceof PRHeadCheckoutStep and - message = "due to privilege checkout of untrusted code." and - path = source.(PRHeadCheckoutStep).getPath() + message = "due to privilege checkout of untrusted code from" and + path = source.(PRHeadCheckoutStep).getPath() and + untrustedInput = getCheckoutReference(source) and + untrustedInputText = getCheckoutReferenceText(untrustedInput) or source instanceof UntrustedArtifactDownloadStep and - message = "due to downloading an untrusted artifact." and - path = source.(UntrustedArtifactDownloadStep).getPath() + message = "due to downloading" and + path = source.(UntrustedArtifactDownloadStep).getPath() and + untrustedInput = source and + untrustedInputText = "an untrusted artifact" ) and // the checkout/download is not controlled by an access check not exists(ControlCheck check | @@ -58,5 +109,5 @@ where // excluding privileged workflows since they can be exploited in easier circumstances not job.isPrivileged() select step, source, step, - "Potential cache poisoning in the context of the default branch " + message + " ($@).", event, - event.getName() + "Potential cache poisoning in the context of the default branch " + message + " $@. ($@).", + untrustedInput, untrustedInputText, event, event.getName() diff --git a/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaPoisonableStep.expected b/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaPoisonableStep.expected index 6b1a3e873134..eaadbe44db39 100644 --- a/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaPoisonableStep.expected +++ b/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaPoisonableStep.expected @@ -44,10 +44,10 @@ edges | .github/workflows/poisonable_step5.yml:17:9:22:6 | Uses Step | .github/workflows/poisonable_step5.yml:22:9:24:6 | Uses Step | | .github/workflows/poisonable_step5.yml:22:9:24:6 | Uses Step | .github/workflows/poisonable_step5.yml:24:9:28:31 | Uses Step | #select -| .github/workflows/poisonable_step1.yml:15:9:17:2 | Run Step | .github/workflows/poisonable_step1.yml:12:9:15:6 | Uses Step | .github/workflows/poisonable_step1.yml:15:9:17:2 | Run Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/poisonable_step1.yml:2:3:2:15 | issue_comment | issue_comment | -| .github/workflows/poisonable_step1.yml:26:9:28:2 | Uses Step | .github/workflows/poisonable_step1.yml:23:9:26:6 | Uses Step | .github/workflows/poisonable_step1.yml:26:9:28:2 | Uses Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/poisonable_step1.yml:2:3:2:15 | issue_comment | issue_comment | -| .github/workflows/poisonable_step1.yml:37:9:37:75 | Run Step | .github/workflows/poisonable_step1.yml:34:9:37:6 | Uses Step | .github/workflows/poisonable_step1.yml:37:9:37:75 | Run Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/poisonable_step1.yml:2:3:2:15 | issue_comment | issue_comment | -| .github/workflows/poisonable_step2.yml:22:9:26:31 | Uses Step | .github/workflows/poisonable_step2.yml:15:9:20:6 | Uses Step | .github/workflows/poisonable_step2.yml:22:9:26:31 | Uses Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/poisonable_step2.yml:5:3:5:21 | pull_request_target | pull_request_target | -| .github/workflows/poisonable_step3.yml:19:7:19:32 | Run Step | .github/workflows/poisonable_step3.yml:13:7:19:4 | Uses Step | .github/workflows/poisonable_step3.yml:19:7:19:32 | Run Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/poisonable_step3.yml:4:3:4:21 | pull_request_target | pull_request_target | -| .github/workflows/poisonable_step4.yml:18:9:18:19 | Run Step | .github/workflows/poisonable_step4.yml:13:9:18:6 | Uses Step | .github/workflows/poisonable_step4.yml:18:9:18:19 | Run Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/poisonable_step4.yml:3:3:3:21 | pull_request_target | pull_request_target | -| .github/workflows/poisonable_step5.yml:24:9:28:31 | Uses Step | .github/workflows/poisonable_step5.yml:17:9:22:6 | Uses Step | .github/workflows/poisonable_step5.yml:24:9:28:31 | Uses Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/poisonable_step5.yml:3:3:3:21 | pull_request_target | pull_request_target | +| .github/workflows/poisonable_step1.yml:15:9:17:2 | Run Step | .github/workflows/poisonable_step1.yml:12:9:15:6 | Uses Step | .github/workflows/poisonable_step1.yml:15:9:17:2 | Run Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code from $@. ($@). | .github/workflows/poisonable_step1.yml:14:17:14:60 | steps.comment-branch.outputs.head_sha | steps.comment-branch.outputs.head_sha | .github/workflows/poisonable_step1.yml:2:3:2:15 | issue_comment | issue_comment | +| .github/workflows/poisonable_step1.yml:26:9:28:2 | Uses Step | .github/workflows/poisonable_step1.yml:23:9:26:6 | Uses Step | .github/workflows/poisonable_step1.yml:26:9:28:2 | Uses Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code from $@. ($@). | .github/workflows/poisonable_step1.yml:25:17:25:60 | steps.comment-branch.outputs.head_sha | steps.comment-branch.outputs.head_sha | .github/workflows/poisonable_step1.yml:2:3:2:15 | issue_comment | issue_comment | +| .github/workflows/poisonable_step1.yml:37:9:37:75 | Run Step | .github/workflows/poisonable_step1.yml:34:9:37:6 | Uses Step | .github/workflows/poisonable_step1.yml:37:9:37:75 | Run Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code from $@. ($@). | .github/workflows/poisonable_step1.yml:36:17:36:60 | steps.comment-branch.outputs.head_sha | steps.comment-branch.outputs.head_sha | .github/workflows/poisonable_step1.yml:2:3:2:15 | issue_comment | issue_comment | +| .github/workflows/poisonable_step2.yml:22:9:26:31 | Uses Step | .github/workflows/poisonable_step2.yml:15:9:20:6 | Uses Step | .github/workflows/poisonable_step2.yml:22:9:26:31 | Uses Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code from $@. ($@). | .github/workflows/poisonable_step2.yml:18:17:18:57 | github.event.pull_request.head.ref | github.event.pull_request.head.ref | .github/workflows/poisonable_step2.yml:5:3:5:21 | pull_request_target | pull_request_target | +| .github/workflows/poisonable_step3.yml:19:7:19:32 | Run Step | .github/workflows/poisonable_step3.yml:13:7:19:4 | Uses Step | .github/workflows/poisonable_step3.yml:19:7:19:32 | Run Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code from $@. ($@). | .github/workflows/poisonable_step3.yml:16:15:16:55 | github.event.pull_request.head.ref | github.event.pull_request.head.ref | .github/workflows/poisonable_step3.yml:4:3:4:21 | pull_request_target | pull_request_target | +| .github/workflows/poisonable_step4.yml:18:9:18:19 | Run Step | .github/workflows/poisonable_step4.yml:13:9:18:6 | Uses Step | .github/workflows/poisonable_step4.yml:18:9:18:19 | Run Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code from $@. ($@). | .github/workflows/poisonable_step4.yml:16:17:16:57 | github.event.pull_request.head.sha | github.event.pull_request.head.sha | .github/workflows/poisonable_step4.yml:3:3:3:21 | pull_request_target | pull_request_target | +| .github/workflows/poisonable_step5.yml:24:9:28:31 | Uses Step | .github/workflows/poisonable_step5.yml:17:9:22:6 | Uses Step | .github/workflows/poisonable_step5.yml:24:9:28:31 | Uses Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code from $@. ($@). | .github/workflows/poisonable_step5.yml:20:17:20:57 | github.event.pull_request.head.ref | github.event.pull_request.head.ref | .github/workflows/poisonable_step5.yml:3:3:3:21 | pull_request_target | pull_request_target | From 99675ae1bc056608f1f44752bb051d4be57e4b26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20Loba=C4=8Devski?= Date: Sun, 19 Jul 2026 11:37:32 +0000 Subject: [PATCH 088/188] Combine a value-provenance prefix with the existing execution-order suffix for cache poisoning query --- .../CachePoisoningViaPoisonableStep.ql | 16 +++++++-- .../cache_write_capable_workflow_dispatch.yml | 23 ++++++++++++ .../CachePoisoningViaDirectCache.expected | 3 ++ .../CachePoisoningViaPoisonableStep.expected | 36 +++++++++++++++---- 4 files changed, 69 insertions(+), 9 deletions(-) create mode 100644 actions/ql/test/query-tests/Security/CWE-349/.github/workflows/cache_write_capable_workflow_dispatch.yml diff --git a/actions/ql/src/Security/CWE-349/CachePoisoningViaPoisonableStep.ql b/actions/ql/src/Security/CWE-349/CachePoisoningViaPoisonableStep.ql index ad961623ae82..d9ffd44cf24d 100644 --- a/actions/ql/src/Security/CWE-349/CachePoisoningViaPoisonableStep.ql +++ b/actions/ql/src/Security/CWE-349/CachePoisoningViaPoisonableStep.ql @@ -18,7 +18,19 @@ import codeql.actions.security.CachePoisoningQuery import codeql.actions.security.PoisonableSteps import codeql.actions.security.ControlChecks -query predicate edges(Step a, Step b) { a.getNextStep() = b } +query predicate edges(AstNode predecessor, AstNode successor) { + exists(Step previous, Step next | + predecessor = previous and + successor = next and + previous.getNextStep() = next + ) + or + exists(PRHeadCheckoutStep checkout | + predecessor = getCheckoutReference(checkout) and + successor = checkout and + not predecessor = successor + ) +} private predicate isRunCheckoutReference( PRHeadCheckoutStep checkout, Expression reference, string variable @@ -108,6 +120,6 @@ where step instanceof PoisonableStep and // excluding privileged workflows since they can be exploited in easier circumstances not job.isPrivileged() -select step, source, step, +select step, untrustedInput, step, "Potential cache poisoning in the context of the default branch " + message + " $@. ($@).", untrustedInput, untrustedInputText, event, event.getName() diff --git a/actions/ql/test/query-tests/Security/CWE-349/.github/workflows/cache_write_capable_workflow_dispatch.yml b/actions/ql/test/query-tests/Security/CWE-349/.github/workflows/cache_write_capable_workflow_dispatch.yml new file mode 100644 index 000000000000..02bea71cfc61 --- /dev/null +++ b/actions/ql/test/query-tests/Security/CWE-349/.github/workflows/cache_write_capable_workflow_dispatch.yml @@ -0,0 +1,23 @@ +on: workflow_dispatch + +jobs: + cache: + permissions: {} + runs-on: ubuntu-latest + steps: + - id: pr + env: + HEAD_SHA: ${{ github.event.inputs.head_sha }} + run: | + jq -cn --arg sha "$HEAD_SHA" '{head: {sha: $sha}}' | + sed 's/^/json=/' >> "$GITHUB_OUTPUT" + - env: + HEAD_SHA: ${{ fromJSON(steps.pr.outputs.json).head.sha }} + run: | + git fetch origin "$HEAD_SHA" + git checkout "$HEAD_SHA" + - run: npm install + - uses: actions/cache@v4 + with: + path: .npm + key: workflow-dispatch diff --git a/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaDirectCache.expected b/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaDirectCache.expected index 4cc8536b5943..e89db92356f2 100644 --- a/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaDirectCache.expected +++ b/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaDirectCache.expected @@ -1,4 +1,7 @@ edges +| .github/workflows/cache_write_capable_workflow_dispatch.yml:8:9:14:6 | Run Step: pr | .github/workflows/cache_write_capable_workflow_dispatch.yml:14:9:19:6 | Run Step | +| .github/workflows/cache_write_capable_workflow_dispatch.yml:14:9:19:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:19:9:20:6 | Run Step | +| .github/workflows/cache_write_capable_workflow_dispatch.yml:19:9:20:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:20:9:23:33 | Uses Step | | .github/workflows/code_injection2.yml:12:9:16:6 | Uses Step: modified_files | .github/workflows/code_injection2.yml:16:9:16:71 | Run Step | | .github/workflows/direct_cache1.yml:10:9:13:6 | Uses Step: comment-branch | .github/workflows/direct_cache1.yml:13:9:18:6 | Uses Step | | .github/workflows/direct_cache1.yml:13:9:18:6 | Uses Step | .github/workflows/direct_cache1.yml:18:9:22:6 | Uses Step | diff --git a/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaPoisonableStep.expected b/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaPoisonableStep.expected index eaadbe44db39..9a5bbb48384e 100644 --- a/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaPoisonableStep.expected +++ b/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaPoisonableStep.expected @@ -1,22 +1,34 @@ edges +| .github/workflows/cache_write_capable_workflow_dispatch.yml:8:9:14:6 | Run Step: pr | .github/workflows/cache_write_capable_workflow_dispatch.yml:14:9:19:6 | Run Step | +| .github/workflows/cache_write_capable_workflow_dispatch.yml:14:9:19:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:19:9:20:6 | Run Step | +| .github/workflows/cache_write_capable_workflow_dispatch.yml:15:22:15:68 | fromJSON(steps.pr.outputs.json).head.sha | .github/workflows/cache_write_capable_workflow_dispatch.yml:14:9:19:6 | Run Step | +| .github/workflows/cache_write_capable_workflow_dispatch.yml:19:9:20:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:20:9:23:33 | Uses Step | | .github/workflows/code_injection2.yml:12:9:16:6 | Uses Step: modified_files | .github/workflows/code_injection2.yml:16:9:16:71 | Run Step | | .github/workflows/direct_cache1.yml:10:9:13:6 | Uses Step: comment-branch | .github/workflows/direct_cache1.yml:13:9:18:6 | Uses Step | | .github/workflows/direct_cache1.yml:13:9:18:6 | Uses Step | .github/workflows/direct_cache1.yml:18:9:22:6 | Uses Step | +| .github/workflows/direct_cache1.yml:16:17:16:60 | steps.comment-branch.outputs.head_sha | .github/workflows/direct_cache1.yml:13:9:18:6 | Uses Step | | .github/workflows/direct_cache1.yml:18:9:22:6 | Uses Step | .github/workflows/direct_cache1.yml:22:9:23:21 | Run Step | | .github/workflows/direct_cache2.yml:11:9:14:6 | Uses Step | .github/workflows/direct_cache2.yml:14:9:18:6 | Uses Step | +| .github/workflows/direct_cache2.yml:13:17:13:57 | github.event.pull_request.head.sha | .github/workflows/direct_cache2.yml:11:9:14:6 | Uses Step | | .github/workflows/direct_cache2.yml:14:9:18:6 | Uses Step | .github/workflows/direct_cache2.yml:18:9:19:21 | Run Step | | .github/workflows/direct_cache3.yml:11:9:14:6 | Uses Step: comment-branch | .github/workflows/direct_cache3.yml:14:9:19:6 | Uses Step | | .github/workflows/direct_cache3.yml:14:9:19:6 | Uses Step | .github/workflows/direct_cache3.yml:19:9:23:6 | Uses Step | +| .github/workflows/direct_cache3.yml:17:17:17:60 | steps.comment-branch.outputs.head_sha | .github/workflows/direct_cache3.yml:14:9:19:6 | Uses Step | | .github/workflows/direct_cache3.yml:19:9:23:6 | Uses Step | .github/workflows/direct_cache3.yml:23:9:24:21 | Run Step | | .github/workflows/direct_cache4.yml:14:9:17:6 | Uses Step | .github/workflows/direct_cache4.yml:17:9:21:6 | Uses Step | +| .github/workflows/direct_cache4.yml:16:17:16:57 | github.event.pull_request.head.sha | .github/workflows/direct_cache4.yml:14:9:17:6 | Uses Step | | .github/workflows/direct_cache4.yml:17:9:21:6 | Uses Step | .github/workflows/direct_cache4.yml:21:9:22:21 | Run Step | | .github/workflows/direct_cache5.yml:14:9:17:6 | Uses Step | .github/workflows/direct_cache5.yml:17:9:21:6 | Uses Step | +| .github/workflows/direct_cache5.yml:16:17:16:57 | github.event.pull_request.head.sha | .github/workflows/direct_cache5.yml:14:9:17:6 | Uses Step | | .github/workflows/direct_cache5.yml:17:9:21:6 | Uses Step | .github/workflows/direct_cache5.yml:21:9:22:21 | Run Step | | .github/workflows/direct_cache6.yml:13:9:16:6 | Uses Step | .github/workflows/direct_cache6.yml:16:9:20:6 | Uses Step | +| .github/workflows/direct_cache6.yml:15:17:15:57 | github.event.pull_request.head.sha | .github/workflows/direct_cache6.yml:13:9:16:6 | Uses Step | | .github/workflows/direct_cache6.yml:16:9:20:6 | Uses Step | .github/workflows/direct_cache6.yml:20:9:26:46 | Uses Step: cache-pip | | .github/workflows/neg_direct_cache1.yml:14:9:17:6 | Uses Step | .github/workflows/neg_direct_cache1.yml:17:9:21:6 | Uses Step | +| .github/workflows/neg_direct_cache1.yml:16:17:16:57 | github.event.pull_request.head.sha | .github/workflows/neg_direct_cache1.yml:14:9:17:6 | Uses Step | | .github/workflows/neg_direct_cache1.yml:17:9:21:6 | Uses Step | .github/workflows/neg_direct_cache1.yml:21:9:22:21 | Run Step | | .github/workflows/neg_direct_cache2.yml:14:9:17:6 | Uses Step | .github/workflows/neg_direct_cache2.yml:17:9:21:6 | Uses Step | +| .github/workflows/neg_direct_cache2.yml:16:17:16:57 | github.event.pull_request.head.sha | .github/workflows/neg_direct_cache2.yml:14:9:17:6 | Uses Step | | .github/workflows/neg_direct_cache2.yml:17:9:21:6 | Uses Step | .github/workflows/neg_direct_cache2.yml:21:9:22:21 | Run Step | | .github/workflows/neg_direct_cache3.yml:13:9:14:6 | Uses Step | .github/workflows/neg_direct_cache3.yml:14:9:18:6 | Uses Step | | .github/workflows/neg_direct_cache3.yml:14:9:18:6 | Uses Step | .github/workflows/neg_direct_cache3.yml:18:9:25:6 | Uses Step: cache-pip | @@ -24,30 +36,40 @@ edges | .github/workflows/neg_direct_cache3.yml:25:9:30:6 | Uses Step | .github/workflows/neg_direct_cache3.yml:30:9:35:36 | Uses Step | | .github/workflows/neg_direct_cache4.yml:10:9:13:6 | Uses Step: comment-branch | .github/workflows/neg_direct_cache4.yml:13:9:18:6 | Uses Step | | .github/workflows/neg_direct_cache4.yml:13:9:18:6 | Uses Step | .github/workflows/neg_direct_cache4.yml:18:9:22:6 | Uses Step | +| .github/workflows/neg_direct_cache4.yml:16:17:16:60 | steps.comment-branch.outputs.head_sha | .github/workflows/neg_direct_cache4.yml:13:9:18:6 | Uses Step | | .github/workflows/neg_direct_cache4.yml:18:9:22:6 | Uses Step | .github/workflows/neg_direct_cache4.yml:22:9:23:21 | Run Step | | .github/workflows/neg_direct_cache5.yml:10:9:13:6 | Uses Step: comment-branch | .github/workflows/neg_direct_cache5.yml:13:9:18:6 | Uses Step | | .github/workflows/neg_direct_cache5.yml:13:9:18:6 | Uses Step | .github/workflows/neg_direct_cache5.yml:18:9:22:6 | Uses Step | +| .github/workflows/neg_direct_cache5.yml:16:17:16:60 | steps.comment-branch.outputs.head_sha | .github/workflows/neg_direct_cache5.yml:13:9:18:6 | Uses Step | | .github/workflows/neg_direct_cache5.yml:18:9:22:6 | Uses Step | .github/workflows/neg_direct_cache5.yml:22:9:23:21 | Run Step | | .github/workflows/neg_poisonable_step1.yml:11:9:14:6 | Uses Step: comment-branch | .github/workflows/neg_poisonable_step1.yml:14:9:19:6 | Uses Step | | .github/workflows/neg_poisonable_step1.yml:14:9:19:6 | Uses Step | .github/workflows/neg_poisonable_step1.yml:19:9:20:30 | Run Step | +| .github/workflows/neg_poisonable_step1.yml:17:17:17:60 | steps.comment-branch.outputs.head_sha | .github/workflows/neg_poisonable_step1.yml:14:9:19:6 | Uses Step | | .github/workflows/neg_poisonable_step2.yml:13:9:16:6 | Uses Step | .github/workflows/neg_poisonable_step2.yml:16:9:17:54 | Run Step | | .github/workflows/poisonable_step1.yml:10:9:12:6 | Uses Step: comment-branch | .github/workflows/poisonable_step1.yml:12:9:15:6 | Uses Step | | .github/workflows/poisonable_step1.yml:12:9:15:6 | Uses Step | .github/workflows/poisonable_step1.yml:15:9:17:2 | Run Step | +| .github/workflows/poisonable_step1.yml:14:17:14:60 | steps.comment-branch.outputs.head_sha | .github/workflows/poisonable_step1.yml:12:9:15:6 | Uses Step | | .github/workflows/poisonable_step1.yml:21:9:23:6 | Uses Step: comment-branch | .github/workflows/poisonable_step1.yml:23:9:26:6 | Uses Step | | .github/workflows/poisonable_step1.yml:23:9:26:6 | Uses Step | .github/workflows/poisonable_step1.yml:26:9:28:2 | Uses Step | +| .github/workflows/poisonable_step1.yml:25:17:25:60 | steps.comment-branch.outputs.head_sha | .github/workflows/poisonable_step1.yml:23:9:26:6 | Uses Step | | .github/workflows/poisonable_step1.yml:32:9:34:6 | Uses Step: comment-branch | .github/workflows/poisonable_step1.yml:34:9:37:6 | Uses Step | | .github/workflows/poisonable_step1.yml:34:9:37:6 | Uses Step | .github/workflows/poisonable_step1.yml:37:9:37:75 | Run Step | +| .github/workflows/poisonable_step1.yml:36:17:36:60 | steps.comment-branch.outputs.head_sha | .github/workflows/poisonable_step1.yml:34:9:37:6 | Uses Step | | .github/workflows/poisonable_step2.yml:15:9:20:6 | Uses Step | .github/workflows/poisonable_step2.yml:20:9:22:6 | Uses Step | +| .github/workflows/poisonable_step2.yml:18:17:18:57 | github.event.pull_request.head.ref | .github/workflows/poisonable_step2.yml:15:9:20:6 | Uses Step | | .github/workflows/poisonable_step2.yml:20:9:22:6 | Uses Step | .github/workflows/poisonable_step2.yml:22:9:26:31 | Uses Step | | .github/workflows/poisonable_step3.yml:13:7:19:4 | Uses Step | .github/workflows/poisonable_step3.yml:19:7:19:32 | Run Step | +| .github/workflows/poisonable_step3.yml:16:15:16:55 | github.event.pull_request.head.ref | .github/workflows/poisonable_step3.yml:13:7:19:4 | Uses Step | | .github/workflows/poisonable_step4.yml:13:9:18:6 | Uses Step | .github/workflows/poisonable_step4.yml:18:9:18:19 | Run Step | +| .github/workflows/poisonable_step4.yml:16:17:16:57 | github.event.pull_request.head.sha | .github/workflows/poisonable_step4.yml:13:9:18:6 | Uses Step | | .github/workflows/poisonable_step5.yml:17:9:22:6 | Uses Step | .github/workflows/poisonable_step5.yml:22:9:24:6 | Uses Step | +| .github/workflows/poisonable_step5.yml:20:17:20:57 | github.event.pull_request.head.ref | .github/workflows/poisonable_step5.yml:17:9:22:6 | Uses Step | | .github/workflows/poisonable_step5.yml:22:9:24:6 | Uses Step | .github/workflows/poisonable_step5.yml:24:9:28:31 | Uses Step | #select -| .github/workflows/poisonable_step1.yml:15:9:17:2 | Run Step | .github/workflows/poisonable_step1.yml:12:9:15:6 | Uses Step | .github/workflows/poisonable_step1.yml:15:9:17:2 | Run Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code from $@. ($@). | .github/workflows/poisonable_step1.yml:14:17:14:60 | steps.comment-branch.outputs.head_sha | steps.comment-branch.outputs.head_sha | .github/workflows/poisonable_step1.yml:2:3:2:15 | issue_comment | issue_comment | -| .github/workflows/poisonable_step1.yml:26:9:28:2 | Uses Step | .github/workflows/poisonable_step1.yml:23:9:26:6 | Uses Step | .github/workflows/poisonable_step1.yml:26:9:28:2 | Uses Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code from $@. ($@). | .github/workflows/poisonable_step1.yml:25:17:25:60 | steps.comment-branch.outputs.head_sha | steps.comment-branch.outputs.head_sha | .github/workflows/poisonable_step1.yml:2:3:2:15 | issue_comment | issue_comment | -| .github/workflows/poisonable_step1.yml:37:9:37:75 | Run Step | .github/workflows/poisonable_step1.yml:34:9:37:6 | Uses Step | .github/workflows/poisonable_step1.yml:37:9:37:75 | Run Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code from $@. ($@). | .github/workflows/poisonable_step1.yml:36:17:36:60 | steps.comment-branch.outputs.head_sha | steps.comment-branch.outputs.head_sha | .github/workflows/poisonable_step1.yml:2:3:2:15 | issue_comment | issue_comment | -| .github/workflows/poisonable_step2.yml:22:9:26:31 | Uses Step | .github/workflows/poisonable_step2.yml:15:9:20:6 | Uses Step | .github/workflows/poisonable_step2.yml:22:9:26:31 | Uses Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code from $@. ($@). | .github/workflows/poisonable_step2.yml:18:17:18:57 | github.event.pull_request.head.ref | github.event.pull_request.head.ref | .github/workflows/poisonable_step2.yml:5:3:5:21 | pull_request_target | pull_request_target | -| .github/workflows/poisonable_step3.yml:19:7:19:32 | Run Step | .github/workflows/poisonable_step3.yml:13:7:19:4 | Uses Step | .github/workflows/poisonable_step3.yml:19:7:19:32 | Run Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code from $@. ($@). | .github/workflows/poisonable_step3.yml:16:15:16:55 | github.event.pull_request.head.ref | github.event.pull_request.head.ref | .github/workflows/poisonable_step3.yml:4:3:4:21 | pull_request_target | pull_request_target | -| .github/workflows/poisonable_step4.yml:18:9:18:19 | Run Step | .github/workflows/poisonable_step4.yml:13:9:18:6 | Uses Step | .github/workflows/poisonable_step4.yml:18:9:18:19 | Run Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code from $@. ($@). | .github/workflows/poisonable_step4.yml:16:17:16:57 | github.event.pull_request.head.sha | github.event.pull_request.head.sha | .github/workflows/poisonable_step4.yml:3:3:3:21 | pull_request_target | pull_request_target | -| .github/workflows/poisonable_step5.yml:24:9:28:31 | Uses Step | .github/workflows/poisonable_step5.yml:17:9:22:6 | Uses Step | .github/workflows/poisonable_step5.yml:24:9:28:31 | Uses Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code from $@. ($@). | .github/workflows/poisonable_step5.yml:20:17:20:57 | github.event.pull_request.head.ref | github.event.pull_request.head.ref | .github/workflows/poisonable_step5.yml:3:3:3:21 | pull_request_target | pull_request_target | +| .github/workflows/poisonable_step1.yml:15:9:17:2 | Run Step | .github/workflows/poisonable_step1.yml:14:17:14:60 | steps.comment-branch.outputs.head_sha | .github/workflows/poisonable_step1.yml:15:9:17:2 | Run Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code from $@. ($@). | .github/workflows/poisonable_step1.yml:14:17:14:60 | steps.comment-branch.outputs.head_sha | steps.comment-branch.outputs.head_sha | .github/workflows/poisonable_step1.yml:2:3:2:15 | issue_comment | issue_comment | +| .github/workflows/poisonable_step1.yml:26:9:28:2 | Uses Step | .github/workflows/poisonable_step1.yml:25:17:25:60 | steps.comment-branch.outputs.head_sha | .github/workflows/poisonable_step1.yml:26:9:28:2 | Uses Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code from $@. ($@). | .github/workflows/poisonable_step1.yml:25:17:25:60 | steps.comment-branch.outputs.head_sha | steps.comment-branch.outputs.head_sha | .github/workflows/poisonable_step1.yml:2:3:2:15 | issue_comment | issue_comment | +| .github/workflows/poisonable_step1.yml:37:9:37:75 | Run Step | .github/workflows/poisonable_step1.yml:36:17:36:60 | steps.comment-branch.outputs.head_sha | .github/workflows/poisonable_step1.yml:37:9:37:75 | Run Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code from $@. ($@). | .github/workflows/poisonable_step1.yml:36:17:36:60 | steps.comment-branch.outputs.head_sha | steps.comment-branch.outputs.head_sha | .github/workflows/poisonable_step1.yml:2:3:2:15 | issue_comment | issue_comment | +| .github/workflows/poisonable_step2.yml:22:9:26:31 | Uses Step | .github/workflows/poisonable_step2.yml:18:17:18:57 | github.event.pull_request.head.ref | .github/workflows/poisonable_step2.yml:22:9:26:31 | Uses Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code from $@. ($@). | .github/workflows/poisonable_step2.yml:18:17:18:57 | github.event.pull_request.head.ref | github.event.pull_request.head.ref | .github/workflows/poisonable_step2.yml:5:3:5:21 | pull_request_target | pull_request_target | +| .github/workflows/poisonable_step3.yml:19:7:19:32 | Run Step | .github/workflows/poisonable_step3.yml:16:15:16:55 | github.event.pull_request.head.ref | .github/workflows/poisonable_step3.yml:19:7:19:32 | Run Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code from $@. ($@). | .github/workflows/poisonable_step3.yml:16:15:16:55 | github.event.pull_request.head.ref | github.event.pull_request.head.ref | .github/workflows/poisonable_step3.yml:4:3:4:21 | pull_request_target | pull_request_target | +| .github/workflows/poisonable_step4.yml:18:9:18:19 | Run Step | .github/workflows/poisonable_step4.yml:16:17:16:57 | github.event.pull_request.head.sha | .github/workflows/poisonable_step4.yml:18:9:18:19 | Run Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code from $@. ($@). | .github/workflows/poisonable_step4.yml:16:17:16:57 | github.event.pull_request.head.sha | github.event.pull_request.head.sha | .github/workflows/poisonable_step4.yml:3:3:3:21 | pull_request_target | pull_request_target | +| .github/workflows/poisonable_step5.yml:24:9:28:31 | Uses Step | .github/workflows/poisonable_step5.yml:20:17:20:57 | github.event.pull_request.head.ref | .github/workflows/poisonable_step5.yml:24:9:28:31 | Uses Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code from $@. ($@). | .github/workflows/poisonable_step5.yml:20:17:20:57 | github.event.pull_request.head.ref | github.event.pull_request.head.ref | .github/workflows/poisonable_step5.yml:3:3:3:21 | pull_request_target | pull_request_target | From 78a9f24a8e2725b319fafd553e5cbf8276f989e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20Loba=C4=8Devski?= Date: Sun, 19 Jul 2026 15:50:11 +0000 Subject: [PATCH 089/188] Improve untrusted checkout path provenance Start critical untrusted-checkout paths at the expression controlling the checkout, and share the provenance helpers with the cache-poisoning query. --- .../security/UntrustedCheckoutQuery.qll | 54 ++++++ .../CachePoisoningViaPoisonableStep.ql | 51 +---- .../CWE-829/UntrustedCheckoutCritical.ql | 12 +- .../UntrustedCheckoutCritical.expected | 175 +++++++++++++----- 4 files changed, 196 insertions(+), 96 deletions(-) diff --git a/actions/ql/lib/codeql/actions/security/UntrustedCheckoutQuery.qll b/actions/ql/lib/codeql/actions/security/UntrustedCheckoutQuery.qll index 9668fce2ae00..c89c483466ae 100644 --- a/actions/ql/lib/codeql/actions/security/UntrustedCheckoutQuery.qll +++ b/actions/ql/lib/codeql/actions/security/UntrustedCheckoutQuery.qll @@ -382,3 +382,57 @@ class GhSHACheckout extends SHACheckoutStep instanceof Run { override string getPath() { result = this.(Run).getWorkingDirectory() } } + +private predicate isRunCheckoutReference( + PRHeadCheckoutStep checkout, Expression reference, string variable +) { + checkout instanceof Run and + reference = checkout.(Run).getInScopeEnvVarExpr(variable) and + ( + checkout instanceof SHACheckoutStep and containsHeadSHA(reference.getExpression()) + or + checkout instanceof MutableRefCheckoutStep and + ( + containsHeadRef(reference.getExpression()) or + containsPullRequestNumber(reference.getExpression()) + ) + ) and + exists(string command | + checkout.(Run).getScript().getACommand() = command and + exists(command.regexpFind(variable, _, _)) + ) +} + +/** Gets the expression that controls the untrusted checkout, if one can be identified. */ +AstNode getCheckoutReference(PRHeadCheckoutStep checkout) { + exists(UsesStep uses | + checkout = uses and + ( + result = uses.getArgumentExpr("ref") + or + not exists(uses.getArgumentExpr("ref")) and result = uses.getArgumentExpr("repository") + ) + ) + or + isRunCheckoutReference(checkout, result, _) + or + checkout instanceof Run and + result = checkout and + not isRunCheckoutReference(checkout, _, _) +} + +/** Gets a display label for the expression that controls the untrusted checkout. */ +string getCheckoutReferenceText(AstNode reference) { + result = reference.(Expression).getExpression() + or + not reference instanceof Expression and result = "the checkout command" +} + +/** Adds checkout-reference provenance before the checkout step in path queries. */ +predicate checkoutReferenceEdge(AstNode predecessor, AstNode successor) { + exists(PRHeadCheckoutStep checkout | + predecessor = getCheckoutReference(checkout) and + successor = checkout and + not predecessor = successor + ) +} diff --git a/actions/ql/src/Security/CWE-349/CachePoisoningViaPoisonableStep.ql b/actions/ql/src/Security/CWE-349/CachePoisoningViaPoisonableStep.ql index d9ffd44cf24d..148a05ef02b9 100644 --- a/actions/ql/src/Security/CWE-349/CachePoisoningViaPoisonableStep.ql +++ b/actions/ql/src/Security/CWE-349/CachePoisoningViaPoisonableStep.ql @@ -25,56 +25,7 @@ query predicate edges(AstNode predecessor, AstNode successor) { previous.getNextStep() = next ) or - exists(PRHeadCheckoutStep checkout | - predecessor = getCheckoutReference(checkout) and - successor = checkout and - not predecessor = successor - ) -} - -private predicate isRunCheckoutReference( - PRHeadCheckoutStep checkout, Expression reference, string variable -) { - checkout instanceof Run and - reference = checkout.(Run).getInScopeEnvVarExpr(variable) and - ( - checkout instanceof SHACheckoutStep and containsHeadSHA(reference.getExpression()) - or - checkout instanceof MutableRefCheckoutStep and - ( - containsHeadRef(reference.getExpression()) or - containsPullRequestNumber(reference.getExpression()) - ) - ) and - exists(string command | - checkout.(Run).getScript().getACommand() = command and - exists(command.regexpFind(variable, _, _)) - ) -} - -private AstNode getCheckoutReference(PRHeadCheckoutStep checkout) { - exists(UsesStep uses | - checkout = uses and - ( - result = uses.getArgumentExpr("ref") - or - not exists(uses.getArgumentExpr("ref")) and result = uses.getArgumentExpr("repository") - ) - ) - or - exists(string variable | isRunCheckoutReference(checkout, result, variable)) - or - checkout instanceof Run and - result = checkout and - not exists(Expression reference, string variable | - isRunCheckoutReference(checkout, reference, variable) - ) -} - -private string getCheckoutReferenceText(AstNode reference) { - result = reference.(Expression).getExpression() - or - not reference instanceof Expression and result = "the checkout command" + checkoutReferenceEdge(predecessor, successor) } from diff --git a/actions/ql/src/Security/CWE-829/UntrustedCheckoutCritical.ql b/actions/ql/src/Security/CWE-829/UntrustedCheckoutCritical.ql index e0af03ca3d02..6ee11a6a3d42 100644 --- a/actions/ql/src/Security/CWE-829/UntrustedCheckoutCritical.ql +++ b/actions/ql/src/Security/CWE-829/UntrustedCheckoutCritical.ql @@ -18,7 +18,15 @@ import codeql.actions.security.UntrustedCheckoutQuery import codeql.actions.security.PoisonableSteps import codeql.actions.security.ControlChecks -query predicate edges(Step a, Step b) { a.getNextStep() = b } +query predicate edges(AstNode predecessor, AstNode successor) { + exists(Step previous, Step next | + predecessor = previous and + successor = next and + previous.getNextStep() = next + ) + or + checkoutReferenceEdge(predecessor, successor) +} from PRHeadCheckoutStep checkout, PoisonableStep poisonable, Event event where @@ -51,6 +59,6 @@ where event.getName() = checkoutTriggers() and not exists(ControlCheck check | check.protects(checkout, event, "untrusted-checkout")) and not exists(ControlCheck check | check.protects(poisonable, event, "untrusted-checkout")) -select checkout, checkout, poisonable, +select checkout, getCheckoutReference(checkout), poisonable, "Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@).", event, event.getName() diff --git a/actions/ql/test/query-tests/Security/CWE-829/UntrustedCheckoutCritical.expected b/actions/ql/test/query-tests/Security/CWE-829/UntrustedCheckoutCritical.expected index b6c349bd64fe..d0b9c2fc8ea3 100644 --- a/actions/ql/test/query-tests/Security/CWE-829/UntrustedCheckoutCritical.expected +++ b/actions/ql/test/query-tests/Security/CWE-829/UntrustedCheckoutCritical.expected @@ -1,5 +1,6 @@ edges | .github/actions/dangerous-git-checkout/action.yml:6:7:11:4 | Uses Step | .github/actions/dangerous-git-checkout/action.yml:11:7:12:18 | Run Step | +| .github/actions/dangerous-git-checkout/action.yml:9:15:9:55 | github.event.pull_request.head.sha | .github/actions/dangerous-git-checkout/action.yml:6:7:11:4 | Uses Step | | .github/actions/dangerous-git-checkout/action.yml:11:7:12:18 | Run Step | .github/workflows/untrusted_checkout3.yml:13:9:13:23 | Run Step | | .github/actions/download-artifact-2/action.yaml:6:7:25:4 | Uses Step | .github/actions/download-artifact-2/action.yaml:25:7:29:4 | Run Step | | .github/actions/download-artifact-2/action.yaml:25:7:29:4 | Run Step | .github/actions/download-artifact-2/action.yaml:29:7:32:18 | Run Step | @@ -10,6 +11,7 @@ edges | .github/actions/download-artifact/action.yaml:29:7:32:18 | Run Step | .github/workflows/resolve-args.yml:22:9:36:13 | Run Step: resolve-step | | .github/actions/unpinned-tag/action.yml:5:7:6:4 | Uses Step | .github/actions/unpinned-tag/action.yml:6:7:6:61 | Uses Step | | .github/workflows/actor_trusted_checkout.yml:9:7:14:4 | Uses Step | .github/workflows/actor_trusted_checkout.yml:14:7:15:4 | Uses Step | +| .github/workflows/actor_trusted_checkout.yml:12:15:12:55 | github.event.pull_request.head.sha | .github/workflows/actor_trusted_checkout.yml:9:7:14:4 | Uses Step | | .github/workflows/actor_trusted_checkout.yml:14:7:15:4 | Uses Step | .github/workflows/actor_trusted_checkout.yml:15:7:19:4 | Run Step | | .github/workflows/actor_trusted_checkout.yml:15:7:19:4 | Run Step | .github/workflows/actor_trusted_checkout.yml:19:7:23:4 | Uses Step | | .github/workflows/actor_trusted_checkout.yml:19:7:23:4 | Uses Step | .github/workflows/actor_trusted_checkout.yml:23:7:26:21 | Uses Step | @@ -35,6 +37,7 @@ edges | .github/workflows/artifactpoisoning53.yml:15:9:18:6 | Run Step | .github/workflows/artifactpoisoning53.yml:18:9:23:29 | Run Step | | .github/workflows/artifactpoisoning71.yml:9:9:16:6 | Uses Step | .github/workflows/artifactpoisoning71.yml:16:9:18:40 | Run Step | | .github/workflows/artifactpoisoning81.yml:11:9:14:6 | Uses Step | .github/workflows/artifactpoisoning81.yml:14:9:16:6 | Run Step | +| .github/workflows/artifactpoisoning81.yml:13:17:13:57 | github.event.pull_request.head.sha | .github/workflows/artifactpoisoning81.yml:11:9:14:6 | Uses Step | | .github/workflows/artifactpoisoning81.yml:14:9:16:6 | Run Step | .github/workflows/artifactpoisoning81.yml:16:9:22:2 | Uses Step | | .github/workflows/artifactpoisoning81.yml:28:9:31:6 | Uses Step | .github/workflows/artifactpoisoning81.yml:31:9:31:28 | Run Step | | .github/workflows/artifactpoisoning82.yml:11:9:14:6 | Uses Step | .github/workflows/artifactpoisoning82.yml:14:9:16:6 | Run Step | @@ -64,12 +67,14 @@ edges | .github/workflows/artifactpoisoning97.yml:13:9:19:6 | Uses Step | .github/workflows/artifactpoisoning97.yml:19:9:19:25 | Run Step | | .github/workflows/artifactpoisoning101.yml:10:9:16:6 | Uses Step | .github/workflows/artifactpoisoning101.yml:16:9:19:59 | Run Step: pr_number | | .github/workflows/auto_ci.yml:20:9:27:6 | Uses Step | .github/workflows/auto_ci.yml:27:9:32:6 | Uses Step | +| .github/workflows/auto_ci.yml:24:17:24:57 | github.event.pull_request.head.ref | .github/workflows/auto_ci.yml:20:9:27:6 | Uses Step | | .github/workflows/auto_ci.yml:27:9:32:6 | Uses Step | .github/workflows/auto_ci.yml:32:9:37:6 | Run Step | | .github/workflows/auto_ci.yml:32:9:37:6 | Run Step | .github/workflows/auto_ci.yml:37:9:40:6 | Run Step | | .github/workflows/auto_ci.yml:37:9:40:6 | Run Step | .github/workflows/auto_ci.yml:40:9:44:6 | Run Step | | .github/workflows/auto_ci.yml:40:9:44:6 | Run Step | .github/workflows/auto_ci.yml:44:9:48:6 | Run Step | | .github/workflows/auto_ci.yml:44:9:48:6 | Run Step | .github/workflows/auto_ci.yml:48:9:52:2 | Run Step | | .github/workflows/auto_ci.yml:67:9:74:6 | Uses Step | .github/workflows/auto_ci.yml:74:9:79:6 | Uses Step | +| .github/workflows/auto_ci.yml:71:17:71:95 | github.event.pull_request.head.ref \|\| github.event.pull_request.base.ref | .github/workflows/auto_ci.yml:67:9:74:6 | Uses Step | | .github/workflows/auto_ci.yml:74:9:79:6 | Uses Step | .github/workflows/auto_ci.yml:79:9:84:6 | Run Step | | .github/workflows/auto_ci.yml:79:9:84:6 | Run Step | .github/workflows/auto_ci.yml:84:9:93:6 | Run Step | | .github/workflows/auto_ci.yml:84:9:93:6 | Run Step | .github/workflows/auto_ci.yml:93:9:96:6 | Uses Step | @@ -85,47 +90,72 @@ edges | .github/workflows/dependabot1.yml:31:9:34:6 | Run Step | .github/workflows/dependabot1.yml:34:9:36:2 | Run Step | | .github/workflows/dependabot1.yml:39:9:43:6 | Uses Step | .github/workflows/dependabot1.yml:43:9:45:29 | Uses Step | | .github/workflows/dependabot2.yml:33:9:38:6 | Uses Step | .github/workflows/dependabot2.yml:38:9:42:6 | Run Step: nvm | +| .github/workflows/dependabot2.yml:35:17:35:57 | github.event.pull_request.head.ref | .github/workflows/dependabot2.yml:33:9:38:6 | Uses Step | | .github/workflows/dependabot2.yml:38:9:42:6 | Run Step: nvm | .github/workflows/dependabot2.yml:42:9:47:6 | Uses Step | | .github/workflows/dependabot2.yml:42:9:47:6 | Uses Step | .github/workflows/dependabot2.yml:47:9:52:6 | Run Step | | .github/workflows/dependabot2.yml:47:9:52:6 | Run Step | .github/workflows/dependabot2.yml:52:9:58:6 | Run Step | | .github/workflows/dependabot2.yml:52:9:58:6 | Run Step | .github/workflows/dependabot2.yml:58:9:61:6 | Run Step | | .github/workflows/dependabot2.yml:58:9:61:6 | Run Step | .github/workflows/dependabot2.yml:61:9:68:19 | Run Step | | .github/workflows/dependabot3.yml:15:9:20:6 | Uses Step | .github/workflows/dependabot3.yml:20:9:25:6 | Uses Step | +| .github/workflows/dependabot3.yml:18:17:18:57 | github.event.pull_request.head.sha | .github/workflows/dependabot3.yml:15:9:20:6 | Uses Step | | .github/workflows/dependabot3.yml:20:9:25:6 | Uses Step | .github/workflows/dependabot3.yml:25:9:48:6 | Run Step: set-milestone | | .github/workflows/dependabot3.yml:25:9:48:6 | Run Step: set-milestone | .github/workflows/dependabot3.yml:48:9:52:57 | Run Step | | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:11:9:14:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:14:9:17:7 | Run Step | +| .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:13:17:13:40 | inputs.COMMIT_SHA | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:11:9:14:6 | Uses Step | | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build_nested_branching.yml:11:9:19:6 | Uses Step: checkAccess | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build_nested_branching.yml:19:9:25:2 | Run Step | | .github/workflows/external/TestOrg/TestRepo/.github/workflows/formal.yml:14:9:19:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/formal.yml:19:9:25:6 | Run Step | | .github/workflows/external/TestOrg/TestRepo/.github/workflows/formal.yml:19:9:25:6 | Run Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/formal.yml:25:9:70:20 | Run Step | | .github/workflows/external/TestOrg/TestRepo/.github/workflows/reusable.yml:23:9:26:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/reusable.yml:26:9:29:7 | Run Step | +| .github/workflows/external/TestOrg/TestRepo/.github/workflows/reusable.yml:25:17:25:36 | inputs.branch | .github/workflows/external/TestOrg/TestRepo/.github/workflows/reusable.yml:23:9:26:6 | Uses Step | | .github/workflows/gitcheckout.yml:10:11:18:8 | Run Step | .github/workflows/gitcheckout.yml:18:11:21:8 | Uses Step | +| .github/workflows/gitcheckout.yml:17:27:17:48 | github.head_ref | .github/workflows/gitcheckout.yml:10:11:18:8 | Run Step | | .github/workflows/gitcheckout.yml:18:11:21:8 | Uses Step | .github/workflows/gitcheckout.yml:21:11:23:22 | Run Step | | .github/workflows/issue_comment_3rd_party_action.yml:12:9:16:6 | Uses Step: comment-branch | .github/workflows/issue_comment_3rd_party_action.yml:16:9:22:2 | Uses Step | +| .github/workflows/issue_comment_3rd_party_action.yml:20:17:20:60 | steps.comment-branch.outputs.head_sha | .github/workflows/issue_comment_3rd_party_action.yml:16:9:22:2 | Uses Step | | .github/workflows/issue_comment_3rd_party_action.yml:25:9:30:6 | Uses Step: comment-branch | .github/workflows/issue_comment_3rd_party_action.yml:30:9:36:2 | Uses Step | +| .github/workflows/issue_comment_3rd_party_action.yml:34:17:34:60 | steps.comment-branch.outputs.head_ref | .github/workflows/issue_comment_3rd_party_action.yml:30:9:36:2 | Uses Step | | .github/workflows/issue_comment_3rd_party_action.yml:39:9:45:6 | Uses Step: refs | .github/workflows/issue_comment_3rd_party_action.yml:45:9:49:6 | Uses Step | | .github/workflows/issue_comment_3rd_party_action.yml:45:9:49:6 | Uses Step | .github/workflows/issue_comment_3rd_party_action.yml:49:9:52:25 | Uses Step | +| .github/workflows/issue_comment_3rd_party_action.yml:47:17:47:50 | steps.refs.outputs.head_ref | .github/workflows/issue_comment_3rd_party_action.yml:45:9:49:6 | Uses Step | +| .github/workflows/issue_comment_3rd_party_action.yml:51:17:51:50 | steps.refs.outputs.head_sha | .github/workflows/issue_comment_3rd_party_action.yml:49:9:52:25 | Uses Step | +| .github/workflows/issue_comment_direct.yml:15:17:15:76 | github.event.pull_request.head.ref \|\| github.head_ref | .github/workflows/issue_comment_direct.yml:12:9:16:2 | Uses Step | +| .github/workflows/issue_comment_direct.yml:22:27:22:58 | github.event.issue.number | .github/workflows/issue_comment_direct.yml:20:9:24:2 | Uses Step | +| .github/workflows/issue_comment_direct.yml:30:17:30:79 | format('refs/pull/{0}/merge', github.event.issue.number) | .github/workflows/issue_comment_direct.yml:28:9:32:2 | Uses Step | +| .github/workflows/issue_comment_direct.yml:38:17:38:149 | (github.event_name == 'pull_request_review_comment') && format('refs/pull/{0}/merge', github.event.pull_request.number) \|\| '' | .github/workflows/issue_comment_direct.yml:35:9:40:2 | Uses Step | +| .github/workflows/issue_comment_direct.yml:46:17:46:126 | github.event_name == 'issue_comment' && format('refs/pull/{0}/merge', github.event.issue.number) \|\| '' | .github/workflows/issue_comment_direct.yml:43:9:46:126 | Uses Step | | .github/workflows/issue_comment_heuristic.yml:11:9:24:6 | Uses Step: get-pr-info | .github/workflows/issue_comment_heuristic.yml:24:9:28:6 | Run Step: get-sha | | .github/workflows/issue_comment_heuristic.yml:24:9:28:6 | Run Step: get-sha | .github/workflows/issue_comment_heuristic.yml:28:9:33:2 | Uses Step | +| .github/workflows/issue_comment_heuristic.yml:31:17:31:48 | steps.get-sha.outputs.sha | .github/workflows/issue_comment_heuristic.yml:28:9:33:2 | Uses Step | | .github/workflows/issue_comment_heuristic.yml:37:7:48:4 | Run Step: vars | .github/workflows/issue_comment_heuristic.yml:48:7:50:46 | Uses Step | +| .github/workflows/issue_comment_heuristic.yml:50:15:50:46 | steps.vars.outputs.branch | .github/workflows/issue_comment_heuristic.yml:48:7:50:46 | Uses Step | | .github/workflows/issue_comment_octokit2.yml:12:9:19:6 | Uses Step: fetch_issue | .github/workflows/issue_comment_octokit2.yml:19:9:26:6 | Uses Step: fetch_pr | | .github/workflows/issue_comment_octokit2.yml:19:9:26:6 | Uses Step: fetch_pr | .github/workflows/issue_comment_octokit2.yml:26:9:27:6 | name: C ... ildcard | | .github/workflows/issue_comment_octokit2.yml:26:9:27:6 | name: C ... ildcard | .github/workflows/issue_comment_octokit2.yml:27:9:31:6 | Uses Step | | .github/workflows/issue_comment_octokit2.yml:27:9:31:6 | Uses Step | .github/workflows/issue_comment_octokit2.yml:31:9:33:6 | Uses Step | +| .github/workflows/issue_comment_octokit2.yml:29:17:29:69 | fromJson(steps.fetch_pr.outputs.data).head.ref | .github/workflows/issue_comment_octokit2.yml:27:9:31:6 | Uses Step | | .github/workflows/issue_comment_octokit2.yml:31:9:33:6 | Uses Step | .github/workflows/issue_comment_octokit2.yml:33:9:37:6 | Uses Step | | .github/workflows/issue_comment_octokit2.yml:33:9:37:6 | Uses Step | .github/workflows/issue_comment_octokit2.yml:37:9:38:37 | Uses Step | | .github/workflows/issue_comment_octokit.yml:12:9:19:6 | Uses Step: fetch_issue | .github/workflows/issue_comment_octokit.yml:19:9:26:6 | Uses Step: fetch_pr | | .github/workflows/issue_comment_octokit.yml:19:9:26:6 | Uses Step: fetch_pr | .github/workflows/issue_comment_octokit.yml:26:9:30:6 | Uses Step | | .github/workflows/issue_comment_octokit.yml:26:9:30:6 | Uses Step | .github/workflows/issue_comment_octokit.yml:30:9:35:2 | Uses Step | +| .github/workflows/issue_comment_octokit.yml:28:17:28:69 | fromJson(steps.fetch_pr.outputs.data).head.ref | .github/workflows/issue_comment_octokit.yml:26:9:30:6 | Uses Step | +| .github/workflows/issue_comment_octokit.yml:32:17:32:69 | fromJson(steps.fetch_pr.outputs.data).head.sha | .github/workflows/issue_comment_octokit.yml:30:9:35:2 | Uses Step | | .github/workflows/issue_comment_octokit.yml:38:9:52:6 | Uses Step: get-pr-info | .github/workflows/issue_comment_octokit.yml:52:9:57:6 | Run Step: get-sha | | .github/workflows/issue_comment_octokit.yml:52:9:57:6 | Run Step: get-sha | .github/workflows/issue_comment_octokit.yml:57:9:62:2 | Uses Step | +| .github/workflows/issue_comment_octokit.yml:60:17:60:48 | steps.get-sha.outputs.sha | .github/workflows/issue_comment_octokit.yml:57:9:62:2 | Uses Step | | .github/workflows/issue_comment_octokit.yml:66:9:79:6 | Uses Step: sha | .github/workflows/issue_comment_octokit.yml:79:9:83:2 | Uses Step | +| .github/workflows/issue_comment_octokit.yml:81:17:81:47 | steps.sha.outputs.result | .github/workflows/issue_comment_octokit.yml:79:9:83:2 | Uses Step | | .github/workflows/issue_comment_octokit.yml:87:9:95:6 | Uses Step: sha | .github/workflows/issue_comment_octokit.yml:95:9:100:2 | Uses Step | +| .github/workflows/issue_comment_octokit.yml:98:17:98:47 | steps.sha.outputs.result | .github/workflows/issue_comment_octokit.yml:95:9:100:2 | Uses Step | | .github/workflows/issue_comment_octokit.yml:103:9:109:6 | Uses Step: request | .github/workflows/issue_comment_octokit.yml:109:9:114:66 | Uses Step | +| .github/workflows/issue_comment_octokit.yml:114:17:114:66 | fromJson(steps.request.outputs.data).head.ref | .github/workflows/issue_comment_octokit.yml:109:9:114:66 | Uses Step | | .github/workflows/label_trusted_checkout1.yml:11:7:15:4 | Uses Step | .github/workflows/label_trusted_checkout1.yml:15:7:16:4 | Uses Step | +| .github/workflows/label_trusted_checkout1.yml:13:15:13:55 | github.event.pull_request.head.sha | .github/workflows/label_trusted_checkout1.yml:11:7:15:4 | Uses Step | | .github/workflows/label_trusted_checkout1.yml:15:7:16:4 | Uses Step | .github/workflows/label_trusted_checkout1.yml:16:7:20:4 | Run Step | | .github/workflows/label_trusted_checkout1.yml:16:7:20:4 | Run Step | .github/workflows/label_trusted_checkout1.yml:20:7:24:4 | Uses Step | | .github/workflows/label_trusted_checkout1.yml:20:7:24:4 | Uses Step | .github/workflows/label_trusted_checkout1.yml:24:7:27:21 | Uses Step | | .github/workflows/label_trusted_checkout2.yml:12:7:16:4 | Uses Step | .github/workflows/label_trusted_checkout2.yml:16:7:17:4 | Uses Step | +| .github/workflows/label_trusted_checkout2.yml:14:15:14:55 | github.event.pull_request.head.sha | .github/workflows/label_trusted_checkout2.yml:12:7:16:4 | Uses Step | | .github/workflows/label_trusted_checkout2.yml:16:7:17:4 | Uses Step | .github/workflows/label_trusted_checkout2.yml:17:7:21:4 | Run Step | | .github/workflows/label_trusted_checkout2.yml:17:7:21:4 | Run Step | .github/workflows/label_trusted_checkout2.yml:21:7:25:4 | Uses Step | | .github/workflows/label_trusted_checkout2.yml:21:7:25:4 | Uses Step | .github/workflows/label_trusted_checkout2.yml:25:7:28:21 | Uses Step | @@ -134,17 +164,22 @@ edges | .github/workflows/level0.yml:62:9:65:6 | Uses Step | .github/workflows/level0.yml:65:9:86:2 | Uses Step | | .github/workflows/level0.yml:96:9:99:6 | Uses Step | .github/workflows/level0.yml:99:9:103:6 | Uses Step | | .github/workflows/level0.yml:99:9:103:6 | Uses Step | .github/workflows/level0.yml:103:9:107:6 | Uses Step | +| .github/workflows/level0.yml:102:17:102:57 | github.event.pull_request.head.sha | .github/workflows/level0.yml:99:9:103:6 | Uses Step | | .github/workflows/level0.yml:103:9:107:6 | Uses Step | .github/workflows/level0.yml:107:9:112:2 | Run Step | | .github/workflows/level0.yml:122:9:125:6 | Uses Step | .github/workflows/level0.yml:125:9:129:6 | Uses Step | | .github/workflows/level0.yml:125:9:129:6 | Uses Step | .github/workflows/level0.yml:129:9:133:6 | Uses Step | +| .github/workflows/level0.yml:128:17:128:57 | github.event.pull_request.head.sha | .github/workflows/level0.yml:125:9:129:6 | Uses Step | | .github/workflows/level0.yml:129:9:133:6 | Uses Step | .github/workflows/level0.yml:133:9:135:23 | Run Step | | .github/workflows/mend.yml:13:9:22:6 | Run Step: set_ref | .github/workflows/mend.yml:22:9:29:6 | Uses Step | | .github/workflows/mend.yml:22:9:29:6 | Uses Step | .github/workflows/mend.yml:29:9:33:28 | Uses Step | +| .github/workflows/mend.yml:27:17:27:48 | steps.set_ref.outputs.ref | .github/workflows/mend.yml:22:9:29:6 | Uses Step | | .github/workflows/poc2.yml:28:9:37:6 | Uses Step: branch-deploy | .github/workflows/poc2.yml:37:9:42:6 | Uses Step | | .github/workflows/poc2.yml:37:9:42:6 | Uses Step | .github/workflows/poc2.yml:42:9:47:6 | Uses Step | +| .github/workflows/poc2.yml:40:17:40:54 | steps.branch-deploy.outputs.ref | .github/workflows/poc2.yml:37:9:42:6 | Uses Step | | .github/workflows/poc2.yml:42:9:47:6 | Uses Step | .github/workflows/poc2.yml:47:9:52:6 | Run Step | | .github/workflows/poc2.yml:47:9:52:6 | Run Step | .github/workflows/poc2.yml:52:9:58:24 | Run Step | | .github/workflows/poc3.yml:18:7:25:4 | Uses Step | .github/workflows/poc3.yml:25:7:31:4 | Uses Step | +| .github/workflows/poc3.yml:22:15:22:55 | github.event.pull_request.head.ref | .github/workflows/poc3.yml:18:7:25:4 | Uses Step | | .github/workflows/poc3.yml:25:7:31:4 | Uses Step | .github/workflows/poc3.yml:31:7:33:4 | Uses Step | | .github/workflows/poc3.yml:31:7:33:4 | Uses Step | .github/workflows/poc3.yml:33:7:38:4 | Uses Step | | .github/workflows/poc3.yml:33:7:38:4 | Uses Step | .github/workflows/poc3.yml:38:7:40:4 | Run Step | @@ -153,26 +188,32 @@ edges | .github/workflows/poc3.yml:41:7:42:4 | Run Step | .github/workflows/poc3.yml:42:7:43:4 | Run Step | | .github/workflows/poc3.yml:42:7:43:4 | Run Step | .github/workflows/poc3.yml:43:7:48:2 | Uses Step | | .github/workflows/poc.yml:30:9:36:6 | Uses Step | .github/workflows/poc.yml:36:9:38:6 | Uses Step | +| .github/workflows/poc.yml:34:17:34:57 | github.event.pull_request.head.ref | .github/workflows/poc.yml:30:9:36:6 | Uses Step | | .github/workflows/poc.yml:36:9:38:6 | Uses Step | .github/workflows/poc.yml:38:9:43:6 | Uses Step | | .github/workflows/poc.yml:38:9:43:6 | Uses Step | .github/workflows/poc.yml:43:9:47:2 | Uses Step | | .github/workflows/pr-workflow.yml:57:9:60:6 | Uses Step | .github/workflows/pr-workflow.yml:60:9:70:6 | Uses Step | | .github/workflows/pr-workflow.yml:60:9:70:6 | Uses Step | .github/workflows/pr-workflow.yml:70:9:78:6 | Uses Step | | .github/workflows/pr-workflow.yml:70:9:78:6 | Uses Step | .github/workflows/pr-workflow.yml:78:9:81:2 | Run Step: ok | | .github/workflows/pr-workflow.yml:103:9:109:6 | Uses Step | .github/workflows/pr-workflow.yml:109:9:124:6 | Uses Step | +| .github/workflows/pr-workflow.yml:105:17:105:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow.yml:103:9:109:6 | Uses Step | | .github/workflows/pr-workflow.yml:109:9:124:6 | Uses Step | .github/workflows/pr-workflow.yml:124:9:126:2 | Run Step | | .github/workflows/pr-workflow.yml:139:9:144:6 | Uses Step | .github/workflows/pr-workflow.yml:144:9:147:6 | Uses Step | +| .github/workflows/pr-workflow.yml:142:17:142:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow.yml:139:9:144:6 | Uses Step | | .github/workflows/pr-workflow.yml:144:9:147:6 | Uses Step | .github/workflows/pr-workflow.yml:147:9:148:6 | Uses Step | | .github/workflows/pr-workflow.yml:147:9:148:6 | Uses Step | .github/workflows/pr-workflow.yml:148:9:154:6 | Uses Step | | .github/workflows/pr-workflow.yml:148:9:154:6 | Uses Step | .github/workflows/pr-workflow.yml:154:9:158:6 | Run Step | | .github/workflows/pr-workflow.yml:154:9:158:6 | Run Step | .github/workflows/pr-workflow.yml:158:9:196:2 | Run Step: ok | | .github/workflows/pr-workflow.yml:209:9:216:6 | Uses Step | .github/workflows/pr-workflow.yml:216:9:222:6 | Uses Step | | .github/workflows/pr-workflow.yml:216:9:222:6 | Uses Step | .github/workflows/pr-workflow.yml:222:9:227:6 | Uses Step | +| .github/workflows/pr-workflow.yml:220:17:220:64 | inputs.github_event_pull_request_head_sha | .github/workflows/pr-workflow.yml:216:9:222:6 | Uses Step | | .github/workflows/pr-workflow.yml:222:9:227:6 | Uses Step | .github/workflows/pr-workflow.yml:227:9:230:2 | Run Step: ok | | .github/workflows/pr-workflow.yml:243:9:250:6 | Uses Step | .github/workflows/pr-workflow.yml:250:9:256:6 | Uses Step | | .github/workflows/pr-workflow.yml:250:9:256:6 | Uses Step | .github/workflows/pr-workflow.yml:256:9:261:6 | Uses Step | +| .github/workflows/pr-workflow.yml:254:17:254:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow.yml:250:9:256:6 | Uses Step | | .github/workflows/pr-workflow.yml:256:9:261:6 | Uses Step | .github/workflows/pr-workflow.yml:261:9:265:2 | Run Step: ok | | .github/workflows/pr-workflow.yml:277:9:284:6 | Uses Step | .github/workflows/pr-workflow.yml:284:9:290:6 | Uses Step | | .github/workflows/pr-workflow.yml:284:9:290:6 | Uses Step | .github/workflows/pr-workflow.yml:290:9:295:6 | Uses Step | +| .github/workflows/pr-workflow.yml:288:17:288:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow.yml:284:9:290:6 | Uses Step | | .github/workflows/pr-workflow.yml:290:9:295:6 | Uses Step | .github/workflows/pr-workflow.yml:295:9:298:2 | Run Step: ok | | .github/workflows/pr-workflow.yml:309:9:314:6 | Run Step | .github/workflows/pr-workflow.yml:314:9:318:6 | Run Step | | .github/workflows/pr-workflow.yml:314:9:318:6 | Run Step | .github/workflows/pr-workflow.yml:318:9:323:2 | Run Step | @@ -182,26 +223,33 @@ edges | .github/workflows/pr-workflow.yml:351:9:355:6 | Run Step | .github/workflows/pr-workflow.yml:355:9:369:2 | Uses Step | | .github/workflows/pr-workflow.yml:380:9:386:6 | Uses Step | .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | | .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | .github/workflows/pr-workflow.yml:391:9:395:6 | Uses Step | +| .github/workflows/pr-workflow.yml:389:17:389:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | | .github/workflows/pr-workflow.yml:391:9:395:6 | Uses Step | .github/workflows/pr-workflow.yml:395:9:404:6 | Uses Step | | .github/workflows/pr-workflow.yml:395:9:404:6 | Uses Step | .github/workflows/pr-workflow.yml:404:9:414:6 | Uses Step | | .github/workflows/pr-workflow.yml:404:9:414:6 | Uses Step | .github/workflows/pr-workflow.yml:414:9:423:6 | Uses Step | | .github/workflows/pr-workflow.yml:414:9:423:6 | Uses Step | .github/workflows/pr-workflow.yml:423:9:432:2 | Uses Step | | .github/workflows/pr-workflow.yml:444:9:449:6 | Uses Step | .github/workflows/pr-workflow.yml:449:9:452:6 | Uses Step | +| .github/workflows/pr-workflow.yml:447:17:447:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow.yml:444:9:449:6 | Uses Step | | .github/workflows/pr-workflow.yml:449:9:452:6 | Uses Step | .github/workflows/pr-workflow.yml:452:9:453:6 | Uses Step | | .github/workflows/pr-workflow.yml:452:9:453:6 | Uses Step | .github/workflows/pr-workflow.yml:453:9:459:6 | Uses Step | | .github/workflows/pr-workflow.yml:453:9:459:6 | Uses Step | .github/workflows/pr-workflow.yml:459:9:462:6 | Run Step | | .github/workflows/pr-workflow.yml:459:9:462:6 | Run Step | .github/workflows/pr-workflow.yml:462:9:463:48 | Run Step: ok | | .github/workflows/priv_pull_request_checkout.yml:14:9:20:6 | Uses Step | .github/workflows/priv_pull_request_checkout.yml:20:9:23:52 | Run Step | +| .github/workflows/priv_pull_request_checkout.yml:17:17:17:38 | github.head_ref | .github/workflows/priv_pull_request_checkout.yml:14:9:20:6 | Uses Step | | .github/workflows/resolve-args.yml:19:9:20:6 | Uses Step | .github/workflows/resolve-args.yml:20:9:22:6 | Uses Step | | .github/workflows/resolve-args.yml:20:9:22:6 | Uses Step | .github/actions/download-artifact/action.yaml:6:7:25:4 | Uses Step | | .github/workflows/resolve-args.yml:20:9:22:6 | Uses Step | .github/workflows/resolve-args.yml:22:9:36:13 | Run Step: resolve-step | | .github/workflows/reusable_local.yml:23:9:26:6 | Uses Step | .github/workflows/reusable_local.yml:26:9:29:7 | Run Step | +| .github/workflows/reusable_local.yml:25:17:25:36 | inputs.branch | .github/workflows/reusable_local.yml:23:9:26:6 | Uses Step | | .github/workflows/test1.yml:18:9:21:6 | Uses Step | .github/workflows/test1.yml:21:9:24:6 | Run Step | | .github/workflows/test1.yml:21:9:24:6 | Run Step | .github/workflows/test1.yml:24:9:25:39 | Run Step | | .github/workflows/test2.yml:13:9:16:6 | Uses Step | .github/workflows/test2.yml:16:9:20:52 | Uses Step | +| .github/workflows/test2.yml:15:17:15:57 | github.event.pull_request.head.sha | .github/workflows/test2.yml:13:9:16:6 | Uses Step | | .github/workflows/test3.yml:28:9:33:6 | Uses Step | .github/workflows/test3.yml:33:9:35:6 | Run Step | +| .github/workflows/test3.yml:31:17:31:57 | github.event.pull_request.head.ref | .github/workflows/test3.yml:28:9:33:6 | Uses Step | | .github/workflows/test3.yml:33:9:35:6 | Run Step | .github/workflows/test3.yml:35:9:41:63 | Uses Step | | .github/workflows/test4.yml:18:7:25:4 | Uses Step | .github/workflows/test4.yml:25:7:31:4 | Uses Step | +| .github/workflows/test4.yml:22:15:22:55 | github.event.pull_request.head.ref | .github/workflows/test4.yml:18:7:25:4 | Uses Step | | .github/workflows/test4.yml:25:7:31:4 | Uses Step | .github/workflows/test4.yml:31:7:33:4 | Uses Step | | .github/workflows/test4.yml:31:7:33:4 | Uses Step | .github/workflows/test4.yml:33:7:38:4 | Uses Step | | .github/workflows/test4.yml:33:7:38:4 | Uses Step | .github/workflows/test4.yml:38:7:40:4 | Run Step | @@ -212,12 +260,16 @@ edges | .github/workflows/test4.yml:43:7:47:4 | Uses Step | .github/workflows/test4.yml:47:7:47:28 | Run Step | | .github/workflows/test5.yml:13:9:28:6 | Uses Step: issue | .github/workflows/test5.yml:28:9:32:6 | Uses Step | | .github/workflows/test5.yml:28:9:32:6 | Uses Step | .github/workflows/test5.yml:32:9:34:2 | Run Step | +| .github/workflows/test5.yml:31:17:31:63 | fromJson(steps.issue.outputs.result).sha | .github/workflows/test5.yml:28:9:32:6 | Uses Step | | .github/workflows/test5.yml:39:9:54:6 | Uses Step: issue | .github/workflows/test5.yml:54:9:58:6 | Uses Step | | .github/workflows/test5.yml:54:9:58:6 | Uses Step | .github/workflows/test5.yml:58:9:60:2 | Run Step | +| .github/workflows/test5.yml:57:17:57:63 | fromJson(steps.issue.outputs.result).ref | .github/workflows/test5.yml:54:9:58:6 | Uses Step | | .github/workflows/test5.yml:64:9:68:6 | Uses Step | .github/workflows/test5.yml:68:9:68:43 | Run Step | +| .github/workflows/test5.yml:67:27:67:52 | github.event.number | .github/workflows/test5.yml:64:9:68:6 | Uses Step | | .github/workflows/test6.yml:19:9:39:6 | Uses Step | .github/workflows/test6.yml:39:9:43:6 | Run Step | | .github/workflows/test6.yml:39:9:43:6 | Run Step | .github/workflows/test6.yml:43:9:45:52 | Run Step | | .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:24:9:27:6 | Uses Step | +| .github/workflows/test7.yml:22:27:22:58 | github.event.issue.number | .github/workflows/test7.yml:19:9:24:6 | Uses Step | | .github/workflows/test7.yml:24:9:27:6 | Uses Step | .github/workflows/test7.yml:27:9:33:6 | Uses Step | | .github/workflows/test7.yml:27:9:33:6 | Uses Step | .github/workflows/test7.yml:33:9:36:6 | Run Step | | .github/workflows/test7.yml:33:9:36:6 | Run Step | .github/workflows/test7.yml:36:9:39:6 | Run Step | @@ -226,16 +278,22 @@ edges | .github/workflows/test7.yml:49:9:59:6 | Run Step: benchmark-pr | .github/workflows/test7.yml:59:9:60:6 | Run Step | | .github/workflows/test7.yml:59:9:60:6 | Run Step | .github/workflows/test7.yml:60:9:60:37 | Run Step | | .github/workflows/test8.yml:20:9:26:6 | Uses Step | .github/workflows/test8.yml:26:9:29:2 | Run Step | +| .github/workflows/test8.yml:23:17:23:57 | github.event.pull_request.head.sha | .github/workflows/test8.yml:20:9:26:6 | Uses Step | | .github/workflows/test9.yml:11:9:16:6 | Uses Step | .github/workflows/test9.yml:16:9:17:48 | Run Step | +| .github/workflows/test9.yml:13:17:13:57 | github.event.pull_request.head.sha | .github/workflows/test9.yml:11:9:16:6 | Uses Step | | .github/workflows/test10.yml:20:9:25:6 | Uses Step | .github/workflows/test10.yml:25:9:30:2 | Run Step | +| .github/workflows/test10.yml:23:17:23:79 | github.event.after \|\| github.event.pull_request.head.sha | .github/workflows/test10.yml:20:9:25:6 | Uses Step | | .github/workflows/test11.yml:30:7:45:4 | Run Step | .github/workflows/test11.yml:45:7:84:4 | Run Step: environment | | .github/workflows/test11.yml:45:7:84:4 | Run Step: environment | .github/workflows/test11.yml:84:7:90:4 | Uses Step | | .github/workflows/test11.yml:84:7:90:4 | Uses Step | .github/workflows/test11.yml:90:7:93:54 | Uses Step | +| .github/workflows/test11.yml:88:15:88:55 | steps.environment.outputs.head_sha | .github/workflows/test11.yml:84:7:90:4 | Uses Step | | .github/workflows/test12.yml:32:7:47:4 | Run Step | .github/workflows/test12.yml:47:7:86:4 | Run Step: environment | | .github/workflows/test12.yml:47:7:86:4 | Run Step: environment | .github/workflows/test12.yml:86:7:92:4 | Uses Step | | .github/workflows/test12.yml:86:7:92:4 | Uses Step | .github/workflows/test12.yml:92:7:95:54 | Uses Step | +| .github/workflows/test12.yml:90:15:90:55 | steps.environment.outputs.head_sha | .github/workflows/test12.yml:86:7:92:4 | Uses Step | | .github/workflows/test13.yml:14:7:20:4 | Uses Step | .github/workflows/test13.yml:20:7:25:4 | Uses Step | | .github/workflows/test13.yml:20:7:25:4 | Uses Step | .github/workflows/test13.yml:25:7:28:4 | Uses Step | +| .github/workflows/test13.yml:23:25:23:56 | github.event.issue.number | .github/workflows/test13.yml:20:7:25:4 | Uses Step | | .github/workflows/test13.yml:25:7:28:4 | Uses Step | .github/workflows/test13.yml:28:7:31:50 | Run Step | | .github/workflows/test14.yml:38:7:41:4 | Uses Step | .github/workflows/test14.yml:41:7:44:4 | Run Step | | .github/workflows/test14.yml:41:7:44:4 | Run Step | .github/workflows/test14.yml:44:7:58:4 | Run Step | @@ -244,6 +302,7 @@ edges | .github/workflows/test14.yml:94:7:101:4 | Uses Step | .github/workflows/test14.yml:101:7:105:4 | Uses Step | | .github/workflows/test14.yml:101:7:105:4 | Uses Step | .github/workflows/test14.yml:105:7:111:4 | Uses Step | | .github/workflows/test14.yml:105:7:111:4 | Uses Step | .github/workflows/test14.yml:111:7:135:4 | Run Step: environment | +| .github/workflows/test14.yml:109:15:109:58 | steps.comment-branch.outputs.head_ref | .github/workflows/test14.yml:105:7:111:4 | Uses Step | | .github/workflows/test14.yml:111:7:135:4 | Run Step: environment | .github/workflows/test14.yml:135:7:141:4 | Run Step: email | | .github/workflows/test14.yml:135:7:141:4 | Run Step: email | .github/workflows/test14.yml:141:7:149:4 | Run Step: slack-id | | .github/workflows/test14.yml:141:7:149:4 | Run Step: slack-id | .github/workflows/test14.yml:149:7:169:4 | Uses Step: slack-initiate | @@ -256,9 +315,11 @@ edges | .github/workflows/test15.yml:38:7:56:4 | Run Step: environment | .github/workflows/test15.yml:56:7:60:4 | Uses Step: comment-branch | | .github/workflows/test15.yml:56:7:60:4 | Uses Step: comment-branch | .github/workflows/test15.yml:60:7:65:4 | Uses Step | | .github/workflows/test15.yml:60:7:65:4 | Uses Step | .github/workflows/test15.yml:65:7:68:4 | Uses Step | +| .github/workflows/test15.yml:63:15:63:58 | steps.comment-branch.outputs.head_ref | .github/workflows/test15.yml:60:7:65:4 | Uses Step | | .github/workflows/test15.yml:65:7:68:4 | Uses Step | .github/workflows/test15.yml:68:7:83:2 | Run Step | | .github/workflows/test15.yml:106:7:110:4 | Uses Step: comment-branch | .github/workflows/test15.yml:110:7:115:4 | Uses Step | | .github/workflows/test15.yml:110:7:115:4 | Uses Step | .github/workflows/test15.yml:115:7:120:4 | Uses Step | +| .github/workflows/test15.yml:113:15:113:58 | steps.comment-branch.outputs.head_ref | .github/workflows/test15.yml:110:7:115:4 | Uses Step | | .github/workflows/test15.yml:115:7:120:4 | Uses Step | .github/workflows/test15.yml:120:7:127:4 | Run Step | | .github/workflows/test15.yml:120:7:127:4 | Run Step | .github/workflows/test15.yml:127:7:131:4 | Run Step | | .github/workflows/test15.yml:127:7:131:4 | Run Step | .github/workflows/test15.yml:131:7:136:4 | Run Step | @@ -266,6 +327,7 @@ edges | .github/workflows/test15.yml:169:7:173:4 | Uses Step: comment-branch | .github/workflows/test15.yml:173:7:180:4 | Uses Step | | .github/workflows/test15.yml:173:7:180:4 | Uses Step | .github/workflows/test15.yml:180:7:185:4 | Uses Step | | .github/workflows/test15.yml:180:7:185:4 | Uses Step | .github/workflows/test15.yml:185:7:197:4 | Run Step: pipeline-info | +| .github/workflows/test15.yml:183:15:183:58 | steps.comment-branch.outputs.head_ref | .github/workflows/test15.yml:180:7:185:4 | Uses Step | | .github/workflows/test15.yml:185:7:197:4 | Run Step: pipeline-info | .github/workflows/test15.yml:197:7:203:4 | Run Step: email | | .github/workflows/test15.yml:197:7:203:4 | Run Step: email | .github/workflows/test15.yml:203:7:211:4 | Run Step: slack-id | | .github/workflows/test15.yml:203:7:211:4 | Run Step: slack-id | .github/workflows/test15.yml:211:7:231:4 | Uses Step: slack-initiate | @@ -286,6 +348,7 @@ edges | .github/workflows/test16.yml:169:9:176:6 | Uses Step: get_token | .github/workflows/test16.yml:176:9:188:2 | Uses Step | | .github/workflows/test16.yml:218:9:221:6 | Uses Step | .github/workflows/test16.yml:221:9:226:6 | Uses Step | | .github/workflows/test16.yml:221:9:226:6 | Uses Step | .github/workflows/test16.yml:226:9:236:6 | Uses Step: get_token | +| .github/workflows/test16.yml:223:17:223:63 | github.event.workflow_run.head_commit.id | .github/workflows/test16.yml:221:9:226:6 | Uses Step | | .github/workflows/test16.yml:226:9:236:6 | Uses Step: get_token | .github/workflows/test16.yml:236:9:248:6 | Uses Step | | .github/workflows/test16.yml:236:9:248:6 | Uses Step | .github/workflows/test16.yml:248:9:270:6 | Run Step | | .github/workflows/test16.yml:248:9:270:6 | Run Step | .github/workflows/test16.yml:270:9:273:6 | Run Step | @@ -293,21 +356,29 @@ edges | .github/workflows/test16.yml:273:9:277:6 | Run Step: zips | .github/workflows/test16.yml:277:9:281:6 | Run Step: tests | | .github/workflows/test16.yml:277:9:281:6 | Run Step: tests | .github/workflows/test16.yml:281:9:294:54 | Uses Step | | .github/workflows/test17.yml:12:15:19:12 | Uses Step | .github/workflows/test17.yml:19:15:23:58 | Uses Step | +| .github/workflows/test17.yml:16:25:16:68 | github.event.workflow_run.head_branch | .github/workflows/test17.yml:12:15:19:12 | Uses Step | | .github/workflows/test18.yml:12:15:33:12 | Uses Step | .github/workflows/test18.yml:33:15:36:12 | Run Step | | .github/workflows/test18.yml:33:15:36:12 | Run Step | .github/workflows/test18.yml:36:15:40:58 | Uses Step | | .github/workflows/test19.yml:16:7:21:4 | Uses Step | .github/workflows/test19.yml:21:7:22:14 | Run Step | +| .github/workflows/test19.yml:20:15:20:55 | github.event.pull_request.head.ref | .github/workflows/test19.yml:16:7:21:4 | Uses Step | | .github/workflows/test20.yml:16:7:21:4 | Uses Step | .github/workflows/test20.yml:21:7:22:14 | Run Step | +| .github/workflows/test20.yml:20:15:20:55 | github.event.pull_request.head.sha | .github/workflows/test20.yml:16:7:21:4 | Uses Step | | .github/workflows/test21.yml:18:9:25:6 | Uses Step | .github/workflows/test21.yml:25:9:27:36 | Run Step | +| .github/workflows/test21.yml:23:17:23:52 | github.head_ref \|\| github.ref | .github/workflows/test21.yml:18:9:25:6 | Uses Step | | .github/workflows/test22.yml:57:15:62:12 | Uses Step | .github/workflows/test22.yml:62:15:62:45 | Run Step | | .github/workflows/test23.yml:38:9:43:6 | Uses Step | .github/workflows/test23.yml:43:9:46:16 | Run Step | +| .github/workflows/test23.yml:41:17:41:62 | needs.resolve-required-data.outputs.ref | .github/workflows/test23.yml:38:9:43:6 | Uses Step | | .github/workflows/test24.yml:7:9:10:6 | Uses Step | .github/workflows/test24.yml:10:9:16:6 | Run Step | | .github/workflows/test24.yml:10:9:16:6 | Run Step | .github/workflows/test24.yml:16:9:20:57 | Run Step | | .github/workflows/test25.yml:17:9:22:6 | Uses Step | .github/workflows/test25.yml:22:9:32:6 | Uses Step: downloadBuildScan | | .github/workflows/test25.yml:22:9:32:6 | Uses Step: downloadBuildScan | .github/workflows/test25.yml:32:9:35:6 | Run Step | | .github/workflows/test25.yml:32:9:35:6 | Run Step | .github/workflows/test25.yml:35:9:42:53 | Run Step | | .github/workflows/test27.yml:18:9:21:6 | Uses Step | .github/workflows/test27.yml:21:9:22:16 | Run Step | +| .github/workflows/test27.yml:20:17:20:37 | inputs.git_ref | .github/workflows/test27.yml:18:9:21:6 | Uses Step | | .github/workflows/test28.yml:17:9:20:6 | Uses Step | .github/workflows/test28.yml:20:9:20:22 | Run Step | +| .github/workflows/test28.yml:19:17:19:38 | github.head_ref | .github/workflows/test28.yml:17:9:20:6 | Uses Step | | .github/workflows/test29.yml:8:7:14:4 | Uses Step | .github/workflows/test29.yml:14:7:21:11 | Uses Step | +| .github/workflows/test29.yml:11:15:11:55 | github.event.pull_request.head.sha | .github/workflows/test29.yml:8:7:14:4 | Uses Step | | .github/workflows/test.yml:13:9:14:6 | Uses Step | .github/workflows/test.yml:14:9:25:6 | Run Step | | .github/workflows/test.yml:14:9:25:6 | Run Step | .github/workflows/test.yml:25:9:33:6 | Run Step | | .github/workflows/test.yml:25:9:33:6 | Run Step | .github/workflows/test.yml:33:9:37:34 | Run Step | @@ -324,74 +395,90 @@ edges | .github/workflows/untrusted_checkout3.yml:12:9:13:6 | Uses Step | .github/workflows/untrusted_checkout3.yml:13:9:13:23 | Run Step | | .github/workflows/untrusted_checkout4.yml:11:7:29:4 | Uses Step: get-pr | .github/workflows/untrusted_checkout4.yml:29:7:35:4 | Uses Step | | .github/workflows/untrusted_checkout4.yml:29:7:35:4 | Uses Step | .github/workflows/untrusted_checkout4.yml:35:7:41:4 | Run Step | +| .github/workflows/untrusted_checkout4.yml:33:15:33:67 | fromJSON(steps.get-pr.outputs.result).head.ref | .github/workflows/untrusted_checkout4.yml:29:7:35:4 | Uses Step | | .github/workflows/untrusted_checkout4.yml:35:7:41:4 | Run Step | .github/workflows/untrusted_checkout4.yml:41:7:47:4 | Run Step | | .github/workflows/untrusted_checkout4.yml:41:7:47:4 | Run Step | .github/workflows/untrusted_checkout4.yml:47:7:51:46 | Run Step | | .github/workflows/untrusted_checkout.yml:8:9:11:6 | Uses Step | .github/workflows/untrusted_checkout.yml:11:9:15:6 | Uses Step | +| .github/workflows/untrusted_checkout.yml:10:17:10:57 | github.event.pull_request.head.sha | .github/workflows/untrusted_checkout.yml:8:9:11:6 | Uses Step | | .github/workflows/untrusted_checkout.yml:11:9:15:6 | Uses Step | .github/workflows/untrusted_checkout.yml:15:9:18:2 | Run Step | | .github/workflows/untrusted_checkout.yml:23:9:26:6 | Uses Step | .github/workflows/untrusted_checkout.yml:26:9:30:6 | Uses Step | +| .github/workflows/untrusted_checkout.yml:25:17:25:31 | env.HEAD | .github/workflows/untrusted_checkout.yml:23:9:26:6 | Uses Step | | .github/workflows/untrusted_checkout.yml:26:9:30:6 | Uses Step | .github/workflows/untrusted_checkout.yml:30:9:32:23 | Run Step | | .github/workflows/untrusted_checkout_5.yml:11:9:14:6 | Uses Step | .github/workflows/untrusted_checkout_5.yml:14:9:17:6 | Uses Step | +| .github/workflows/untrusted_checkout_5.yml:13:17:13:57 | github.event.pull_request.head.sha | .github/workflows/untrusted_checkout_5.yml:11:9:14:6 | Uses Step | | .github/workflows/untrusted_checkout_5.yml:14:9:17:6 | Uses Step | .github/workflows/untrusted_checkout_5.yml:17:9:21:6 | Uses Step | +| .github/workflows/untrusted_checkout_5.yml:16:17:16:31 | env.HEAD | .github/workflows/untrusted_checkout_5.yml:14:9:17:6 | Uses Step | | .github/workflows/untrusted_checkout_5.yml:17:9:21:6 | Uses Step | .github/workflows/untrusted_checkout_5.yml:21:9:23:23 | Run Step | | .github/workflows/untrusted_checkout_6.yml:11:9:14:6 | Uses Step | .github/workflows/untrusted_checkout_6.yml:14:9:17:6 | Uses Step | +| .github/workflows/untrusted_checkout_6.yml:13:17:13:57 | github.event.pull_request.head.sha | .github/workflows/untrusted_checkout_6.yml:11:9:14:6 | Uses Step | | .github/workflows/untrusted_checkout_6.yml:14:9:17:6 | Uses Step | .github/workflows/untrusted_checkout_6.yml:17:9:21:6 | Uses Step | +| .github/workflows/untrusted_checkout_6.yml:16:17:16:31 | env.HEAD | .github/workflows/untrusted_checkout_6.yml:14:9:17:6 | Uses Step | | .github/workflows/untrusted_checkout_6.yml:17:9:21:6 | Uses Step | .github/workflows/untrusted_checkout_6.yml:21:9:23:23 | Run Step | | .github/workflows/untrusted_checkout_no_needs.yml:8:9:16:6 | Uses Step: checkAccess | .github/workflows/untrusted_checkout_no_needs.yml:16:9:22:2 | Run Step | | .github/workflows/untrusted_checkout_no_needs.yml:26:9:31:6 | Uses Step | .github/workflows/untrusted_checkout_no_needs.yml:31:9:31:23 | Run Step | +| .github/workflows/untrusted_checkout_no_needs.yml:29:17:29:57 | github.event.pull_request.head.sha | .github/workflows/untrusted_checkout_no_needs.yml:26:9:31:6 | Uses Step | | .github/workflows/untrusted_checkout_permission_check_reusable2.yml:8:9:16:6 | Uses Step: checkAccess | .github/workflows/untrusted_checkout_permission_check_reusable2.yml:16:9:22:2 | Run Step | | .github/workflows/untrusted_checkout_permission_check_reusable.yml:8:9:16:6 | Uses Step: checkAccess | .github/workflows/untrusted_checkout_permission_check_reusable.yml:16:9:22:2 | Run Step | | .github/workflows/untrusted_checkout_permission_check_reusable_level2.yml:8:9:16:6 | Uses Step: checkAccess | .github/workflows/untrusted_checkout_permission_check_reusable_level2.yml:16:9:22:2 | Run Step | | .github/workflows/untrusted_checkout_permission_check_reusable_no_needs.yml:8:9:16:6 | Uses Step: checkAccess | .github/workflows/untrusted_checkout_permission_check_reusable_no_needs.yml:16:9:22:2 | Run Step | | .github/workflows/untrusted_checkout_permissions_check.yml:8:9:16:6 | Uses Step: checkAccess | .github/workflows/untrusted_checkout_permissions_check.yml:16:9:22:2 | Run Step | | .github/workflows/untrusted_checkout_permissions_check.yml:26:9:31:6 | Uses Step | .github/workflows/untrusted_checkout_permissions_check.yml:31:9:32:2 | Run Step | +| .github/workflows/untrusted_checkout_permissions_check.yml:29:17:29:57 | github.event.pull_request.head.sha | .github/workflows/untrusted_checkout_permissions_check.yml:26:9:31:6 | Uses Step | | .github/workflows/untrusted_checkout_permissions_check.yml:36:9:41:6 | Uses Step | .github/workflows/untrusted_checkout_permissions_check.yml:41:9:41:22 | Run Step | +| .github/workflows/untrusted_checkout_permissions_check.yml:39:17:39:57 | github.event.pull_request.head.sha | .github/workflows/untrusted_checkout_permissions_check.yml:36:9:41:6 | Uses Step | | .github/workflows/untrusted_checkout_two_callers_both_protected.yml:8:9:16:6 | Uses Step: checkAccess | .github/workflows/untrusted_checkout_two_callers_both_protected.yml:16:9:22:2 | Run Step | | .github/workflows/untrusted_checkout_two_callers_both_protected.yml:30:9:38:6 | Uses Step: checkAccess | .github/workflows/untrusted_checkout_two_callers_both_protected.yml:38:9:44:2 | Run Step | | .github/workflows/workflow_run_untrusted_checkout.yml:13:9:16:6 | Uses Step | .github/workflows/workflow_run_untrusted_checkout.yml:16:9:18:31 | Uses Step | +| .github/workflows/workflow_run_untrusted_checkout.yml:15:17:15:57 | github.event.workflow_run.head.sha | .github/workflows/workflow_run_untrusted_checkout.yml:13:9:16:6 | Uses Step | +| .github/workflows/workflow_run_untrusted_checkout.yml:18:17:18:31 | env.HEAD | .github/workflows/workflow_run_untrusted_checkout.yml:16:9:18:31 | Uses Step | | .github/workflows/workflow_run_untrusted_checkout_2.yml:13:9:16:6 | Uses Step | .github/workflows/workflow_run_untrusted_checkout_2.yml:16:9:18:31 | Uses Step | +| .github/workflows/workflow_run_untrusted_checkout_2.yml:15:17:15:57 | github.event.workflow_run.head.sha | .github/workflows/workflow_run_untrusted_checkout_2.yml:13:9:16:6 | Uses Step | +| .github/workflows/workflow_run_untrusted_checkout_2.yml:18:17:18:31 | env.HEAD | .github/workflows/workflow_run_untrusted_checkout_2.yml:16:9:18:31 | Uses Step | | .github/workflows/workflow_run_untrusted_checkout_3.yml:13:9:16:6 | Uses Step | .github/workflows/workflow_run_untrusted_checkout_3.yml:16:9:18:31 | Uses Step | +| .github/workflows/workflow_run_untrusted_checkout_3.yml:15:17:15:57 | github.event.workflow_run.head.sha | .github/workflows/workflow_run_untrusted_checkout_3.yml:13:9:16:6 | Uses Step | +| .github/workflows/workflow_run_untrusted_checkout_3.yml:18:17:18:31 | env.HEAD | .github/workflows/workflow_run_untrusted_checkout_3.yml:16:9:18:31 | Uses Step | #select -| .github/actions/dangerous-git-checkout/action.yml:6:7:11:4 | Uses Step | .github/actions/dangerous-git-checkout/action.yml:6:7:11:4 | Uses Step | .github/workflows/untrusted_checkout3.yml:13:9:13:23 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout3.yml:4:3:4:14 | workflow_run | workflow_run | -| .github/workflows/auto_ci.yml:20:9:27:6 | Uses Step | .github/workflows/auto_ci.yml:20:9:27:6 | Uses Step | .github/workflows/auto_ci.yml:32:9:37:6 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/auto_ci.yml:6:3:6:21 | pull_request_target | pull_request_target | -| .github/workflows/auto_ci.yml:20:9:27:6 | Uses Step | .github/workflows/auto_ci.yml:20:9:27:6 | Uses Step | .github/workflows/auto_ci.yml:48:9:52:2 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/auto_ci.yml:6:3:6:21 | pull_request_target | pull_request_target | -| .github/workflows/auto_ci.yml:67:9:74:6 | Uses Step | .github/workflows/auto_ci.yml:67:9:74:6 | Uses Step | .github/workflows/auto_ci.yml:79:9:84:6 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/auto_ci.yml:6:3:6:21 | pull_request_target | pull_request_target | -| .github/workflows/auto_ci.yml:67:9:74:6 | Uses Step | .github/workflows/auto_ci.yml:67:9:74:6 | Uses Step | .github/workflows/auto_ci.yml:84:9:93:6 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/auto_ci.yml:6:3:6:21 | pull_request_target | pull_request_target | -| .github/workflows/dependabot3.yml:15:9:20:6 | Uses Step | .github/workflows/dependabot3.yml:15:9:20:6 | Uses Step | .github/workflows/dependabot3.yml:25:9:48:6 | Run Step: set-milestone | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/dependabot3.yml:3:5:3:23 | pull_request_target | pull_request_target | -| .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:11:9:14:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:11:9:14:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:14:9:17:7 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_permission_check_reusable2.yml:2:3:2:21 | pull_request_target | pull_request_target | -| .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:11:9:14:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:11:9:14:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:14:9:17:7 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_permission_check_reusable_branching_nested.yml:2:3:2:21 | pull_request_target | pull_request_target | -| .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:11:9:14:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:11:9:14:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:14:9:17:7 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_permission_check_reusable_no_needs.yml:2:3:2:21 | pull_request_target | pull_request_target | -| .github/workflows/external/TestOrg/TestRepo/.github/workflows/reusable.yml:23:9:26:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/reusable.yml:23:9:26:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/reusable.yml:26:9:29:7 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/reusable_caller1.yaml:4:3:4:21 | pull_request_target | pull_request_target | -| .github/workflows/gitcheckout.yml:10:11:18:8 | Run Step | .github/workflows/gitcheckout.yml:10:11:18:8 | Run Step | .github/workflows/gitcheckout.yml:21:11:23:22 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/gitcheckout.yml:2:3:2:21 | pull_request_target | pull_request_target | -| .github/workflows/label_trusted_checkout2.yml:12:7:16:4 | Uses Step | .github/workflows/label_trusted_checkout2.yml:12:7:16:4 | Uses Step | .github/workflows/label_trusted_checkout2.yml:17:7:21:4 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/label_trusted_checkout2.yml:2:3:2:21 | pull_request_target | pull_request_target | -| .github/workflows/level0.yml:99:9:103:6 | Uses Step | .github/workflows/level0.yml:99:9:103:6 | Uses Step | .github/workflows/level0.yml:107:9:112:2 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/level0.yml:5:3:5:15 | issue_comment | issue_comment | -| .github/workflows/level0.yml:99:9:103:6 | Uses Step | .github/workflows/level0.yml:99:9:103:6 | Uses Step | .github/workflows/level0.yml:107:9:112:2 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/level0.yml:7:3:7:21 | pull_request_target | pull_request_target | -| .github/workflows/level0.yml:125:9:129:6 | Uses Step | .github/workflows/level0.yml:125:9:129:6 | Uses Step | .github/workflows/level0.yml:133:9:135:23 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/level0.yml:5:3:5:15 | issue_comment | issue_comment | -| .github/workflows/level0.yml:125:9:129:6 | Uses Step | .github/workflows/level0.yml:125:9:129:6 | Uses Step | .github/workflows/level0.yml:133:9:135:23 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/level0.yml:7:3:7:21 | pull_request_target | pull_request_target | -| .github/workflows/poc2.yml:37:9:42:6 | Uses Step | .github/workflows/poc2.yml:37:9:42:6 | Uses Step | .github/workflows/poc2.yml:42:9:47:6 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/poc2.yml:4:3:4:15 | issue_comment | issue_comment | -| .github/workflows/poc2.yml:37:9:42:6 | Uses Step | .github/workflows/poc2.yml:37:9:42:6 | Uses Step | .github/workflows/poc2.yml:52:9:58:24 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/poc2.yml:4:3:4:15 | issue_comment | issue_comment | -| .github/workflows/pr-workflow.yml:216:9:222:6 | Uses Step | .github/workflows/pr-workflow.yml:216:9:222:6 | Uses Step | .github/workflows/pr-workflow.yml:222:9:227:6 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | -| .github/workflows/pr-workflow.yml:250:9:256:6 | Uses Step | .github/workflows/pr-workflow.yml:250:9:256:6 | Uses Step | .github/workflows/pr-workflow.yml:256:9:261:6 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | -| .github/workflows/pr-workflow.yml:284:9:290:6 | Uses Step | .github/workflows/pr-workflow.yml:284:9:290:6 | Uses Step | .github/workflows/pr-workflow.yml:290:9:295:6 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | -| .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | .github/workflows/pr-workflow.yml:391:9:395:6 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | -| .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | .github/workflows/pr-workflow.yml:395:9:404:6 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | -| .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | .github/workflows/pr-workflow.yml:404:9:414:6 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | -| .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | .github/workflows/pr-workflow.yml:414:9:423:6 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | -| .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | .github/workflows/pr-workflow.yml:423:9:432:2 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | -| .github/workflows/reusable_local.yml:23:9:26:6 | Uses Step | .github/workflows/reusable_local.yml:23:9:26:6 | Uses Step | .github/workflows/reusable_local.yml:26:9:29:7 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/reusable_caller3.yaml:4:3:4:21 | pull_request_target | pull_request_target | -| .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:33:9:36:6 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test7.yml:4:3:4:15 | issue_comment | issue_comment | -| .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:36:9:39:6 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test7.yml:4:3:4:15 | issue_comment | issue_comment | -| .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:49:9:59:6 | Run Step: benchmark-pr | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test7.yml:4:3:4:15 | issue_comment | issue_comment | -| .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:59:9:60:6 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test7.yml:4:3:4:15 | issue_comment | issue_comment | -| .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:60:9:60:37 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test7.yml:4:3:4:15 | issue_comment | issue_comment | -| .github/workflows/test10.yml:20:9:25:6 | Uses Step | .github/workflows/test10.yml:20:9:25:6 | Uses Step | .github/workflows/test10.yml:25:9:30:2 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test10.yml:8:3:8:21 | pull_request_target | pull_request_target | -| .github/workflows/test11.yml:84:7:90:4 | Uses Step | .github/workflows/test11.yml:84:7:90:4 | Uses Step | .github/workflows/test11.yml:90:7:93:54 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test11.yml:5:3:5:15 | issue_comment | issue_comment | -| .github/workflows/test17.yml:12:15:19:12 | Uses Step | .github/workflows/test17.yml:12:15:19:12 | Uses Step | .github/workflows/test17.yml:19:15:23:58 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test17.yml:3:5:3:16 | workflow_run | workflow_run | -| .github/workflows/test27.yml:18:9:21:6 | Uses Step | .github/workflows/test27.yml:18:9:21:6 | Uses Step | .github/workflows/test27.yml:21:9:22:16 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test26.yml:4:3:4:14 | workflow_run | workflow_run | -| .github/workflows/test29.yml:8:7:14:4 | Uses Step | .github/workflows/test29.yml:8:7:14:4 | Uses Step | .github/workflows/test29.yml:14:7:21:11 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test29.yml:1:5:1:23 | pull_request_target | pull_request_target | -| .github/workflows/untrusted_checkout4.yml:29:7:35:4 | Uses Step | .github/workflows/untrusted_checkout4.yml:29:7:35:4 | Uses Step | .github/workflows/untrusted_checkout4.yml:35:7:41:4 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout4.yml:2:3:2:15 | issue_comment | issue_comment | -| .github/workflows/untrusted_checkout4.yml:29:7:35:4 | Uses Step | .github/workflows/untrusted_checkout4.yml:29:7:35:4 | Uses Step | .github/workflows/untrusted_checkout4.yml:41:7:47:4 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout4.yml:2:3:2:15 | issue_comment | issue_comment | -| .github/workflows/untrusted_checkout4.yml:29:7:35:4 | Uses Step | .github/workflows/untrusted_checkout4.yml:29:7:35:4 | Uses Step | .github/workflows/untrusted_checkout4.yml:47:7:51:46 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout4.yml:2:3:2:15 | issue_comment | issue_comment | -| .github/workflows/untrusted_checkout.yml:8:9:11:6 | Uses Step | .github/workflows/untrusted_checkout.yml:8:9:11:6 | Uses Step | .github/workflows/untrusted_checkout.yml:15:9:18:2 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout.yml:2:3:2:21 | pull_request_target | pull_request_target | -| .github/workflows/untrusted_checkout.yml:23:9:26:6 | Uses Step | .github/workflows/untrusted_checkout.yml:23:9:26:6 | Uses Step | .github/workflows/untrusted_checkout.yml:30:9:32:23 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout.yml:2:3:2:21 | pull_request_target | pull_request_target | -| .github/workflows/untrusted_checkout_no_needs.yml:26:9:31:6 | Uses Step | .github/workflows/untrusted_checkout_no_needs.yml:26:9:31:6 | Uses Step | .github/workflows/untrusted_checkout_no_needs.yml:31:9:31:23 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_no_needs.yml:2:3:2:21 | pull_request_target | pull_request_target | -| .github/workflows/untrusted_checkout_permissions_check.yml:36:9:41:6 | Uses Step | .github/workflows/untrusted_checkout_permissions_check.yml:36:9:41:6 | Uses Step | .github/workflows/untrusted_checkout_permissions_check.yml:41:9:41:22 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_permissions_check.yml:2:3:2:21 | pull_request_target | pull_request_target | +| .github/actions/dangerous-git-checkout/action.yml:6:7:11:4 | Uses Step | .github/actions/dangerous-git-checkout/action.yml:9:15:9:55 | github.event.pull_request.head.sha | .github/workflows/untrusted_checkout3.yml:13:9:13:23 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout3.yml:4:3:4:14 | workflow_run | workflow_run | +| .github/workflows/auto_ci.yml:20:9:27:6 | Uses Step | .github/workflows/auto_ci.yml:24:17:24:57 | github.event.pull_request.head.ref | .github/workflows/auto_ci.yml:32:9:37:6 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/auto_ci.yml:6:3:6:21 | pull_request_target | pull_request_target | +| .github/workflows/auto_ci.yml:20:9:27:6 | Uses Step | .github/workflows/auto_ci.yml:24:17:24:57 | github.event.pull_request.head.ref | .github/workflows/auto_ci.yml:48:9:52:2 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/auto_ci.yml:6:3:6:21 | pull_request_target | pull_request_target | +| .github/workflows/auto_ci.yml:67:9:74:6 | Uses Step | .github/workflows/auto_ci.yml:71:17:71:95 | github.event.pull_request.head.ref \|\| github.event.pull_request.base.ref | .github/workflows/auto_ci.yml:79:9:84:6 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/auto_ci.yml:6:3:6:21 | pull_request_target | pull_request_target | +| .github/workflows/auto_ci.yml:67:9:74:6 | Uses Step | .github/workflows/auto_ci.yml:71:17:71:95 | github.event.pull_request.head.ref \|\| github.event.pull_request.base.ref | .github/workflows/auto_ci.yml:84:9:93:6 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/auto_ci.yml:6:3:6:21 | pull_request_target | pull_request_target | +| .github/workflows/dependabot3.yml:15:9:20:6 | Uses Step | .github/workflows/dependabot3.yml:18:17:18:57 | github.event.pull_request.head.sha | .github/workflows/dependabot3.yml:25:9:48:6 | Run Step: set-milestone | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/dependabot3.yml:3:5:3:23 | pull_request_target | pull_request_target | +| .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:11:9:14:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:13:17:13:40 | inputs.COMMIT_SHA | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:14:9:17:7 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_permission_check_reusable2.yml:2:3:2:21 | pull_request_target | pull_request_target | +| .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:11:9:14:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:13:17:13:40 | inputs.COMMIT_SHA | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:14:9:17:7 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_permission_check_reusable_branching_nested.yml:2:3:2:21 | pull_request_target | pull_request_target | +| .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:11:9:14:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:13:17:13:40 | inputs.COMMIT_SHA | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:14:9:17:7 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_permission_check_reusable_no_needs.yml:2:3:2:21 | pull_request_target | pull_request_target | +| .github/workflows/external/TestOrg/TestRepo/.github/workflows/reusable.yml:23:9:26:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/reusable.yml:25:17:25:36 | inputs.branch | .github/workflows/external/TestOrg/TestRepo/.github/workflows/reusable.yml:26:9:29:7 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/reusable_caller1.yaml:4:3:4:21 | pull_request_target | pull_request_target | +| .github/workflows/gitcheckout.yml:10:11:18:8 | Run Step | .github/workflows/gitcheckout.yml:17:27:17:48 | github.head_ref | .github/workflows/gitcheckout.yml:21:11:23:22 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/gitcheckout.yml:2:3:2:21 | pull_request_target | pull_request_target | +| .github/workflows/label_trusted_checkout2.yml:12:7:16:4 | Uses Step | .github/workflows/label_trusted_checkout2.yml:14:15:14:55 | github.event.pull_request.head.sha | .github/workflows/label_trusted_checkout2.yml:17:7:21:4 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/label_trusted_checkout2.yml:2:3:2:21 | pull_request_target | pull_request_target | +| .github/workflows/level0.yml:99:9:103:6 | Uses Step | .github/workflows/level0.yml:102:17:102:57 | github.event.pull_request.head.sha | .github/workflows/level0.yml:107:9:112:2 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/level0.yml:5:3:5:15 | issue_comment | issue_comment | +| .github/workflows/level0.yml:99:9:103:6 | Uses Step | .github/workflows/level0.yml:102:17:102:57 | github.event.pull_request.head.sha | .github/workflows/level0.yml:107:9:112:2 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/level0.yml:7:3:7:21 | pull_request_target | pull_request_target | +| .github/workflows/level0.yml:125:9:129:6 | Uses Step | .github/workflows/level0.yml:128:17:128:57 | github.event.pull_request.head.sha | .github/workflows/level0.yml:133:9:135:23 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/level0.yml:5:3:5:15 | issue_comment | issue_comment | +| .github/workflows/level0.yml:125:9:129:6 | Uses Step | .github/workflows/level0.yml:128:17:128:57 | github.event.pull_request.head.sha | .github/workflows/level0.yml:133:9:135:23 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/level0.yml:7:3:7:21 | pull_request_target | pull_request_target | +| .github/workflows/poc2.yml:37:9:42:6 | Uses Step | .github/workflows/poc2.yml:40:17:40:54 | steps.branch-deploy.outputs.ref | .github/workflows/poc2.yml:42:9:47:6 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/poc2.yml:4:3:4:15 | issue_comment | issue_comment | +| .github/workflows/poc2.yml:37:9:42:6 | Uses Step | .github/workflows/poc2.yml:40:17:40:54 | steps.branch-deploy.outputs.ref | .github/workflows/poc2.yml:52:9:58:24 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/poc2.yml:4:3:4:15 | issue_comment | issue_comment | +| .github/workflows/pr-workflow.yml:216:9:222:6 | Uses Step | .github/workflows/pr-workflow.yml:220:17:220:64 | inputs.github_event_pull_request_head_sha | .github/workflows/pr-workflow.yml:222:9:227:6 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | +| .github/workflows/pr-workflow.yml:250:9:256:6 | Uses Step | .github/workflows/pr-workflow.yml:254:17:254:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow.yml:256:9:261:6 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | +| .github/workflows/pr-workflow.yml:284:9:290:6 | Uses Step | .github/workflows/pr-workflow.yml:288:17:288:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow.yml:290:9:295:6 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | +| .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | .github/workflows/pr-workflow.yml:389:17:389:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow.yml:391:9:395:6 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | +| .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | .github/workflows/pr-workflow.yml:389:17:389:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow.yml:395:9:404:6 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | +| .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | .github/workflows/pr-workflow.yml:389:17:389:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow.yml:404:9:414:6 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | +| .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | .github/workflows/pr-workflow.yml:389:17:389:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow.yml:414:9:423:6 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | +| .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | .github/workflows/pr-workflow.yml:389:17:389:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow.yml:423:9:432:2 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | +| .github/workflows/reusable_local.yml:23:9:26:6 | Uses Step | .github/workflows/reusable_local.yml:25:17:25:36 | inputs.branch | .github/workflows/reusable_local.yml:26:9:29:7 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/reusable_caller3.yaml:4:3:4:21 | pull_request_target | pull_request_target | +| .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:22:27:22:58 | github.event.issue.number | .github/workflows/test7.yml:33:9:36:6 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test7.yml:4:3:4:15 | issue_comment | issue_comment | +| .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:22:27:22:58 | github.event.issue.number | .github/workflows/test7.yml:36:9:39:6 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test7.yml:4:3:4:15 | issue_comment | issue_comment | +| .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:22:27:22:58 | github.event.issue.number | .github/workflows/test7.yml:49:9:59:6 | Run Step: benchmark-pr | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test7.yml:4:3:4:15 | issue_comment | issue_comment | +| .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:22:27:22:58 | github.event.issue.number | .github/workflows/test7.yml:59:9:60:6 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test7.yml:4:3:4:15 | issue_comment | issue_comment | +| .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:22:27:22:58 | github.event.issue.number | .github/workflows/test7.yml:60:9:60:37 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test7.yml:4:3:4:15 | issue_comment | issue_comment | +| .github/workflows/test10.yml:20:9:25:6 | Uses Step | .github/workflows/test10.yml:23:17:23:79 | github.event.after \|\| github.event.pull_request.head.sha | .github/workflows/test10.yml:25:9:30:2 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test10.yml:8:3:8:21 | pull_request_target | pull_request_target | +| .github/workflows/test11.yml:84:7:90:4 | Uses Step | .github/workflows/test11.yml:88:15:88:55 | steps.environment.outputs.head_sha | .github/workflows/test11.yml:90:7:93:54 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test11.yml:5:3:5:15 | issue_comment | issue_comment | +| .github/workflows/test17.yml:12:15:19:12 | Uses Step | .github/workflows/test17.yml:16:25:16:68 | github.event.workflow_run.head_branch | .github/workflows/test17.yml:19:15:23:58 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test17.yml:3:5:3:16 | workflow_run | workflow_run | +| .github/workflows/test27.yml:18:9:21:6 | Uses Step | .github/workflows/test27.yml:20:17:20:37 | inputs.git_ref | .github/workflows/test27.yml:21:9:22:16 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test26.yml:4:3:4:14 | workflow_run | workflow_run | +| .github/workflows/test29.yml:8:7:14:4 | Uses Step | .github/workflows/test29.yml:11:15:11:55 | github.event.pull_request.head.sha | .github/workflows/test29.yml:14:7:21:11 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test29.yml:1:5:1:23 | pull_request_target | pull_request_target | +| .github/workflows/untrusted_checkout4.yml:29:7:35:4 | Uses Step | .github/workflows/untrusted_checkout4.yml:33:15:33:67 | fromJSON(steps.get-pr.outputs.result).head.ref | .github/workflows/untrusted_checkout4.yml:35:7:41:4 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout4.yml:2:3:2:15 | issue_comment | issue_comment | +| .github/workflows/untrusted_checkout4.yml:29:7:35:4 | Uses Step | .github/workflows/untrusted_checkout4.yml:33:15:33:67 | fromJSON(steps.get-pr.outputs.result).head.ref | .github/workflows/untrusted_checkout4.yml:41:7:47:4 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout4.yml:2:3:2:15 | issue_comment | issue_comment | +| .github/workflows/untrusted_checkout4.yml:29:7:35:4 | Uses Step | .github/workflows/untrusted_checkout4.yml:33:15:33:67 | fromJSON(steps.get-pr.outputs.result).head.ref | .github/workflows/untrusted_checkout4.yml:47:7:51:46 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout4.yml:2:3:2:15 | issue_comment | issue_comment | +| .github/workflows/untrusted_checkout.yml:8:9:11:6 | Uses Step | .github/workflows/untrusted_checkout.yml:10:17:10:57 | github.event.pull_request.head.sha | .github/workflows/untrusted_checkout.yml:15:9:18:2 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout.yml:2:3:2:21 | pull_request_target | pull_request_target | +| .github/workflows/untrusted_checkout.yml:23:9:26:6 | Uses Step | .github/workflows/untrusted_checkout.yml:25:17:25:31 | env.HEAD | .github/workflows/untrusted_checkout.yml:30:9:32:23 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout.yml:2:3:2:21 | pull_request_target | pull_request_target | +| .github/workflows/untrusted_checkout_no_needs.yml:26:9:31:6 | Uses Step | .github/workflows/untrusted_checkout_no_needs.yml:29:17:29:57 | github.event.pull_request.head.sha | .github/workflows/untrusted_checkout_no_needs.yml:31:9:31:23 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_no_needs.yml:2:3:2:21 | pull_request_target | pull_request_target | +| .github/workflows/untrusted_checkout_permissions_check.yml:36:9:41:6 | Uses Step | .github/workflows/untrusted_checkout_permissions_check.yml:39:17:39:57 | github.event.pull_request.head.sha | .github/workflows/untrusted_checkout_permissions_check.yml:41:9:41:22 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_permissions_check.yml:2:3:2:21 | pull_request_target | pull_request_target | From 43d485af93fa979a1c05c55c387daf5a63574d9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20Loba=C4=8Devski?= Date: Sun, 19 Jul 2026 16:13:59 +0000 Subject: [PATCH 090/188] Write a clickable source link in untrusted checkout message --- .../security/UntrustedCheckoutQuery.qll | 2 +- .../CWE-829/UntrustedCheckoutCritical.ql | 12 ++- .../2026-07-28-checkout-provenance.md | 4 + .../UntrustedCheckoutCritical.expected | 88 +++++++++---------- 4 files changed, 57 insertions(+), 49 deletions(-) create mode 100644 actions/ql/src/change-notes/2026-07-28-checkout-provenance.md diff --git a/actions/ql/lib/codeql/actions/security/UntrustedCheckoutQuery.qll b/actions/ql/lib/codeql/actions/security/UntrustedCheckoutQuery.qll index c89c483466ae..357a55a1ec9b 100644 --- a/actions/ql/lib/codeql/actions/security/UntrustedCheckoutQuery.qll +++ b/actions/ql/lib/codeql/actions/security/UntrustedCheckoutQuery.qll @@ -423,7 +423,7 @@ AstNode getCheckoutReference(PRHeadCheckoutStep checkout) { /** Gets a display label for the expression that controls the untrusted checkout. */ string getCheckoutReferenceText(AstNode reference) { - result = reference.(Expression).getExpression() + result = reference.(Expression).toString() or not reference instanceof Expression and result = "the checkout command" } diff --git a/actions/ql/src/Security/CWE-829/UntrustedCheckoutCritical.ql b/actions/ql/src/Security/CWE-829/UntrustedCheckoutCritical.ql index 6ee11a6a3d42..1f3c8813c9b5 100644 --- a/actions/ql/src/Security/CWE-829/UntrustedCheckoutCritical.ql +++ b/actions/ql/src/Security/CWE-829/UntrustedCheckoutCritical.ql @@ -28,8 +28,12 @@ query predicate edges(AstNode predecessor, AstNode successor) { checkoutReferenceEdge(predecessor, successor) } -from PRHeadCheckoutStep checkout, PoisonableStep poisonable, Event event +from + PRHeadCheckoutStep checkout, PoisonableStep poisonable, Event event, AstNode checkoutReference, + string checkoutReferenceText where + checkoutReference = getCheckoutReference(checkout) and + checkoutReferenceText = getCheckoutReferenceText(checkoutReference) and // the checkout is followed by a known poisonable step checkout.getAFollowingStep() = poisonable and ( @@ -59,6 +63,6 @@ where event.getName() = checkoutTriggers() and not exists(ControlCheck check | check.protects(checkout, event, "untrusted-checkout")) and not exists(ControlCheck check | check.protects(poisonable, event, "untrusted-checkout")) -select checkout, getCheckoutReference(checkout), poisonable, - "Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@).", - event, event.getName() +select checkout, checkoutReference, poisonable, + "Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@).", + checkoutReference, checkoutReferenceText, event, event.getName() diff --git a/actions/ql/src/change-notes/2026-07-28-checkout-provenance.md b/actions/ql/src/change-notes/2026-07-28-checkout-provenance.md new file mode 100644 index 000000000000..9a1bb29be1d9 --- /dev/null +++ b/actions/ql/src/change-notes/2026-07-28-checkout-provenance.md @@ -0,0 +1,4 @@ +--- +category: fix +--- +* The `actions/cache-poisoning/poisonable-step` and `actions/untrusted-checkout/critical` queries now start paths at the expressions that control untrusted checkouts and link their alert messages to those expressions. diff --git a/actions/ql/test/query-tests/Security/CWE-829/UntrustedCheckoutCritical.expected b/actions/ql/test/query-tests/Security/CWE-829/UntrustedCheckoutCritical.expected index d0b9c2fc8ea3..910d5742e572 100644 --- a/actions/ql/test/query-tests/Security/CWE-829/UntrustedCheckoutCritical.expected +++ b/actions/ql/test/query-tests/Security/CWE-829/UntrustedCheckoutCritical.expected @@ -438,47 +438,47 @@ edges | .github/workflows/workflow_run_untrusted_checkout_3.yml:15:17:15:57 | github.event.workflow_run.head.sha | .github/workflows/workflow_run_untrusted_checkout_3.yml:13:9:16:6 | Uses Step | | .github/workflows/workflow_run_untrusted_checkout_3.yml:18:17:18:31 | env.HEAD | .github/workflows/workflow_run_untrusted_checkout_3.yml:16:9:18:31 | Uses Step | #select -| .github/actions/dangerous-git-checkout/action.yml:6:7:11:4 | Uses Step | .github/actions/dangerous-git-checkout/action.yml:9:15:9:55 | github.event.pull_request.head.sha | .github/workflows/untrusted_checkout3.yml:13:9:13:23 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout3.yml:4:3:4:14 | workflow_run | workflow_run | -| .github/workflows/auto_ci.yml:20:9:27:6 | Uses Step | .github/workflows/auto_ci.yml:24:17:24:57 | github.event.pull_request.head.ref | .github/workflows/auto_ci.yml:32:9:37:6 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/auto_ci.yml:6:3:6:21 | pull_request_target | pull_request_target | -| .github/workflows/auto_ci.yml:20:9:27:6 | Uses Step | .github/workflows/auto_ci.yml:24:17:24:57 | github.event.pull_request.head.ref | .github/workflows/auto_ci.yml:48:9:52:2 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/auto_ci.yml:6:3:6:21 | pull_request_target | pull_request_target | -| .github/workflows/auto_ci.yml:67:9:74:6 | Uses Step | .github/workflows/auto_ci.yml:71:17:71:95 | github.event.pull_request.head.ref \|\| github.event.pull_request.base.ref | .github/workflows/auto_ci.yml:79:9:84:6 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/auto_ci.yml:6:3:6:21 | pull_request_target | pull_request_target | -| .github/workflows/auto_ci.yml:67:9:74:6 | Uses Step | .github/workflows/auto_ci.yml:71:17:71:95 | github.event.pull_request.head.ref \|\| github.event.pull_request.base.ref | .github/workflows/auto_ci.yml:84:9:93:6 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/auto_ci.yml:6:3:6:21 | pull_request_target | pull_request_target | -| .github/workflows/dependabot3.yml:15:9:20:6 | Uses Step | .github/workflows/dependabot3.yml:18:17:18:57 | github.event.pull_request.head.sha | .github/workflows/dependabot3.yml:25:9:48:6 | Run Step: set-milestone | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/dependabot3.yml:3:5:3:23 | pull_request_target | pull_request_target | -| .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:11:9:14:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:13:17:13:40 | inputs.COMMIT_SHA | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:14:9:17:7 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_permission_check_reusable2.yml:2:3:2:21 | pull_request_target | pull_request_target | -| .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:11:9:14:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:13:17:13:40 | inputs.COMMIT_SHA | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:14:9:17:7 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_permission_check_reusable_branching_nested.yml:2:3:2:21 | pull_request_target | pull_request_target | -| .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:11:9:14:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:13:17:13:40 | inputs.COMMIT_SHA | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:14:9:17:7 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_permission_check_reusable_no_needs.yml:2:3:2:21 | pull_request_target | pull_request_target | -| .github/workflows/external/TestOrg/TestRepo/.github/workflows/reusable.yml:23:9:26:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/reusable.yml:25:17:25:36 | inputs.branch | .github/workflows/external/TestOrg/TestRepo/.github/workflows/reusable.yml:26:9:29:7 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/reusable_caller1.yaml:4:3:4:21 | pull_request_target | pull_request_target | -| .github/workflows/gitcheckout.yml:10:11:18:8 | Run Step | .github/workflows/gitcheckout.yml:17:27:17:48 | github.head_ref | .github/workflows/gitcheckout.yml:21:11:23:22 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/gitcheckout.yml:2:3:2:21 | pull_request_target | pull_request_target | -| .github/workflows/label_trusted_checkout2.yml:12:7:16:4 | Uses Step | .github/workflows/label_trusted_checkout2.yml:14:15:14:55 | github.event.pull_request.head.sha | .github/workflows/label_trusted_checkout2.yml:17:7:21:4 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/label_trusted_checkout2.yml:2:3:2:21 | pull_request_target | pull_request_target | -| .github/workflows/level0.yml:99:9:103:6 | Uses Step | .github/workflows/level0.yml:102:17:102:57 | github.event.pull_request.head.sha | .github/workflows/level0.yml:107:9:112:2 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/level0.yml:5:3:5:15 | issue_comment | issue_comment | -| .github/workflows/level0.yml:99:9:103:6 | Uses Step | .github/workflows/level0.yml:102:17:102:57 | github.event.pull_request.head.sha | .github/workflows/level0.yml:107:9:112:2 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/level0.yml:7:3:7:21 | pull_request_target | pull_request_target | -| .github/workflows/level0.yml:125:9:129:6 | Uses Step | .github/workflows/level0.yml:128:17:128:57 | github.event.pull_request.head.sha | .github/workflows/level0.yml:133:9:135:23 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/level0.yml:5:3:5:15 | issue_comment | issue_comment | -| .github/workflows/level0.yml:125:9:129:6 | Uses Step | .github/workflows/level0.yml:128:17:128:57 | github.event.pull_request.head.sha | .github/workflows/level0.yml:133:9:135:23 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/level0.yml:7:3:7:21 | pull_request_target | pull_request_target | -| .github/workflows/poc2.yml:37:9:42:6 | Uses Step | .github/workflows/poc2.yml:40:17:40:54 | steps.branch-deploy.outputs.ref | .github/workflows/poc2.yml:42:9:47:6 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/poc2.yml:4:3:4:15 | issue_comment | issue_comment | -| .github/workflows/poc2.yml:37:9:42:6 | Uses Step | .github/workflows/poc2.yml:40:17:40:54 | steps.branch-deploy.outputs.ref | .github/workflows/poc2.yml:52:9:58:24 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/poc2.yml:4:3:4:15 | issue_comment | issue_comment | -| .github/workflows/pr-workflow.yml:216:9:222:6 | Uses Step | .github/workflows/pr-workflow.yml:220:17:220:64 | inputs.github_event_pull_request_head_sha | .github/workflows/pr-workflow.yml:222:9:227:6 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | -| .github/workflows/pr-workflow.yml:250:9:256:6 | Uses Step | .github/workflows/pr-workflow.yml:254:17:254:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow.yml:256:9:261:6 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | -| .github/workflows/pr-workflow.yml:284:9:290:6 | Uses Step | .github/workflows/pr-workflow.yml:288:17:288:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow.yml:290:9:295:6 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | -| .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | .github/workflows/pr-workflow.yml:389:17:389:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow.yml:391:9:395:6 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | -| .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | .github/workflows/pr-workflow.yml:389:17:389:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow.yml:395:9:404:6 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | -| .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | .github/workflows/pr-workflow.yml:389:17:389:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow.yml:404:9:414:6 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | -| .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | .github/workflows/pr-workflow.yml:389:17:389:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow.yml:414:9:423:6 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | -| .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | .github/workflows/pr-workflow.yml:389:17:389:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow.yml:423:9:432:2 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | -| .github/workflows/reusable_local.yml:23:9:26:6 | Uses Step | .github/workflows/reusable_local.yml:25:17:25:36 | inputs.branch | .github/workflows/reusable_local.yml:26:9:29:7 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/reusable_caller3.yaml:4:3:4:21 | pull_request_target | pull_request_target | -| .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:22:27:22:58 | github.event.issue.number | .github/workflows/test7.yml:33:9:36:6 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test7.yml:4:3:4:15 | issue_comment | issue_comment | -| .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:22:27:22:58 | github.event.issue.number | .github/workflows/test7.yml:36:9:39:6 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test7.yml:4:3:4:15 | issue_comment | issue_comment | -| .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:22:27:22:58 | github.event.issue.number | .github/workflows/test7.yml:49:9:59:6 | Run Step: benchmark-pr | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test7.yml:4:3:4:15 | issue_comment | issue_comment | -| .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:22:27:22:58 | github.event.issue.number | .github/workflows/test7.yml:59:9:60:6 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test7.yml:4:3:4:15 | issue_comment | issue_comment | -| .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:22:27:22:58 | github.event.issue.number | .github/workflows/test7.yml:60:9:60:37 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test7.yml:4:3:4:15 | issue_comment | issue_comment | -| .github/workflows/test10.yml:20:9:25:6 | Uses Step | .github/workflows/test10.yml:23:17:23:79 | github.event.after \|\| github.event.pull_request.head.sha | .github/workflows/test10.yml:25:9:30:2 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test10.yml:8:3:8:21 | pull_request_target | pull_request_target | -| .github/workflows/test11.yml:84:7:90:4 | Uses Step | .github/workflows/test11.yml:88:15:88:55 | steps.environment.outputs.head_sha | .github/workflows/test11.yml:90:7:93:54 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test11.yml:5:3:5:15 | issue_comment | issue_comment | -| .github/workflows/test17.yml:12:15:19:12 | Uses Step | .github/workflows/test17.yml:16:25:16:68 | github.event.workflow_run.head_branch | .github/workflows/test17.yml:19:15:23:58 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test17.yml:3:5:3:16 | workflow_run | workflow_run | -| .github/workflows/test27.yml:18:9:21:6 | Uses Step | .github/workflows/test27.yml:20:17:20:37 | inputs.git_ref | .github/workflows/test27.yml:21:9:22:16 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test26.yml:4:3:4:14 | workflow_run | workflow_run | -| .github/workflows/test29.yml:8:7:14:4 | Uses Step | .github/workflows/test29.yml:11:15:11:55 | github.event.pull_request.head.sha | .github/workflows/test29.yml:14:7:21:11 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test29.yml:1:5:1:23 | pull_request_target | pull_request_target | -| .github/workflows/untrusted_checkout4.yml:29:7:35:4 | Uses Step | .github/workflows/untrusted_checkout4.yml:33:15:33:67 | fromJSON(steps.get-pr.outputs.result).head.ref | .github/workflows/untrusted_checkout4.yml:35:7:41:4 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout4.yml:2:3:2:15 | issue_comment | issue_comment | -| .github/workflows/untrusted_checkout4.yml:29:7:35:4 | Uses Step | .github/workflows/untrusted_checkout4.yml:33:15:33:67 | fromJSON(steps.get-pr.outputs.result).head.ref | .github/workflows/untrusted_checkout4.yml:41:7:47:4 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout4.yml:2:3:2:15 | issue_comment | issue_comment | -| .github/workflows/untrusted_checkout4.yml:29:7:35:4 | Uses Step | .github/workflows/untrusted_checkout4.yml:33:15:33:67 | fromJSON(steps.get-pr.outputs.result).head.ref | .github/workflows/untrusted_checkout4.yml:47:7:51:46 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout4.yml:2:3:2:15 | issue_comment | issue_comment | -| .github/workflows/untrusted_checkout.yml:8:9:11:6 | Uses Step | .github/workflows/untrusted_checkout.yml:10:17:10:57 | github.event.pull_request.head.sha | .github/workflows/untrusted_checkout.yml:15:9:18:2 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout.yml:2:3:2:21 | pull_request_target | pull_request_target | -| .github/workflows/untrusted_checkout.yml:23:9:26:6 | Uses Step | .github/workflows/untrusted_checkout.yml:25:17:25:31 | env.HEAD | .github/workflows/untrusted_checkout.yml:30:9:32:23 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout.yml:2:3:2:21 | pull_request_target | pull_request_target | -| .github/workflows/untrusted_checkout_no_needs.yml:26:9:31:6 | Uses Step | .github/workflows/untrusted_checkout_no_needs.yml:29:17:29:57 | github.event.pull_request.head.sha | .github/workflows/untrusted_checkout_no_needs.yml:31:9:31:23 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_no_needs.yml:2:3:2:21 | pull_request_target | pull_request_target | -| .github/workflows/untrusted_checkout_permissions_check.yml:36:9:41:6 | Uses Step | .github/workflows/untrusted_checkout_permissions_check.yml:39:17:39:57 | github.event.pull_request.head.sha | .github/workflows/untrusted_checkout_permissions_check.yml:41:9:41:22 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_permissions_check.yml:2:3:2:21 | pull_request_target | pull_request_target | +| .github/actions/dangerous-git-checkout/action.yml:6:7:11:4 | Uses Step | .github/actions/dangerous-git-checkout/action.yml:9:15:9:55 | github.event.pull_request.head.sha | .github/workflows/untrusted_checkout3.yml:13:9:13:23 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/actions/dangerous-git-checkout/action.yml:9:15:9:55 | github.event.pull_request.head.sha | github.event.pull_request.head.sha | .github/workflows/untrusted_checkout3.yml:4:3:4:14 | workflow_run | workflow_run | +| .github/workflows/auto_ci.yml:20:9:27:6 | Uses Step | .github/workflows/auto_ci.yml:24:17:24:57 | github.event.pull_request.head.ref | .github/workflows/auto_ci.yml:32:9:37:6 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/auto_ci.yml:24:17:24:57 | github.event.pull_request.head.ref | github.event.pull_request.head.ref | .github/workflows/auto_ci.yml:6:3:6:21 | pull_request_target | pull_request_target | +| .github/workflows/auto_ci.yml:20:9:27:6 | Uses Step | .github/workflows/auto_ci.yml:24:17:24:57 | github.event.pull_request.head.ref | .github/workflows/auto_ci.yml:48:9:52:2 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/auto_ci.yml:24:17:24:57 | github.event.pull_request.head.ref | github.event.pull_request.head.ref | .github/workflows/auto_ci.yml:6:3:6:21 | pull_request_target | pull_request_target | +| .github/workflows/auto_ci.yml:67:9:74:6 | Uses Step | .github/workflows/auto_ci.yml:71:17:71:95 | github.event.pull_request.head.ref \|\| github.event.pull_request.base.ref | .github/workflows/auto_ci.yml:79:9:84:6 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/auto_ci.yml:71:17:71:95 | github.event.pull_request.head.ref \|\| github.event.pull_request.base.ref | github.event.pull_request.head.ref \|\| github.event.pull_request.base.ref | .github/workflows/auto_ci.yml:6:3:6:21 | pull_request_target | pull_request_target | +| .github/workflows/auto_ci.yml:67:9:74:6 | Uses Step | .github/workflows/auto_ci.yml:71:17:71:95 | github.event.pull_request.head.ref \|\| github.event.pull_request.base.ref | .github/workflows/auto_ci.yml:84:9:93:6 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/auto_ci.yml:71:17:71:95 | github.event.pull_request.head.ref \|\| github.event.pull_request.base.ref | github.event.pull_request.head.ref \|\| github.event.pull_request.base.ref | .github/workflows/auto_ci.yml:6:3:6:21 | pull_request_target | pull_request_target | +| .github/workflows/dependabot3.yml:15:9:20:6 | Uses Step | .github/workflows/dependabot3.yml:18:17:18:57 | github.event.pull_request.head.sha | .github/workflows/dependabot3.yml:25:9:48:6 | Run Step: set-milestone | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/dependabot3.yml:18:17:18:57 | github.event.pull_request.head.sha | github.event.pull_request.head.sha | .github/workflows/dependabot3.yml:3:5:3:23 | pull_request_target | pull_request_target | +| .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:11:9:14:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:13:17:13:40 | inputs.COMMIT_SHA | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:14:9:17:7 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:13:17:13:40 | inputs.COMMIT_SHA | inputs.COMMIT_SHA | .github/workflows/untrusted_checkout_permission_check_reusable2.yml:2:3:2:21 | pull_request_target | pull_request_target | +| .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:11:9:14:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:13:17:13:40 | inputs.COMMIT_SHA | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:14:9:17:7 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:13:17:13:40 | inputs.COMMIT_SHA | inputs.COMMIT_SHA | .github/workflows/untrusted_checkout_permission_check_reusable_branching_nested.yml:2:3:2:21 | pull_request_target | pull_request_target | +| .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:11:9:14:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:13:17:13:40 | inputs.COMMIT_SHA | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:14:9:17:7 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:13:17:13:40 | inputs.COMMIT_SHA | inputs.COMMIT_SHA | .github/workflows/untrusted_checkout_permission_check_reusable_no_needs.yml:2:3:2:21 | pull_request_target | pull_request_target | +| .github/workflows/external/TestOrg/TestRepo/.github/workflows/reusable.yml:23:9:26:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/reusable.yml:25:17:25:36 | inputs.branch | .github/workflows/external/TestOrg/TestRepo/.github/workflows/reusable.yml:26:9:29:7 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/external/TestOrg/TestRepo/.github/workflows/reusable.yml:25:17:25:36 | inputs.branch | inputs.branch | .github/workflows/reusable_caller1.yaml:4:3:4:21 | pull_request_target | pull_request_target | +| .github/workflows/gitcheckout.yml:10:11:18:8 | Run Step | .github/workflows/gitcheckout.yml:17:27:17:48 | github.head_ref | .github/workflows/gitcheckout.yml:21:11:23:22 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/gitcheckout.yml:17:27:17:48 | github.head_ref | github.head_ref | .github/workflows/gitcheckout.yml:2:3:2:21 | pull_request_target | pull_request_target | +| .github/workflows/label_trusted_checkout2.yml:12:7:16:4 | Uses Step | .github/workflows/label_trusted_checkout2.yml:14:15:14:55 | github.event.pull_request.head.sha | .github/workflows/label_trusted_checkout2.yml:17:7:21:4 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/label_trusted_checkout2.yml:14:15:14:55 | github.event.pull_request.head.sha | github.event.pull_request.head.sha | .github/workflows/label_trusted_checkout2.yml:2:3:2:21 | pull_request_target | pull_request_target | +| .github/workflows/level0.yml:99:9:103:6 | Uses Step | .github/workflows/level0.yml:102:17:102:57 | github.event.pull_request.head.sha | .github/workflows/level0.yml:107:9:112:2 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/level0.yml:102:17:102:57 | github.event.pull_request.head.sha | github.event.pull_request.head.sha | .github/workflows/level0.yml:5:3:5:15 | issue_comment | issue_comment | +| .github/workflows/level0.yml:99:9:103:6 | Uses Step | .github/workflows/level0.yml:102:17:102:57 | github.event.pull_request.head.sha | .github/workflows/level0.yml:107:9:112:2 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/level0.yml:102:17:102:57 | github.event.pull_request.head.sha | github.event.pull_request.head.sha | .github/workflows/level0.yml:7:3:7:21 | pull_request_target | pull_request_target | +| .github/workflows/level0.yml:125:9:129:6 | Uses Step | .github/workflows/level0.yml:128:17:128:57 | github.event.pull_request.head.sha | .github/workflows/level0.yml:133:9:135:23 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/level0.yml:128:17:128:57 | github.event.pull_request.head.sha | github.event.pull_request.head.sha | .github/workflows/level0.yml:5:3:5:15 | issue_comment | issue_comment | +| .github/workflows/level0.yml:125:9:129:6 | Uses Step | .github/workflows/level0.yml:128:17:128:57 | github.event.pull_request.head.sha | .github/workflows/level0.yml:133:9:135:23 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/level0.yml:128:17:128:57 | github.event.pull_request.head.sha | github.event.pull_request.head.sha | .github/workflows/level0.yml:7:3:7:21 | pull_request_target | pull_request_target | +| .github/workflows/poc2.yml:37:9:42:6 | Uses Step | .github/workflows/poc2.yml:40:17:40:54 | steps.branch-deploy.outputs.ref | .github/workflows/poc2.yml:42:9:47:6 | Uses Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/poc2.yml:40:17:40:54 | steps.branch-deploy.outputs.ref | steps.branch-deploy.outputs.ref | .github/workflows/poc2.yml:4:3:4:15 | issue_comment | issue_comment | +| .github/workflows/poc2.yml:37:9:42:6 | Uses Step | .github/workflows/poc2.yml:40:17:40:54 | steps.branch-deploy.outputs.ref | .github/workflows/poc2.yml:52:9:58:24 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/poc2.yml:40:17:40:54 | steps.branch-deploy.outputs.ref | steps.branch-deploy.outputs.ref | .github/workflows/poc2.yml:4:3:4:15 | issue_comment | issue_comment | +| .github/workflows/pr-workflow.yml:216:9:222:6 | Uses Step | .github/workflows/pr-workflow.yml:220:17:220:64 | inputs.github_event_pull_request_head_sha | .github/workflows/pr-workflow.yml:222:9:227:6 | Uses Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow.yml:220:17:220:64 | inputs.github_event_pull_request_head_sha | inputs.github_event_pull_request_head_sha | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | +| .github/workflows/pr-workflow.yml:250:9:256:6 | Uses Step | .github/workflows/pr-workflow.yml:254:17:254:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow.yml:256:9:261:6 | Uses Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow.yml:254:17:254:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | +| .github/workflows/pr-workflow.yml:284:9:290:6 | Uses Step | .github/workflows/pr-workflow.yml:288:17:288:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow.yml:290:9:295:6 | Uses Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow.yml:288:17:288:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | +| .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | .github/workflows/pr-workflow.yml:389:17:389:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow.yml:391:9:395:6 | Uses Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow.yml:389:17:389:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | +| .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | .github/workflows/pr-workflow.yml:389:17:389:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow.yml:395:9:404:6 | Uses Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow.yml:389:17:389:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | +| .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | .github/workflows/pr-workflow.yml:389:17:389:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow.yml:404:9:414:6 | Uses Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow.yml:389:17:389:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | +| .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | .github/workflows/pr-workflow.yml:389:17:389:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow.yml:414:9:423:6 | Uses Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow.yml:389:17:389:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | +| .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | .github/workflows/pr-workflow.yml:389:17:389:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow.yml:423:9:432:2 | Uses Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow.yml:389:17:389:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | +| .github/workflows/reusable_local.yml:23:9:26:6 | Uses Step | .github/workflows/reusable_local.yml:25:17:25:36 | inputs.branch | .github/workflows/reusable_local.yml:26:9:29:7 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/reusable_local.yml:25:17:25:36 | inputs.branch | inputs.branch | .github/workflows/reusable_caller3.yaml:4:3:4:21 | pull_request_target | pull_request_target | +| .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:22:27:22:58 | github.event.issue.number | .github/workflows/test7.yml:33:9:36:6 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test7.yml:22:27:22:58 | github.event.issue.number | github.event.issue.number | .github/workflows/test7.yml:4:3:4:15 | issue_comment | issue_comment | +| .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:22:27:22:58 | github.event.issue.number | .github/workflows/test7.yml:36:9:39:6 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test7.yml:22:27:22:58 | github.event.issue.number | github.event.issue.number | .github/workflows/test7.yml:4:3:4:15 | issue_comment | issue_comment | +| .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:22:27:22:58 | github.event.issue.number | .github/workflows/test7.yml:49:9:59:6 | Run Step: benchmark-pr | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test7.yml:22:27:22:58 | github.event.issue.number | github.event.issue.number | .github/workflows/test7.yml:4:3:4:15 | issue_comment | issue_comment | +| .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:22:27:22:58 | github.event.issue.number | .github/workflows/test7.yml:59:9:60:6 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test7.yml:22:27:22:58 | github.event.issue.number | github.event.issue.number | .github/workflows/test7.yml:4:3:4:15 | issue_comment | issue_comment | +| .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:22:27:22:58 | github.event.issue.number | .github/workflows/test7.yml:60:9:60:37 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test7.yml:22:27:22:58 | github.event.issue.number | github.event.issue.number | .github/workflows/test7.yml:4:3:4:15 | issue_comment | issue_comment | +| .github/workflows/test10.yml:20:9:25:6 | Uses Step | .github/workflows/test10.yml:23:17:23:79 | github.event.after \|\| github.event.pull_request.head.sha | .github/workflows/test10.yml:25:9:30:2 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test10.yml:23:17:23:79 | github.event.after \|\| github.event.pull_request.head.sha | github.event.after \|\| github.event.pull_request.head.sha | .github/workflows/test10.yml:8:3:8:21 | pull_request_target | pull_request_target | +| .github/workflows/test11.yml:84:7:90:4 | Uses Step | .github/workflows/test11.yml:88:15:88:55 | steps.environment.outputs.head_sha | .github/workflows/test11.yml:90:7:93:54 | Uses Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test11.yml:88:15:88:55 | steps.environment.outputs.head_sha | steps.environment.outputs.head_sha | .github/workflows/test11.yml:5:3:5:15 | issue_comment | issue_comment | +| .github/workflows/test17.yml:12:15:19:12 | Uses Step | .github/workflows/test17.yml:16:25:16:68 | github.event.workflow_run.head_branch | .github/workflows/test17.yml:19:15:23:58 | Uses Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test17.yml:16:25:16:68 | github.event.workflow_run.head_branch | github.event.workflow_run.head_branch | .github/workflows/test17.yml:3:5:3:16 | workflow_run | workflow_run | +| .github/workflows/test27.yml:18:9:21:6 | Uses Step | .github/workflows/test27.yml:20:17:20:37 | inputs.git_ref | .github/workflows/test27.yml:21:9:22:16 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test27.yml:20:17:20:37 | inputs.git_ref | inputs.git_ref | .github/workflows/test26.yml:4:3:4:14 | workflow_run | workflow_run | +| .github/workflows/test29.yml:8:7:14:4 | Uses Step | .github/workflows/test29.yml:11:15:11:55 | github.event.pull_request.head.sha | .github/workflows/test29.yml:14:7:21:11 | Uses Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test29.yml:11:15:11:55 | github.event.pull_request.head.sha | github.event.pull_request.head.sha | .github/workflows/test29.yml:1:5:1:23 | pull_request_target | pull_request_target | +| .github/workflows/untrusted_checkout4.yml:29:7:35:4 | Uses Step | .github/workflows/untrusted_checkout4.yml:33:15:33:67 | fromJSON(steps.get-pr.outputs.result).head.ref | .github/workflows/untrusted_checkout4.yml:35:7:41:4 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout4.yml:33:15:33:67 | fromJSON(steps.get-pr.outputs.result).head.ref | fromJSON(steps.get-pr.outputs.result).head.ref | .github/workflows/untrusted_checkout4.yml:2:3:2:15 | issue_comment | issue_comment | +| .github/workflows/untrusted_checkout4.yml:29:7:35:4 | Uses Step | .github/workflows/untrusted_checkout4.yml:33:15:33:67 | fromJSON(steps.get-pr.outputs.result).head.ref | .github/workflows/untrusted_checkout4.yml:41:7:47:4 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout4.yml:33:15:33:67 | fromJSON(steps.get-pr.outputs.result).head.ref | fromJSON(steps.get-pr.outputs.result).head.ref | .github/workflows/untrusted_checkout4.yml:2:3:2:15 | issue_comment | issue_comment | +| .github/workflows/untrusted_checkout4.yml:29:7:35:4 | Uses Step | .github/workflows/untrusted_checkout4.yml:33:15:33:67 | fromJSON(steps.get-pr.outputs.result).head.ref | .github/workflows/untrusted_checkout4.yml:47:7:51:46 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout4.yml:33:15:33:67 | fromJSON(steps.get-pr.outputs.result).head.ref | fromJSON(steps.get-pr.outputs.result).head.ref | .github/workflows/untrusted_checkout4.yml:2:3:2:15 | issue_comment | issue_comment | +| .github/workflows/untrusted_checkout.yml:8:9:11:6 | Uses Step | .github/workflows/untrusted_checkout.yml:10:17:10:57 | github.event.pull_request.head.sha | .github/workflows/untrusted_checkout.yml:15:9:18:2 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout.yml:10:17:10:57 | github.event.pull_request.head.sha | github.event.pull_request.head.sha | .github/workflows/untrusted_checkout.yml:2:3:2:21 | pull_request_target | pull_request_target | +| .github/workflows/untrusted_checkout.yml:23:9:26:6 | Uses Step | .github/workflows/untrusted_checkout.yml:25:17:25:31 | env.HEAD | .github/workflows/untrusted_checkout.yml:30:9:32:23 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout.yml:25:17:25:31 | env.HEAD | env.HEAD | .github/workflows/untrusted_checkout.yml:2:3:2:21 | pull_request_target | pull_request_target | +| .github/workflows/untrusted_checkout_no_needs.yml:26:9:31:6 | Uses Step | .github/workflows/untrusted_checkout_no_needs.yml:29:17:29:57 | github.event.pull_request.head.sha | .github/workflows/untrusted_checkout_no_needs.yml:31:9:31:23 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_no_needs.yml:29:17:29:57 | github.event.pull_request.head.sha | github.event.pull_request.head.sha | .github/workflows/untrusted_checkout_no_needs.yml:2:3:2:21 | pull_request_target | pull_request_target | +| .github/workflows/untrusted_checkout_permissions_check.yml:36:9:41:6 | Uses Step | .github/workflows/untrusted_checkout_permissions_check.yml:39:17:39:57 | github.event.pull_request.head.sha | .github/workflows/untrusted_checkout_permissions_check.yml:41:9:41:22 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_permissions_check.yml:39:17:39:57 | github.event.pull_request.head.sha | github.event.pull_request.head.sha | .github/workflows/untrusted_checkout_permissions_check.yml:2:3:2:21 | pull_request_target | pull_request_target | From f9c1279041bed5435f3acb495d94d46b2ad82fd3 Mon Sep 17 00:00:00 2001 From: Taus Date: Thu, 23 Jul 2026 13:03:01 +0000 Subject: [PATCH 091/188] unified: Emit constructor parameters Emit an initializer's parameters on the `constructor_declaration`, captured from the `initializerDecl` signature (as for `functionDecl`). The tree-sitter path dropped them -- its positional `(parameter)*` capture missed the field-attached parameters -- and the mapping matched that for corpus parity; swift-syntax exposes them cleanly, so emitting them is a correctness improvement. Adds a focused `constructor-with-parameters` corpus case and updates `class-with-initializer` to witness the restored parameters. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../extractor/src/languages/swift/swift.rs | 10 +-- .../swift/types/class-with-initializer.output | 5 ++ .../types/constructor-with-parameters.output | 82 +++++++++++++++++++ .../types/constructor-with-parameters.swift | 3 + 4 files changed, 95 insertions(+), 5 deletions(-) create mode 100644 unified/extractor/tests/corpus/swift/types/constructor-with-parameters.output create mode 100644 unified/extractor/tests/corpus/swift/types/constructor-with-parameters.swift diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index ef3672e1b91c..6066e411cec6 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -1089,18 +1089,18 @@ fn translation_rules() -> Vec> { // A member of a type declaration unwraps to the contained declaration. rule!((memberBlockItem decl: _* @d) => member* { d }), // Init declaration → constructor_declaration. Body statements optional; - // body itself is also optional (protocol requirement). - // - // PARITY(tree-sitter): the parameters are not emitted, because the - // tree-sitter path dropped them (its `(parameter)*` capture missed the - // field-attached parameters). Emitting them is a future improvement. + // body itself is also optional (protocol requirement). The parameters + // nest under `signature` (as for `functionDecl`). rule!( (initializerDecl modifiers: _* @mods + signature: (functionSignature + parameterClause: (functionParameterClause parameters: _* @params)) body: (codeBlock statements: _* @body_stmts)?) => (constructor_declaration modifier: {mods} + parameter: {params} body: (block stmt: {body_stmts})) ), // Deinit declaration → destructor_declaration. Body statements optional. diff --git a/unified/extractor/tests/corpus/swift/types/class-with-initializer.output b/unified/extractor/tests/corpus/swift/types/class-with-initializer.output index 5e712d739e5f..32f94417d66d 100644 --- a/unified/extractor/tests/corpus/swift/types/class-with-initializer.output +++ b/unified/extractor/tests/corpus/swift/types/class-with-initializer.output @@ -103,6 +103,11 @@ top_level named_type_expr name: identifier "Int" constructor_declaration + parameter: + parameter + pattern: + name_pattern + identifier: identifier "x" body: block stmt: diff --git a/unified/extractor/tests/corpus/swift/types/constructor-with-parameters.output b/unified/extractor/tests/corpus/swift/types/constructor-with-parameters.output new file mode 100644 index 000000000000..c26d04b6ce08 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/types/constructor-with-parameters.output @@ -0,0 +1,82 @@ +struct Size { + init(width w: Int, height h: Int) {} +} + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + structDecl + attributes: + name: identifier "Size" + memberBlock: + memberBlock + leftBrace: { + rightBrace: } + members: + memberBlockItem + decl: + initializerDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + modifiers: + signature: + functionSignature + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + functionParameter + colon: : + attributes: + modifiers: + trailingComma: , + type: + identifierType + name: identifier "Int" + firstName: identifier "width" + secondName: identifier "w" + functionParameter + colon: : + attributes: + modifiers: + type: + identifierType + name: identifier "Int" + firstName: identifier "height" + secondName: identifier "h" + initKeyword: init + modifiers: + structKeyword: struct + +--- + +top_level + body: + block + stmt: + class_like_declaration + modifier: modifier "struct" + name: identifier "Size" + member: + constructor_declaration + parameter: + parameter + external_name: identifier "width" + pattern: + name_pattern + identifier: identifier "w" + parameter + external_name: identifier "height" + pattern: + name_pattern + identifier: identifier "h" + body: block "init(width w: Int, height h: Int) {}" diff --git a/unified/extractor/tests/corpus/swift/types/constructor-with-parameters.swift b/unified/extractor/tests/corpus/swift/types/constructor-with-parameters.swift new file mode 100644 index 000000000000..4f6377fc7803 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/types/constructor-with-parameters.swift @@ -0,0 +1,3 @@ +struct Size { + init(width w: Int, height h: Int) {} +} From 3f56bc7d5e803f99236ed2976cf7ab33dd704dda Mon Sep 17 00:00:00 2001 From: Taus Date: Thu, 23 Jul 2026 13:05:28 +0000 Subject: [PATCH 092/188] unified: Emit function and initializer parameter types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Emit a parameter's declared type on the mapped `parameter` node. The tree-sitter path dropped it — its untyped-parameter rule was ordered before the typed one and shadowed it — and the mapping matched that for corpus parity; swift-syntax models the type as a required `functionParameter.type`, so emitting it is a correctness improvement. The existing function-parameter corpus cases (and the initializer cases from the previous commit) witness the restored types. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- unified/extractor/src/languages/swift/swift.rs | 11 ++++------- .../function-with-default-parameter-value.output | 3 +++ .../functions/function-with-named-parameters.output | 3 +++ .../function-with-parameters-and-return-type.output | 6 ++++++ .../corpus/swift/functions/generic-function.output | 3 +++ .../corpus/swift/functions/variadic-function.output | 3 +++ .../corpus/swift/types/class-with-initializer.output | 3 +++ .../swift/types/constructor-with-parameters.output | 6 ++++++ 8 files changed, 31 insertions(+), 7 deletions(-) diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index 6066e411cec6..77b3d1e6decf 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -560,17 +560,13 @@ fn translation_rules() -> Vec> { ), // A function parameter. With two names (`firstName`+`secondName`) the // first is the external argument label and the second the internal name; - // with one name it is just the internal name. The default value is - // optional. - // - // PARITY: the declared type is intentionally dropped. In the tree-sitter - // path the untyped-parameter rule was ordered before the typed one and - // shadowed it (first match wins), so the baseline emits no parameter - // type; emitting one here would diverge from it. + // with one name it is just the internal name. The declared type is + // emitted; the default value is optional. rule!( (functionParameter firstName: @@first secondName: _? @@second + type: @ty defaultValue: (initializerClause value: @val)?) => parameter { @@ -581,6 +577,7 @@ fn translation_rules() -> Vec> { tree!((parameter external_name: {external} pattern: (name_pattern identifier: (identifier #{name})) + type: {ty} default: {val})) } ), diff --git a/unified/extractor/tests/corpus/swift/functions/function-with-default-parameter-value.output b/unified/extractor/tests/corpus/swift/functions/function-with-default-parameter-value.output index 01c0ddef8560..3495a13106fb 100644 --- a/unified/extractor/tests/corpus/swift/functions/function-with-default-parameter-value.output +++ b/unified/extractor/tests/corpus/swift/functions/function-with-default-parameter-value.output @@ -69,6 +69,9 @@ top_level name: identifier "greet" parameter: parameter + type: + named_type_expr + name: identifier "String" pattern: name_pattern identifier: identifier "name" diff --git a/unified/extractor/tests/corpus/swift/functions/function-with-named-parameters.output b/unified/extractor/tests/corpus/swift/functions/function-with-named-parameters.output index f2024b473620..7488edbcb231 100644 --- a/unified/extractor/tests/corpus/swift/functions/function-with-named-parameters.output +++ b/unified/extractor/tests/corpus/swift/functions/function-with-named-parameters.output @@ -61,6 +61,9 @@ top_level parameter: parameter external_name: identifier "person" + type: + named_type_expr + name: identifier "String" pattern: name_pattern identifier: identifier "name" diff --git a/unified/extractor/tests/corpus/swift/functions/function-with-parameters-and-return-type.output b/unified/extractor/tests/corpus/swift/functions/function-with-parameters-and-return-type.output index 1ffb391dbc5a..e69b19307674 100644 --- a/unified/extractor/tests/corpus/swift/functions/function-with-parameters-and-return-type.output +++ b/unified/extractor/tests/corpus/swift/functions/function-with-parameters-and-return-type.output @@ -78,11 +78,17 @@ top_level parameter: parameter external_name: identifier "_" + type: + named_type_expr + name: identifier "Int" pattern: name_pattern identifier: identifier "a" parameter external_name: identifier "_" + type: + named_type_expr + name: identifier "Int" pattern: name_pattern identifier: identifier "b" diff --git a/unified/extractor/tests/corpus/swift/functions/generic-function.output b/unified/extractor/tests/corpus/swift/functions/generic-function.output index 1652f7f47414..d09aac2744a2 100644 --- a/unified/extractor/tests/corpus/swift/functions/generic-function.output +++ b/unified/extractor/tests/corpus/swift/functions/generic-function.output @@ -68,6 +68,9 @@ top_level parameter: parameter external_name: identifier "_" + type: + named_type_expr + name: identifier "T" pattern: name_pattern identifier: identifier "x" diff --git a/unified/extractor/tests/corpus/swift/functions/variadic-function.output b/unified/extractor/tests/corpus/swift/functions/variadic-function.output index 571f07c35e0c..78c20ffc01e9 100644 --- a/unified/extractor/tests/corpus/swift/functions/variadic-function.output +++ b/unified/extractor/tests/corpus/swift/functions/variadic-function.output @@ -82,6 +82,9 @@ top_level parameter: parameter external_name: identifier "_" + type: + named_type_expr + name: identifier "Int" pattern: name_pattern identifier: identifier "values" diff --git a/unified/extractor/tests/corpus/swift/types/class-with-initializer.output b/unified/extractor/tests/corpus/swift/types/class-with-initializer.output index 32f94417d66d..83945d89e3a0 100644 --- a/unified/extractor/tests/corpus/swift/types/class-with-initializer.output +++ b/unified/extractor/tests/corpus/swift/types/class-with-initializer.output @@ -105,6 +105,9 @@ top_level constructor_declaration parameter: parameter + type: + named_type_expr + name: identifier "Int" pattern: name_pattern identifier: identifier "x" diff --git a/unified/extractor/tests/corpus/swift/types/constructor-with-parameters.output b/unified/extractor/tests/corpus/swift/types/constructor-with-parameters.output index c26d04b6ce08..c9be21dd156a 100644 --- a/unified/extractor/tests/corpus/swift/types/constructor-with-parameters.output +++ b/unified/extractor/tests/corpus/swift/types/constructor-with-parameters.output @@ -71,11 +71,17 @@ top_level parameter: parameter external_name: identifier "width" + type: + named_type_expr + name: identifier "Int" pattern: name_pattern identifier: identifier "w" parameter external_name: identifier "height" + type: + named_type_expr + name: identifier "Int" pattern: name_pattern identifier: identifier "h" From 08024d8f4a777c551a7540bc4a3ab1d19d4b0fe9 Mon Sep 17 00:00:00 2001 From: Taus Date: Thu, 23 Jul 2026 13:09:51 +0000 Subject: [PATCH 093/188] unified: Emit structured generic type arguments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Map a generic type applied with explicit arguments (`Set`, `Dictionary>`) to a `generic_type_expr` whose `base` is the type name and whose `type_argument`s are the structured, recursively-mapped arguments — the same shape the sugared `?`/`[]`/`[:]` types already desugar to. Previously the whole application was kept opaquely as a `named_type_expr` whose name was the raw source text, matching the tree-sitter path for corpus parity. Adds a focused `generic-type-arguments` corpus case (multiple and nested arguments) and updates `set-literal` to witness the structured arguments. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../extractor/src/languages/swift/swift.rs | 17 ++-- .../swift/collections/set-literal.output | 9 +- .../swift/types/generic-type-arguments.output | 83 +++++++++++++++++++ .../swift/types/generic-type-arguments.swift | 1 + 4 files changed, 102 insertions(+), 8 deletions(-) create mode 100644 unified/extractor/tests/corpus/swift/types/generic-type-arguments.output create mode 100644 unified/extractor/tests/corpus/swift/types/generic-type-arguments.swift diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index 77b3d1e6decf..467d136a5b2e 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -944,14 +944,19 @@ fn translation_rules() -> Vec> { // an ordinary `declReferenceExpr`, already mapped to a `name_expr`.) rule!((superExpr) => (super_expr)), // Type expressions. A generic type applied with explicit arguments - // (`Set`) is represented opaquely, using the whole source text as - // the name (PARITY(tree-sitter): the generic arguments are not - // structured `type_argument`s). Matched before the plain `identifierType` - // rule, which would otherwise drop the arguments. + // (`Set`) becomes a `generic_type_expr` whose `base` is the type + // name and whose `type_argument`s are the (structured) arguments — the + // same shape the sugared `?`/`[]`/`[:]` types desugar to. Matched before + // the plain `identifierType` rule, which would otherwise drop the + // arguments. rule!( - (identifierType genericArgumentClause: (genericArgumentClause)) @@ty + (identifierType + name: @@name + genericArgumentClause: (genericArgumentClause arguments: (genericArgument argument: @args)*)) => - (named_type_expr name: (identifier #{ty})) + (generic_type_expr + base: (named_type_expr name: (identifier #{name})) + type_argument: {args}) ), // A named type (`Int`). `identifierType.name` is the type-name token. rule!((identifierType name: @@n) => (named_type_expr name: (identifier #{n}))), diff --git a/unified/extractor/tests/corpus/swift/collections/set-literal.output b/unified/extractor/tests/corpus/swift/collections/set-literal.output index c29492c9bc0b..a06670231ebb 100644 --- a/unified/extractor/tests/corpus/swift/collections/set-literal.output +++ b/unified/extractor/tests/corpus/swift/collections/set-literal.output @@ -66,8 +66,13 @@ top_level name_pattern identifier: identifier "s" type: - named_type_expr - name: identifier "Set" + generic_type_expr + base: + named_type_expr + name: identifier "Set" + type_argument: + named_type_expr + name: identifier "Int" value: array_literal element: diff --git a/unified/extractor/tests/corpus/swift/types/generic-type-arguments.output b/unified/extractor/tests/corpus/swift/types/generic-type-arguments.output new file mode 100644 index 000000000000..ce12c853d9d5 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/types/generic-type-arguments.output @@ -0,0 +1,83 @@ +let cache: Dictionary> = [:] + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + dictionaryExpr + leftSquare: [ + rightSquare: ] + content: : + pattern: + identifierPattern + identifier: identifier "cache" + typeAnnotation: + typeAnnotation + colon: : + type: + identifierType + name: identifier "Dictionary" + genericArgumentClause: + genericArgumentClause + arguments: + genericArgument + trailingComma: , + argument: + identifierType + name: identifier "String" + genericArgument + argument: + identifierType + name: identifier "Array" + genericArgumentClause: + genericArgumentClause + arguments: + genericArgument + argument: + identifierType + name: identifier "Int" + leftAngle: < + rightAngle: > + leftAngle: < + rightAngle: > + +--- + +top_level + body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "cache" + type: + generic_type_expr + base: + named_type_expr + name: identifier "Dictionary" + type_argument: + named_type_expr + name: identifier "String" + generic_type_expr + base: + named_type_expr + name: identifier "Array" + type_argument: + named_type_expr + name: identifier "Int" + value: map_literal "[:]" diff --git a/unified/extractor/tests/corpus/swift/types/generic-type-arguments.swift b/unified/extractor/tests/corpus/swift/types/generic-type-arguments.swift new file mode 100644 index 000000000000..d2156f9cee76 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/types/generic-type-arguments.swift @@ -0,0 +1 @@ +let cache: Dictionary> = [:] From 80c4b443f6441980594940e90b334e41b25f1da8 Mon Sep 17 00:00:00 2001 From: Taus Date: Thu, 23 Jul 2026 13:43:13 +0000 Subject: [PATCH 094/188] unified: Emit base types from inheritance clauses Map a nominal type's inheritance clause (`class C: Base, Proto`, and likewise for enum/struct/protocol/extension) to `base_type` children on the `class_like_declaration`, one per inherited type. The tree-sitter path dropped these (no corpus target had a `base_type`) and the mapping matched that for parity; swift-syntax exposes the clause cleanly. Adds a focused `class-with-multiple-base-types` corpus case and updates `class-inheritance` to witness the restored base types. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../extractor/src/languages/swift/swift.rs | 51 +++++++++++++++---- .../swift/types/class-inheritance.output | 5 ++ .../class-with-multiple-base-types.output | 51 +++++++++++++++++++ .../class-with-multiple-base-types.swift | 1 + 4 files changed, 97 insertions(+), 11 deletions(-) create mode 100644 unified/extractor/tests/corpus/swift/types/class-with-multiple-base-types.output create mode 100644 unified/extractor/tests/corpus/swift/types/class-with-multiple-base-types.swift diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index 467d136a5b2e..e2f9010d70dd 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -1028,50 +1028,73 @@ fn translation_rules() -> Vec> { // (swift-syntax represents `#selector`/`#keyPath` and other macro // expansions uniformly as a `macroExpansionExpr`). rule!((macroExpansionExpr) => (unsupported_node)), - // PARITY(tree-sitter): a nominal type's `inheritanceClause` (`: Base, - // Proto`) is not emitted as a `base_type` — the tree-sitter path drops - // it (no corpus target has a `base_type`). swift-syntax exposes it - // cleanly, so emitting `base_type` is a correctness improvement to make - // once tree-sitter is retired. Each declaration keyword gets its own - // rule; the bodies are identical but for the keyword. + // A nominal type's `inheritanceClause` (`: Base, Proto`) becomes a list + // of `base_type`s, one per inherited type. The tree-sitter path dropped + // it (no corpus target had a `base_type`) and the mapping matched that + // for parity; swift-syntax exposes it cleanly. Each declaration keyword + // gets its own rule; the bodies are identical but for the keyword. // Class declaration with body containing members rule!( - (classDecl classKeyword: @kind modifiers: _* @mods name: @name memberBlock: (memberBlock members: _* @members)) + (classDecl + classKeyword: @kind + modifiers: _* @mods + name: @name + inheritanceClause: (inheritanceClause inheritedTypes: (inheritedType type: @bases)*)? + memberBlock: (memberBlock members: _* @members)) => (class_like_declaration modifier: (modifier #{kind}) modifier: {mods} name: (identifier #{name}) + base_type: {bases.into_iter().map(|ty| tree!((base_type type: {ty})))} member: {members}) ), // Enum class declaration: same as a regular class but with an enum body. rule!( - (enumDecl enumKeyword: @kind modifiers: _* @mods name: @name memberBlock: (memberBlock members: _* @members)) + (enumDecl + enumKeyword: @kind + modifiers: _* @mods + name: @name + inheritanceClause: (inheritanceClause inheritedTypes: (inheritedType type: @bases)*)? + memberBlock: (memberBlock members: _* @members)) => (class_like_declaration modifier: (modifier #{kind}) modifier: {mods} name: (identifier #{name}) + base_type: {bases.into_iter().map(|ty| tree!((base_type type: {ty})))} member: {members}) ), // A `struct` declaration. rule!( - (structDecl structKeyword: @kind modifiers: _* @mods name: @name memberBlock: (memberBlock members: _* @members)) + (structDecl + structKeyword: @kind + modifiers: _* @mods + name: @name + inheritanceClause: (inheritanceClause inheritedTypes: (inheritedType type: @bases)*)? + memberBlock: (memberBlock members: _* @members)) => (class_like_declaration modifier: (modifier #{kind}) modifier: {mods} name: (identifier #{name}) + base_type: {bases.into_iter().map(|ty| tree!((base_type type: {ty})))} member: {members}) ), // Protocol declaration rule!( - (protocolDecl protocolKeyword: @kind modifiers: _* @mods name: @name memberBlock: (memberBlock members: _* @members)) + (protocolDecl + protocolKeyword: @kind + modifiers: _* @mods + name: @name + inheritanceClause: (inheritanceClause inheritedTypes: (inheritedType type: @bases)*)? + memberBlock: (memberBlock members: _* @members)) => (class_like_declaration modifier: (modifier #{kind}) modifier: {mods} name: (identifier #{name}) + base_type: {bases.into_iter().map(|ty| tree!((base_type type: {ty})))} member: {members}) ), // An `extension Foo { … }` is likewise a `class_like_declaration`, named @@ -1080,12 +1103,18 @@ fn translation_rules() -> Vec> { // a `memberType`) name the declaration just like simple ones, matching the // old tree-sitter `user_type` behaviour. rule!( - (extensionDecl extensionKeyword: @kind modifiers: _* @mods extendedType: @@name memberBlock: (memberBlock members: _* @members)) + (extensionDecl + extensionKeyword: @kind + modifiers: _* @mods + extendedType: @@name + inheritanceClause: (inheritanceClause inheritedTypes: (inheritedType type: @bases)*)? + memberBlock: (memberBlock members: _* @members)) => (class_like_declaration modifier: (modifier #{kind}) modifier: {mods} name: (identifier #{name}) + base_type: {bases.into_iter().map(|ty| tree!((base_type type: {ty})))} member: {members}) ), // A member of a type declaration unwraps to the contained declaration. diff --git a/unified/extractor/tests/corpus/swift/types/class-inheritance.output b/unified/extractor/tests/corpus/swift/types/class-inheritance.output index 62a0a43414d0..12328f4acb0d 100644 --- a/unified/extractor/tests/corpus/swift/types/class-inheritance.output +++ b/unified/extractor/tests/corpus/swift/types/class-inheritance.output @@ -35,3 +35,8 @@ top_level class_like_declaration modifier: modifier "class" name: identifier "Dog" + base_type: + base_type + type: + named_type_expr + name: identifier "Animal" diff --git a/unified/extractor/tests/corpus/swift/types/class-with-multiple-base-types.output b/unified/extractor/tests/corpus/swift/types/class-with-multiple-base-types.output new file mode 100644 index 000000000000..e66b88e9be3d --- /dev/null +++ b/unified/extractor/tests/corpus/swift/types/class-with-multiple-base-types.output @@ -0,0 +1,51 @@ +class Button: Control, Drawable {} + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + classDecl + attributes: + name: identifier "Button" + inheritanceClause: + inheritanceClause + colon: : + inheritedTypes: + inheritedType + trailingComma: , + type: + identifierType + name: identifier "Control" + inheritedType + type: + identifierType + name: identifier "Drawable" + memberBlock: + memberBlock + leftBrace: { + rightBrace: } + members: + modifiers: + classKeyword: class + +--- + +top_level + body: + block + stmt: + class_like_declaration + modifier: modifier "class" + name: identifier "Button" + base_type: + base_type + type: + named_type_expr + name: identifier "Control" + base_type + type: + named_type_expr + name: identifier "Drawable" diff --git a/unified/extractor/tests/corpus/swift/types/class-with-multiple-base-types.swift b/unified/extractor/tests/corpus/swift/types/class-with-multiple-base-types.swift new file mode 100644 index 000000000000..b4f45e5c7a03 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/types/class-with-multiple-base-types.swift @@ -0,0 +1 @@ +class Button: Control, Drawable {} From 97b5a9d82823963916792795a11bd71b54e95313 Mon Sep 17 00:00:00 2001 From: Taus Date: Tue, 28 Jul 2026 15:50:11 +0000 Subject: [PATCH 095/188] unified: Stop using the tree-sitter-swift grammar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With the Swift front-end fully switched to swift-syntax, nothing links the tree-sitter Swift grammar any more. Remove every reference to it; the vendored crate itself is deleted in the following commit, so that this one shows only what actually changed. - Drop `unified/extractor/tree-sitter-swift` as a workspace member, path dependency and BUILD.bazel dependency. - Drop the now-unused `tree-sitter` and `tree-sitter-embedded-template` direct dependencies from the extractor (neither is referenced any longer; the tree-sitter runtime is still pulled in transitively where the shared extractor needs it). - Rewrite the "Swift Parser" section of `AGENTS.md`, which still pointed at `grammar.js` and `node-types.yml`, to describe `swift-syntax-parse` and the hand-maintained `swift_node_types.yml`, and note that the tests need the parser binary. The mapping's comments also explained many rules by how the tree-sitter path had behaved. That is now of historical interest only, so each is restated in terms of swift-syntax and the target AST alone — no rule changes, and the corpus is unaffected. Two were more than stylistic: - The `subscriptCallExpr` rule and its corpus case said the parser reports `xs[0]` and `xs(0)` identically. swift-syntax distinguishes them, so the collapse to `call_expr` is now purely ours, and a dedicated `subscript_expr` would need only a schema addition and a remap. - `discardAssignmentExpr` mapped to `name_expr` "because tree-sitter treated `_` as a name". The standing reason is that the target AST has no expression-level discard — only `ignore_pattern`, which is a pattern. References to tree-sitter's *node model* are kept: yeast is built on it, so `adapter.rs` still explains named/anonymous nodes, `extra` tokens and byte-offset conventions in those terms. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- Cargo.lock | 309 +----------------- Cargo.toml | 1 - unified/AGENTS.md | 19 +- unified/extractor/BUILD.bazel | 1 - unified/extractor/Cargo.toml | 3 - unified/extractor/ast_types.yml | 3 - .../extractor/src/languages/swift/adapter.rs | 5 +- .../extractor/src/languages/swift/swift.rs | 58 ++-- .../swift/collections/subscript-access.output | 6 +- .../swift/collections/subscript-access.swift | 6 +- 10 files changed, 51 insertions(+), 360 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7a9f19667911..24479c721561 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -140,26 +140,6 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" -[[package]] -name = "bindgen" -version = "0.72.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" -dependencies = [ - "bitflags 2.9.4", - "cexpr", - "clang-sys", - "itertools 0.12.1", - "log 0.4.28", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash 2.1.1", - "shlex", - "syn", -] - [[package]] name = "bitflags" version = "1.3.2" @@ -270,15 +250,6 @@ dependencies = [ "shlex", ] -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom", -] - [[package]] name = "cfg-if" version = "1.0.3" @@ -378,17 +349,6 @@ dependencies = [ "windows-link 0.2.0", ] -[[package]] -name = "clang-sys" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" -dependencies = [ - "glob", - "libc", - "libloading", -] - [[package]] name = "clap" version = "4.5.48" @@ -491,9 +451,6 @@ dependencies = [ "serde_json", "tracing", "tracing-subscriber", - "tree-sitter", - "tree-sitter-embedded-template", - "tree-sitter-swift", "yeast", ] @@ -545,15 +502,6 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" -[[package]] -name = "convert_case" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baaaa0ecca5b51987b9423ccdc971514dd8b0bb7b4060b983d3664dad3f1f89f" -dependencies = [ - "unicode-segmentation", -] - [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -807,12 +755,6 @@ dependencies = [ "typeid", ] -[[package]] -name = "fastrand" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" - [[package]] name = "figment" version = "0.10.19" @@ -861,12 +803,6 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" -[[package]] -name = "foldhash" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" - [[package]] name = "form_urlencoded" version = "1.2.2" @@ -951,18 +887,7 @@ checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ "allocator-api2", "equivalent", - "foldhash 0.1.5", -] - -[[package]] -name = "hashbrown" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" -dependencies = [ - "allocator-api2", - "equivalent", - "foldhash 0.2.0", + "foldhash", ] [[package]] @@ -1167,15 +1092,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "indoc" -version = "2.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" -dependencies = [ - "rustversion", -] - [[package]] name = "inlinable_string" version = "0.1.15" @@ -1305,16 +1221,6 @@ version = "0.2.175" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" -[[package]] -name = "libloading" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" -dependencies = [ - "cfg-if", - "windows-link 0.2.0", -] - [[package]] name = "line-index" version = "0.1.2" @@ -1380,12 +1286,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - [[package]] name = "miniz_oxide" version = "0.8.9" @@ -1432,16 +1332,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - [[package]] name = "notify" version = "8.2.0" @@ -1569,12 +1459,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "pathdiff" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" - [[package]] name = "pear" version = "0.2.9" @@ -1633,35 +1517,6 @@ dependencies = [ "indexmap 2.14.0", ] -[[package]] -name = "phf" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" -dependencies = [ - "phf_shared", - "serde", -] - -[[package]] -name = "phf_generator" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" -dependencies = [ - "fastrand", - "phf_shared", -] - -[[package]] -name = "phf_shared" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" -dependencies = [ - "siphasher", -] - [[package]] name = "pin-project-lite" version = "0.2.16" @@ -1704,25 +1559,6 @@ dependencies = [ "zerocopy", ] -[[package]] -name = "prettyplease" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" -dependencies = [ - "proc-macro2", - "syn", -] - -[[package]] -name = "proc-macro-crate" -version = "3.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" -dependencies = [ - "toml_edit 0.25.11+spec-1.1.0", -] - [[package]] name = "proc-macro2" version = "1.0.101" @@ -2426,15 +2262,6 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" -[[package]] -name = "relative-path" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bca40a312222d8ba74837cb474edef44b37f561da5f773981007a10bbaa992b0" -dependencies = [ - "serde", -] - [[package]] name = "rowan" version = "0.15.15" @@ -2448,57 +2275,6 @@ dependencies = [ "text-size", ] -[[package]] -name = "rquickjs" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a135375fbac5ba723bb6a48f432a72f81539cedde422f0121a86c7c4e96d8e0d" -dependencies = [ - "rquickjs-core", - "rquickjs-macro", -] - -[[package]] -name = "rquickjs-core" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bccb7121a123865c8ace4dea42e7ed84d78b90cbaf4ca32c59849d8d210c9672" -dependencies = [ - "hashbrown 0.16.1", - "phf", - "relative-path", - "rquickjs-sys", -] - -[[package]] -name = "rquickjs-macro" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89f93602cc3112c7f30bf5f29e722784232138692c7df4c52ebbac7e035d900d" -dependencies = [ - "convert_case", - "fnv", - "ident_case", - "indexmap 2.14.0", - "phf_generator", - "phf_shared", - "proc-macro-crate", - "proc-macro2", - "quote", - "rquickjs-core", - "syn", -] - -[[package]] -name = "rquickjs-sys" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57b1b6528590d4d65dc86b5159eae2d0219709546644c66408b2441696d1d725" -dependencies = [ - "bindgen", - "cc", -] - [[package]] name = "rust-extractor-macros" version = "0.1.0" @@ -2804,18 +2580,6 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" -[[package]] -name = "siphasher" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649" - -[[package]] -name = "smallbitvec" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b0e903ee191d8f7a8fbf0d712c3a1699d19e04ceba5ad1eb673053c7d938a09" - [[package]] name = "smallvec" version = "1.15.1" @@ -2972,7 +2736,7 @@ dependencies = [ "serde", "serde_spanned 0.6.9", "toml_datetime 0.6.11", - "toml_edit 0.22.27", + "toml_edit", ] [[package]] @@ -3008,15 +2772,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "toml_datetime" -version = "1.1.1+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" -dependencies = [ - "serde_core", -] - [[package]] name = "toml_edit" version = "0.22.27" @@ -3031,18 +2786,6 @@ dependencies = [ "winnow 0.7.13", ] -[[package]] -name = "toml_edit" -version = "0.25.11+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b" -dependencies = [ - "indexmap 2.14.0", - "toml_datetime 1.1.1+spec-1.1.0", - "toml_parser", - "winnow 1.0.2", -] - [[package]] name = "toml_parser" version = "1.1.2+spec-1.1.0" @@ -3064,12 +2807,6 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d163a63c116ce562a22cda521fcc4d79152e7aba014456fb5eb442f6d6a10109" -[[package]] -name = "topological-sort" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea68304e134ecd095ac6c3574494fc62b909f416c4fca77e440530221e549d3d" - [[package]] name = "tracing" version = "0.1.41" @@ -3166,30 +2903,6 @@ dependencies = [ "tree-sitter-language", ] -[[package]] -name = "tree-sitter-generate" -version = "0.26.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3fb2e1bdb1d5f9d23cd5fa68cf98b3bedbd223c92a2edd60bbcf30bcf7180a5" -dependencies = [ - "bitflags 2.9.4", - "dunce", - "indexmap 2.14.0", - "indoc", - "log 0.4.28", - "pathdiff", - "regex", - "regex-syntax", - "rquickjs", - "rustc-hash 2.1.1", - "semver", - "serde", - "serde_json", - "smallbitvec", - "thiserror", - "topological-sort", -] - [[package]] name = "tree-sitter-json" version = "0.24.8" @@ -3236,15 +2949,6 @@ dependencies = [ "tree-sitter-language", ] -[[package]] -name = "tree-sitter-swift" -version = "0.7.2" -dependencies = [ - "cc", - "tree-sitter-generate", - "tree-sitter-language", -] - [[package]] name = "triomphe" version = "0.1.14" @@ -3294,12 +2998,6 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" -[[package]] -name = "unicode-segmentation" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" - [[package]] name = "unicode-xid" version = "0.2.6" @@ -3694,9 +3392,6 @@ name = "winnow" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2ee1708bef14716a11bae175f579062d4554d95be2c6829f518df847b7b3fdd0" -dependencies = [ - "memchr", -] [[package]] name = "wit-bindgen" diff --git a/Cargo.toml b/Cargo.toml index 9f3780bb1d77..21bde5432803 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,6 @@ members = [ "shared/yeast-schema", "ruby/extractor", "unified/extractor", - "unified/extractor/tree-sitter-swift", "unified/swift-syntax-rs", "rust/extractor", "rust/extractor/macros", diff --git a/unified/AGENTS.md b/unified/AGENTS.md index a50a49868a24..9c9bbbb534cb 100644 --- a/unified/AGENTS.md +++ b/unified/AGENTS.md @@ -1,23 +1,32 @@ # Agent instructions -This is a CodeQL extractor based on tree-sitter. +This is a CodeQL extractor that maps a language's parse tree onto a shared AST +using the `yeast` desugaring engine. Swift, the only language so far, is parsed +by Apple's swift-syntax rather than by tree-sitter. ## Building - To build the extractor, run `scripts/create-extractor-pack.sh` ## Swift Parser -- The Swift parser is defined by `extractor/tree-sitter-swift/grammar.js` and can be edited if needed. +- Swift source is parsed by `swift-syntax-parse`, a small Swift/Rust binary in + `swift-syntax-rs` that wraps Apple's swift-syntax and emits the parse tree as + JSON. There is no grammar in this repository to edit. -- After editing the grammar, always run `scripts/regenerate-grammar.sh`. +- `extractor/src/languages/swift/adapter.rs` converts that JSON into a yeast AST. -- The raw parse tree is described by `extractor/tree-sitter-swift/node-types.yml` and should be reviewed after grammar changes. +- The raw parse tree's shape is described by `extractor/swift_node_types.yml`, + which is maintained by hand. ## AST Mapping - The target AST shape is described by `extractor/ast_types.yml`. - The mapping from the parse tree to the target AST is found in `extractor/src/languages/swift/swift.rs` -- To run tests for the parser and mapping, run `cargo test` in the `extractor` directory. +- To run tests for the parser and mapping, run `cargo test` in the `extractor` + directory. The tests need the `swift-syntax-parse` binary: point + `CODEQL_EXTRACTOR_UNIFIED_SWIFT_SYNTAX_PARSE` at it, or put it on `PATH`. + Corpus tests skip themselves when it cannot be found, so check for skips + before concluding a change is clean. - Extractor test cases are located at `extractor/tests/corpus/swift/*/*.swift`. diff --git a/unified/extractor/BUILD.bazel b/unified/extractor/BUILD.bazel index 13a3b6b287bc..58b32d9fc5c3 100644 --- a/unified/extractor/BUILD.bazel +++ b/unified/extractor/BUILD.bazel @@ -20,6 +20,5 @@ codeql_rust_binary( ) + [ "//shared/tree-sitter-extractor", "//shared/yeast", - "//unified/extractor/tree-sitter-swift", ], ) diff --git a/unified/extractor/Cargo.toml b/unified/extractor/Cargo.toml index 39c20598b1ff..be333298f1ad 100644 --- a/unified/extractor/Cargo.toml +++ b/unified/extractor/Cargo.toml @@ -7,9 +7,6 @@ edition = "2024" # When updating these dependencies, run `misc/bazel/3rdparty/update_cargo_deps.sh` [dependencies] -tree-sitter = ">= 0.23.0" -tree-sitter-embedded-template = "0.25.0" -tree-sitter-swift = { path = "tree-sitter-swift" } clap = { version = "4.5", features = ["derive"] } tracing = "0.1" tracing-subscriber = { version = "0.3.20", features = ["env-filter"] } diff --git a/unified/extractor/ast_types.yml b/unified/extractor/ast_types.yml index 4fa1ff169428..92fadc33e081 100644 --- a/unified/extractor/ast_types.yml +++ b/unified/extractor/ast_types.yml @@ -56,9 +56,6 @@ supertypes: # A statement is anything that can appear in a block. # This type contains all of 'expr' and has partial overlap with 'member'. # For example, type_alias_declaration can appear either as a stmt or member. - # constructor_declaration and destructor_declaration appear here because - # tree-sitter-swift's error recovery for #if/#endif in class bodies can place - # init/deinit declarations at the wrong (statement) level. stmt: - expr - variable_declaration diff --git a/unified/extractor/src/languages/swift/adapter.rs b/unified/extractor/src/languages/swift/adapter.rs index 4ae4040d043d..f34e5df3d00b 100644 --- a/unified/extractor/src/languages/swift/adapter.rs +++ b/unified/extractor/src/languages/swift/adapter.rs @@ -17,9 +17,8 @@ //! * Collection nodes are already elided to JSON arrays upstream, so a //! list-valued field maps directly to that field holding several children. //! -//! Note: this preserves swift-syntax's own kind/field names. Aligning those -//! names with the tree-sitter-swift schema (so the rewrite rules in -//! [`super::swift`] fire) is done incrementally in the rules. +//! Note: this preserves swift-syntax's own kind/field names; the rewrite rules +//! in [`super::swift`] match those names directly. use std::collections::BTreeMap; diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index e2f9010d70dd..575c66733a51 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -77,8 +77,8 @@ fn chained_modifier(ctx: &mut yeast::build::BuildCtx<'_, SwiftContext>) -> Optio /// Combine a list of boolean sub-conditions into a single expression by /// left-folding with the infix `&&` operator. Used by control-flow -/// rules (`if`, `guard`, `while`, `repeat-while`) whose tree-sitter -/// nodes carry one or more comma-separated conditions that the target +/// rules (`if`, `guard`, `while`, `repeat-while`), which carry one or +/// more comma-separated conditions that the target /// AST represents as a single `condition:` field. Panics on an empty /// input because every caller's grammar guarantees at least one /// condition. @@ -144,7 +144,7 @@ fn translation_rules() -> Vec> { // ---- Literals ---- // swift-syntax does not distinguish the lexical integer/string forms // (hex/binary/octal, single- vs multi-line, raw): each is a single - // `*LiteralExpr` kind, so the tree-sitter variants collapse to one rule. + // `*LiteralExpr` kind, so one rule per literal type suffices. rule!((integerLiteralExpr) => (int_literal)), rule!((floatLiteralExpr) => (float_literal)), rule!((booleanLiteralExpr) => (boolean_literal)), @@ -169,8 +169,8 @@ fn translation_rules() -> Vec> { rule!((declReferenceExpr baseName: @name) => (name_expr identifier: (identifier #{name}))), // A discard `_` used as an expression — e.g. the target of a discarding // assignment `_ = x`. swift-syntax models it as a `discardAssignmentExpr`; - // the tree-sitter path treated the bare `_` as a name, so map it to a - // `name_expr` too. + // the target AST has no expression-level discard (only `ignore_pattern`, + // which is a pattern), so it becomes a `name_expr` over the `_` token. rule!((discardAssignmentExpr wildcard: @@w) => (name_expr identifier: (identifier #{w}))), // ---- Operators ---- // The parser front-end folds operator chains into nested @@ -244,10 +244,9 @@ fn translation_rules() -> Vec> { accessor_kind: (accessor_kind "get") body: (block stmt: {body})) ), - // A property with an explicit accessor block. The two shapes differ only - // by the presence of an initializer (tree-sitter split them into distinct - // `willset_didset_block` vs computed-accessor node types; swift-syntax - // makes both plain `accessorDecl`s): + // A property with an explicit accessor block. swift-syntax makes both + // shapes plain `accessorDecl`s, so they are told apart by the presence + // of an initializer: // // * With an initializer (`var x: T = e { willSet {…} didSet {…} }`) it is // a *stored* property with observers: emit the backing @@ -398,8 +397,8 @@ fn translation_rules() -> Vec> { // payload parameters; an element with a raw value (`case a = 1`) or a // plain element (`case north`) becomes a `variable_declaration`. All // carry the shared case modifiers / chained tag from `ctx` (set by the - // `enumCaseDecl` rule below) and are tagged `enum_case` (after any - // `chained_declaration` tag, matching the tree-sitter modifier order). + // `enumCaseDecl` rule below) and are tagged `enum_case`, after any + // `chained_declaration` tag. rule!( (enumCaseElement name: @name parameterClause: (enumCaseParameterClause parameters: _* @params)) => @@ -432,8 +431,8 @@ fn translation_rules() -> Vec> { // Enum cases. A single `case` declaration may carry modifiers // (e.g. `indirect`) and list several comma-separated elements; each // becomes its own declaration carrying those shared modifiers, and - // non-first ones are tagged `chained_declaration` (mirroring the - // tree-sitter `enum_entry` rule). The modifiers are published into `ctx` + // non-first ones are tagged `chained_declaration`. The modifiers are + // published into `ctx` // for the element rules above, which build the actual declaration. rule!( (enumCaseDecl modifiers: _* @mods elements: _* @@cases) @@ -530,7 +529,7 @@ fn translation_rules() -> Vec> { // A function declaration (parameters/return type/body optional). The // parameters and return type nest under `signature`; the body is a // `codeBlock`. A bodyless function (a protocol requirement) still emits - // an empty `block`, matching the tree-sitter path. + // an empty `block`. rule!( (functionDecl name: @name @@ -723,8 +722,7 @@ fn translation_rules() -> Vec> { condition: {and_chain(&mut ctx, cond)} else: {else_stmts}) ), - // Ternary (`c ? a : b`) desugars to an `if_expr`, as in the tree-sitter - // path. + // Ternary (`c ? a : b`) desugars to an `if_expr`. rule!( (ternaryExpr condition: @cond thenExpression: @then_val elseExpression: @else_val) => @@ -769,8 +767,8 @@ fn translation_rules() -> Vec> { (pattern_guard_expr pattern: {pat} value: {val}) ), // Optional binding (`if let x = foo`, or shorthand `if let x`) desugars - // to a `pattern_guard_expr` matching `Optional.some(x)`, exactly as the - // tree-sitter path does. The initialized form is matched first. + // to a `pattern_guard_expr` matching `Optional.some(x)`. The initialized + // form is matched first. rule!( (optionalBindingCondition pattern: (identifierPattern identifier: @name) @@ -845,10 +843,12 @@ fn translation_rules() -> Vec> { ), rule!((arrayElement expression: @e) => expr { e }), // A dictionary literal (`["a": 1]`) is kept as an opaque `map_literal` - // leaf (its source span), matching the tree-sitter path. + // leaf (its source span). rule!((dictionaryExpr) => (map_literal)), - // A subscript access (`xs[0]`) is modelled as a call, exactly as the - // tree-sitter grammar does (it parses `xs[0]` like `xs(0)`). + // A subscript access (`xs[0]`) is modelled as a call. swift-syntax does + // report a distinct `subscriptCallExpr`, so giving + // subscripts their own shape needs only a `subscript_expr` node in + // ast_types.yml and a remap here. rule!( (subscriptCallExpr calledExpression: @callee arguments: _* @args) => @@ -898,9 +898,8 @@ fn translation_rules() -> Vec> { rule!((isExpr expression: @val type: @ty) => (type_test_expr expr: {val} operator: (infix_operator "is") type: {ty})), // Await expression → unary_expr with operator "await" rule!((awaitExpr expression: @val) => (unary_expr operator: (prefix_operator "await") operand: {val})), - // Force-unwrap (`x!`) → postfix unary_expr. swift-syntax has a dedicated - // `forceUnwrapExpr` node (the tree-sitter path used the generic postfix - // operator rule instead). + // Force-unwrap (`x!`) → postfix unary_expr, via swift-syntax's dedicated + // `forceUnwrapExpr` node. rule!((forceUnwrapExpr expression: @e) => (unary_expr operator: (postfix_operator "!") operand: {e})), // ---- Imports ---- // An import declaration. The dotted path (a list of @@ -961,8 +960,8 @@ fn translation_rules() -> Vec> { // A named type (`Int`). `identifierType.name` is the type-name token. rule!((identifierType name: @@n) => (named_type_expr name: (identifier #{n}))), // A qualified type (`Outer.Inner`, `NSString.CompareOptions`). swift-syntax - // nests these as `memberType` nodes; like the old tree-sitter `user_type` - // rule, we keep the whole dotted path as the opaque `named_type_expr` name. + // nests these as `memberType` nodes; we keep the whole dotted path as the + // opaque `named_type_expr` name. rule!((memberType) @ty => (named_type_expr name: (identifier #{ty}))), // Sugared types desugar to `generic_type_expr`: `T?` -> Optional, // `[T]` -> Array, `[K: V]` -> Dictionary. @@ -1029,9 +1028,7 @@ fn translation_rules() -> Vec> { // expansions uniformly as a `macroExpansionExpr`). rule!((macroExpansionExpr) => (unsupported_node)), // A nominal type's `inheritanceClause` (`: Base, Proto`) becomes a list - // of `base_type`s, one per inherited type. The tree-sitter path dropped - // it (no corpus target had a `base_type`) and the mapping matched that - // for parity; swift-syntax exposes it cleanly. Each declaration keyword + // of `base_type`s, one per inherited type. Each declaration keyword // gets its own rule; the bodies are identical but for the keyword. // Class declaration with body containing members rule!( @@ -1100,8 +1097,7 @@ fn translation_rules() -> Vec> { // An `extension Foo { … }` is likewise a `class_like_declaration`, named // by the extended type. The extended type is captured opaquely (as its // source text) so that qualified names (`extension String.Interpolation`, - // a `memberType`) name the declaration just like simple ones, matching the - // old tree-sitter `user_type` behaviour. + // a `memberType`) name the declaration just like simple ones. rule!( (extensionDecl extensionKeyword: @kind diff --git a/unified/extractor/tests/corpus/swift/collections/subscript-access.output b/unified/extractor/tests/corpus/swift/collections/subscript-access.output index f7e518b84773..ec24f0c1f1df 100644 --- a/unified/extractor/tests/corpus/swift/collections/subscript-access.output +++ b/unified/extractor/tests/corpus/swift/collections/subscript-access.output @@ -1,6 +1,6 @@ -// TODO: tree-sitter-swift parses `xs[0]` as a call_expression (same shape -// as `xs(0)`), so the mapping currently produces a call_expr. Update the -// parser / add a separate subscript_expr node and remap when fixed. +// TODO: `xs[0]` is mapped to a call_expr, even though swift-syntax reports a +// distinct subscriptCallExpr. Giving subscripts their own shape needs only a +// subscript_expr node in ast_types.yml and a remap. let first = xs[0] --- diff --git a/unified/extractor/tests/corpus/swift/collections/subscript-access.swift b/unified/extractor/tests/corpus/swift/collections/subscript-access.swift index 00a85bda4336..eeffca017397 100644 --- a/unified/extractor/tests/corpus/swift/collections/subscript-access.swift +++ b/unified/extractor/tests/corpus/swift/collections/subscript-access.swift @@ -1,4 +1,4 @@ -// TODO: tree-sitter-swift parses `xs[0]` as a call_expression (same shape -// as `xs(0)`), so the mapping currently produces a call_expr. Update the -// parser / add a separate subscript_expr node and remap when fixed. +// TODO: `xs[0]` is mapped to a call_expr, even though swift-syntax reports a +// distinct subscriptCallExpr. Giving subscripts their own shape needs only a +// subscript_expr node in ast_types.yml and a remap. let first = xs[0] From 1c4dfca7caf0cdebcabda8890ccc3291f0852df0 Mon Sep 17 00:00:00 2001 From: Taus Date: Tue, 28 Jul 2026 15:50:11 +0000 Subject: [PATCH 096/188] unified: Delete the vendored tree-sitter-swift crate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pure deletion of the files the previous commit left unreferenced: - the vendored `unified/extractor/tree-sitter-swift` crate — grammar, generated parser tables, editor queries and Node bindings; - `scripts/regenerate-grammar.sh`, which regenerated those tables from the grammar; - the `rules_macro_smoke` test, which type-checked the `rules!` macro against the crate's `node-types.yml` and so cannot outlive it. The extractor now builds with no Swift grammar and no Swift toolchain; the Swift dependency lives solely in the separate `swift-syntax-parse` binary. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- unified/extractor/tests/rules_macro_smoke.rs | 25 - .../extractor/tree-sitter-swift/.gitignore | 9 - .../extractor/tree-sitter-swift/BUILD.bazel | 42 - .../extractor/tree-sitter-swift/Cargo.toml | 22 - unified/extractor/tree-sitter-swift/LICENSE | 21 - unified/extractor/tree-sitter-swift/README.md | 127 - .../extractor/tree-sitter-swift/binding.gyp | 44 - .../bindings/node/binding.cc | 20 - .../tree-sitter-swift/bindings/node/index.js | 7 - .../tree-sitter-swift/bindings/rust/build.rs | 51 - .../tree-sitter-swift/bindings/rust/lib.rs | 68 - .../extractor/tree-sitter-swift/grammar.js | 2113 ----------------- .../tree-sitter-swift/node-types.yml | 875 ------- .../extractor/tree-sitter-swift/package.json | 68 - .../tree-sitter-swift/queries/folds.scm | 35 - .../tree-sitter-swift/queries/highlights.scm | 336 --- .../tree-sitter-swift/queries/indents.scm | 123 - .../tree-sitter-swift/queries/injections.scm | 10 - .../tree-sitter-swift/queries/locals.scm | 23 - .../tree-sitter-swift/queries/outline.scm | 66 - .../tree-sitter-swift/queries/tags.scm | 51 - .../tree-sitter-swift/queries/textobjects.scm | 19 - .../extractor/tree-sitter-swift/src/scanner.c | 929 -------- .../tree-sitter-swift/tree-sitter.json | 39 - unified/scripts/regenerate-grammar.sh | 28 - 25 files changed, 5151 deletions(-) delete mode 100644 unified/extractor/tests/rules_macro_smoke.rs delete mode 100644 unified/extractor/tree-sitter-swift/.gitignore delete mode 100644 unified/extractor/tree-sitter-swift/BUILD.bazel delete mode 100644 unified/extractor/tree-sitter-swift/Cargo.toml delete mode 100644 unified/extractor/tree-sitter-swift/LICENSE delete mode 100644 unified/extractor/tree-sitter-swift/README.md delete mode 100644 unified/extractor/tree-sitter-swift/binding.gyp delete mode 100644 unified/extractor/tree-sitter-swift/bindings/node/binding.cc delete mode 100644 unified/extractor/tree-sitter-swift/bindings/node/index.js delete mode 100644 unified/extractor/tree-sitter-swift/bindings/rust/build.rs delete mode 100644 unified/extractor/tree-sitter-swift/bindings/rust/lib.rs delete mode 100644 unified/extractor/tree-sitter-swift/grammar.js delete mode 100644 unified/extractor/tree-sitter-swift/node-types.yml delete mode 100644 unified/extractor/tree-sitter-swift/package.json delete mode 100644 unified/extractor/tree-sitter-swift/queries/folds.scm delete mode 100644 unified/extractor/tree-sitter-swift/queries/highlights.scm delete mode 100644 unified/extractor/tree-sitter-swift/queries/indents.scm delete mode 100644 unified/extractor/tree-sitter-swift/queries/injections.scm delete mode 100644 unified/extractor/tree-sitter-swift/queries/locals.scm delete mode 100644 unified/extractor/tree-sitter-swift/queries/outline.scm delete mode 100644 unified/extractor/tree-sitter-swift/queries/tags.scm delete mode 100644 unified/extractor/tree-sitter-swift/queries/textobjects.scm delete mode 100644 unified/extractor/tree-sitter-swift/src/scanner.c delete mode 100644 unified/extractor/tree-sitter-swift/tree-sitter.json delete mode 100755 unified/scripts/regenerate-grammar.sh diff --git a/unified/extractor/tests/rules_macro_smoke.rs b/unified/extractor/tests/rules_macro_smoke.rs deleted file mode 100644 index cde8ae3ca4ab..000000000000 --- a/unified/extractor/tests/rules_macro_smoke.rs +++ /dev/null @@ -1,25 +0,0 @@ -/// Smoke test: load a few real Swift translation rules through the new -/// `yeast::rules!` macro using the bare-rule-body syntax, and confirm the -/// input + output schemas accept them. Compiles only — any type-checking -/// error surfaces as a compile-time error. -#[test] -fn rules_macro_compiles_against_real_swift_schemas() { - let _rules: Vec = yeast::rules! { - input: "tree-sitter-swift/node-types.yml", - output: "ast_types.yml", - [ - (simple_identifier) @name - => - (name_expr - identifier: (identifier #{name})), - - (integer_literal) @lit - => - (int_literal #{lit}), - - (line_string_literal) @lit - => - (string_literal #{lit}), - ] - }; -} diff --git a/unified/extractor/tree-sitter-swift/.gitignore b/unified/extractor/tree-sitter-swift/.gitignore deleted file mode 100644 index 53796875297e..000000000000 --- a/unified/extractor/tree-sitter-swift/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -# Generated by tree-sitter from grammar.js. The Cargo build script -# (bindings/rust/build.rs) and Bazel's cargo_build_script regenerate them into -# OUT_DIR. The tree-sitter CLI (parse, test, playground, etc.) expects them in -# src/, so contributors can run `tree-sitter generate` locally to populate -# these — they are intentionally untracked. -src/parser.c -src/grammar.json -src/node-types.json -src/tree_sitter/ diff --git a/unified/extractor/tree-sitter-swift/BUILD.bazel b/unified/extractor/tree-sitter-swift/BUILD.bazel deleted file mode 100644 index f865f22a1420..000000000000 --- a/unified/extractor/tree-sitter-swift/BUILD.bazel +++ /dev/null @@ -1,42 +0,0 @@ -load("@rules_rust//cargo:defs.bzl", "cargo_build_script") -load("@rules_rust//rust:defs.bzl", "rust_library") -load("//misc/bazel/3rdparty/tree_sitter_extractors_deps:defs.bzl", "aliases", "all_crate_deps") - -package(default_visibility = ["//visibility:public"]) - -# This will run the build script from the root of the workspace, and -# collect the outputs. -cargo_build_script( - name = "tree-sitter-swift-build", - srcs = ["bindings/rust/build.rs"], - data = glob([ - "src/scanner.c", - ]) + [ - "grammar.js", - ], - deps = all_crate_deps( - build = True, - ), -) - -rust_library( - name = "tree-sitter-swift", - srcs = [ - "bindings/rust/lib.rs", - ], - aliases = aliases(), - compile_data = glob([ - "src/**", - "queries/**", - ]) + [ - "grammar.js", - ], - proc_macro_deps = all_crate_deps( - proc_macro = True, - ), - deps = [":tree-sitter-swift-build"] + all_crate_deps( - normal = True, - ), -) - -exports_files(["Cargo.toml"]) diff --git a/unified/extractor/tree-sitter-swift/Cargo.toml b/unified/extractor/tree-sitter-swift/Cargo.toml deleted file mode 100644 index 8cec03889a83..000000000000 --- a/unified/extractor/tree-sitter-swift/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "tree-sitter-swift" -description = "Swift grammar for the tree-sitter parsing library (vendored copy for the unified extractor)" -version = "0.7.2" -keywords = ["incremental", "parsing", "swift"] -categories = ["parsing", "text-editors"] -repository = "https://github.com/alex-pinkus/tree-sitter-swift" -edition = "2024" -license = "MIT" - -build = "bindings/rust/build.rs" - -[lib] -path = "bindings/rust/lib.rs" - -# When updating these dependencies, run `misc/bazel/3rdparty/update_cargo_deps.sh` -[dependencies] -tree-sitter-language = "0.1" - -[build-dependencies] -cc = "1.2" -tree-sitter-generate = "0.26.8" diff --git a/unified/extractor/tree-sitter-swift/LICENSE b/unified/extractor/tree-sitter-swift/LICENSE deleted file mode 100644 index f158d7005311..000000000000 --- a/unified/extractor/tree-sitter-swift/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2021 alex-pinkus - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/unified/extractor/tree-sitter-swift/README.md b/unified/extractor/tree-sitter-swift/README.md deleted file mode 100644 index 5b54f4b617f6..000000000000 --- a/unified/extractor/tree-sitter-swift/README.md +++ /dev/null @@ -1,127 +0,0 @@ -![Parse rate badge](https://byob.yarr.is/alex-pinkus/tree-sitter-swift/parse_rate) -[![Crates.io badge](https://byob.yarr.is/alex-pinkus/tree-sitter-swift/crates_io_version)](https://crates.io/crates/tree-sitter-swift) -[![NPM badge](https://byob.yarr.is/alex-pinkus/tree-sitter-swift/npm_version)](https://www.npmjs.com/package/tree-sitter-swift) -[![Build](https://github.com/alex-pinkus/tree-sitter-swift/actions/workflows/top-repos.yml/badge.svg)](https://github.com/alex-pinkus/tree-sitter-swift/actions/workflows/top-repos.yml) - -# tree-sitter-swift - -This contains a [`tree-sitter`](https://tree-sitter.github.io/tree-sitter) grammar for the Swift programming language. - -## Getting started - -To use this parser to parse Swift code, you'll want to depend on either the Rust crate or the NPM package. - -### Rust - -To use the Rust crate, you'll add this to your `Cargo.toml`: - -``` -tree-sitter = "0.23.0" -tree-sitter-swift = "=0.7.0" -``` - -Then you can use a `tree-sitter` parser with the language declared here: - -``` -let mut parser = tree_sitter::Parser::new(); -parser.set_language(tree_sitter_swift::language())?; - -// ... - -let tree = parser.parse(&my_source_code, None) - .ok_or_else(|| /* error handling code */)?; -``` - -### Javascript - -To use this from NPM, you'll add similar dependencies to `package.json`: - -``` -"dependencies: { - "tree-sitter-swift": "0.7.0", - "tree-sitter": "^0.22.1" -} -``` - -Your usage of the parser will look like: - -``` -const Parser = require("tree-sitter"); -const Swift = require("tree-sitter-swift"); - -const parser = new Parser(); -parser.setLanguage(Swift); - -// ... - -const tree = parser.parse(mySourceCode); -``` - -### Editing the grammar - -With this package checked out, a common workflow for editing the grammar will look something like: - -1. Make a change to `grammar.ts`. -2. Run `npm install && npm test` to see whether the change has had impact on existing parsing behavior. The default - `npm test` target requires `valgrind` to be installed; if you do not have it installed, and do not wish to, you can - substitute `tree-sitter test` directly. -3. Run `tree-sitter parse` on some real Swift codebase and see whether (or where) it fails. -4. Use any failures to create new corpus test cases. - -## Contributions - -All contributions to this repository are welcome. - -If said contribution is to check generated files (e.g., `parser.c`) into the repository, be aware that your contribution will not be accepted. Make sure to read the [FAQ entry](https://github.com/alex-pinkus/tree-sitter-swift?tab=readme-ov-file#where-is-your-parserc) and the [prior](https://github.com/alex-pinkus/tree-sitter-swift/issues/362) [discussions](https://github.com/alex-pinkus/tree-sitter-swift/pull/315) and [compromises](https://github.com/alex-pinkus/tree-sitter-swift/issues/149) that have occurred already on this topic. - -## Using tree-sitter-swift in Web Assembly - -To use tree-sitter-swift as a language for the web bindings version tree-sitter, which will likely be a more modern version than the published node -module. [see](https://github.com/tree-sitter/tree-sitter/blob/master/lib/binding_web/README.md). Follow the instructions below - -1. Install the node modules `npm install web-tree-sitter tree-sitter-swift` -2. Run the tree-sitter cli to create the wasm bundle - ```sh - $ npx tree-sitter build-asm ./node_modules/tree-sitter - ``` -3. Boot tree-sitter wasm like this. - -```js -const Parser = require("web-tree-sitter"); -async function run() { - //needs to happen first - await Parser.init(); - //wait for the load of swift - const Swift = await Parser.Language.load("./tree-sitter-swift.wasm"); - - const parser = new Parser(); - parser.setLanguage(Swift); - - //Parse your swift code here. - const tree = parser.parse('print("Hello, World!")'); -} -//if you want to run this -run().then(console.log, console.error); -``` - -## Frequently asked questions - -### Where is your `parser.c`? - -This repository currently omits most of the code that is autogenerated during a build. This means, for instance, that -`grammar.json` and `parser.c` are both only available following a build. It also significantly reduces noise during -diffs. - -The side benefit of not checking in `parser.c` is that you can guarantee backwards compatibility. Parsers generated by -the tree-sitter CLI aren't always backwards compatible. If you need a parser, generate it yourself using the CLI; all -the information to do so is available in this package. By doing that, you'll also know for sure that your parser version -and your library version are compatible. - -If you need a `parser.c`, and you don't care about the tree-sitter version, but you don't have a local setup that would -allow you to obtain the parser, you can just download one from a recent workflow run in this package. To do so: - -- Go to the [GitHub actions page](https://github.com/alex-pinkus/tree-sitter-swift/actions) for this - repository. -- Click on the "Publish `grammar.json` and `parser.c`" action for the appropriate commit. -- Go down to `Artifacts` and click on `generated-parser-src`. All the relevant parser files will be available in your - download. diff --git a/unified/extractor/tree-sitter-swift/binding.gyp b/unified/extractor/tree-sitter-swift/binding.gyp deleted file mode 100644 index 4d9270af7d47..000000000000 --- a/unified/extractor/tree-sitter-swift/binding.gyp +++ /dev/null @@ -1,44 +0,0 @@ -{ - "targets": [ - { - "target_name": "tree_sitter_swift_binding", - "dependencies": [ - " - -typedef struct TSLanguage TSLanguage; - -extern "C" TSLanguage *tree_sitter_swift(); - -// "tree-sitter", "language" hashed with BLAKE2 -const napi_type_tag LANGUAGE_TYPE_TAG = { - 0x8AF2E5212AD58ABF, 0xD5006CAD83ABBA16 -}; - -Napi::Object Init(Napi::Env env, Napi::Object exports) { - exports["name"] = Napi::String::New(env, "swift"); - auto language = Napi::External::New(env, tree_sitter_swift()); - language.TypeTag(&LANGUAGE_TYPE_TAG); - exports["language"] = language; - return exports; -} - -NODE_API_MODULE(tree_sitter_swift_binding, Init) diff --git a/unified/extractor/tree-sitter-swift/bindings/node/index.js b/unified/extractor/tree-sitter-swift/bindings/node/index.js deleted file mode 100644 index 6657bcf42dec..000000000000 --- a/unified/extractor/tree-sitter-swift/bindings/node/index.js +++ /dev/null @@ -1,7 +0,0 @@ -const root = require("path").join(__dirname, "..", ".."); - -module.exports = require("node-gyp-build")(root); - -try { - module.exports.nodeTypeInfo = require("../../src/node-types.json"); -} catch (_) {} diff --git a/unified/extractor/tree-sitter-swift/bindings/rust/build.rs b/unified/extractor/tree-sitter-swift/bindings/rust/build.rs deleted file mode 100644 index 2dd899ea5213..000000000000 --- a/unified/extractor/tree-sitter-swift/bindings/rust/build.rs +++ /dev/null @@ -1,51 +0,0 @@ -use std::env; -use std::path::PathBuf; - -fn main() { - // tree-sitter-generate produces parser.c, grammar.json, node-types.json, - // and src/tree_sitter/*.h headers from grammar.js. We write them into - // OUT_DIR so the build is sandbox-friendly and we don't litter the source - // tree. - let crate_dir: PathBuf = env::var("CARGO_MANIFEST_DIR").unwrap().into(); - let out_dir: PathBuf = env::var("OUT_DIR").unwrap().into(); - let grammar_js = crate_dir.join("grammar.js"); - - tree_sitter_generate::generate_parser_in_directory( - &crate_dir, - Some(&out_dir), - Some(&grammar_js), - tree_sitter_generate::ABI_VERSION_MAX, - None, - // Evaluate grammar.js with the embedded QuickJS runtime instead of - // spawning `node`, which isn't available inside Bazel's sandbox. - Some("native"), - true, - tree_sitter_generate::OptLevel::default(), - ) - .expect("failed to generate tree-sitter-swift parser"); - - let mut c_config = cc::Build::new(); - c_config - .std("c11") - .include(&out_dir) - .include(out_dir.join("tree_sitter")); - - #[cfg(target_env = "msvc")] - c_config.flag("-utf-8"); - - c_config.file(out_dir.join("parser.c")); - - // scanner.c is hand-written and lives in the source tree. - let scanner_path = crate_dir.join("src").join("scanner.c"); - c_config.include(crate_dir.join("src")).file(&scanner_path); - - println!("cargo:rerun-if-changed={}", grammar_js.to_str().unwrap()); - println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap()); - // Re-export OUT_DIR so consumers can include_str! the generated files. - println!( - "cargo:rustc-env=TREE_SITTER_SWIFT_OUT_DIR={}", - out_dir.to_str().unwrap() - ); - - c_config.compile("tree-sitter-swift"); -} diff --git a/unified/extractor/tree-sitter-swift/bindings/rust/lib.rs b/unified/extractor/tree-sitter-swift/bindings/rust/lib.rs deleted file mode 100644 index 891df87778f0..000000000000 --- a/unified/extractor/tree-sitter-swift/bindings/rust/lib.rs +++ /dev/null @@ -1,68 +0,0 @@ -//! This crate provides Swift language support for the [tree-sitter][] parsing library. -//! -//! Typically, you will use the [language][language func] function to add this language to a -//! tree-sitter [Parser][], and then use the parser to parse some code: -//! -//! ``` -//! let code = r#" -//! "#; -//! let mut parser = tree_sitter::Parser::new(); -//! let language = tree_sitter_swift::LANGUAGE; -//! parser -//! .set_language(&language.into()) -//! .expect("Error loading Swift parser"); -//! let tree = parser.parse(code, None).unwrap(); -//! assert!(!tree.root_node().has_error()); -//! ``` -//! -//! [Language]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Language.html -//! [language func]: fn.language.html -//! [Parser]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Parser.html -//! [tree-sitter]: https://tree-sitter.github.io/ - -use tree_sitter_language::LanguageFn; - -unsafe extern "C" { - fn tree_sitter_swift() -> *const (); -} - -/// The tree-sitter [`LanguageFn`] for this grammar. -pub const LANGUAGE: LanguageFn = unsafe { LanguageFn::from_raw(tree_sitter_swift) }; - -/// The content of the [`node-types.json`][] file for this grammar. -/// -/// [`node-types.json`]: https://tree-sitter.github.io/tree-sitter/using-parsers#static-node-types -pub const NODE_TYPES: &str = include_str!(concat!(env!("TREE_SITTER_SWIFT_OUT_DIR"), "/node-types.json")); - -pub const HIGHLIGHTS_QUERY: &str = include_str!("../../queries/highlights.scm"); -pub const INJECTIONS_QUERY: &str = include_str!("../../queries/injections.scm"); -pub const LOCALS_QUERY: &str = include_str!("../../queries/locals.scm"); -pub const TAGS_QUERY: &str = include_str!("../../queries/tags.scm"); - -#[cfg(test)] -mod tests { - #[test] - fn test_can_load_grammar() { - let mut parser = tree_sitter::Parser::new(); - parser - .set_language(&super::LANGUAGE.into()) - .expect("Error loading Swift parser"); - } - - #[test] - fn test_can_parse_basic_file() { - let mut parser = tree_sitter::Parser::new(); - parser - .set_language(&super::LANGUAGE.into()) - .expect("Error loading Swift parser"); - - let tree = parser - .parse("_ = \"Hello!\"\n", None) - .expect("Unable to parse!"); - - assert_eq!( - "(source_file (assignment target: (directly_assignable_expression (simple_identifier)) result: (line_string_literal text: (line_str_text))))", - tree.root_node().to_sexp(), - ); - } -} diff --git a/unified/extractor/tree-sitter-swift/grammar.js b/unified/extractor/tree-sitter-swift/grammar.js deleted file mode 100644 index 7052d2ebdd5b..000000000000 --- a/unified/extractor/tree-sitter-swift/grammar.js +++ /dev/null @@ -1,2113 +0,0 @@ -"use strict"; -/* - * MIT License - * - * Copyright (c) 2021 alex-pinkus - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -const PRECS = { - multiplication: 11, - addition: 10, - infix_operations: 9, - nil_coalescing: 8, - check: 7, - prefix_operations: 7, - comparison: 6, - postfix_operations: 6, - equality: 5, - conjunction: 4, - disjunction: 3, - block: 2, - loop: 1, - keypath: 1, - parameter_pack: 1, - control_transfer: 0, - as: -1, - tuple: -1, - if: -1, - switch: -1, - do: -1, - fully_open_range: -1, - range: -1, - navigation: -1, - expr: -1, - ty: -1, - call: -2, - ternary: -2, - try: -2, - call_suffix: -2, - range_suffix: -2, - ternary_binary_suffix: -2, - await: -2, - assignment: -3, - comment: -3, - lambda: -3, - regex: -4, -}; - -const DYNAMIC_PRECS = { - call: 1, -}; - -const DEC_DIGITS = token(sep1(/[0-9]+/, /_+/)); -const HEX_DIGITS = token(sep1(/[0-9a-fA-F]+/, /_+/)); -const OCT_DIGITS = token(sep1(/[0-7]+/, /_+/)); -const BIN_DIGITS = token(sep1(/[01]+/, /_+/)); -const REAL_EXPONENT = token(seq(/[eE]/, optional(/[+-]/), DEC_DIGITS)); -const HEX_REAL_EXPONENT = token(seq(/[pP]/, optional(/[+-]/), DEC_DIGITS)); - -var LEXICAL_IDENTIFIER; - -if (tree_sitter_version_supports_emoji()) { - LEXICAL_IDENTIFIER = - /[_\p{XID_Start}\p{Emoji}&&[^0-9#*]](\p{EMod}|\x{FE0F}\x{20E3}?)?([_\p{XID_Continue}\p{Emoji}\x{200D}](\p{EMod}|\x{FE0F}\x{20E3}?)?)*/; -} else { - LEXICAL_IDENTIFIER = /[_\p{XID_Start}][_\p{XID_Continue}]*/; -} - -module.exports = grammar({ - name: "swift", - supertypes: ($) => [ - $.expression, - $.unannotated_type, - $.global_declaration, - $.type_level_declaration, - $.local_declaration, - $.protocol_member_declaration, - ], - conflicts: ($) => [ - // @Type(... could either be an annotation constructor invocation or an annotated expression - [$.attribute], - [$._attribute_argument], - // Is `foo { ... }` a constructor invocation or function invocation? - [$.simple_user_type, $.expression], - // To support nested types A.B not being interpreted as `(navigation_expression ... (type_identifier)) (navigation_suffix)` - [$.user_type], - // How to tell the difference between Foo.bar(with:and:), and Foo.bar(with: smth, and: other)? You need GLR - [$.value_argument], - // { (foo, bar) ... - [$.expression, $.lambda_parameter], - [$._primary_expression, $.lambda_parameter], - // (foo) where foo could be a binding pattern or a tuple expression item. - [$._binding_pattern_with_expr, $.tuple_expression_item], - // After a `{` in a function or switch context, it's ambigous whether we're starting a set of local statements or - // applying some modifiers to a capture or pattern. - [$.modifiers], - // `+(...)` is ambigously either "call the function produced by a reference to the operator `+`" or "use the unary - // operator `+` on the result of the parenthetical expression." - [$._additive_operator, $._prefix_unary_operator], - [$.referenceable_operator, $._prefix_unary_operator], - // `{ [self, b, c] ...` could be a capture list or an array literal depending on what else happens. - [$.capture_list_item, $.expression], - [$.capture_list_item, $.expression, $.simple_user_type], - [$._primary_expression, $.capture_list_item], - // a ? b : c () could be calling c(), or it could be calling a function that's produced by the result of - // `(a ? b : c)`. We have a small hack to force it to be the former of these by intentionally introducing a - // conflict. - [$.call_suffix, $.expr_hack_at_ternary_binary_call_suffix], - // try {expression} is a bit magic and applies quite broadly: `try foo()` and `try foo { }` show that this is right - // associative, and `try foo ? bar() : baz` even more so. But it doesn't always win: something like - // `if try foo { } ...` should award its braces to the `if`. In order to make this actually happen, we need to parse - // all the options and pick the best one that doesn't error out. - [$.try_expression, $._unary_expression], - [$.try_expression, $.expression], - // await {expression} has the same special cases as `try`. - [$.await_expression, $._unary_expression], - [$.await_expression, $.expression], - // In a computed property, when you see an @attribute, it's not yet clear if that's going to be for a - // locally-declared class or a getter / setter specifier. - [ - $._local_property_declaration, - $._local_typealias_declaration, - $._local_function_declaration, - $._local_class_declaration, - $.computed_getter, - $.computed_modify, - $.computed_setter, - ], - // The `class` modifier is legal in many of the same positions that a class declaration itself would be. - [$._bodyless_function_declaration, $.property_modifier], - [$.init_declaration, $.property_modifier], - // Patterns, man - [$._navigable_type_expression, $.case_pattern], - [$._no_expr_pattern_already_bound, $._binding_pattern_no_expr], - - // On encountering a closure starting with `{ @Foo ...`, we don't yet know if that attribute applies to the closure - // type or to a declaration within the closure. What a mess! We just have to hope that if we keep going, only one of - // those will parse (because there will be an `in` or a `let`). - [ - $._lambda_type_declaration, - $._local_property_declaration, - $._local_typealias_declaration, - $._local_function_declaration, - $._local_class_declaration, - ], - - // We want `foo() { }` to be treated as one function call, but we _also_ want `if foo() { ... }` to be treated as a - // full if-statement. This means we have to treat it as a conflict rather than purely a left or right associative - // construct, and let the parser realize that the second expression won't parse properly with the `{ ... }` as a - // lambda. - [$.constructor_suffix], - [$.call_suffix], - - // `actor` is allowed to be an identifier, even though it is also a locally permitted declaration. If we encounter - // it, the only way to know what it's meant to be is to keep going. - [$._modifierless_class_declaration, $.property_modifier], - [$._fn_call_lambda_arguments], - - // `borrowing` and `consuming` are legal as identifiers, but are also legal modifiers - [$.parameter_modifiers], - - // These are keywords sometimes, but simple identifiers other times, and it just depends on the rest of their usage. - [$._contextual_simple_identifier, $._modifierless_class_declaration], - [$._contextual_simple_identifier, $.property_behavior_modifier], - [$._contextual_simple_identifier, $.parameter_modifier], - [$._contextual_simple_identifier, $.type_parameter_pack], - [$._contextual_simple_identifier, $.type_pack_expansion], - [$._contextual_simple_identifier, $.visibility_modifier], - ], - extras: ($) => [ - $.comment, - $.multiline_comment, - /\s+/, // Whitespace - ], - externals: ($) => [ - // Comments and raw strings are parsed in a custom scanner because they require us to carry forward state to - // maintain symmetry. For instance, parsing a multiline comment requires us to increment a counter whenever we see - // `/*`, and decrement it whenever we see `*/`. A standard grammar would only be able to exit the comment at the - // first `*/` (like C does). Similarly, when you start a string with `##"`, you're required to include the same - // number of `#` symbols to end it. - $._multiline_comment, - $.raw_str_part, - $.raw_str_continuing_indicator, - $.raw_str_end_part, - // Because Swift doesn't have explicit semicolons, we also do some whitespace handling in a custom scanner. Line - // breaks are _sometimes_ meaningful as the end of a statement: try to write `let foo: Foo let bar: Bar`, for - // instance and the compiler will complain, but add either a newline or a semicolon and it's fine. We borrow the - // idea from the Kotlin grammar that a newline is sometimes a "semicolon". By including `\n` in both `_semi` and - // an anonymous `whitespace` extras, we _should_ be able to let the parser decide if a newline is meaningful. If the - // parser sees something like `foo.bar(1\n)`, it knows that a "semicolon" would not be valid there, so it parses - // that as whitespace. On the other hand, `let foo: Foo\n let bar: Bar` has a meaningful newline. - // Unfortunately, we can't simply stop at that. There are some expressions and statements that remain valid if you - // end them early, but are expected to be parsed across multiple lines. One particular nefarious example is a - // function declaration, where you might have something like `func foo(args: A) -> Foo throws where A: Hashable`. - // This would still be a valid declaration even if it ended after the `)`, the `Foo`, or the `throws`, so a grammar - // that simply interprets a newline as "sometimes a semi" would parse those incorrectly. - // To solve that case, our custom scanner must do a bit of extra lookahead itself. If we're about to generate a - // `_semi`, we advance a bit further to see if the next non-whitespace token would be one of these other operators. - // If so, we ignore the `_semi` and just produce the operator; if not, we produce the `_semi` and let the rest of - // the grammar sort it out. This isn't perfect, but it works well enough most of the time. - $._implicit_semi, - $._explicit_semi, - // Every one of the below operators will suppress a `_semi` if we encounter it after a newline. - $._arrow_operator_custom, - $._dot_custom, - $._conjunction_operator_custom, - $._disjunction_operator_custom, - $._nil_coalescing_operator_custom, - $._eq_custom, - $._eq_eq_custom, - $._plus_then_ws, - $._minus_then_ws, - $._bang_custom, - $._throws_keyword, - $._rethrows_keyword, - $.default_keyword, - $.where_keyword, - $["else"], - $.catch_keyword, - $._as_custom, - $._as_quest_custom, - $._as_bang_custom, - $._async_keyword_custom, - $._custom_operator, - $._hash_symbol_custom, - $._directive_if, - $._directive_elseif, - $._directive_else, - $._directive_endif, - - // Fake operator that will never get triggered, but follows the sequence of characters for `try!`. Tracked by the - // custom scanner so that it can avoid triggering `$.bang` for that case. - $._fake_try_bang, - ], - inline: ($) => [$._locally_permitted_modifiers], - rules: { - //////////////////////////////// - // File Structure - //////////////////////////////// - source_file: ($) => - seq( - optional(field("shebang", $.shebang_line)), - optional( - seq( - field("statement", $._top_level_statement), - repeat(seq($._semi, field("statement", $._top_level_statement))), - optional($._semi) - ) - ) - ), - _semi: ($) => choice($._implicit_semi, $._explicit_semi), - shebang_line: ($) => seq($._hash_symbol, "!", /[^\r\n]*/), - //////////////////////////////// - // Lexical Structure - https://docs.swift.org/swift-book/ReferenceManual/LexicalStructure.html - //////////////////////////////// - comment: ($) => token(prec(PRECS.comment, seq("//", /.*/))), - // Named wrapper for the unnamed `_multiline_comment` external token, so - // that multi-line comments still appear in the AST (e.g. as extras between - // top-level statements) without being extracted as class body members when - // used only to separate those members. - multiline_comment: ($) => $._multiline_comment, - // Identifiers - simple_identifier: ($) => - choice( - LEXICAL_IDENTIFIER, - /`[^\r\n` ]*`/, - /\$[0-9]+/, - token(seq("$", LEXICAL_IDENTIFIER)), - $._contextual_simple_identifier - ), - // Keywords that were added after they were already legal as identifiers. `tree-sitter` will prefer exact matches - // when parsing so unless we explicitly say that these are legal, the parser will interpret them as their keyword. - _contextual_simple_identifier: ($) => - choice( - "actor", - "async", - "each", - "lazy", - "repeat", - "package", - $._parameter_ownership_modifier - ), - identifier: ($) => sep1(field("part", $.simple_identifier), $._dot), - // Literals - _basic_literal: ($) => - choice( - $.integer_literal, - $.hex_literal, - $.oct_literal, - $.bin_literal, - $.real_literal, - $.boolean_literal, - $._string_literal, - $.regex_literal, - "nil" - ), - real_literal: ($) => - token( - choice( - seq(DEC_DIGITS, REAL_EXPONENT), - seq(optional(DEC_DIGITS), ".", DEC_DIGITS, optional(REAL_EXPONENT)), - seq( - "0x", - HEX_DIGITS, - optional(seq(".", HEX_DIGITS)), - HEX_REAL_EXPONENT - ) - ) - ), - integer_literal: ($) => token(seq(optional(/[1-9]/), DEC_DIGITS)), - hex_literal: ($) => token(seq("0", /[xX]/, HEX_DIGITS)), - oct_literal: ($) => token(seq("0", /[oO]/, OCT_DIGITS)), - bin_literal: ($) => token(seq("0", /[bB]/, BIN_DIGITS)), - boolean_literal: ($) => choice("true", "false"), - // String literals - _string_literal: ($) => - choice( - $.line_string_literal, - $.multi_line_string_literal, - $.raw_string_literal - ), - line_string_literal: ($) => - seq( - '"', - repeat(choice(field("text", $._line_string_content), $._interpolation)), - '"' - ), - _line_string_content: ($) => choice($.line_str_text, $.str_escaped_char), - line_str_text: ($) => /[^\\"]+/, - str_escaped_char: ($) => - choice($._escaped_identifier, $._uni_character_literal), - _uni_character_literal: ($) => seq("\\", "u", /\{[0-9a-fA-F]+\}/), - multi_line_string_literal: ($) => - seq( - '"""', - repeat( - choice(field("text", $._multi_line_string_content), $._interpolation) - ), - '"""' - ), - raw_string_literal: ($) => - seq( - repeat( - seq( - field("text", $.raw_str_part), - field("interpolation", $.raw_str_interpolation), - field("continuing", optional($.raw_str_continuing_indicator)) - ) - ), - field("text", $.raw_str_end_part) - ), - raw_str_interpolation: ($) => - seq(field("start", $.raw_str_interpolation_start), $._interpolation_contents, ")"), - raw_str_interpolation_start: ($) => /\\#*\(/, - _multi_line_string_content: ($) => - choice($.multi_line_str_text, $.str_escaped_char, '"'), - _interpolation: ($) => seq("\\(", $._interpolation_contents, ")"), - _interpolation_contents: ($) => - sep1Opt( - field( - "interpolation", - alias($.value_argument, $.interpolated_expression) - ), - "," - ), - _escaped_identifier: ($) => /\\[0\\tnr"'\n]/, - multi_line_str_text: ($) => /[^\\"]+/, - // Based on https://gitlab.com/woolsweater/tree-sitter-swifter/-/blob/3d47c85bd47ce54cdf2023a9c0e01eb90adfcc1d/grammar.js#L1019 - // But required modifications to hit all of the cases in SE-354 - regex_literal: ($) => - choice( - $._extended_regex_literal, - $._multiline_regex_literal, - $._oneline_regex_literal - ), - - _extended_regex_literal: ($) => - seq($._hash_symbol, /\/((\/[^#])|[^\n])+\/#/), - - _multiline_regex_literal: ($) => - seq($._hash_symbol, /\/\n/, /(\/[^#]|[^/])*?\n\/#/), - - _oneline_regex_literal: ($) => - token( - prec( - PRECS.regex, - seq( - "/", - token.immediate(/[^ \t\n]?[^/\n]*[^ \t\n/]/), - token.immediate("/") - ) - ) - ), - //////////////////////////////// - // Types - https://docs.swift.org/swift-book/ReferenceManual/Types.html - //////////////////////////////// - type_annotation: ($) => - seq(":", field("type", $._possibly_implicitly_unwrapped_type)), - _possibly_implicitly_unwrapped_type: ($) => - choice($.type, $.implicitly_unwrapped_type), - implicitly_unwrapped_type: ($) => - seq(field("name", $.type), token.immediate("!")), - type: ($) => - prec.right( - PRECS.ty, - seq(field("modifiers", optional($.type_modifiers)), field("name", $.unannotated_type)) - ), - unannotated_type: ($) => - prec.right( - PRECS.ty, - choice( - $.user_type, - $.tuple_type, - $.function_type, - $.array_type, - $.dictionary_type, - $.optional_type, - $.metatype, - $.opaque_type, - $.existential_type, - $.protocol_composition_type, - $.type_parameter_pack, - $.type_pack_expansion, - $.suppressed_constraint - ) - ), - // The grammar just calls this whole thing a `type-identifier` but that's a bit confusing. - user_type: ($) => sep1(field("part", $.simple_user_type), $._dot), - simple_user_type: ($) => - prec.right( - PRECS.ty, - seq( - field("name", alias($.simple_identifier, $.type_identifier)), - field("arguments", optional($.type_arguments)) - ) - ), - tuple_type: ($) => - choice( - seq( - "(", - optional(sep1Opt(field("element", $.tuple_type_item), ",")), - ")" - ), - field("element", alias($.parenthesized_type, $.tuple_type_item)) - ), - tuple_type_item: ($) => - prec( - PRECS.expr, - seq( - optional($._tuple_type_item_identifier), - field("modifiers", optional($.parameter_modifiers)), - field("type", $.type) - ) - ), - _tuple_type_item_identifier: ($) => - prec( - PRECS.expr, - seq( - optional(field("external_name", $.wildcard_pattern)), - field("name", $.simple_identifier), - ":" - ) - ), - function_type: ($) => - seq( - field("params", choice($.tuple_type, $.unannotated_type)), - field("async", optional($._async_keyword)), - field("throws", optional(choice($.throws_clause, $.throws))), - $._arrow_operator, - field("return_type", $.type) - ), - array_type: ($) => seq("[", field("element", $.type), "]"), - dictionary_type: ($) => - seq("[", field("key", $.type), ":", field("value", $.type), "]"), - optional_type: ($) => - prec.left( - seq( - field( - "wrapped", - choice($.user_type, $.tuple_type, $.array_type, $.dictionary_type) - ), - repeat1(alias($._immediate_quest, "?")) - ) - ), - metatype: ($) => seq(field("name", $.unannotated_type), ".", choice("Type", "Protocol")), - _quest: ($) => "?", - _immediate_quest: ($) => token.immediate("?"), - opaque_type: ($) => prec.right(seq("some", field("name", $.unannotated_type))), - existential_type: ($) => prec.right(seq("any", field("name", $.unannotated_type))), - type_parameter_pack: ($) => prec.left(seq("each", field("name", $.unannotated_type))), - type_pack_expansion: ($) => prec.left(seq("repeat", field("name", $.unannotated_type))), - protocol_composition_type: ($) => - prec.left( - seq( - field("type", $.unannotated_type), - repeat1(seq("&", prec.right(field("type", $.unannotated_type)))) - ) - ), - suppressed_constraint: ($) => - prec.right( - seq( - "~", - field("suppressed", alias($.simple_identifier, $.type_identifier)) - ) - ), - //////////////////////////////// - // Expressions - https://docs.swift.org/swift-book/ReferenceManual/Expressions.html - //////////////////////////////// - expression: ($) => - prec( - PRECS.expr, - choice( - $.simple_identifier, - $._unary_expression, - $._binary_expression, - $.ternary_expression, - $._primary_expression, - $.if_statement, - $.switch_statement, - $.assignment, - $.value_parameter_pack, - $.value_pack_expansion, - $.optional_chain_marker - ) - ), - optional_chain_marker: ($) => - seq(field("expr", $.expression), alias($._immediate_quest, "?")), - // Unary expressions - _unary_expression: ($) => - choice( - $.postfix_expression, - $.call_expression, - $.macro_invocation, - $.constructor_expression, - $.navigation_expression, - $.prefix_expression, - $.as_expression, - $.selector_expression, - $.open_start_range_expression, - $.open_end_range_expression, - $.directive, - $.diagnostic - ), - postfix_expression: ($) => - prec.left( - PRECS.postfix_operations, - seq( - field("target", $.expression), - field("operation", $._postfix_unary_operator) - ) - ), - constructor_expression: ($) => - prec( - PRECS.call, - seq( - field( - "constructed_type", - choice($.array_type, $.dictionary_type, $.user_type) - ), - field("suffix", $.constructor_suffix) - ) - ), - parenthesized_type: ($) => - seq( - "(", - field("type", choice($.opaque_type, $.existential_type, $.dictionary_type)), - ")" - ), - navigation_expression: ($) => - prec.left( - PRECS.navigation, - seq( - field( - "target", - choice( - $._navigable_type_expression, - $.expression, - $.parenthesized_type - ) - ), - field("suffix", $.navigation_suffix) - ) - ), - _navigable_type_expression: ($) => - choice($.user_type, $.array_type, $.dictionary_type), - open_start_range_expression: ($) => - prec.right( - PRECS.range, - seq( - $._range_operator, - prec.right(PRECS.range_suffix, field("end", $.expression)) - ) - ), - _range_operator: ($) => - choice($._open_ended_range_operator, $._three_dot_operator), - open_end_range_expression: ($) => - prec.right( - PRECS.range, - seq(field("start", $.expression), $._three_dot_operator) - ), - prefix_expression: ($) => - prec.left( - PRECS.prefix_operations, - seq( - field("operation", $._prefix_unary_operator), - field( - "target", - choice( - $.expression, - alias(choice("async", "if", "switch"), $.expression) - ) - ) - ) - ), - as_expression: ($) => - prec.left( - PRECS.as, - seq(field("expr", $.expression), field("operator", $.as_operator), field("type", $.type)) - ), - selector_expression: ($) => - seq( - $._hash_symbol, - "selector", - "(", - optional(choice("getter:", "setter:")), - field("expr", $.expression), - ")" - ), - // Binary expressions - _binary_expression: ($) => - choice( - $.multiplicative_expression, - $.additive_expression, - $.range_expression, - $.infix_expression, - $.nil_coalescing_expression, - $.check_expression, - $.equality_expression, - $.comparison_expression, - $.conjunction_expression, - $.disjunction_expression, - $.bitwise_operation - ), - multiplicative_expression: ($) => - prec.left( - PRECS.multiplication, - seq( - field("lhs", $.expression), - field("op", $._multiplicative_operator), - field("rhs", $.expression) - ) - ), - additive_expression: ($) => - prec.left( - PRECS.addition, - seq( - field("lhs", $.expression), - field("op", $._additive_operator), - field("rhs", $.expression) - ) - ), - range_expression: ($) => - prec.right( - PRECS.range, - seq( - field("start", $.expression), - field("op", $._range_operator), - field("end", $._expr_hack_at_ternary_binary_suffix) - ) - ), - infix_expression: ($) => - prec.left( - PRECS.infix_operations, - seq( - field("lhs", $.expression), - field("op", $.custom_operator), - field("rhs", $._expr_hack_at_ternary_binary_suffix) - ) - ), - nil_coalescing_expression: ($) => - prec.right( - PRECS.nil_coalescing, - seq( - field("value", $.expression), - $._nil_coalescing_operator, - field("if_nil", $._expr_hack_at_ternary_binary_suffix) - ) - ), - check_expression: ($) => - prec.left( - PRECS.check, - seq( - field("target", $.expression), - field("op", $._is_operator), - field("type", $.type) - ) - ), - comparison_expression: ($) => - prec.left( - seq( - field("lhs", $.expression), - field("op", $._comparison_operator), - field("rhs", $._expr_hack_at_ternary_binary_suffix) - ) - ), - equality_expression: ($) => - prec.left( - PRECS.equality, - seq( - field("lhs", $.expression), - field("op", $._equality_operator), - field("rhs", $._expr_hack_at_ternary_binary_suffix) - ) - ), - conjunction_expression: ($) => - prec.left( - PRECS.conjunction, - seq( - field("lhs", $.expression), - field("op", $._conjunction_operator), - field("rhs", $._expr_hack_at_ternary_binary_suffix) - ) - ), - disjunction_expression: ($) => - prec.left( - PRECS.disjunction, - seq( - field("lhs", $.expression), - field("op", $._disjunction_operator), - field("rhs", $._expr_hack_at_ternary_binary_suffix) - ) - ), - bitwise_operation: ($) => - prec.left( - seq( - field("lhs", $.expression), - field("op", $._bitwise_binary_operator), - field("rhs", $._expr_hack_at_ternary_binary_suffix) - ) - ), - custom_operator: ($) => choice(token(/[\/]+[*]+/), $._custom_operator), - // Suffixes - navigation_suffix: ($) => - seq( - $._dot, - field("suffix", choice($.simple_identifier, $.integer_literal)) - ), - call_suffix: ($) => - prec( - PRECS.call_suffix, - choice( - field("arguments", $.value_arguments), - prec.dynamic(-1, $._fn_call_lambda_arguments), // Prefer to treat `foo() { }` as one call not two - seq(field("arguments", $.value_arguments), $._fn_call_lambda_arguments) - ) - ), - constructor_suffix: ($) => - prec( - PRECS.call_suffix, - choice( - field("arguments", alias($._constructor_value_arguments, $.value_arguments)), - prec.dynamic(-1, $._fn_call_lambda_arguments), // As above - seq( - field("arguments", alias($._constructor_value_arguments, $.value_arguments)), - $._fn_call_lambda_arguments - ) - ) - ), - _constructor_value_arguments: ($) => - seq("(", optional(sep1Opt(field("argument", $.value_argument), ",")), ")"), - _fn_call_lambda_arguments: ($) => - sep1(field("lambda", $.lambda_literal), seq(field("name", $.simple_identifier), ":")), - type_arguments: ($) => prec.left(seq("<", sep1Opt(field("argument", $.type), ","), ">")), - value_arguments: ($) => - seq( - choice( - seq("(", optional(sep1Opt(field("argument", $.value_argument), ",")), ")"), - seq("[", optional(sep1Opt(field("argument", $.value_argument), ",")), "]") - ) - ), - value_argument_label: ($) => - prec.left( - field("name", choice( - $.simple_identifier, - // We don't rely on $._contextual_simple_identifier here because - // these don't usually fall into that category. - alias("if", $.simple_identifier), - alias("switch", $.simple_identifier) - )) - ), - value_argument: ($) => - prec.left( - seq( - field("type_modifiers", optional($.type_modifiers)), - choice( - repeat1( - seq(field("reference_specifier", $.value_argument_label), ":") - ), - seq( - optional(seq(field("name", $.value_argument_label), ":")), - field("value", $.expression) - ) - ) - ) - ), - try_expression: ($) => - prec.right( - PRECS["try"], - seq( - field("operator", $.try_operator), - field( - "expr", - choice( - // Prefer direct calls, e.g. `try foo()`, over indirect like `try a ? b() : c`. This allows us to have - // left associativity for the direct calls, which is technically wrong but is the only way to resolve the - // ambiguity of `if foo { ... }` in the correct direction. - prec.right(-2, $.expression), - prec.left(0, $._binary_expression), - prec.left(0, $.call_expression), - // Similarly special case the ternary expression, where `try` may come earlier than it is actually needed. - // When the parser just encounters some identifier after a `try`, it should prefer the `call_expression` (so - // this should be lower in priority than that), but when we encounter an ambiguous expression that might be - // either `try (foo() ? ...)` or `(try foo()) ? ...`, we should prefer the former. We accomplish that by - // giving it a _static precedence_ of -1 but a _dynamic precedence_ of 1. - prec.dynamic(1, prec.left(-1, $.ternary_expression)) - ) - ) - ) - ), - await_expression: ($) => - prec.right( - PRECS.await, - seq( - $._await_operator, - field( - "expr", - choice( - // Prefer direct calls over indirect (same as with `try`). - prec.right(-2, $.expression), - prec.left(0, $.call_expression), - // Special case ternary to `await` the whole thing (same as with `try`). - prec.dynamic(1, prec.left(-1, $.ternary_expression)) - ) - ) - ) - ), - _await_operator: ($) => alias("await", "await"), - ternary_expression: ($) => - prec.right( - PRECS.ternary, - seq( - field("condition", $.expression), - $._quest, - field("if_true", $.expression), - ":", - field("if_false", $._expr_hack_at_ternary_binary_suffix) - ) - ), - _expr_hack_at_ternary_binary_suffix: ($) => - prec.left( - PRECS.ternary_binary_suffix, - choice( - $.expression, - alias($.expr_hack_at_ternary_binary_call, $.call_expression) - ) - ), - expr_hack_at_ternary_binary_call: ($) => - seq( - field("function", $.expression), - field("suffix", alias($.expr_hack_at_ternary_binary_call_suffix, $.call_suffix)) - ), - expr_hack_at_ternary_binary_call_suffix: ($) => - prec(PRECS.call_suffix, field("arguments", $.value_arguments)), - call_expression: ($) => - prec( - PRECS.call, - prec.dynamic(DYNAMIC_PRECS.call, seq(field("function", $.expression), field("suffix", $.call_suffix))) - ), - macro_invocation: ($) => - prec( - PRECS.call, - prec.dynamic( - DYNAMIC_PRECS.call, - seq( - $._hash_symbol, - field("name", $.simple_identifier), - field("type_parameters", optional($.type_parameters)), - field("suffix", $.call_suffix) - ) - ) - ), - _primary_expression: ($) => - choice( - $.tuple_expression, - $._basic_literal, - $.lambda_literal, - $.special_literal, - $.playground_literal, - $.array_literal, - $.dictionary_literal, - $.self_expression, - $.super_expression, - $.try_expression, - $.await_expression, - $.referenceable_operator, - $.key_path_expression, - $.key_path_string_expression, - prec.right( - PRECS.fully_open_range, - alias($._three_dot_operator, $.fully_open_range) - ) - ), - tuple_expression: ($) => - prec.right( - PRECS.tuple, - seq( - "(", - sep1Opt(field("element", $.tuple_expression_item), ","), - ")" - ) - ), - tuple_expression_item: ($) => - seq( - optional(seq(field("name", $.simple_identifier), ":")), - field("value", $.expression) - ), - array_literal: ($) => - seq("[", optional(sep1Opt(field("element", $.expression), ",")), "]"), - dictionary_literal: ($) => - seq( - "[", - choice(":", sep1Opt(field("element", $.dictionary_literal_item), ",")), - optional(","), - "]" - ), - dictionary_literal_item: ($) => - seq(field("key", $.expression), ":", field("value", $.expression)), - special_literal: ($) => - seq( - $._hash_symbol, - choice( - "file", - "fileID", - "filePath", - "line", - "column", - "function", - "dsohandle" - ) - ), - playground_literal: ($) => - seq( - $._hash_symbol, - field("kind", choice("colorLiteral", "fileLiteral", "imageLiteral")), - "(", - sep1Opt(field("argument", $.playground_literal_argument), ","), - ")" - ), - playground_literal_argument: ($) => - seq(field("name", $.simple_identifier), ":", field("value", $.expression)), - lambda_literal: ($) => - prec.left( - PRECS.lambda, - seq( - choice("{", "^{"), - optional($._lambda_type_declaration), - optional($._statements), - "}" - ) - ), - _lambda_type_declaration: ($) => - seq( - repeat(field("attribute", $.attribute)), - prec(PRECS.expr, optional(field("captures", $.capture_list))), - optional(field("type", $.lambda_function_type)), - "in" - ), - capture_list: ($) => seq("[", sep1Opt(field("item", $.capture_list_item), ","), "]"), - capture_list_item: ($) => - choice( - field("name", $.self_expression), - prec( - PRECS.expr, - seq( - field("ownership", optional($.ownership_modifier)), - field("name", $.simple_identifier), - optional(seq($._equal_sign, field("value", $.expression))) - ) - ) - ), - lambda_function_type: ($) => - prec( - PRECS.expr, - seq( - choice( - field("params", $.lambda_function_type_parameters), - seq("(", field("params", optional($.lambda_function_type_parameters)), ")") - ), - field("async", optional($._async_keyword)), - field("throws", optional(choice($.throws_clause, $.throws))), - optional( - seq( - $._arrow_operator, - field("return_type", $._possibly_implicitly_unwrapped_type) - ) - ) - ) - ), - lambda_function_type_parameters: ($) => sep1Opt(field("parameter", $.lambda_parameter), ","), - lambda_parameter: ($) => - seq( - choice( - field("name", $.self_expression), - prec(PRECS.expr, field("name", $.simple_identifier)), - prec( - PRECS.expr, - seq( - optional(field("external_name", $.simple_identifier)), - field("name", $.simple_identifier), - ":", - field("modifiers", optional($.parameter_modifiers)), - field("type", $._possibly_implicitly_unwrapped_type) - ) - ) - ) - ), - self_expression: ($) => "self", - super_expression: ($) => seq("super"), - _else_options: ($) => choice(field("else_branch", $.block), field("else_branch", $.if_statement)), - if_statement: ($) => - prec.right( - PRECS["if"], - seq( - "if", - sep1(field("condition", $.if_condition), ","), - field("body", $.block), - optional(seq(alias($["else"], "else"), $._else_options)) - ) - ), - if_condition: ($) => - field("kind", choice($.if_let_binding, $.expression, $.availability_condition)), - if_let_binding: ($) => - seq( - $._direct_or_indirect_binding, - optional(seq($._equal_sign, field("value", $.expression))), - field("where", optional($.where_clause)) - ), - guard_statement: ($) => - prec.right( - PRECS["if"], - seq( - "guard", - sep1(field("condition", $.if_condition), ","), - alias($["else"], "else"), - field("body", $.block) - ) - ), - switch_statement: ($) => - prec.right( - PRECS["switch"], - seq( - "switch", - field("expr", $.expression), - "{", - repeat(field("entry", $.switch_entry)), - "}" - ) - ), - switch_entry: ($) => - seq( - field("modifiers", optional($.modifiers)), - choice( - seq( - "case", - field("pattern", $.switch_pattern), - field("where", optional($.where_clause)), - repeat(seq(",", field("pattern", $.switch_pattern))) - ), - field("default", $.default_keyword) - ), - ":", - $._statements, - optional("fallthrough") - ), - switch_pattern: ($) => field("pattern", alias($._binding_pattern_with_expr, $.pattern)), - do_statement: ($) => - prec.right(PRECS["do"], seq("do", field("body", $.block), repeat(field("catch", $.catch_block)))), - catch_block: ($) => - seq( - field("keyword", $.catch_keyword), - field("error", optional(alias($._binding_pattern_no_expr, $.pattern))), - field("where", optional($.where_clause)), - field("body", $.block) - ), - where_clause: ($) => prec.left(seq(field("keyword", $.where_keyword), field("expr", $.expression))), - key_path_expression: ($) => - prec.right( - PRECS.keypath, - seq( - "\\", - field("type", optional( - choice($.simple_user_type, $.array_type, $.dictionary_type) - )), - repeat(seq(".", field("component", $.key_path_component))) - ) - ), - key_path_string_expression: ($) => - prec.left(seq($._hash_symbol, "keyPath", "(", field("expr", $.expression), ")")), - key_path_component: ($) => - prec.left( - choice( - seq(field("name", $.simple_identifier), repeat(field("postfix", $.key_path_postfix))), - repeat1(field("postfix", $.key_path_postfix)) - ) - ), - key_path_postfix: ($) => - choice( - "?", - field("force_unwrap", $.bang), - "self", - seq("[", optional(sep1(field("argument", $.value_argument), ",")), "]") - ), - try_operator: ($) => - prec.right( - seq("try", choice(optional($._try_operator_type), $._fake_try_bang)) - ), - _try_operator_type: ($) => - choice(token.immediate("!"), token.immediate("?")), - _assignment_and_operator: ($) => - choice("+=", "-=", "*=", "/=", "%=", $._equal_sign), - _equality_operator: ($) => choice("!=", "!==", $._eq_eq, "==="), - _comparison_operator: ($) => choice("<", ">", "<=", ">="), - _three_dot_operator: ($) => alias("...", "..."), // Weird alias to satisfy highlight queries - _open_ended_range_operator: ($) => alias("..<", "..<"), - _is_operator: ($) => "is", - _additive_operator: ($) => - choice( - alias($._plus_then_ws, "+"), - alias($._minus_then_ws, "-"), - "+", - "-" - ), - // The `/` operator conflicts with a regex literal (which itself appears to conflict with a - // comment, for some reason), so we must give it equivalent token precedence. - _multiplicative_operator: ($) => - choice("*", alias(token(prec(PRECS.regex, "/")), "/"), "%"), - as_operator: ($) => choice($._as, $._as_quest, $._as_bang), - _prefix_unary_operator: ($) => - prec.right( - choice( - "++", - "--", - "-", - "+", - $.bang, - "&", - "~", - $._dot, - $.custom_operator - ) - ), - _bitwise_binary_operator: ($) => choice("&", "|", "^", "<<", ">>"), - _postfix_unary_operator: ($) => choice("++", "--", $.bang), - directly_assignable_expression: ($) => field("expr", $.expression), - - //////////////////////////////// - // Statements - https://docs.swift.org/swift-book/ReferenceManual/Statements.html - //////////////////////////////// - _statements: ($) => - prec.left( - // Left precedence is required in switch statements - seq( - field("statement", $._local_statement), - repeat(seq($._semi, field("statement", $._local_statement))), - optional($._semi) - ) - ), - _local_statement: ($) => - choice( - $.expression, - $.local_declaration, - $._labeled_statement, - $.control_transfer_statement - ), - _top_level_statement: ($) => - choice( - $.expression, - $.global_declaration, - $._labeled_statement, - $._throw_statement - ), - block: ($) => prec(PRECS.block, seq("{", optional($._statements), "}")), - _labeled_statement: ($) => - seq( - optional($.statement_label), - choice( - $.for_statement, - $.while_statement, - $.repeat_while_statement, - $.do_statement, - $.if_statement, - $.guard_statement, - $.switch_statement - ) - ), - statement_label: ($) => token(/[a-zA-Z_][a-zA-Z_0-9]*:/), - for_statement: ($) => - prec( - PRECS.loop, - seq( - "for", - field("try", optional($.try_operator)), - optional($._await_operator), - field("item", alias($._binding_pattern_no_expr, $.pattern)), - field("type", optional($.type_annotation)), - "in", - field("collection", $._for_statement_collection), - field("where", optional($.where_clause)), - field("body", $.block) - ) - ), - _for_statement_collection: ($) => - // If this expression has "await", this triggers some special-cased logic to prefer function calls. We prefer - // the opposite, though, since function calls may contain trailing code blocks, which are undesirable here. - // - // To fix that, we simply undo the special casing by defining our own `await_expression`. - choice($.expression, alias($.for_statement_await, $.await_expression)), - for_statement_await: ($) => seq($._await_operator, field("expr", $.expression)), - - while_statement: ($) => - prec( - PRECS.loop, - seq( - "while", - sep1(field("condition", $.if_condition), ","), - field("body", $.block) - ) - ), - repeat_while_statement: ($) => - prec( - PRECS.loop, - seq( - "repeat", - field("body", $.block), - // Make sure we make it to the `while` before assuming this is a parameter pack. - repeat($._implicit_semi), - "while", - sep1(field("condition", $.if_condition), ",") - ) - ), - control_transfer_statement: ($) => - choice( - prec.right( - PRECS.control_transfer, - seq(field("kind", $.throw_keyword), field("result", $.expression)) - ), - prec.right( - PRECS.control_transfer, - seq( - field("kind", $._optionally_valueful_control_keyword), - field("result", optional($.expression)) - ) - ) - ), - _throw_statement: ($) => seq($.throw_keyword, $.expression), - throw_keyword: ($) => "throw", - _optionally_valueful_control_keyword: ($) => - choice("return", "continue", "break", "yield"), - assignment: ($) => - prec.left( - PRECS.assignment, - seq( - field("target", $.directly_assignable_expression), - field("operator", $._assignment_and_operator), - field("result", $.expression) - ) - ), - value_parameter_pack: ($) => - prec.left(PRECS.parameter_pack, seq("each", field("expr", $.expression))), - value_pack_expansion: ($) => - prec.left(PRECS.parameter_pack, seq("repeat", field("expr", $.expression))), - availability_condition: ($) => - seq( - $._hash_symbol, - choice("available", "unavailable"), - "(", - sep1Opt($._availability_argument, ","), - ")" - ), - _availability_argument: ($) => - choice(seq(field("platform", $.identifier), sep1(field("version", $.integer_literal), ".")), "*"), - //////////////////////////////// - // Declarations - https://docs.swift.org/swift-book/ReferenceManual/Declarations.html - //////////////////////////////// - global_declaration: ($) => - choice( - $.import_declaration, - $.property_declaration, - $.typealias_declaration, - $.function_declaration, - $.init_declaration, - $.class_declaration, - $.protocol_declaration, - $.operator_declaration, - $.precedence_group_declaration, - $.associatedtype_declaration, - $.macro_declaration - ), - type_level_declaration: ($) => - choice( - $.import_declaration, - $.property_declaration, - $.typealias_declaration, - $.function_declaration, - $.init_declaration, - $.class_declaration, - $.protocol_declaration, - $.deinit_declaration, - $.subscript_declaration, - $.operator_declaration, - $.precedence_group_declaration, - $.associatedtype_declaration - ), - local_declaration: ($) => - choice( - alias($._local_property_declaration, $.property_declaration), - alias($._local_typealias_declaration, $.typealias_declaration), - alias($._local_function_declaration, $.function_declaration), - alias($._local_class_declaration, $.class_declaration) - ), - _local_property_declaration: ($) => - seq( - field("modifiers", optional($._locally_permitted_modifiers)), - $._modifierless_property_declaration - ), - _local_typealias_declaration: ($) => - seq( - field("modifiers", optional($._locally_permitted_modifiers)), - $._modifierless_typealias_declaration - ), - _local_function_declaration: ($) => - seq( - field("modifiers", optional($._locally_permitted_modifiers)), - $._modifierless_function_declaration - ), - _local_class_declaration: ($) => - seq( - field("modifiers", optional($._locally_permitted_modifiers)), - $._modifierless_class_declaration - ), - import_declaration: ($) => - seq( - field("modifiers", optional($.modifiers)), - "import", - optional(field("scoped_import_kind", $._import_kind)), - field("name", $.identifier) - ), - _import_kind: ($) => - choice( - "typealias", - "struct", - "class", - "enum", - "protocol", - "let", - "var", - "func" - ), - protocol_property_declaration: ($) => - prec.right( - seq( - field("modifiers", optional($.modifiers)), - field("name", alias($._binding_kind_and_pattern, $.pattern)), - field("type", optional($.type_annotation)), - field("type_constraints", optional($.type_constraints)), - field("requirements", $.protocol_property_requirements) - ) - ), - protocol_property_requirements: ($) => - seq("{", repeat(field("accessor", choice($.getter_specifier, $.setter_specifier))), "}"), - property_declaration: ($) => - seq(field("modifiers", optional($.modifiers)), $._modifierless_property_declaration), - _modifierless_property_declaration: ($) => - prec.right( - seq( - $._possibly_async_binding_pattern_kind, - sep1(field("declarator", $.property_binding), ",") - ) - ), - property_binding: ($) => - prec.left( - seq( - field("name", alias($._no_expr_pattern_already_bound, $.pattern)), - field("type", optional($.type_annotation)), - field("type_constraints", optional($.type_constraints)), - optional( - choice( - $._expression_with_willset_didset, - $._expression_without_willset_didset, - field("observers", $.willset_didset_block), - field("computed_value", $.computed_property) - ) - ) - ) - ), - _expression_with_willset_didset: ($) => - prec.dynamic( - 1, - seq( - $._equal_sign, - field("value", $.expression), - field("observers", $.willset_didset_block) - ) - ), - _expression_without_willset_didset: ($) => - seq($._equal_sign, field("value", $.expression)), - willset_didset_block: ($) => - choice( - seq("{", field("willset", $.willset_clause), field("didset", optional($.didset_clause)), "}"), - seq("{", field("didset", $.didset_clause), field("willset", optional($.willset_clause)), "}") - ), - willset_clause: ($) => - seq( - field("modifiers", optional($.modifiers)), - "willSet", - optional(seq("(", field("parameter", $.simple_identifier), ")")), - field("body", $.block) - ), - didset_clause: ($) => - seq( - field("modifiers", optional($.modifiers)), - "didSet", - optional(seq("(", field("parameter", $.simple_identifier), ")")), - field("body", $.block) - ), - typealias_declaration: ($) => - seq(field("modifiers", optional($.modifiers)), $._modifierless_typealias_declaration), - _modifierless_typealias_declaration: ($) => - seq( - "typealias", - field("name", alias($.simple_identifier, $.type_identifier)), - field("type_parameters", optional($.type_parameters)), - $._equal_sign, - field("value", $.type) - ), - function_declaration: ($) => - prec.right( - seq($._bodyless_function_declaration, field("body", $.block)) - ), - _modifierless_function_declaration: ($) => - prec.right( - seq( - $._modifierless_function_declaration_no_body, - field("body", $.block) - ) - ), - _bodyless_function_declaration: ($) => - seq( - field("modifiers", optional($.modifiers)), - optional("class"), // XXX: This should be possible in non-last position, but that creates parsing ambiguity - $._modifierless_function_declaration_no_body - ), - _modifierless_function_declaration_no_body: ($) => - prec.right( - seq( - $._non_constructor_function_decl, - field("type_parameters", optional($.type_parameters)), - $._function_value_parameters, - field("async", optional($._async_keyword)), - field("throws", optional(choice($.throws_clause, $.throws))), - optional( - seq( - $._arrow_operator, - field("return_type", $._possibly_implicitly_unwrapped_type) - ) - ), - field("type_constraints", optional($.type_constraints)) - ) - ), - macro_declaration: ($) => - seq( - $._macro_head, - field("name", $.simple_identifier), - field("type_parameters", optional($.type_parameters)), - $._macro_signature, - optional(field("definition", $.macro_definition)), - field("type_constraints", optional($.type_constraints)) - ), - _macro_head: ($) => seq(field("modifiers", optional($.modifiers)), "macro"), - _macro_signature: ($) => - seq( - $._function_value_parameters, - optional(seq($._arrow_operator, field("return_type", $.unannotated_type))) - ), - macro_definition: ($) => - seq( - $._equal_sign, - field("body", choice($.expression, $.external_macro_definition)) - ), - - external_macro_definition: ($) => - seq($._hash_symbol, "externalMacro", field("arguments", $.value_arguments)), - - class_declaration: ($) => - seq(field("modifiers", optional($.modifiers)), $._modifierless_class_declaration), - _modifierless_class_declaration: ($) => - prec.right( - choice( - seq( - field("declaration_kind", choice("class", "struct", "actor")), - field("name", alias($.simple_identifier, $.type_identifier)), - field("type_parameters", optional($.type_parameters)), - optional(seq(":", $._inheritance_specifiers)), - field("type_constraints", optional($.type_constraints)), - field("body", $.class_body) - ), - seq( - field("declaration_kind", "extension"), - field("name", $.unannotated_type), - field("type_parameters", optional($.type_parameters)), - optional(seq(":", $._inheritance_specifiers)), - field("type_constraints", optional($.type_constraints)), - field("body", $.class_body) - ), - seq( - optional("indirect"), - field("declaration_kind", "enum"), - field("name", alias($.simple_identifier, $.type_identifier)), - field("type_parameters", optional($.type_parameters)), - optional(seq(":", $._inheritance_specifiers)), - field("type_constraints", optional($.type_constraints)), - field("body", $.enum_class_body) - ) - ) - ), - class_body: ($) => seq("{", optional($._class_member_declarations), "}"), - _inheritance_specifiers: ($) => - prec.left(sep1($._annotated_inheritance_specifier, choice(",", "&"))), - _annotated_inheritance_specifier: ($) => - seq(repeat(field("attribute", $.attribute)), field("inherits", $.inheritance_specifier)), - inheritance_specifier: ($) => - prec.left( - field( - "inherits_from", - choice($.user_type, $.function_type, $.suppressed_constraint) - ) - ), - type_parameters: ($) => - seq( - "<", - sep1Opt(field("parameter", $.type_parameter), ","), - field("constraints", optional($.type_constraints)), - ">" - ), - type_parameter: ($) => - seq( - field("modifiers", optional($.type_parameter_modifiers)), - field("name", $._type_parameter_possibly_packed), - optional(seq(":", field("type", $.type))) - ), - _type_parameter_possibly_packed: ($) => - choice( - alias($.simple_identifier, $.type_identifier), - $.type_parameter_pack - ), - - type_constraints: ($) => - prec.right(seq(field("keyword", $.where_keyword), sep1Opt(field("constraint", $.type_constraint), ","))), - type_constraint: ($) => - field("constraint", choice($.inheritance_constraint, $.equality_constraint)), - inheritance_constraint: ($) => - seq( - repeat(field("attribute", $.attribute)), - field("constrained_type", $._constrained_type), - ":", - field("inherits_from", $._possibly_implicitly_unwrapped_type) - ), - equality_constraint: ($) => - seq( - repeat(field("attribute", $.attribute)), - field("constrained_type", $._constrained_type), - choice($._equal_sign, $._eq_eq), - field("must_equal", $.type) - ), - _constrained_type: ($) => choice($.identifier, $.nested_type_identifier), - nested_type_identifier: ($) => - seq( - field("base", $.unannotated_type), - optional(seq(".", sep1(field("member", $.simple_identifier), "."))) - ), - _class_member_separator: ($) => choice($._semi, $._multiline_comment), - _class_member_declarations: ($) => - seq( - sep1(field("member", $.type_level_declaration), $._class_member_separator), - optional($._class_member_separator) - ), - _function_value_parameters: ($) => - repeat1( - seq("(", optional(sep1Opt(field("parameter", $.function_parameter), ",")), ")") - ), - function_parameter: ($) => - seq( - field("attribute", optional($.attribute)), - field("parameter", $.parameter), - optional(seq($._equal_sign, field("default_value", $.expression))) - ), - parameter: ($) => - seq( - optional(field("external_name", $.simple_identifier)), - field("name", $.simple_identifier), - ":", - field("modifiers", optional($.parameter_modifiers)), - field("type", $._possibly_implicitly_unwrapped_type), - optional($._three_dot_operator) - ), - _non_constructor_function_decl: ($) => - seq( - "func", - field("name", choice($.simple_identifier, $.referenceable_operator)) - ), - referenceable_operator: ($) => - field("operator", choice( - $.custom_operator, - $._comparison_operator, - $._additive_operator, - $._multiplicative_operator, - $._equality_operator, - $._assignment_and_operator, - "++", - "--", - $.bang, - "~", - "|", - "^", - "<<", - ">>", - "&" - )), - // Hide the fact that certain symbols come from the custom scanner by aliasing them to their - // string variants. This keeps us from having to see them in the syntax tree (which would be - // noisy) but allows callers to refer to them as nodes by their text form like with any - // operator. - _equal_sign: ($) => alias($._eq_custom, "="), - _eq_eq: ($) => alias($._eq_eq_custom, "=="), - _dot: ($) => alias($._dot_custom, "."), - _arrow_operator: ($) => alias($._arrow_operator_custom, "->"), - _conjunction_operator: ($) => alias($._conjunction_operator_custom, "&&"), - _disjunction_operator: ($) => alias($._disjunction_operator_custom, "||"), - _nil_coalescing_operator: ($) => - alias($._nil_coalescing_operator_custom, "??"), - _as: ($) => alias($._as_custom, "as"), - _as_quest: ($) => alias($._as_quest_custom, "as?"), - _as_bang: ($) => alias($._as_bang_custom, "as!"), - _hash_symbol: ($) => alias($._hash_symbol_custom, "#"), - bang: ($) => choice($._bang_custom, "!"), - _async_keyword: ($) => alias($._async_keyword_custom, "async"), - _async_modifier: ($) => token("async"), - throws: ($) => choice($._throws_keyword, $._rethrows_keyword), - throws_clause: ($) => - seq($._throws_keyword, "(", field("type", $.unannotated_type), ")"), - enum_class_body: ($) => - seq("{", repeat(field("member", choice($.enum_entry, $.type_level_declaration))), "}"), - enum_entry: ($) => - seq( - field("modifiers", optional($.modifiers)), - optional("indirect"), - "case", - sep1(field("case", $.enum_case_entry), ","), - optional(";") - ), - enum_case_entry: ($) => - seq( - field("name", $.simple_identifier), - optional($._enum_entry_suffix) - ), - _enum_entry_suffix: ($) => - choice( - field("data_contents", $.enum_type_parameters), - seq($._equal_sign, field("raw_value", $.expression)) - ), - enum_type_parameters: ($) => - seq( - "(", - optional(sep1(field("parameter", $.enum_type_parameter), ",")), - ")" - ), - enum_type_parameter: ($) => - seq( - optional( - seq(optional(field("external_name", $.wildcard_pattern)), field("name", $.simple_identifier), ":") - ), - field("type", $.type), - optional(seq($._equal_sign, field("default_value", $.expression))) - ), - protocol_declaration: ($) => - prec.right( - seq( - field("modifiers", optional($.modifiers)), - "protocol", - field("name", alias($.simple_identifier, $.type_identifier)), - field("type_parameters", optional($.type_parameters)), - optional(seq(":", $._inheritance_specifiers)), - field("type_constraints", optional($.type_constraints)), - field("body", $.protocol_body) - ) - ), - protocol_body: ($) => - seq("{", optional($._protocol_member_declarations), "}"), - _protocol_member_declarations: ($) => - seq(sep1(field("member", $.protocol_member_declaration), $._semi), optional($._semi)), - protocol_member_declaration: ($) => - choice( - $.protocol_function_declaration, - $.init_declaration, - $.deinit_declaration, - $.protocol_property_declaration, - $.typealias_declaration, - $.associatedtype_declaration, - $.subscript_declaration - ), - protocol_function_declaration: ($) => - seq( - $._bodyless_function_declaration, - optional(field("body", $.block)) - ), - init_declaration: ($) => - prec.right( - seq( - field("modifiers", optional($.modifiers)), - optional("class"), - "init", - optional(choice($._quest, field("bang", $.bang))), - field("type_parameters", optional($.type_parameters)), - $._function_value_parameters, - field("async", optional($._async_keyword)), - field("throws", optional(choice($.throws_clause, $.throws))), - field("type_constraints", optional($.type_constraints)), - optional(field("body", $.block)) - ) - ), - deinit_declaration: ($) => - prec.right( - seq(field("modifiers", optional($.modifiers)), "deinit", field("body", $.block)) - ), - subscript_declaration: ($) => - prec.right( - seq( - field("modifiers", optional($.modifiers)), - "subscript", - field("type_parameters", optional($.type_parameters)), - $._function_value_parameters, - optional( - seq( - $._arrow_operator, - field("return_type", $._possibly_implicitly_unwrapped_type) - ) - ), - field("type_constraints", optional($.type_constraints)), - field("body", $.computed_property) - ) - ), - computed_property: ($) => - seq( - "{", - choice( - optional($._statements), - repeat( - field("accessor", choice($.computed_getter, $.computed_setter, $.computed_modify)) - ) - ), - "}" - ), - computed_getter: ($) => - seq(repeat(field("attribute", $.attribute)), field("specifier", $.getter_specifier), optional(field("body", $.block))), - computed_modify: ($) => - seq(repeat(field("attribute", $.attribute)), field("specifier", $.modify_specifier), optional(field("body", $.block))), - computed_setter: ($) => - seq( - repeat(field("attribute", $.attribute)), - field("specifier", $.setter_specifier), - optional(seq("(", field("parameter", $.simple_identifier), ")")), - optional(field("body", $.block)) - ), - getter_specifier: ($) => - seq(field("mutation", optional($.mutation_modifier)), "get", optional($._getter_effects)), - setter_specifier: ($) => seq(field("mutation", optional($.mutation_modifier)), "set"), - modify_specifier: ($) => seq(field("mutation", optional($.mutation_modifier)), "_modify"), - _getter_effects: ($) => - repeat1(field("effect", choice(alias($._async_keyword, $.async_keyword), $.throws_clause, $.throws))), - operator_declaration: ($) => - seq( - field("kind", choice("prefix", "infix", "postfix")), - "operator", - field("name", $.referenceable_operator), - optional(seq(":", field("precedence_group", $.simple_identifier))), - field("body", optional($.deprecated_operator_declaration_body)) - ), - // The Swift compiler no longer accepts these, but some very old code still uses it. - deprecated_operator_declaration_body: ($) => - seq("{", repeat(field("entry", choice($.simple_identifier, $._basic_literal))), "}"), - precedence_group_declaration: ($) => - seq( - "precedencegroup", - field("name", $.simple_identifier), - "{", - field("attributes", optional($.precedence_group_attributes)), - "}" - ), - precedence_group_attributes: ($) => repeat1(field("attribute", $.precedence_group_attribute)), - precedence_group_attribute: ($) => - seq( - field("name", $.simple_identifier), - ":", - field("value", choice($.simple_identifier, $.boolean_literal)) - ), - associatedtype_declaration: ($) => - seq( - field("modifiers", optional($.modifiers)), - "associatedtype", - field("name", alias($.simple_identifier, $.type_identifier)), - optional(seq(":", field("must_inherit", $.type))), - field("type_constraints", optional($.type_constraints)), - optional(seq($._equal_sign, field("default_value", $.type))) - ), - //////////////////////////////// - // Attributes - https://docs.swift.org/swift-book/ReferenceManual/Attributes.html - //////////////////////////////// - attribute: ($) => - seq( - "@", - field("name", $.user_type), - // attribute arguments are a mess of special cases, maybe this is good enough? - optional(seq("(", sep1Opt($._attribute_argument, ","), ")")) - ), - _attribute_argument: ($) => - choice( - // labeled function parameters, used in custom property wrappers - seq(field("argument_name", $.simple_identifier), ":", field("argument", $.expression)), - // Unlabeled function parameters, simple identifiers, or `*` - field("argument", $.expression), - // References to param names (used in `@objc(foo:bar:)`) - repeat1(seq(field("param_ref", $.simple_identifier), ":")), - // Version restrictions (iOS 3.4.5, Swift 5.0.0) - seq(repeat1(field("platform", $.simple_identifier)), sep1(field("version", $.integer_literal), ".")) - ), - //////////////////////////////// - // Patterns - https://docs.swift.org/swift-book/ReferenceManual/Patterns.html - //////////////////////////////// - _universally_allowed_pattern: ($) => - choice( - $.wildcard_pattern, - $.tuple_pattern, - $.type_casting_pattern, - $.case_pattern - ), - _bound_identifier: ($) => field("bound_identifier", $.simple_identifier), - - _binding_pattern_no_expr: ($) => - seq( - field("kind", choice( - $._universally_allowed_pattern, - $.binding_pattern, - $._bound_identifier - )), - optional($._quest) - ), - _no_expr_pattern_already_bound: ($) => - seq( - field("kind", choice($._universally_allowed_pattern, $._bound_identifier)), - optional($._quest) - ), - _binding_pattern_with_expr: ($) => - seq( - field("kind", choice( - $._universally_allowed_pattern, - $.binding_pattern, - $.expression - )), - optional($._quest) - ), - _non_binding_pattern_with_expr: ($) => - seq( - field("kind", choice($._universally_allowed_pattern, $.expression)), - optional($._quest) - ), - _direct_or_indirect_binding: ($) => - seq( - choice( - field("pattern", alias($._binding_kind_and_pattern, $.pattern)), - seq("case", field("pattern", alias($._binding_pattern_no_expr, $.pattern))) - ), - field("type", optional($.type_annotation)) - ), - value_binding_pattern: ($) => field("mutability", choice("var", "let")), - _possibly_async_binding_pattern_kind: ($) => - seq(optional($._async_modifier), field("binding", $.value_binding_pattern)), - _binding_kind_and_pattern: ($) => - seq( - $._possibly_async_binding_pattern_kind, - $._no_expr_pattern_already_bound - ), - wildcard_pattern: ($) => "_", - tuple_pattern_item: ($) => - choice( - seq( - field("name", $.simple_identifier), - ":", - field("pattern", alias($._binding_pattern_with_expr, $.pattern)) - ), - field("pattern", alias($._binding_pattern_with_expr, $.pattern)) - ), - tuple_pattern: ($) => seq("(", sep1Opt(field("item", $.tuple_pattern_item), ","), ")"), - case_pattern: ($) => - seq( - optional("case"), - optional(field("type", $.user_type)), // XXX this should just be _type but that creates ambiguity - field("dot", $._dot), - field("name", $.simple_identifier), - optional(field("arguments", $.tuple_pattern)) - ), - type_casting_pattern: ($) => - choice( - seq("is", field("type", $.type)), - seq(field("pattern", alias($._binding_pattern_no_expr, $.pattern)), $._as, field("type", $.type)) - ), - binding_pattern: ($) => - seq( - seq(optional("case"), field("binding", $.value_binding_pattern)), - field("pattern", alias($._no_expr_pattern_already_bound, $.pattern)) - ), - - // ========== - // Modifiers - // ========== - modifiers: ($) => - repeat1( - prec.left( - field("modifier", choice($._non_local_scope_modifier, $._locally_permitted_modifiers)) - ) - ), - _locally_permitted_modifiers: ($) => - repeat1(choice($.attribute, $._locally_permitted_modifier)), - parameter_modifiers: ($) => repeat1(field("modifier", $.parameter_modifier)), - _modifier: ($) => - choice($._non_local_scope_modifier, $._locally_permitted_modifier), - _non_local_scope_modifier: ($) => - choice( - $.member_modifier, - $.visibility_modifier, - $.function_modifier, - $.mutation_modifier, - $.property_modifier, - $.parameter_modifier - ), - _locally_permitted_modifier: ($) => - choice( - $.ownership_modifier, - $.inheritance_modifier, - $.property_behavior_modifier - ), - property_behavior_modifier: ($) => "lazy", - type_modifiers: ($) => repeat1(field("attribute", $.attribute)), - member_modifier: ($) => - choice("override", "convenience", "required", "nonisolated"), - visibility_modifier: ($) => - seq( - choice( - "public", - "private", - "internal", - "fileprivate", - "open", - "package" - ), - optional(seq("(", "set", ")")) - ), - type_parameter_modifiers: ($) => repeat1(field("attribute", $.attribute)), - function_modifier: ($) => choice("infix", "postfix", "prefix"), - mutation_modifier: ($) => choice("mutating", "nonmutating"), - property_modifier: ($) => - choice("static", "dynamic", "optional", "class", "distributed"), - inheritance_modifier: ($) => choice("final"), - parameter_modifier: ($) => - choice( - "inout", - "@escaping", - "@autoclosure", - $._parameter_ownership_modifier - ), - ownership_modifier: ($) => - choice("weak", "unowned", "unowned(safe)", "unowned(unsafe)"), - _parameter_ownership_modifier: ($) => choice("borrowing", "consuming"), - use_site_target: ($) => - seq( - choice( - "property", - "get", - "set", - "receiver", - "param", - "setparam", - "delegate" - ), - ":" - ), - directive: ($) => - prec.right( - PRECS.comment, - choice( - seq(alias($._directive_if, "#if"), field("condition", $.compilation_condition)), - seq(alias($._directive_elseif, "#elseif"), field("condition", $.compilation_condition)), - seq(alias($._directive_else, "#else")), - seq(alias($._directive_endif, "#endif")) - ) - ), - compilation_condition: ($) => - prec.right( - choice( - seq("os", "(", field("name", $.simple_identifier), ")"), - seq("arch", "(", field("name", $.simple_identifier), ")"), - seq( - "swift", - "(", - $._comparison_operator, - sep1(field("version", $.integer_literal), "."), - ")" - ), - seq( - "compiler", - "(", - $._comparison_operator, - sep1(field("version", $.integer_literal), "."), - ")" - ), - seq("canImport", "(", sep1(field("name", $.simple_identifier), "."), ")"), - seq("targetEnvironment", "(", field("name", $.simple_identifier), ")"), - field("value", $.boolean_literal), - field("name", $.simple_identifier), - seq("(", field("inner", $.compilation_condition), ")"), - seq("!", field("operand", $.compilation_condition)), - seq( - field("lhs", $.compilation_condition), - $._conjunction_operator, - field("rhs", $.compilation_condition) - ), - seq( - field("lhs", $.compilation_condition), - $._disjunction_operator, - field("rhs", $.compilation_condition) - ) - ) - ), - diagnostic: ($) => - prec( - PRECS.comment, - seq( - $._hash_symbol, - choice( - // Using regexes here, rather than actually validating the string literal, because complex string literals - // cannot be used inside `token()` and we need that to ensure we get the right precedence. - seq(/error([^\r\n]*)/), - seq(/warning([^\r\n]*)/), - seq(/sourceLocation([^\r\n]*)/) - ) - ) - ), - // Dumping ground for any nodes that used to exist in the grammar, but have since been removed for whatever - // reason. - // Neovim applies updates non-atomically to the parser and the queries. Meanwhile, `tree-sitter` rejects any query - // that contains any unrecognized nodes. Putting those two facts together, we see that we must never remove nodes - // that once existed. - unused_for_backward_compatibility: ($) => - choice(alias("unused1", "try?"), alias("unused2", "try!")), - }, -}); -function sep1(rule, separator) { - return seq(rule, repeat(seq(separator, rule))); -} -function sep1Opt(rule, separator) { - return seq(rule, repeat(seq(separator, rule)), optional(separator)); -} - -function tree_sitter_version_supports_emoji() { - try { - return ( - TREE_SITTER_CLI_VERSION_MAJOR > 0 || - TREE_SITTER_CLI_VERSION_MINOR > 20 || - TREE_SITTER_CLI_VERSION_PATCH >= 5 - ); - } catch (err) { - if (err instanceof ReferenceError) { - return false; - } else { - throw err; - } - } -} diff --git a/unified/extractor/tree-sitter-swift/node-types.yml b/unified/extractor/tree-sitter-swift/node-types.yml deleted file mode 100644 index 35dfb985b4a8..000000000000 --- a/unified/extractor/tree-sitter-swift/node-types.yml +++ /dev/null @@ -1,875 +0,0 @@ -supertypes: - expression: - - additive_expression - - array_literal - - as_expression - - assignment - - await_expression - - bin_literal - - bitwise_operation - - boolean_literal - - call_expression - - check_expression - - comparison_expression - - conjunction_expression - - constructor_expression - - diagnostic - - dictionary_literal - - directive - - disjunction_expression - - equality_expression - - fully_open_range - - hex_literal - - if_statement - - infix_expression - - integer_literal - - key_path_expression - - key_path_string_expression - - lambda_literal - - line_string_literal - - macro_invocation - - multi_line_string_literal - - multiplicative_expression - - navigation_expression - - "nil" - - nil_coalescing_expression - - oct_literal - - open_end_range_expression - - open_start_range_expression - - optional_chain_marker - - playground_literal - - postfix_expression - - prefix_expression - - range_expression - - raw_string_literal - - real_literal - - referenceable_operator - - regex_literal - - selector_expression - - self_expression - - simple_identifier - - special_literal - - super_expression - - switch_statement - - ternary_expression - - try_expression - - tuple_expression - - value_pack_expansion - - value_parameter_pack - global_declaration: - - associatedtype_declaration - - class_declaration - - function_declaration - - import_declaration - - init_declaration - - macro_declaration - - operator_declaration - - precedence_group_declaration - - property_declaration - - protocol_declaration - - typealias_declaration - local_declaration: - - class_declaration - - function_declaration - - property_declaration - - typealias_declaration - protocol_member_declaration: - - associatedtype_declaration - - deinit_declaration - - init_declaration - - protocol_function_declaration - - protocol_property_declaration - - subscript_declaration - - typealias_declaration - type_level_declaration: - - associatedtype_declaration - - class_declaration - - deinit_declaration - - function_declaration - - import_declaration - - init_declaration - - operator_declaration - - precedence_group_declaration - - property_declaration - - protocol_declaration - - subscript_declaration - - typealias_declaration - unannotated_type: - - array_type - - dictionary_type - - existential_type - - function_type - - metatype - - opaque_type - - optional_type - - protocol_composition_type - - suppressed_constraint - - tuple_type - - type_pack_expansion - - type_parameter_pack - - user_type - -named: - additive_expression: - lhs: expression - op: ["+", "-"] - rhs: expression - array_literal: - element*: expression - array_type: - element: type - as_expression: - expr: expression - operator: as_operator - type: type - as_operator: - assignment: - operator: ["%=", "*=", "+=", "-=", "/=", "="] - result: expression - target: directly_assignable_expression - associatedtype_declaration: - default_value?: type - modifiers?: modifiers - must_inherit?: type - name: type_identifier - type_constraints?: type_constraints - async_keyword: - attribute: - argument*: expression - argument_name*: simple_identifier - name: user_type - param_ref*: simple_identifier - platform*: simple_identifier - version*: integer_literal - availability_condition: - platform*: identifier - version*: integer_literal - await_expression: - expr: expression - bang: - bin_literal: - binding_pattern: - binding: value_binding_pattern - pattern: pattern - bitwise_operation: - lhs: expression - op: ["&", "<<", ">>", "^", "|"] - rhs: expression - block: - statement*: [control_transfer_statement, do_statement, expression, for_statement, guard_statement, local_declaration, repeat_while_statement, statement_label, while_statement] - boolean_literal: - call_expression: - function: expression - suffix: call_suffix - call_suffix: - arguments?: value_arguments - lambda*: lambda_literal - name*: simple_identifier - capture_list: - item+: capture_list_item - capture_list_item: - name: [self_expression, simple_identifier] - ownership?: ownership_modifier - value?: expression - case_pattern: - arguments?: tuple_pattern - dot: "." - name: simple_identifier - type?: user_type - catch_block: - body: block - error?: pattern - keyword: catch_keyword - where?: where_clause - catch_keyword: - check_expression: - op: "is" - target: expression - type: type - class_body: - member*: type_level_declaration - class_declaration: - attribute*: attribute - body: [class_body, enum_class_body] - declaration_kind: ["actor", "class", "enum", "extension", "struct"] - inherits*: inheritance_specifier - modifiers*: [attribute, inheritance_modifier, modifiers, ownership_modifier, property_behavior_modifier] - name: [type_identifier, unannotated_type] - type_constraints?: type_constraints - type_parameters?: type_parameters - comment: - comparison_expression: - lhs: expression - op: ["<", "<=", ">", ">="] - rhs: expression - compilation_condition: - inner?: compilation_condition - lhs?: compilation_condition - name*: simple_identifier - operand?: compilation_condition - rhs?: compilation_condition - value?: boolean_literal - version*: integer_literal - computed_getter: - attribute*: attribute - body?: block - specifier: getter_specifier - computed_modify: - attribute*: attribute - body?: block - specifier: modify_specifier - computed_property: - accessor*: [computed_getter, computed_modify, computed_setter] - statement*: [control_transfer_statement, do_statement, expression, for_statement, guard_statement, local_declaration, repeat_while_statement, statement_label, while_statement] - computed_setter: - attribute*: attribute - body?: block - parameter?: simple_identifier - specifier: setter_specifier - conjunction_expression: - lhs: expression - op: "&&" - rhs: expression - constructor_expression: - constructed_type: [array_type, dictionary_type, user_type] - suffix: constructor_suffix - constructor_suffix: - arguments?: value_arguments - lambda*: lambda_literal - name*: simple_identifier - control_transfer_statement: - kind: ["break", "continue", "return", throw_keyword, "yield"] - result?: expression - custom_operator: - default_keyword: - deinit_declaration: - body: block - modifiers?: modifiers - deprecated_operator_declaration_body: - entry*: [bin_literal, boolean_literal, hex_literal, integer_literal, line_string_literal, multi_line_string_literal, "nil", oct_literal, raw_string_literal, real_literal, regex_literal, simple_identifier] - diagnostic: - dictionary_literal: - element*: dictionary_literal_item - dictionary_literal_item: - key: expression - value: expression - dictionary_type: - key: type - value: type - didset_clause: - body: block - modifiers?: modifiers - parameter?: simple_identifier - directive: - condition?: compilation_condition - directly_assignable_expression: - expr: expression - disjunction_expression: - lhs: expression - op: "||" - rhs: expression - do_statement: - body: block - catch*: catch_block - enum_case_entry: - data_contents?: enum_type_parameters - name: simple_identifier - raw_value?: expression - enum_class_body: - member*: [enum_entry, type_level_declaration] - enum_entry: - case+: enum_case_entry - modifiers?: modifiers - enum_type_parameter: - default_value?: expression - external_name?: wildcard_pattern - name?: simple_identifier - type: type - enum_type_parameters: - parameter*: enum_type_parameter - equality_constraint: - attribute*: attribute - constrained_type: [identifier, nested_type_identifier] - must_equal: type - equality_expression: - lhs: expression - op: ["!=", "!==", "==", "==="] - rhs: expression - existential_type: - name: unannotated_type - external_macro_definition: - arguments: value_arguments - for_statement: - body: block - collection: expression - item: pattern - try?: try_operator - type?: type_annotation - where?: where_clause - fully_open_range: - function_declaration: - async?: "async" - body: block - modifiers*: [attribute, inheritance_modifier, modifiers, ownership_modifier, property_behavior_modifier] - name: [referenceable_operator, simple_identifier] - parameter*: function_parameter - return_type?: [implicitly_unwrapped_type, type] - throws?: [throws, throws_clause] - type_constraints?: type_constraints - type_parameters?: type_parameters - function_modifier: - function_parameter: - attribute?: attribute - default_value?: expression - parameter: parameter - function_type: - async?: "async" - params: unannotated_type - return_type: type - throws?: [throws, throws_clause] - getter_specifier: - effect*: [async_keyword, throws, throws_clause] - mutation?: mutation_modifier - guard_statement: - body: block - condition+: if_condition - hex_literal: - identifier: - part+: simple_identifier - if_condition: - kind: [availability_condition, expression, if_let_binding] - if_let_binding: - pattern: pattern - type?: type_annotation - value?: expression - where?: where_clause - if_statement: - body: block - condition+: if_condition - else_branch?: [block, if_statement] - implicitly_unwrapped_type: - name: type - import_declaration: - modifiers?: modifiers - name: identifier - scoped_import_kind?: ["class", "enum", "func", "let", "protocol", "struct", "typealias", "var"] - infix_expression: - lhs: expression - op: custom_operator - rhs: expression - inheritance_constraint: - attribute*: attribute - constrained_type: [identifier, nested_type_identifier] - inherits_from: [implicitly_unwrapped_type, type] - inheritance_modifier: - inheritance_specifier: - inherits_from: [function_type, suppressed_constraint, user_type] - init_declaration: - async?: "async" - bang?: bang - body?: block - modifiers?: modifiers - parameter*: function_parameter - throws?: [throws, throws_clause] - type_constraints?: type_constraints - type_parameters?: type_parameters - integer_literal: - interpolated_expression: - name?: value_argument_label - reference_specifier*: value_argument_label - type_modifiers?: type_modifiers - value?: expression - key_path_component: - name?: simple_identifier - postfix*: key_path_postfix - key_path_expression: - component*: key_path_component - type?: [array_type, dictionary_type, simple_user_type] - key_path_postfix: - argument*: value_argument - force_unwrap?: bang - key_path_string_expression: - expr: expression - lambda_function_type: - async?: "async" - params?: lambda_function_type_parameters - return_type?: [implicitly_unwrapped_type, type] - throws?: [throws, throws_clause] - lambda_function_type_parameters: - parameter+: lambda_parameter - lambda_literal: - attribute*: attribute - captures?: capture_list - statement*: [control_transfer_statement, do_statement, expression, for_statement, guard_statement, local_declaration, repeat_while_statement, statement_label, while_statement] - type?: lambda_function_type - lambda_parameter: - external_name?: simple_identifier - modifiers?: parameter_modifiers - name: [self_expression, simple_identifier] - type?: [implicitly_unwrapped_type, type] - line_str_text: - line_string_literal: - interpolation*: interpolated_expression - text*: [line_str_text, str_escaped_char] - macro_declaration: - definition?: macro_definition - modifiers?: modifiers - name: simple_identifier - parameter*: function_parameter - return_type?: unannotated_type - type_constraints?: type_constraints - type_parameters?: type_parameters - macro_definition: - body: [expression, external_macro_definition] - macro_invocation: - name: simple_identifier - suffix: call_suffix - type_parameters?: type_parameters - member_modifier: - metatype: - name: unannotated_type - modifiers: - modifier+: [attribute, function_modifier, inheritance_modifier, member_modifier, mutation_modifier, ownership_modifier, parameter_modifier, property_behavior_modifier, property_modifier, visibility_modifier] - modify_specifier: - mutation?: mutation_modifier - multi_line_str_text: - multi_line_string_literal: - interpolation*: interpolated_expression - text*: ["\"", multi_line_str_text, str_escaped_char] - multiline_comment: - multiplicative_expression: - lhs: expression - op: ["%", "*", "/"] - rhs: expression - mutation_modifier: - navigation_expression: - suffix: navigation_suffix - target: [array_type, dictionary_type, expression, parenthesized_type, user_type] - navigation_suffix: - suffix: [integer_literal, simple_identifier] - nested_type_identifier: - base: unannotated_type - member*: simple_identifier - nil_coalescing_expression: - if_nil: expression - value: expression - oct_literal: - opaque_type: - name: unannotated_type - open_end_range_expression: - start: expression - open_start_range_expression: - end: expression - operator_declaration: - body?: deprecated_operator_declaration_body - kind: ["infix", "postfix", "prefix"] - name: referenceable_operator - precedence_group?: simple_identifier - optional_chain_marker: - expr: expression - optional_type: - wrapped: [array_type, dictionary_type, tuple_type, user_type] - ownership_modifier: - parameter: - external_name?: simple_identifier - modifiers?: parameter_modifiers - name: simple_identifier - type: [implicitly_unwrapped_type, type] - parameter_modifier: - parameter_modifiers: - modifier+: parameter_modifier - parenthesized_type: - type: [dictionary_type, existential_type, opaque_type] - pattern: - binding?: value_binding_pattern - bound_identifier?: simple_identifier - kind: [binding_pattern, case_pattern, expression, tuple_pattern, type_casting_pattern, wildcard_pattern] - playground_literal: - argument+: playground_literal_argument - kind: ["colorLiteral", "fileLiteral", "imageLiteral"] - playground_literal_argument: - name: simple_identifier - value: expression - postfix_expression: - operation: ["++", "--", bang] - target: expression - precedence_group_attribute: - name: simple_identifier - value: [boolean_literal, simple_identifier] - precedence_group_attributes: - attribute+: precedence_group_attribute - precedence_group_declaration: - attributes?: precedence_group_attributes - name: simple_identifier - prefix_expression: - operation: ["&", "+", "++", "-", "--", ".", bang, custom_operator, "~"] - target: expression - property_behavior_modifier: - property_binding: - computed_value?: computed_property - name: pattern - observers?: willset_didset_block - type?: type_annotation - type_constraints?: type_constraints - value?: expression - property_declaration: - binding: value_binding_pattern - declarator+: property_binding - modifiers*: [attribute, inheritance_modifier, modifiers, ownership_modifier, property_behavior_modifier] - property_modifier: - protocol_body: - member*: protocol_member_declaration - protocol_composition_type: - type+: unannotated_type - protocol_declaration: - attribute*: attribute - body: protocol_body - inherits*: inheritance_specifier - modifiers?: modifiers - name: type_identifier - type_constraints?: type_constraints - type_parameters?: type_parameters - protocol_function_declaration: - async?: "async" - body?: block - modifiers?: modifiers - name: [referenceable_operator, simple_identifier] - parameter*: function_parameter - return_type?: [implicitly_unwrapped_type, type] - throws?: [throws, throws_clause] - type_constraints?: type_constraints - type_parameters?: type_parameters - protocol_property_declaration: - modifiers?: modifiers - name: pattern - requirements: protocol_property_requirements - type?: type_annotation - type_constraints?: type_constraints - protocol_property_requirements: - accessor*: [getter_specifier, setter_specifier] - range_expression: - end: expression - op: ["...", "..<"] - start: expression - raw_str_continuing_indicator: - raw_str_end_part: - raw_str_interpolation: - interpolation+: interpolated_expression - start: raw_str_interpolation_start - raw_str_interpolation_start: - raw_str_part: - raw_string_literal: - continuing*: raw_str_continuing_indicator - interpolation*: raw_str_interpolation - text+: [raw_str_end_part, raw_str_part] - real_literal: - referenceable_operator: - operator: ["!=", "!==", "%", "%=", "&", "*", "*=", "+", "++", "+=", "-", "--", "-=", "/", "/=", "<", "<<", "<=", "=", "==", "===", ">", ">=", ">>", "^", bang, custom_operator, "|", "~"] - regex_literal: - repeat_while_statement: - body: block - condition+: if_condition - selector_expression: - expr: expression - self_expression: - setter_specifier: - mutation?: mutation_modifier - shebang_line: - simple_identifier: - simple_user_type: - arguments?: type_arguments - name: type_identifier - source_file: - shebang?: shebang_line - statement*: [do_statement, expression, for_statement, global_declaration, guard_statement, repeat_while_statement, statement_label, throw_keyword, while_statement] - special_literal: - statement_label: - str_escaped_char: - subscript_declaration: - body: computed_property - modifiers?: modifiers - parameter*: function_parameter - return_type?: [implicitly_unwrapped_type, type] - type_constraints?: type_constraints - type_parameters?: type_parameters - super_expression: - suppressed_constraint: - suppressed: type_identifier - switch_entry: - default?: default_keyword - modifiers?: modifiers - pattern*: switch_pattern - statement+: [control_transfer_statement, do_statement, expression, for_statement, guard_statement, local_declaration, repeat_while_statement, statement_label, while_statement] - where?: where_clause - switch_pattern: - pattern: pattern - switch_statement: - entry*: switch_entry - expr: expression - ternary_expression: - condition: expression - if_false: expression - if_true: expression - throw_keyword: - throws: - throws_clause: - type: unannotated_type - try_expression: - expr: expression - operator: try_operator - try_operator: - tuple_expression: - element+: tuple_expression_item - tuple_expression_item: - name?: simple_identifier - value: expression - tuple_pattern: - item+: tuple_pattern_item - tuple_pattern_item: - name?: simple_identifier - pattern: pattern - tuple_type: - element*: tuple_type_item - tuple_type_item: - external_name?: wildcard_pattern - modifiers?: parameter_modifiers - name?: simple_identifier - type: [dictionary_type, existential_type, opaque_type, type] - type: - modifiers?: type_modifiers - name: unannotated_type - type_annotation: - type: [implicitly_unwrapped_type, type] - type_arguments: - argument+: type - type_casting_pattern: - pattern?: pattern - type: type - type_constraint: - constraint: [equality_constraint, inheritance_constraint] - type_constraints: - constraint+: type_constraint - keyword: where_keyword - type_identifier: - type_modifiers: - attribute+: attribute - type_pack_expansion: - name: unannotated_type - type_parameter: - modifiers?: type_parameter_modifiers - name: [type_identifier, type_parameter_pack] - type?: type - type_parameter_modifiers: - attribute+: attribute - type_parameter_pack: - name: unannotated_type - type_parameters: - constraints?: type_constraints - parameter+: type_parameter - typealias_declaration: - modifiers*: [attribute, inheritance_modifier, modifiers, ownership_modifier, property_behavior_modifier] - name: type_identifier - type_parameters?: type_parameters - value: type - user_type: - part+: simple_user_type - value_argument: - name?: value_argument_label - reference_specifier*: value_argument_label - type_modifiers?: type_modifiers - value?: expression - value_argument_label: - name: simple_identifier - value_arguments: - argument*: value_argument - value_binding_pattern: - mutability: ["let", "var"] - value_pack_expansion: - expr: expression - value_parameter_pack: - expr: expression - visibility_modifier: - where_clause: - expr: expression - keyword: where_keyword - where_keyword: - while_statement: - body: block - condition+: if_condition - wildcard_pattern: - willset_clause: - body: block - modifiers?: modifiers - parameter?: simple_identifier - willset_didset_block: - didset?: didset_clause - willset?: willset_clause - -unnamed: - - "?" - - "!" - - "!=" - - "!==" - - "\"" - - "\"\"\"" - - "#" - - "#else" - - "#elseif" - - "#endif" - - "#if" - - "%" - - "%=" - - "&" - - "&&" - - "(" - - ")" - - "*" - - "*=" - - "+" - - "++" - - "+=" - - "," - - "-" - - "--" - - "-=" - - "->" - - "." - - "..." - - "..<" - - "/" - - "/=" - - ":" - - ";" - - "<" - - "<<" - - "<=" - - "=" - - "==" - - "===" - - ">" - - ">=" - - ">>" - - "?" - - "??" - - "@" - - "@autoclosure" - - "@escaping" - - "Protocol" - - "Type" - - "[" - - "\\" - - "\\(" - - "]" - - "^" - - "^{" - - "_modify" - - "actor" - - "any" - - "arch" - - "as" - - "as!" - - "as?" - - "associatedtype" - - "async" - - "available" - - "await" - - "borrowing" - - "break" - - "canImport" - - "case" - - "class" - - "colorLiteral" - - "column" - - "compiler" - - "consuming" - - "continue" - - "convenience" - - "deinit" - - "didSet" - - "distributed" - - "do" - - "dsohandle" - - "dynamic" - - "each" - - "else" - - "enum" - - "extension" - - "externalMacro" - - "fallthrough" - - "false" - - "file" - - "fileID" - - "fileLiteral" - - "filePath" - - "fileprivate" - - "final" - - "for" - - "func" - - "function" - - "get" - - "getter:" - - "guard" - - "if" - - "imageLiteral" - - "import" - - "in" - - "indirect" - - "infix" - - "init" - - "inout" - - "internal" - - "is" - - "keyPath" - - "lazy" - - "let" - - "line" - - "macro" - - "mutating" - - "nil" - - "nonisolated" - - "nonmutating" - - "open" - - "operator" - - "optional" - - "os" - - "override" - - "package" - - "postfix" - - "precedencegroup" - - "prefix" - - "private" - - "protocol" - - "public" - - "repeat" - - "required" - - "return" - - "selector" - - "self" - - "set" - - "setter:" - - "some" - - "static" - - "struct" - - "subscript" - - "super" - - "swift" - - "switch" - - "targetEnvironment" - - "true" - - "try" - - "typealias" - - "u" - - "unavailable" - - "unowned" - - "unowned(safe)" - - "unowned(unsafe)" - - "var" - - "weak" - - "while" - - "willSet" - - "yield" - - "{" - - "|" - - "||" - - "}" - - "~" diff --git a/unified/extractor/tree-sitter-swift/package.json b/unified/extractor/tree-sitter-swift/package.json deleted file mode 100644 index 68dcf7cc42fc..000000000000 --- a/unified/extractor/tree-sitter-swift/package.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "name": "tree-sitter-swift", - "version": "0.7.2", - "description": "A tree-sitter grammar for the Swift programming language.", - "main": "bindings/node/index.js", - "types": "bindings/node", - "scripts": { - "install": "node-gyp-build", - "prestart": "tree-sitter build --wasm", - "start": "tree-sitter playground", - "test": "node --test bindings/node/*_test.js" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/alex-pinkus/tree-sitter-swift.git" - }, - "tree-sitter": [ - { - "scope": "source.swift", - "file-types": [ - "swift" - ], - "injection-regex": "swift", - "highlights": "queries/highlights.scm", - "locals": "queries/locals.scm", - "injections": "queries/injections.scm" - } - ], - "keywords": [ - "parser", - "swift" - ], - "files": [ - "grammar.js", - "tree-sitter.json", - "binding.gyp", - "prebuilds/**", - "bindings/node/*", - "queries/*", - "scripts/*", - "src/**" - ], - "author": "Alex Pinkus ", - "license": "MIT", - "bugs": { - "url": "https://github.com/alex-pinkus/tree-sitter-swift/issues" - }, - "homepage": "https://github.com/alex-pinkus/tree-sitter-swift#readme", - "dependencies": { - "node-addon-api": "^8.0.0", - "node-gyp-build": "^4.8.0", - "tree-sitter-cli": "^0.23", - "which": "2.0.2" - }, - "peerDependencies": { - "tree-sitter": "^0.22.1" - }, - "peerDependenciesMeta": { - "tree_sitter": { - "optional": true - } - }, - "devDependencies": { - "node-gyp": "^10.0.1", - "prebuildify": "^6.0.0", - "prettier": "2.3.2" - } -} diff --git a/unified/extractor/tree-sitter-swift/queries/folds.scm b/unified/extractor/tree-sitter-swift/queries/folds.scm deleted file mode 100644 index ca7f72593aa8..000000000000 --- a/unified/extractor/tree-sitter-swift/queries/folds.scm +++ /dev/null @@ -1,35 +0,0 @@ -; format-ignore -[ - (protocol_body) ; protocol Foo { ... } - (class_body) ; class Foo { ... } - (enum_class_body) ; enum Foo { ... } - (function_body) ; func Foo (...) {...} - (computed_property) ; { ... } - - (computed_getter) ; get { ... } - (computed_setter) ; set { ... } - - (do_statement) - (if_statement) - (for_statement) - (switch_statement) - (while_statement) - (guard_statement) - (switch_entry) - - (type_parameters) ; x - (tuple_type) ; (...) - (array_type) ; [String] - (dictionary_type) ; [Foo: Bar] - - (call_expression) ; callFunc(...) - (tuple_expression) ; ( foo + bar ) - (array_literal) ; [ foo, bar ] - (dictionary_literal) ; [ foo: bar, x: y ] - (lambda_literal) - (willset_didset_block) - (willset_clause) - (didset_clause) - - (import_declaration)+ -] @fold diff --git a/unified/extractor/tree-sitter-swift/queries/highlights.scm b/unified/extractor/tree-sitter-swift/queries/highlights.scm deleted file mode 100644 index 82ad68d4ed1c..000000000000 --- a/unified/extractor/tree-sitter-swift/queries/highlights.scm +++ /dev/null @@ -1,336 +0,0 @@ -[ - "." - ";" - ":" - "," -] @punctuation.delimiter - -[ - "(" - ")" - "[" - "]" - "{" - "}" -] @punctuation.bracket - -; Identifiers -(type_identifier) @type - -[ - (self_expression) - (super_expression) -] @variable.builtin - -; Declarations -[ - "func" - "deinit" -] @keyword.function - -[ - (visibility_modifier) - (member_modifier) - (function_modifier) - (property_modifier) - (parameter_modifier) - (inheritance_modifier) - (mutation_modifier) -] @keyword.modifier - -(simple_identifier) @variable - -(function_declaration - (simple_identifier) @function.method) - -(protocol_function_declaration - name: (simple_identifier) @function.method) - -(init_declaration - "init" @constructor) - -(parameter - external_name: (simple_identifier) @variable.parameter) - -(parameter - name: (simple_identifier) @variable.parameter) - -(type_parameter - (type_identifier) @variable.parameter) - -(inheritance_constraint - (identifier - (simple_identifier) @variable.parameter)) - -(equality_constraint - (identifier - (simple_identifier) @variable.parameter)) - -[ - "protocol" - "extension" - "indirect" - "nonisolated" - "override" - "convenience" - "required" - "some" - "any" - "weak" - "unowned" - "didSet" - "willSet" - "subscript" - "let" - "var" - (throws) - (where_keyword) - (getter_specifier) - (setter_specifier) - (modify_specifier) - (else) - (as_operator) -] @keyword - -[ - "enum" - "struct" - "class" - "typealias" -] @keyword.type - -[ - "async" - "await" -] @keyword.coroutine - -(shebang_line) @keyword.directive - -(class_body - (property_declaration - (pattern - (simple_identifier) @variable.member))) - -(protocol_property_declaration - (pattern - (simple_identifier) @variable.member)) - -(navigation_expression - (navigation_suffix - (simple_identifier) @variable.member)) - -(value_argument - name: (value_argument_label - (simple_identifier) @variable.member)) - -(import_declaration - "import" @keyword.import) - -(enum_entry - "case" @keyword) - -(modifiers - (attribute - "@" @attribute - (user_type - (type_identifier) @attribute))) - -; Function calls -(call_expression - (simple_identifier) @function.call) ; foo() - -(call_expression - ; foo.bar.baz(): highlight the baz() - (navigation_expression - (navigation_suffix - (simple_identifier) @function.call))) - -(call_expression - (prefix_expression - (simple_identifier) @function.call)) ; .foo() - -((navigation_expression - (simple_identifier) @type) ; SomeType.method(): highlight SomeType as a type - (#match? @type "^[A-Z]")) - -(directive) @keyword.directive - -; See https://docs.swift.org/swift-book/documentation/the-swift-programming-language/lexicalstructure/#Keywords-and-Punctuation -[ - (diagnostic) - (availability_condition) - (playground_literal) - (key_path_string_expression) - (selector_expression) - (external_macro_definition) -] @function.macro - -(special_literal) @constant.macro - -; Statements -(for_statement - "for" @keyword.repeat) - -(for_statement - "in" @keyword.repeat) - -[ - "while" - "repeat" - "continue" - "break" -] @keyword.repeat - -(guard_statement - "guard" @keyword.conditional) - -(if_statement - "if" @keyword.conditional) - -(switch_statement - "switch" @keyword.conditional) - -(switch_entry - "case" @keyword) - -(switch_entry - "fallthrough" @keyword) - -(switch_entry - (default_keyword) @keyword) - -"return" @keyword.return - -(ternary_expression - [ - "?" - ":" - ] @keyword.conditional.ternary) - -[ - (try_operator) - "do" - (throw_keyword) - (catch_keyword) -] @keyword.exception - -(statement_label) @label - -; Comments -[ - (comment) - (multiline_comment) -] @comment @spell - -((comment) @comment.documentation - (#match? @comment.documentation "^///[^/]")) - -((comment) @comment.documentation - (#match? @comment.documentation "^///$")) - -((multiline_comment) @comment.documentation - (#match? @comment.documentation "^/[*][*][^*].*[*]/$")) - -; String literals -(line_str_text) @string - -(str_escaped_char) @string.escape - -(multi_line_str_text) @string - -(raw_str_part) @string - -(raw_str_end_part) @string - -(line_string_literal - [ - "\\(" - ")" - ] @punctuation.special) - -(multi_line_string_literal - [ - "\\(" - ")" - ] @punctuation.special) - -(raw_str_interpolation - [ - (raw_str_interpolation_start) - ")" - ] @punctuation.special) - -[ - "\"" - "\"\"\"" -] @string - -; Lambda literals -(lambda_literal - "in" @keyword.operator) - -; Basic literals -[ - (integer_literal) - (hex_literal) - (oct_literal) - (bin_literal) -] @number - -(real_literal) @number.float - -(boolean_literal) @boolean - -"nil" @constant.builtin - -(wildcard_pattern) @character.special - -; Regex literals -(regex_literal) @string.regexp - -; Operators -(custom_operator) @operator - -[ - "+" - "-" - "*" - "/" - "%" - "=" - "+=" - "-=" - "*=" - "/=" - "<" - ">" - "<<" - ">>" - "<=" - ">=" - "++" - "--" - "^" - "&" - "&&" - "|" - "||" - "~" - "%=" - "!=" - "!==" - "==" - "===" - "?" - "??" - "->" - "..<" - "..." - (bang) -] @operator - -(type_arguments - [ - "<" - ">" - ] @punctuation.bracket) diff --git a/unified/extractor/tree-sitter-swift/queries/indents.scm b/unified/extractor/tree-sitter-swift/queries/indents.scm deleted file mode 100644 index ec8f8af95c6f..000000000000 --- a/unified/extractor/tree-sitter-swift/queries/indents.scm +++ /dev/null @@ -1,123 +0,0 @@ -; format-ignore -[ - ; ... refers to the section that will get affected by this indent.begin capture - (protocol_body) ; protocol Foo { ... } - (class_body) ; class Foo { ... } - (enum_class_body) ; enum Foo { ... } - (function_declaration) ; func Foo (...) {...} - (init_declaration) ; init(...) {...} - (deinit_declaration) ; deinit {...} - (computed_property) ; { ... } - (subscript_declaration) ; subscript Foo(...) { ... } - - (computed_getter) ; get { ... } - (computed_setter) ; set { ... } - - (assignment) ; a = b - - (control_transfer_statement) ; return ... - (for_statement) - (while_statement) - (repeat_while_statement) - (do_statement) - (if_statement) - (switch_statement) - (guard_statement) - - (type_parameters) ; x - (tuple_type) ; (...) - (array_type) ; [String] - (dictionary_type) ; [Foo: Bar] - - (call_expression) ; callFunc(...) - (tuple_expression) ; ( foo + bar ) - (array_literal) ; [ foo, bar ] - (dictionary_literal) ; [ foo: bar, x: y ] - (lambda_literal) - (willset_didset_block) - (willset_clause) - (didset_clause) -] @indent.begin - -(init_declaration) @indent.begin - -(init_declaration - [ - "init" - "(" - ] @indent.branch) - -; indentation for init parameters -(init_declaration - ")" @indent.branch @indent.end) - -(init_declaration - (parameter) @indent.begin - (#set! indent.immediate)) - -; @something(...) -(modifiers - (attribute) @indent.begin) - -(function_declaration - (modifiers - . - (attribute) - (_)* @indent.branch) - . - _ @indent.branch - (#not-kind-eq? @indent.branch "type_parameters" "parameter")) - -(ERROR - [ - "<" - "{" - "(" - "[" - ]) @indent.begin - -; if-elseif -(if_statement - (if_statement) @indent.dedent) - -; case Foo: -; default Foo: -; @attribute default Foo: -(switch_entry - . - _ @indent.branch) - -(function_declaration - ")" @indent.branch) - -(type_parameters - ">" @indent.branch @indent.end .) - -(tuple_expression - ")" @indent.branch @indent.end) - -(value_arguments - ")" @indent.branch @indent.end) - -(tuple_type - ")" @indent.branch @indent.end) - -(modifiers - (attribute - ")" @indent.branch @indent.end)) - -[ - "}" - "]" -] @indent.branch @indent.end - -[ - ; (ERROR) - (comment) - (multiline_comment) - (raw_str_part) - (multi_line_string_literal) -] @indent.auto - -(directive) @indent.ignore - diff --git a/unified/extractor/tree-sitter-swift/queries/injections.scm b/unified/extractor/tree-sitter-swift/queries/injections.scm deleted file mode 100644 index 512cfa0d5223..000000000000 --- a/unified/extractor/tree-sitter-swift/queries/injections.scm +++ /dev/null @@ -1,10 +0,0 @@ -; Parse regex syntax within regex literals - -((regex_literal) @injection.content - (#set! injection.language "regex")) - -([ - (comment) - (multiline_comment) -] @injection.content - (#set! injection.language "comment")) diff --git a/unified/extractor/tree-sitter-swift/queries/locals.scm b/unified/extractor/tree-sitter-swift/queries/locals.scm deleted file mode 100644 index 78032a81810b..000000000000 --- a/unified/extractor/tree-sitter-swift/queries/locals.scm +++ /dev/null @@ -1,23 +0,0 @@ -(import_declaration - (identifier) @local.definition.import) - -(function_declaration - name: (simple_identifier) @local.definition.function) - -; Scopes -[ - (statements) - (for_statement) - (while_statement) - (repeat_while_statement) - (do_statement) - (if_statement) - (guard_statement) - (switch_statement) - (property_declaration) - (function_declaration) - (class_declaration) - (protocol_declaration) -] @local.scope - - diff --git a/unified/extractor/tree-sitter-swift/queries/outline.scm b/unified/extractor/tree-sitter-swift/queries/outline.scm deleted file mode 100644 index 31fe5d9d4a43..000000000000 --- a/unified/extractor/tree-sitter-swift/queries/outline.scm +++ /dev/null @@ -1,66 +0,0 @@ -(protocol_declaration - declaration_kind: "protocol" @name - . - _ * @name - . - body: (protocol_body) -) @item - -(class_declaration - declaration_kind: ( - [ - "actor" - "class" - "extension" - "enum" - "struct" - ] - ) @name - . - _ * @name - . - body: (_) -) @item - -(init_declaration - name: "init" @name - . - _ * @name - . - body: (function_body) -) @item - -(deinit_declaration - "deinit" @name) @item - -(function_declaration - "func" @name - . - _ * @name - . - body: (function_body) -) @item - -(class_body - (property_declaration - (value_binding_pattern) @name - name: (pattern) @name - (type_annotation)? @name - ) @item -) - -(enum_class_body - (property_declaration - (value_binding_pattern) @name - name: (pattern) @name - (type_annotation)? @name - ) @item -) - -( - (protocol_function_declaration) @name -) @item - -( - (protocol_property_declaration) @name -) @item diff --git a/unified/extractor/tree-sitter-swift/queries/tags.scm b/unified/extractor/tree-sitter-swift/queries/tags.scm deleted file mode 100644 index 0038571e5d72..000000000000 --- a/unified/extractor/tree-sitter-swift/queries/tags.scm +++ /dev/null @@ -1,51 +0,0 @@ -(class_declaration - name: (type_identifier) @name) @definition.class - -(protocol_declaration - name: (type_identifier) @name) @definition.interface - -(class_declaration - (class_body - [ - (function_declaration - name: (simple_identifier) @name - ) - (subscript_declaration - (parameter (simple_identifier) @name) - ) - (init_declaration "init" @name) - (deinit_declaration "deinit" @name) - ] - ) -) @definition.method - -(protocol_declaration - (protocol_body - [ - (protocol_function_declaration - name: (simple_identifier) @name - ) - (subscript_declaration - (parameter (simple_identifier) @name) - ) - (init_declaration "init" @name) - ] - ) -) @definition.method - -(class_declaration - (class_body - [ - (property_declaration - (pattern (simple_identifier) @name) - ) - ] - ) -) @definition.property - -(property_declaration - (pattern (simple_identifier) @name) -) @definition.property - -(function_declaration - name: (simple_identifier) @name) @definition.function \ No newline at end of file diff --git a/unified/extractor/tree-sitter-swift/queries/textobjects.scm b/unified/extractor/tree-sitter-swift/queries/textobjects.scm deleted file mode 100644 index da689a1b29f6..000000000000 --- a/unified/extractor/tree-sitter-swift/queries/textobjects.scm +++ /dev/null @@ -1,19 +0,0 @@ - - -; MARK: Structure - -(function_declaration - body: (_) @function.inside) @function.around - -; TODO: Classes/structs/enums - - -; MARK: Tests - -; Only matches prefix test. Other conventions -; might be nice to add! -(function_declaration - name: (simple_identifier) @_name - (#match? @_name "^test") -) - diff --git a/unified/extractor/tree-sitter-swift/src/scanner.c b/unified/extractor/tree-sitter-swift/src/scanner.c deleted file mode 100644 index bb2dcac58b28..000000000000 --- a/unified/extractor/tree-sitter-swift/src/scanner.c +++ /dev/null @@ -1,929 +0,0 @@ -#include "tree_sitter/parser.h" -#include -#include - -#define TOKEN_COUNT 33 - -enum TokenType { - BLOCK_COMMENT, - RAW_STR_PART, - RAW_STR_CONTINUING_INDICATOR, - RAW_STR_END_PART, - IMPLICIT_SEMI, - EXPLICIT_SEMI, - ARROW_OPERATOR, - DOT_OPERATOR, - CONJUNCTION_OPERATOR, - DISJUNCTION_OPERATOR, - NIL_COALESCING_OPERATOR, - EQUAL_SIGN, - EQ_EQ, - PLUS_THEN_WS, - MINUS_THEN_WS, - BANG, - THROWS_KEYWORD, - RETHROWS_KEYWORD, - DEFAULT_KEYWORD, - WHERE_KEYWORD, - ELSE_KEYWORD, - CATCH_KEYWORD, - AS_KEYWORD, - AS_QUEST, - AS_BANG, - ASYNC_KEYWORD, - CUSTOM_OPERATOR, - HASH_SYMBOL, - DIRECTIVE_IF, - DIRECTIVE_ELSEIF, - DIRECTIVE_ELSE, - DIRECTIVE_ENDIF, - FAKE_TRY_BANG -}; - -#define OPERATOR_COUNT 20 - -const char* OPERATORS[OPERATOR_COUNT] = { - "->", - ".", - "&&", - "||", - "??", - "=", - "==", - "+", - "-", - "!", - "throws", - "rethrows", - "default", - "where", - "else", - "catch", - "as", - "as?", - "as!", - "async" -}; - -enum IllegalTerminatorGroup { - ALPHANUMERIC, - OPERATOR_SYMBOLS, - OPERATOR_OR_DOT, - NON_WHITESPACE -}; - -const enum IllegalTerminatorGroup OP_ILLEGAL_TERMINATORS[OPERATOR_COUNT] = { - OPERATOR_SYMBOLS, // -> - OPERATOR_OR_DOT, // . - OPERATOR_SYMBOLS, // && - OPERATOR_SYMBOLS, // || - OPERATOR_SYMBOLS, // ?? - OPERATOR_SYMBOLS, // = - OPERATOR_SYMBOLS, // == - NON_WHITESPACE, // + - NON_WHITESPACE, // - - OPERATOR_SYMBOLS, // ! - ALPHANUMERIC, // throws - ALPHANUMERIC, // rethrows - ALPHANUMERIC, // default - ALPHANUMERIC, // where - ALPHANUMERIC, // else - ALPHANUMERIC, // catch - ALPHANUMERIC, // as - OPERATOR_SYMBOLS, // as? - OPERATOR_SYMBOLS, // as! - ALPHANUMERIC // async -}; - -const enum TokenType OP_SYMBOLS[OPERATOR_COUNT] = { - ARROW_OPERATOR, - DOT_OPERATOR, - CONJUNCTION_OPERATOR, - DISJUNCTION_OPERATOR, - NIL_COALESCING_OPERATOR, - EQUAL_SIGN, - EQ_EQ, - PLUS_THEN_WS, - MINUS_THEN_WS, - BANG, - THROWS_KEYWORD, - RETHROWS_KEYWORD, - DEFAULT_KEYWORD, - WHERE_KEYWORD, - ELSE_KEYWORD, - CATCH_KEYWORD, - AS_KEYWORD, - AS_QUEST, - AS_BANG, - ASYNC_KEYWORD -}; - -const uint64_t OP_SYMBOL_SUPPRESSOR[OPERATOR_COUNT] = { - 0, // ARROW_OPERATOR, - 0, // DOT_OPERATOR, - 0, // CONJUNCTION_OPERATOR, - 0, // DISJUNCTION_OPERATOR, - 0, // NIL_COALESCING_OPERATOR, - 0, // EQUAL_SIGN, - 0, // EQ_EQ, - 0, // PLUS_THEN_WS, - 0, // MINUS_THEN_WS, - 1UL << FAKE_TRY_BANG, // BANG, - 0, // THROWS_KEYWORD, - 0, // RETHROWS_KEYWORD, - 0, // DEFAULT_KEYWORD, - 0, // WHERE_KEYWORD, - 0, // ELSE_KEYWORD, - 0, // CATCH_KEYWORD, - 0, // AS_KEYWORD, - 0, // AS_QUEST, - 0, // AS_BANG, - 0, // ASYNC_KEYWORD -}; - -#define RESERVED_OP_COUNT 31 - -const char* RESERVED_OPS[RESERVED_OP_COUNT] = { - "/", - "=", - "-", - "+", - "!", - "*", - "%", - "<", - ">", - "&", - "|", - "^", - "?", - "~", - ".", - "..", - "->", - "/*", - "*/", - "+=", - "-=", - "*=", - "/=", - "%=", - ">>", - "<<", - "++", - "--", - "===", - "...", - "..<" -}; - -static bool is_cross_semi_token(enum TokenType op) { - switch(op) { - case ARROW_OPERATOR: - case DOT_OPERATOR: - case CONJUNCTION_OPERATOR: - case DISJUNCTION_OPERATOR: - case NIL_COALESCING_OPERATOR: - case EQUAL_SIGN: - case EQ_EQ: - case PLUS_THEN_WS: - case MINUS_THEN_WS: - case THROWS_KEYWORD: - case RETHROWS_KEYWORD: - case DEFAULT_KEYWORD: - case WHERE_KEYWORD: - case ELSE_KEYWORD: - case CATCH_KEYWORD: - case AS_KEYWORD: - case AS_QUEST: - case AS_BANG: - case ASYNC_KEYWORD: - case CUSTOM_OPERATOR: - return true; - case BANG: - default: - return false; - } -} - -#define NON_CONSUMING_CROSS_SEMI_CHAR_COUNT 3 -const uint32_t NON_CONSUMING_CROSS_SEMI_CHARS[NON_CONSUMING_CROSS_SEMI_CHAR_COUNT] = { '?', ':', '{' }; - -/** - * All possible results of having performed some sort of parsing. - * - * A parser can return a result along two dimensions: - * 1. Should the scanner continue trying to find another result? - * 2. Was some result produced by this parsing attempt? - * - * These are flattened into a single enum together. When the function returns one of the `TOKEN_FOUND` cases, it - * will always populate its `symbol_result` field. When it returns one of the `STOP_PARSING` cases, callers should - * immediately return (with the value, if there is one). - */ -enum ParseDirective { - CONTINUE_PARSING_NOTHING_FOUND, - CONTINUE_PARSING_TOKEN_FOUND, - CONTINUE_PARSING_SLASH_CONSUMED, - STOP_PARSING_NOTHING_FOUND, - STOP_PARSING_TOKEN_FOUND, - STOP_PARSING_END_OF_FILE -}; - -struct ScannerState { - uint32_t ongoing_raw_str_hash_count; -}; - -void *tree_sitter_swift_external_scanner_create() { - return calloc(1, sizeof(struct ScannerState)); -} - -void tree_sitter_swift_external_scanner_destroy(void *payload) { - free(payload); -} - -void tree_sitter_swift_external_scanner_reset(void *payload) { - struct ScannerState *state = (struct ScannerState *)payload; - state->ongoing_raw_str_hash_count = 0; -} - -unsigned tree_sitter_swift_external_scanner_serialize(void *payload, char *buffer) { - struct ScannerState *state = (struct ScannerState *)payload; - uint32_t hash_count = state->ongoing_raw_str_hash_count; - buffer[0] = (hash_count >> 24) & 0xff; - buffer[1] = (hash_count >> 16) & 0xff; - buffer[2] = (hash_count >> 8) & 0xff; - buffer[3] = (hash_count) & 0xff; - return 4; -} - -void tree_sitter_swift_external_scanner_deserialize( - void *payload, - const char *buffer, - unsigned length -) { - if (length < 4) { - return; - } - - uint32_t hash_count = ( - (((uint32_t) buffer[0]) << 24) | - (((uint32_t) buffer[1]) << 16) | - (((uint32_t) buffer[2]) << 8) | - (((uint32_t) buffer[3])) - ); - struct ScannerState *state = (struct ScannerState *)payload; - state->ongoing_raw_str_hash_count = hash_count; -} - -static void advance(TSLexer *lexer) { - lexer->advance(lexer, false); -} - -static bool should_treat_as_wspace(int32_t character) { - return iswspace(character) || (((int32_t) ';') == character); -} - -static int32_t encountered_op_count(bool *encountered_operator) { - int32_t encountered = 0; - for (int op_idx = 0; op_idx < OPERATOR_COUNT; op_idx++) { - if (encountered_operator[op_idx]) { - encountered++; - } - } - - return encountered; -} - -static bool any_reserved_ops(uint8_t *encountered_reserved_ops) { - for (int op_idx = 0; op_idx < RESERVED_OP_COUNT; op_idx++) { - if (encountered_reserved_ops[op_idx] == 2) { - return true; - } - } - - return false; -} - -static bool is_legal_custom_operator( - int32_t char_idx, - int32_t first_char, - int32_t cur_char -) { - bool is_first_char = !char_idx; - switch (cur_char) { - case '=': - case '-': - case '+': - case '!': - case '%': - case '<': - case '>': - case '&': - case '|': - case '^': - case '?': - case '~': - return true; - case '.': - // Grammar allows `.` for any operator that starts with `.` - return is_first_char || first_char == '.'; - case '*': - case '/': - // Not listed in the grammar, but `/*` and `//` can't be the start of an operator since they start comments - return char_idx != 1 || first_char != '/'; - default: - if ( - (cur_char >= 0x00A1 && cur_char <= 0x00A7) || - (cur_char == 0x00A9) || - (cur_char == 0x00AB) || - (cur_char == 0x00AC) || - (cur_char == 0x00AE) || - (cur_char >= 0x00B0 && cur_char <= 0x00B1) || - (cur_char == 0x00B6) || - (cur_char == 0x00BB) || - (cur_char == 0x00BF) || - (cur_char == 0x00D7) || - (cur_char == 0x00F7) || - (cur_char >= 0x2016 && cur_char <= 0x2017) || - (cur_char >= 0x2020 && cur_char <= 0x2027) || - (cur_char >= 0x2030 && cur_char <= 0x203E) || - (cur_char >= 0x2041 && cur_char <= 0x2053) || - (cur_char >= 0x2055 && cur_char <= 0x205E) || - (cur_char >= 0x2190 && cur_char <= 0x23FF) || - (cur_char >= 0x2500 && cur_char <= 0x2775) || - (cur_char >= 0x2794 && cur_char <= 0x2BFF) || - (cur_char >= 0x2E00 && cur_char <= 0x2E7F) || - (cur_char >= 0x3001 && cur_char <= 0x3003) || - (cur_char >= 0x3008 && cur_char <= 0x3020) || - (cur_char == 0x3030) - ) { - return true; - } else if ( - (cur_char >= 0x0300 && cur_char <= 0x036f) || - (cur_char >= 0x1DC0 && cur_char <= 0x1DFF) || - (cur_char >= 0x20D0 && cur_char <= 0x20FF) || - (cur_char >= 0xFE00 && cur_char <= 0xFE0F) || - (cur_char >= 0xFE20 && cur_char <= 0xFE2F) || - (cur_char >= 0xE0100 && cur_char <= 0xE01EF) - ) { - return !is_first_char; - } else { - return false; - } - } -} - -static bool eat_operators( - TSLexer *lexer, - const bool *valid_symbols, - bool mark_end, - const int32_t prior_char, - enum TokenType *symbol_result -) { - bool possible_operators[OPERATOR_COUNT]; - uint8_t reserved_operators[RESERVED_OP_COUNT]; - for (int op_idx = 0; op_idx < OPERATOR_COUNT; op_idx++) { - possible_operators[op_idx] = valid_symbols[OP_SYMBOLS[op_idx]] && (!prior_char || OPERATORS[op_idx][0] == prior_char); - } - for (int op_idx = 0; op_idx < RESERVED_OP_COUNT; op_idx++) { - reserved_operators[op_idx] = !prior_char || RESERVED_OPS[op_idx][0] == prior_char; - } - - bool possible_custom_operator = valid_symbols[CUSTOM_OPERATOR]; - int32_t first_char = prior_char ? prior_char : lexer->lookahead; - int32_t last_examined_char = first_char; - - int32_t str_idx = prior_char ? 1 : 0; - int32_t full_match = -1; - while(true) { - for (int op_idx = 0; op_idx < OPERATOR_COUNT; op_idx++) { - if (!possible_operators[op_idx]) { - continue; - } - - if (OPERATORS[op_idx][str_idx] == '\0') { - // Make sure that the operator is allowed to have the next character as its lookahead. - enum IllegalTerminatorGroup illegal_terminators = OP_ILLEGAL_TERMINATORS[op_idx]; - switch (lexer->lookahead) { - // See "Operators": - // https://docs.swift.org/swift-book/ReferenceManual/LexicalStructure.html#ID418 - case '/': - case '=': - case '-': - case '+': - case '!': - case '*': - case '%': - case '<': - case '>': - case '&': - case '|': - case '^': - case '?': - case '~': - if (illegal_terminators == OPERATOR_SYMBOLS) { - break; - } // Otherwise, intentionally fall through to the OPERATOR_OR_DOT case - // fall through - case '.': - if (illegal_terminators == OPERATOR_OR_DOT) { - break; - } // Otherwise, fall through to DEFAULT which checks its groups directly - // fall through - default: - if (iswalnum(lexer->lookahead) && illegal_terminators == ALPHANUMERIC) { - break; - } - - if (!iswspace(lexer->lookahead) && illegal_terminators == NON_WHITESPACE) { - break; - } - - full_match = op_idx; - if (mark_end) { - lexer->mark_end(lexer); - } - } - - possible_operators[op_idx] = false; - continue; - } - - if (OPERATORS[op_idx][str_idx] != lexer->lookahead) { - possible_operators[op_idx] = false; - continue; - } - } - - for (int op_idx = 0; op_idx < RESERVED_OP_COUNT; op_idx++) { - if (!reserved_operators[op_idx]) { - continue; - } - - if (RESERVED_OPS[op_idx][str_idx] == '\0') { - reserved_operators[op_idx] = 0; - continue; - } - - if (RESERVED_OPS[op_idx][str_idx] != lexer->lookahead) { - reserved_operators[op_idx] = 0; - continue; - } - - if (RESERVED_OPS[op_idx][str_idx + 1] == '\0') { - reserved_operators[op_idx] = 2; - continue; - } - } - - possible_custom_operator = possible_custom_operator && is_legal_custom_operator( - str_idx, - first_char, - lexer->lookahead - ); - - uint32_t encountered_ops = encountered_op_count(possible_operators); - if (encountered_ops == 0) { - if (!possible_custom_operator) { - break; - } else if (mark_end && full_match == -1) { - lexer->mark_end(lexer); - } - } - - last_examined_char = lexer->lookahead; - lexer->advance(lexer, false); - str_idx += 1; - - if (encountered_ops == 0 && !is_legal_custom_operator( - str_idx, - first_char, - lexer->lookahead - )) { - break; - } - } - - if (full_match != -1) { - // We have a match -- first see if that match has a symbol that suppresses it. For example, in `try!`, we do not - // want to emit the `!` as a symbol in our scanner, because we want the parser to have the chance to parse it as - // an immediate token. - uint64_t suppressing_symbols = OP_SYMBOL_SUPPRESSOR[full_match]; - if (suppressing_symbols) { - for (uint64_t suppressor = 0; suppressor < TOKEN_COUNT; suppressor++) { - if (!(suppressing_symbols & 1ULL << suppressor)) { - continue; - } - - // The suppressing symbol is valid in this position, so skip it. - if (valid_symbols[suppressor]) { - return false; - } - } - } - *symbol_result = OP_SYMBOLS[full_match]; - return true; - } - - if (possible_custom_operator && !any_reserved_ops(reserved_operators)) { - if ((last_examined_char != '<' || iswspace(lexer->lookahead)) && mark_end) { - lexer->mark_end(lexer); - } - *symbol_result = CUSTOM_OPERATOR; - return true; - } - - return false; -} - -static enum ParseDirective eat_comment( - TSLexer *lexer, - const bool *valid_symbols, - bool mark_end, - enum TokenType *symbol_result -) { - if (lexer->lookahead != '/') { - return CONTINUE_PARSING_NOTHING_FOUND; - } - - advance(lexer); - - if (lexer->lookahead != '*') { - return CONTINUE_PARSING_SLASH_CONSUMED; - } - - advance(lexer); - - bool after_star = false; - unsigned nesting_depth = 1; - for (;;) { - switch (lexer->lookahead) { - case '\0': - return STOP_PARSING_END_OF_FILE; - case '*': - advance(lexer); - after_star = true; - break; - case '/': - if (after_star) { - advance(lexer); - after_star = false; - nesting_depth--; - if (nesting_depth == 0) { - if (mark_end) { - lexer->mark_end(lexer); - } - *symbol_result = BLOCK_COMMENT; - return STOP_PARSING_TOKEN_FOUND; - } - } else { - advance(lexer); - after_star = false; - if (lexer->lookahead == '*') { - nesting_depth++; - advance(lexer); - } - } - break; - default: - advance(lexer); - after_star = false; - break; - } - } -} - -static enum ParseDirective eat_whitespace( - TSLexer *lexer, - const bool *valid_symbols, - enum TokenType *symbol_result -) { - enum ParseDirective ws_directive = CONTINUE_PARSING_NOTHING_FOUND; - bool semi_is_valid = valid_symbols[IMPLICIT_SEMI] && valid_symbols[EXPLICIT_SEMI]; - uint32_t lookahead; - while (should_treat_as_wspace(lookahead = lexer->lookahead)) { - if (lookahead == ';') { - if (semi_is_valid) { - ws_directive = STOP_PARSING_TOKEN_FOUND; - lexer->advance(lexer, false); - } - - break; - } - - lexer->advance(lexer, true); - - lexer->mark_end(lexer); - - if (ws_directive == CONTINUE_PARSING_NOTHING_FOUND && (lookahead == '\n' || lookahead == '\r')) { - ws_directive = CONTINUE_PARSING_TOKEN_FOUND; - } - } - - enum ParseDirective any_comment = CONTINUE_PARSING_NOTHING_FOUND; - if (ws_directive == CONTINUE_PARSING_TOKEN_FOUND && lookahead == '/') { - bool has_seen_single_comment = false; - while (lexer->lookahead == '/') { - // It's possible that this is a comment - start an exploratory mission to find out, and if it is, look for what - // comes after it. We care about what comes after it for the purpose of suppressing the newline. - - enum TokenType multiline_comment_result; - any_comment = eat_comment(lexer, valid_symbols, /* mark_end */ false, &multiline_comment_result); - if (any_comment == STOP_PARSING_TOKEN_FOUND) { - // This is a multiline comment. This scanner should be parsing those, so we might want to bail out and - // emit it instead. However, we only want to do that if we haven't advanced through a _single_ line - // comment on the way - otherwise that will get lumped into this. - if (!has_seen_single_comment) { - lexer->mark_end(lexer); - *symbol_result = multiline_comment_result; - return STOP_PARSING_TOKEN_FOUND; - } - } else if (any_comment == STOP_PARSING_END_OF_FILE) { - return STOP_PARSING_END_OF_FILE; - } else if (any_comment == CONTINUE_PARSING_SLASH_CONSUMED) { - // We accidentally ate a slash -- we should actually bail out, say we saw nothing, and let the next pass - // take it from after the newline. - return CONTINUE_PARSING_SLASH_CONSUMED; - } else if (lexer->lookahead == '/') { - // There wasn't a multiline comment, which we know means that the comment parser ate its `/` and then - // bailed out. If it had seen anything comment-like after that first `/` it would have continued going - // and eventually had a well-formed comment or an EOF. Thus, if we're currently looking at a `/`, it's - // the second one of those and it means we have a single-line comment. - has_seen_single_comment = true; - while (lexer->lookahead != '\n' && lexer->lookahead != '\0') { - lexer->advance(lexer, true); - } - } else if (iswspace(lexer->lookahead)) { - // We didn't see any type of comment - in fact, we saw an operator that we don't normally treat as an - // operator. Still, this is a reason to stop parsing. - return STOP_PARSING_NOTHING_FOUND; - } - - // If we skipped through some comment, we're at whitespace now, so advance. - while(iswspace(lexer->lookahead)) { - any_comment = CONTINUE_PARSING_NOTHING_FOUND; // We're advancing, so clear out the comment - lexer->advance(lexer, true); - } - } - - enum TokenType operator_result; - bool saw_operator = eat_operators( - lexer, - valid_symbols, - /* mark_end */ false, - '\0', - &operator_result - ); - if (saw_operator) { - // The operator we saw should suppress the newline, so bail out. - return STOP_PARSING_NOTHING_FOUND; - } else { - // Promote the implicit newline to an explicit one so we don't check for operators again. - *symbol_result = IMPLICIT_SEMI; - ws_directive = STOP_PARSING_TOKEN_FOUND; - } - } - - // Let's consume operators that can live after a "semicolon" style newline. Before we do that, though, we want to - // check for a set of characters that we do not consume, but that still suppress the semi. - if (ws_directive == CONTINUE_PARSING_TOKEN_FOUND) { - for (int i = 0; i < NON_CONSUMING_CROSS_SEMI_CHAR_COUNT; i++) { - if (NON_CONSUMING_CROSS_SEMI_CHARS[i] == lookahead) { - return CONTINUE_PARSING_NOTHING_FOUND; - } - } - } - - if (semi_is_valid && ws_directive != CONTINUE_PARSING_NOTHING_FOUND) { - *symbol_result = lookahead == ';' ? EXPLICIT_SEMI : IMPLICIT_SEMI; - return ws_directive; - } - - return CONTINUE_PARSING_NOTHING_FOUND; -} - -#define DIRECTIVE_COUNT 4 -const char* DIRECTIVES[OPERATOR_COUNT] = { - "if", - "elseif", - "else", - "endif" -}; - -const enum TokenType DIRECTIVE_SYMBOLS[DIRECTIVE_COUNT] = { - DIRECTIVE_IF, - DIRECTIVE_ELSEIF, - DIRECTIVE_ELSE, - DIRECTIVE_ENDIF -}; - -static enum TokenType find_possible_compiler_directive(TSLexer *lexer) { - bool possible_directives[DIRECTIVE_COUNT]; - for (int dir_idx = 0; dir_idx < DIRECTIVE_COUNT; dir_idx++) { - possible_directives[dir_idx] = true; - } - - int32_t str_idx = 0; - int32_t full_match = -1; - while(true) { - for (int dir_idx = 0; dir_idx < DIRECTIVE_COUNT; dir_idx++) { - if (!possible_directives[dir_idx]) { - continue; - } - - uint8_t expected_char = DIRECTIVES[dir_idx][str_idx]; - if (expected_char == '\0') { - full_match = dir_idx; - lexer->mark_end(lexer); - } - - if (expected_char != lexer->lookahead) { - possible_directives[dir_idx] = false; - continue; - } - } - - uint8_t match_count = 0; - for (int dir_idx = 0; dir_idx < DIRECTIVE_COUNT; dir_idx += 1) { - if (possible_directives[dir_idx]) { - match_count += 1; - } - } - - if (match_count == 0) { - break; - } - - lexer->advance(lexer, false); - str_idx += 1; - } - - if (full_match == -1) { - // No compiler directive found, so just match the starting symbol - return HASH_SYMBOL; - } - - return DIRECTIVE_SYMBOLS[full_match]; -} - -static bool eat_raw_str_part( - struct ScannerState *state, - TSLexer *lexer, - const bool *valid_symbols, - enum TokenType *symbol_result -) { - uint32_t hash_count = state->ongoing_raw_str_hash_count; - if (!valid_symbols[RAW_STR_PART]) { - return false; - } else if (hash_count == 0) { - // If this is a raw_str_part, it's the first one - look for hashes - while (lexer->lookahead == '#') { - hash_count += 1; - advance(lexer); - } - - if (hash_count == 0) { - return false; - } - - if (lexer->lookahead == '"') { - advance(lexer); - } else if (hash_count == 1) { - lexer->mark_end(lexer); - *symbol_result = find_possible_compiler_directive(lexer); - return true; - } else { - return false; - } - - } else if (valid_symbols[RAW_STR_CONTINUING_INDICATOR]) { - // This is the end of an interpolation - now it's another raw_str_part. This is a synthetic - // marker to tell us that the grammar just consumed a `(` symbol to close a raw - // interpolation (since we don't want to fire on every `(` in existence). We don't have - // anything to do except continue. - } else { - return false; - } - - // We're in a state where anything other than `hash_count` hash symbols in a row should be eaten - // and is part of a string. - // The last character _before_ the hashes will tell us what happens next. - // Matters are also complicated by the fact that we don't want to consume every character we - // visit; if we see a `\#(`, for instance, with the appropriate number of hash symbols, we want - // to end our parsing _before_ that sequence. This allows highlighting tools to treat that as a - // separate token. - while (lexer->lookahead != '\0') { - uint8_t last_char = '\0'; - lexer->mark_end(lexer); // We always want to parse thru the start of the string so far - // Advance through anything that isn't a hash symbol, because we want to count those. - while (lexer->lookahead != '#' && lexer->lookahead != '\0') { - last_char = lexer->lookahead; - advance(lexer); - if (last_char != '\\' || lexer->lookahead == '\\') { - // Mark a new end, but only if we didn't just advance past a `\` symbol, since we - // don't want to consume that. Exception: if this is a `\` that happens _right - // after_ another `\`, we for some reason _do_ want to consume that, because - // apparently that is parsed as a literal `\` followed by something escaped. - lexer->mark_end(lexer); - } - } - - // We hit at least one hash - count them and see if they match. - uint32_t current_hash_count = 0; - while (lexer->lookahead == '#' && current_hash_count < hash_count) { - current_hash_count += 1; - advance(lexer); - } - - // If we saw exactly the right number of hashes, one of three things is true: - // 1. We're trying to interpolate into this string. - // 2. The string just ended. - // 3. This was just some hash characters doing nothing important. - if (current_hash_count == hash_count) { - if (last_char == '\\' && lexer->lookahead == '(') { - // Interpolation case! Don't consume those chars; they get saved for grammar.js. - *symbol_result = RAW_STR_PART; - state->ongoing_raw_str_hash_count = hash_count; - return true; - } else if (last_char == '"') { - // The string is finished! Mark the end here, on the very last hash symbol. - lexer->mark_end(lexer); - *symbol_result = RAW_STR_END_PART; - state->ongoing_raw_str_hash_count = 0; - return true; - } - // Nothing special happened - let the string continue. - } - } - - return false; -} - -bool tree_sitter_swift_external_scanner_scan( - void *payload, - TSLexer *lexer, - const bool *valid_symbols -) { - // Figure out our scanner state - struct ScannerState *state = (struct ScannerState *)payload; - - // Consume any whitespace at the start. - enum TokenType ws_result; - enum ParseDirective ws_directive = eat_whitespace(lexer, valid_symbols, &ws_result); - if (ws_directive == STOP_PARSING_TOKEN_FOUND) { - lexer->result_symbol = ws_result; - return true; - } - - if (ws_directive == STOP_PARSING_NOTHING_FOUND || ws_directive == STOP_PARSING_END_OF_FILE) { - return false; - } - - bool has_ws_result = (ws_directive == CONTINUE_PARSING_TOKEN_FOUND); - - // Now consume comments (before custom operators so that those aren't treated as comments) - enum TokenType comment_result; - enum ParseDirective comment = ws_directive == CONTINUE_PARSING_SLASH_CONSUMED ? ws_directive : eat_comment(lexer, valid_symbols, /* mark_end */ true, &comment_result); - if (comment == STOP_PARSING_TOKEN_FOUND) { - lexer->mark_end(lexer); - lexer->result_symbol = comment_result; - return true; - } - - if (comment == STOP_PARSING_END_OF_FILE) { - return false; - } - // Now consume any operators that might cause our whitespace to be suppressed. - enum TokenType operator_result; - bool saw_operator = eat_operators( - lexer, - valid_symbols, - /* mark_end */ !has_ws_result, - comment == CONTINUE_PARSING_SLASH_CONSUMED ? '/' : '\0', - &operator_result - ); - - if (saw_operator && (!has_ws_result || is_cross_semi_token(operator_result))) { - lexer->result_symbol = operator_result; - if (has_ws_result) lexer->mark_end(lexer); - return true; - } - - if (has_ws_result) { - // Don't `mark_end`, since we may have advanced through some operators. - lexer->result_symbol = ws_result; - return true; - } - - // NOTE: this will consume any `#` characters it sees, even if it does not find a result. Keep - // it at the end so that it doesn't interfere with special literals or selectors! - enum TokenType raw_str_result; - bool saw_raw_str_part = eat_raw_str_part(state, lexer, valid_symbols, &raw_str_result); - if (saw_raw_str_part) { - lexer->result_symbol = raw_str_result; - return true; - } - - return false; -} - diff --git a/unified/extractor/tree-sitter-swift/tree-sitter.json b/unified/extractor/tree-sitter-swift/tree-sitter.json deleted file mode 100644 index 3cd49a28a38f..000000000000 --- a/unified/extractor/tree-sitter-swift/tree-sitter.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "grammars": [ - { - "name": "swift", - "camelcase": "Swift", - "scope": "source.swift", - "path": ".", - "file-types": [ - "swift" - ], - "highlights": "queries/highlights.scm", - "injections": "queries/injections.scm", - "locals": "queries/locals.scm", - "injection-regex": "swift" - } - ], - "metadata": { - "version": "0.7.2", - "license": "MIT", - "description": "A tree-sitter grammar for the Swift programming language.", - "authors": [ - { - "name": "Alex Pinkus", - "email": "alex.pinkus@gmail.com" - } - ], - "links": { - "repository": "git+https://github.com/alex-pinkus/tree-sitter-swift.git" - } - }, - "bindings": { - "c": true, - "go": true, - "node": true, - "python": true, - "rust": true, - "swift": true - } -} diff --git a/unified/scripts/regenerate-grammar.sh b/unified/scripts/regenerate-grammar.sh deleted file mode 100755 index b7a5ce263fb8..000000000000 --- a/unified/scripts/regenerate-grammar.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash -# Regenerate the vendored tree-sitter-swift parser tables from grammar.js, -# then refresh the human-readable node-types.yml companion file. -# -# Run this after editing -# unified/extractor/tree-sitter-swift/grammar.js so that: -# * src/parser.c, src/grammar.json, src/node-types.json (and the -# src/tree_sitter/*.h headers) reflect the current grammar; and -# * node-types.yml shows the same information in a form that's -# pleasant to review in PR diffs. -# -# Requirements: tree-sitter CLI on PATH, and a working cargo toolchain. -set -euo pipefail - -cd "$(dirname "$0")/.." -SWIFT_DIR="extractor/tree-sitter-swift" - -( - cd "$SWIFT_DIR" - tree-sitter generate -) - -# Build yeast's node_types_yaml binary and use it to convert the freshly -# generated src/node-types.json into the human-readable node-types.yml. -cargo run --release --quiet -p yeast --bin node_types_yaml -- \ - --from-json "$SWIFT_DIR/src/node-types.json" > "$SWIFT_DIR/node-types.yml" - -echo "Regenerated $SWIFT_DIR/{src/parser.c,src/grammar.json,src/node-types.json,node-types.yml}" From 0c17c699c1c87e3dd340dcd74615119d31f28a82 Mon Sep 17 00:00:00 2001 From: Taus Date: Fri, 24 Jul 2026 11:22:52 +0000 Subject: [PATCH 097/188] unified: Add corpus cases for currently-unsupported Swift constructs Add corpus test cases that witness Swift constructs the swift-syntax mapping does not yet handle, so they map to `unsupported_node` (or, for unfoldable operator chains, `unresolved_operator_sequence`). These document the current behaviour and give us a place to observe the diff when each construct is eventually supported. The cases are placed alongside the feature they exercise: - functions: `inout` parameter types and `&`-prefixed inout arguments. - expressions: key paths, generic specialization in expression position (`Array()`), `copy`/`consume` expressions, and `unsafe` expressions. - operators: unresolved operator sequences (pointwise operators the parser cannot fold), custom postfix operators, and partial ranges. - control-flow: `fallthrough`, `defer`, and `discard` statements. - types: `actor` declarations, inline array types (`[3 of Int]`), function-type attributes (`@convention(c)`, `@Sendable`), noncopyable (`~Copyable`) types, and conditional compilation in a class body. - literals: the `#line` magic literal. The conditional-compilation case is worth calling out because it swallows members: swift-syntax reports a structured `ifConfigDecl` whose branches hold ordinary member items, but with no rule for it the whole `#if` block collapses into a single `unsupported_node`, so the declarations inside are not extracted at all. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../swift/control-flow/defer-statement.output | 94 ++++++++++++++ .../swift/control-flow/defer-statement.swift | 4 + .../control-flow/discard-statement.output | 81 ++++++++++++ .../control-flow/discard-statement.swift | 5 + .../swift/control-flow/fallthrough.output | 118 ++++++++++++++++++ .../swift/control-flow/fallthrough.swift | 8 ++ .../expressions/consume-expression.output | 85 +++++++++++++ .../expressions/consume-expression.swift | 2 + .../swift/expressions/copy-expression.output | 85 +++++++++++++ .../swift/expressions/copy-expression.swift | 2 + .../generic-specialization-expression.output | 56 +++++++++ .../generic-specialization-expression.swift | 1 + .../expressions/key-path-expression.output | 48 +++++++ .../expressions/key-path-expression.swift | 1 + .../expressions/unsafe-expression.output | 51 ++++++++ .../swift/expressions/unsafe-expression.swift | 2 + .../functions/call-with-inout-argument.output | 96 ++++++++++++++ .../functions/call-with-inout-argument.swift | 3 + .../function-with-inout-parameter.output | 81 ++++++++++++ .../function-with-inout-parameter.swift | 3 + .../swift/literals/line-magic-literal.output | 40 ++++++ .../swift/literals/line-magic-literal.swift | 1 + .../operators/custom-postfix-operator.output | 48 +++++++ .../operators/custom-postfix-operator.swift | 2 + .../swift/operators/partial-range-from.output | 40 ++++++ .../swift/operators/partial-range-from.swift | 1 + .../unresolved-operator-sequence.output | 100 +++++++++++++++ .../unresolved-operator-sequence.swift | 3 + .../swift/types/actor-declaration.output | 45 +++++++ .../swift/types/actor-declaration.swift | 3 + ...nditional-compilation-in-class-body.output | 87 +++++++++++++ ...onditional-compilation-in-class-body.swift | 10 ++ ...tion-type-with-convention-attribute.output | 73 +++++++++++ ...ction-type-with-convention-attribute.swift | 1 + ...nction-type-with-sendable-attribute.output | 66 ++++++++++ ...unction-type-with-sendable-attribute.swift | 1 + .../swift/types/inline-array-type.output | 77 ++++++++++++ .../swift/types/inline-array-type.swift | 1 + .../swift/types/noncopyable-type.output | 71 +++++++++++ .../corpus/swift/types/noncopyable-type.swift | 3 + 40 files changed, 1499 insertions(+) create mode 100644 unified/extractor/tests/corpus/swift/control-flow/defer-statement.output create mode 100644 unified/extractor/tests/corpus/swift/control-flow/defer-statement.swift create mode 100644 unified/extractor/tests/corpus/swift/control-flow/discard-statement.output create mode 100644 unified/extractor/tests/corpus/swift/control-flow/discard-statement.swift create mode 100644 unified/extractor/tests/corpus/swift/control-flow/fallthrough.output create mode 100644 unified/extractor/tests/corpus/swift/control-flow/fallthrough.swift create mode 100644 unified/extractor/tests/corpus/swift/expressions/consume-expression.output create mode 100644 unified/extractor/tests/corpus/swift/expressions/consume-expression.swift create mode 100644 unified/extractor/tests/corpus/swift/expressions/copy-expression.output create mode 100644 unified/extractor/tests/corpus/swift/expressions/copy-expression.swift create mode 100644 unified/extractor/tests/corpus/swift/expressions/generic-specialization-expression.output create mode 100644 unified/extractor/tests/corpus/swift/expressions/generic-specialization-expression.swift create mode 100644 unified/extractor/tests/corpus/swift/expressions/key-path-expression.output create mode 100644 unified/extractor/tests/corpus/swift/expressions/key-path-expression.swift create mode 100644 unified/extractor/tests/corpus/swift/expressions/unsafe-expression.output create mode 100644 unified/extractor/tests/corpus/swift/expressions/unsafe-expression.swift create mode 100644 unified/extractor/tests/corpus/swift/functions/call-with-inout-argument.output create mode 100644 unified/extractor/tests/corpus/swift/functions/call-with-inout-argument.swift create mode 100644 unified/extractor/tests/corpus/swift/functions/function-with-inout-parameter.output create mode 100644 unified/extractor/tests/corpus/swift/functions/function-with-inout-parameter.swift create mode 100644 unified/extractor/tests/corpus/swift/literals/line-magic-literal.output create mode 100644 unified/extractor/tests/corpus/swift/literals/line-magic-literal.swift create mode 100644 unified/extractor/tests/corpus/swift/operators/custom-postfix-operator.output create mode 100644 unified/extractor/tests/corpus/swift/operators/custom-postfix-operator.swift create mode 100644 unified/extractor/tests/corpus/swift/operators/partial-range-from.output create mode 100644 unified/extractor/tests/corpus/swift/operators/partial-range-from.swift create mode 100644 unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence.output create mode 100644 unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence.swift create mode 100644 unified/extractor/tests/corpus/swift/types/actor-declaration.output create mode 100644 unified/extractor/tests/corpus/swift/types/actor-declaration.swift create mode 100644 unified/extractor/tests/corpus/swift/types/conditional-compilation-in-class-body.output create mode 100644 unified/extractor/tests/corpus/swift/types/conditional-compilation-in-class-body.swift create mode 100644 unified/extractor/tests/corpus/swift/types/function-type-with-convention-attribute.output create mode 100644 unified/extractor/tests/corpus/swift/types/function-type-with-convention-attribute.swift create mode 100644 unified/extractor/tests/corpus/swift/types/function-type-with-sendable-attribute.output create mode 100644 unified/extractor/tests/corpus/swift/types/function-type-with-sendable-attribute.swift create mode 100644 unified/extractor/tests/corpus/swift/types/inline-array-type.output create mode 100644 unified/extractor/tests/corpus/swift/types/inline-array-type.swift create mode 100644 unified/extractor/tests/corpus/swift/types/noncopyable-type.output create mode 100644 unified/extractor/tests/corpus/swift/types/noncopyable-type.swift diff --git a/unified/extractor/tests/corpus/swift/control-flow/defer-statement.output b/unified/extractor/tests/corpus/swift/control-flow/defer-statement.output new file mode 100644 index 000000000000..6e8ec9ae3b9a --- /dev/null +++ b/unified/extractor/tests/corpus/swift/control-flow/defer-statement.output @@ -0,0 +1,94 @@ +func withCleanup() { + defer { print("cleanup") } + print("work") +} + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + functionDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + deferStmt + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment "cleanup" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + deferKeyword: defer + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment "work" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + name: identifier "withCleanup" + modifiers: + signature: + functionSignature + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + funcKeyword: func + +--- + +top_level + body: + block + stmt: + function_declaration + name: identifier "withCleanup" + body: + block + stmt: + unsupported_node "defer { print(\"cleanup\") }" + call_expr + callee: + name_expr + identifier: identifier "print" + argument: + argument + value: string_literal "\"work\"" diff --git a/unified/extractor/tests/corpus/swift/control-flow/defer-statement.swift b/unified/extractor/tests/corpus/swift/control-flow/defer-statement.swift new file mode 100644 index 000000000000..0bb8820326db --- /dev/null +++ b/unified/extractor/tests/corpus/swift/control-flow/defer-statement.swift @@ -0,0 +1,4 @@ +func withCleanup() { + defer { print("cleanup") } + print("work") +} diff --git a/unified/extractor/tests/corpus/swift/control-flow/discard-statement.output b/unified/extractor/tests/corpus/swift/control-flow/discard-statement.output new file mode 100644 index 000000000000..7e0eac29c0fc --- /dev/null +++ b/unified/extractor/tests/corpus/swift/control-flow/discard-statement.output @@ -0,0 +1,81 @@ +struct Resource: ~Copyable { + consuming func close() { + discard self + } +} + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + structDecl + attributes: + name: identifier "Resource" + inheritanceClause: + inheritanceClause + colon: : + inheritedTypes: + inheritedType + type: + suppressedType + type: + identifierType + name: identifier "Copyable" + withoutTilde: prefixOperator "~" + memberBlock: + memberBlock + leftBrace: { + rightBrace: } + members: + memberBlockItem + decl: + functionDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + discardStmt + expression: + declReferenceExpr + baseName: self + discardKeyword: discard + name: identifier "close" + modifiers: + declModifier + name: consuming + signature: + functionSignature + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + funcKeyword: func + modifiers: + structKeyword: struct + +--- + +top_level + body: + block + stmt: + class_like_declaration + modifier: modifier "struct" + name: identifier "Resource" + base_type: + base_type + type: unsupported_node "~Copyable" + member: + function_declaration + name: identifier "close" + body: + block + stmt: unsupported_node "discard self" diff --git a/unified/extractor/tests/corpus/swift/control-flow/discard-statement.swift b/unified/extractor/tests/corpus/swift/control-flow/discard-statement.swift new file mode 100644 index 000000000000..8f207d03da9c --- /dev/null +++ b/unified/extractor/tests/corpus/swift/control-flow/discard-statement.swift @@ -0,0 +1,5 @@ +struct Resource: ~Copyable { + consuming func close() { + discard self + } +} diff --git a/unified/extractor/tests/corpus/swift/control-flow/fallthrough.output b/unified/extractor/tests/corpus/swift/control-flow/fallthrough.output new file mode 100644 index 000000000000..9cfe81048402 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/control-flow/fallthrough.output @@ -0,0 +1,118 @@ +func classify(_ x: Int) { + switch x { + case 1: + fallthrough + default: + break + } +} + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + functionDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + expressionStmt + expression: + switchExpr + leftBrace: { + rightBrace: } + cases: + switchCase + label: + switchCaseLabel + colon: : + caseKeyword: case + caseItems: + switchCaseItem + pattern: + expressionPattern + expression: + integerLiteralExpr + literal: integerLiteral "1" + statements: + codeBlockItem + item: + fallThroughStmt + fallthroughKeyword: fallthrough + switchCase + label: + switchDefaultLabel + colon: : + defaultKeyword: default + statements: + codeBlockItem + item: + breakStmt + breakKeyword: break + subject: + declReferenceExpr + baseName: identifier "x" + switchKeyword: switch + name: identifier "classify" + modifiers: + signature: + functionSignature + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + functionParameter + colon: : + attributes: + modifiers: + type: + identifierType + name: identifier "Int" + firstName: _ + secondName: identifier "x" + funcKeyword: func + +--- + +top_level + body: + block + stmt: + function_declaration + name: identifier "classify" + parameter: + parameter + external_name: identifier "_" + type: + named_type_expr + name: identifier "Int" + pattern: + name_pattern + identifier: identifier "x" + body: + block + stmt: + switch_expr + value: + name_expr + identifier: identifier "x" + case: + switch_case + pattern: + expr_equality_pattern + expr: int_literal "1" + body: + block + stmt: unsupported_node "fallthrough" + switch_case + body: + block + stmt: break_expr "break" diff --git a/unified/extractor/tests/corpus/swift/control-flow/fallthrough.swift b/unified/extractor/tests/corpus/swift/control-flow/fallthrough.swift new file mode 100644 index 000000000000..bedbf0590753 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/control-flow/fallthrough.swift @@ -0,0 +1,8 @@ +func classify(_ x: Int) { + switch x { + case 1: + fallthrough + default: + break + } +} diff --git a/unified/extractor/tests/corpus/swift/expressions/consume-expression.output b/unified/extractor/tests/corpus/swift/expressions/consume-expression.output new file mode 100644 index 000000000000..f20f89b72558 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/expressions/consume-expression.output @@ -0,0 +1,85 @@ +let original = [1, 2, 3] +let consumed = consume original + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + arrayExpr + elements: + arrayElement + expression: + integerLiteralExpr + literal: integerLiteral "1" + trailingComma: , + arrayElement + expression: + integerLiteralExpr + literal: integerLiteral "2" + trailingComma: , + arrayElement + expression: + integerLiteralExpr + literal: integerLiteral "3" + leftSquare: [ + rightSquare: ] + pattern: + identifierPattern + identifier: identifier "original" + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + consumeExpr + expression: + declReferenceExpr + baseName: identifier "original" + consumeKeyword: consume + pattern: + identifierPattern + identifier: identifier "consumed" + +--- + +top_level + body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "original" + value: + array_literal + element: + int_literal "1" + int_literal "2" + int_literal "3" + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "consumed" + value: unsupported_node "consume original" diff --git a/unified/extractor/tests/corpus/swift/expressions/consume-expression.swift b/unified/extractor/tests/corpus/swift/expressions/consume-expression.swift new file mode 100644 index 000000000000..37922e036792 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/expressions/consume-expression.swift @@ -0,0 +1,2 @@ +let original = [1, 2, 3] +let consumed = consume original diff --git a/unified/extractor/tests/corpus/swift/expressions/copy-expression.output b/unified/extractor/tests/corpus/swift/expressions/copy-expression.output new file mode 100644 index 000000000000..9f065b046a90 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/expressions/copy-expression.output @@ -0,0 +1,85 @@ +let original = [1, 2, 3] +let copied = copy original + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + arrayExpr + elements: + arrayElement + expression: + integerLiteralExpr + literal: integerLiteral "1" + trailingComma: , + arrayElement + expression: + integerLiteralExpr + literal: integerLiteral "2" + trailingComma: , + arrayElement + expression: + integerLiteralExpr + literal: integerLiteral "3" + leftSquare: [ + rightSquare: ] + pattern: + identifierPattern + identifier: identifier "original" + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + copyExpr + expression: + declReferenceExpr + baseName: identifier "original" + copyKeyword: copy + pattern: + identifierPattern + identifier: identifier "copied" + +--- + +top_level + body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "original" + value: + array_literal + element: + int_literal "1" + int_literal "2" + int_literal "3" + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "copied" + value: unsupported_node "copy original" diff --git a/unified/extractor/tests/corpus/swift/expressions/copy-expression.swift b/unified/extractor/tests/corpus/swift/expressions/copy-expression.swift new file mode 100644 index 000000000000..9b7fa65909b1 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/expressions/copy-expression.swift @@ -0,0 +1,2 @@ +let original = [1, 2, 3] +let copied = copy original diff --git a/unified/extractor/tests/corpus/swift/expressions/generic-specialization-expression.output b/unified/extractor/tests/corpus/swift/expressions/generic-specialization-expression.output new file mode 100644 index 000000000000..4f3bd0214411 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/expressions/generic-specialization-expression.output @@ -0,0 +1,56 @@ +let numbers = Array() + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + additionalTrailingClosures: + calledExpression: + genericSpecializationExpr + expression: + declReferenceExpr + baseName: identifier "Array" + genericArgumentClause: + genericArgumentClause + arguments: + genericArgument + argument: + identifierType + name: identifier "Int" + leftAngle: < + rightAngle: > + pattern: + identifierPattern + identifier: identifier "numbers" + +--- + +top_level + body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "numbers" + value: + call_expr + callee: unsupported_node "Array" diff --git a/unified/extractor/tests/corpus/swift/expressions/generic-specialization-expression.swift b/unified/extractor/tests/corpus/swift/expressions/generic-specialization-expression.swift new file mode 100644 index 000000000000..8e5f07de5562 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/expressions/generic-specialization-expression.swift @@ -0,0 +1 @@ +let numbers = Array() diff --git a/unified/extractor/tests/corpus/swift/expressions/key-path-expression.output b/unified/extractor/tests/corpus/swift/expressions/key-path-expression.output new file mode 100644 index 000000000000..a803e9e594fd --- /dev/null +++ b/unified/extractor/tests/corpus/swift/expressions/key-path-expression.output @@ -0,0 +1,48 @@ +let keyPath = \String.count + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + keyPathExpr + backslash: \ + components: + keyPathComponent + period: . + component: + keyPathPropertyComponent + declName: + declReferenceExpr + baseName: identifier "count" + root: + identifierType + name: identifier "String" + pattern: + identifierPattern + identifier: identifier "keyPath" + +--- + +top_level + body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "keyPath" + value: unsupported_node "\\String.count" diff --git a/unified/extractor/tests/corpus/swift/expressions/key-path-expression.swift b/unified/extractor/tests/corpus/swift/expressions/key-path-expression.swift new file mode 100644 index 000000000000..943f181b3404 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/expressions/key-path-expression.swift @@ -0,0 +1 @@ +let keyPath = \String.count diff --git a/unified/extractor/tests/corpus/swift/expressions/unsafe-expression.output b/unified/extractor/tests/corpus/swift/expressions/unsafe-expression.output new file mode 100644 index 000000000000..2bdc964ddeaa --- /dev/null +++ b/unified/extractor/tests/corpus/swift/expressions/unsafe-expression.output @@ -0,0 +1,51 @@ +func doWork() {} +unsafe doWork() + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + functionDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + name: identifier "doWork" + modifiers: + signature: + functionSignature + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + funcKeyword: func + codeBlockItem + item: + unsafeExpr + expression: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "doWork" + unsafeKeyword: unsafe + +--- + +top_level + body: + block + stmt: + function_declaration + name: identifier "doWork" + body: block "func doWork() {}" + unsupported_node "unsafe doWork()" diff --git a/unified/extractor/tests/corpus/swift/expressions/unsafe-expression.swift b/unified/extractor/tests/corpus/swift/expressions/unsafe-expression.swift new file mode 100644 index 000000000000..e398f9cb6596 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/expressions/unsafe-expression.swift @@ -0,0 +1,2 @@ +func doWork() {} +unsafe doWork() diff --git a/unified/extractor/tests/corpus/swift/functions/call-with-inout-argument.output b/unified/extractor/tests/corpus/swift/functions/call-with-inout-argument.output new file mode 100644 index 000000000000..3dae9884c81e --- /dev/null +++ b/unified/extractor/tests/corpus/swift/functions/call-with-inout-argument.output @@ -0,0 +1,96 @@ +var a = 1 +var b = 2 +swap(&a, &b) + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: var + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + integerLiteralExpr + literal: integerLiteral "1" + pattern: + identifierPattern + identifier: identifier "a" + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: var + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + integerLiteralExpr + literal: integerLiteral "2" + pattern: + identifierPattern + identifier: identifier "b" + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + inOutExpr + expression: + declReferenceExpr + baseName: identifier "a" + ampersand: & + trailingComma: , + labeledExpr + expression: + inOutExpr + expression: + declReferenceExpr + baseName: identifier "b" + ampersand: & + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "swap" + +--- + +top_level + body: + block + stmt: + variable_declaration + modifier: modifier "var" + pattern: + name_pattern + identifier: identifier "a" + value: int_literal "1" + variable_declaration + modifier: modifier "var" + pattern: + name_pattern + identifier: identifier "b" + value: int_literal "2" + call_expr + callee: + name_expr + identifier: identifier "swap" + argument: + argument + value: unsupported_node "&a" + argument + value: unsupported_node "&b" diff --git a/unified/extractor/tests/corpus/swift/functions/call-with-inout-argument.swift b/unified/extractor/tests/corpus/swift/functions/call-with-inout-argument.swift new file mode 100644 index 000000000000..fb71b4c89bf3 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/functions/call-with-inout-argument.swift @@ -0,0 +1,3 @@ +var a = 1 +var b = 2 +swap(&a, &b) diff --git a/unified/extractor/tests/corpus/swift/functions/function-with-inout-parameter.output b/unified/extractor/tests/corpus/swift/functions/function-with-inout-parameter.output new file mode 100644 index 000000000000..232fb6dc2dbc --- /dev/null +++ b/unified/extractor/tests/corpus/swift/functions/function-with-inout-parameter.output @@ -0,0 +1,81 @@ +func increment(_ x: inout Int) { + x += 1 +} + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + functionDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "+=" + leftOperand: + declReferenceExpr + baseName: identifier "x" + rightOperand: + integerLiteralExpr + literal: integerLiteral "1" + name: identifier "increment" + modifiers: + signature: + functionSignature + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + functionParameter + colon: : + attributes: + modifiers: + type: + attributedType + attributes: + baseType: + identifierType + name: identifier "Int" + lateSpecifiers: + specifiers: + simpleTypeSpecifier + specifier: inout + firstName: _ + secondName: identifier "x" + funcKeyword: func + +--- + +top_level + body: + block + stmt: + function_declaration + name: identifier "increment" + parameter: + parameter + external_name: identifier "_" + type: unsupported_node "inout Int" + pattern: + name_pattern + identifier: identifier "x" + body: + block + stmt: + compound_assign_expr + target: + name_expr + identifier: identifier "x" + operator: infix_operator "+=" + value: int_literal "1" diff --git a/unified/extractor/tests/corpus/swift/functions/function-with-inout-parameter.swift b/unified/extractor/tests/corpus/swift/functions/function-with-inout-parameter.swift new file mode 100644 index 000000000000..5741998e8b53 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/functions/function-with-inout-parameter.swift @@ -0,0 +1,3 @@ +func increment(_ x: inout Int) { + x += 1 +} diff --git a/unified/extractor/tests/corpus/swift/literals/line-magic-literal.output b/unified/extractor/tests/corpus/swift/literals/line-magic-literal.output new file mode 100644 index 000000000000..1616055fc16c --- /dev/null +++ b/unified/extractor/tests/corpus/swift/literals/line-magic-literal.output @@ -0,0 +1,40 @@ +let currentLine = #line + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + macroExpansionExpr + arguments: + additionalTrailingClosures: + macroName: identifier "line" + pound: # + pattern: + identifierPattern + identifier: identifier "currentLine" + +--- + +top_level + body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "currentLine" + value: unsupported_node "#line" diff --git a/unified/extractor/tests/corpus/swift/literals/line-magic-literal.swift b/unified/extractor/tests/corpus/swift/literals/line-magic-literal.swift new file mode 100644 index 000000000000..11bb1ab77a92 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/literals/line-magic-literal.swift @@ -0,0 +1 @@ +let currentLine = #line diff --git a/unified/extractor/tests/corpus/swift/operators/custom-postfix-operator.output b/unified/extractor/tests/corpus/swift/operators/custom-postfix-operator.output new file mode 100644 index 000000000000..5067671aa997 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/operators/custom-postfix-operator.output @@ -0,0 +1,48 @@ +postfix operator ^^ +let squared = 3^^ + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + operatorDecl + name: binaryOperator "^^" + fixitySpecifier: postfix + operatorKeyword: operator + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + postfixOperatorExpr + expression: + integerLiteralExpr + literal: integerLiteral "3" + operator: postfixOperator "^^" + pattern: + identifierPattern + identifier: identifier "squared" + +--- + +top_level + body: + block + stmt: + unsupported_node "postfix operator ^^" + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "squared" + value: unsupported_node "3^^" diff --git a/unified/extractor/tests/corpus/swift/operators/custom-postfix-operator.swift b/unified/extractor/tests/corpus/swift/operators/custom-postfix-operator.swift new file mode 100644 index 000000000000..719517400392 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/operators/custom-postfix-operator.swift @@ -0,0 +1,2 @@ +postfix operator ^^ +let squared = 3^^ diff --git a/unified/extractor/tests/corpus/swift/operators/partial-range-from.output b/unified/extractor/tests/corpus/swift/operators/partial-range-from.output new file mode 100644 index 000000000000..1b9208cedf8b --- /dev/null +++ b/unified/extractor/tests/corpus/swift/operators/partial-range-from.output @@ -0,0 +1,40 @@ +let range = 3... + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + postfixOperatorExpr + expression: + integerLiteralExpr + literal: integerLiteral "3" + operator: postfixOperator "..." + pattern: + identifierPattern + identifier: identifier "range" + +--- + +top_level + body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "range" + value: unsupported_node "3..." diff --git a/unified/extractor/tests/corpus/swift/operators/partial-range-from.swift b/unified/extractor/tests/corpus/swift/operators/partial-range-from.swift new file mode 100644 index 000000000000..e223dc295165 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/operators/partial-range-from.swift @@ -0,0 +1 @@ +let range = 3... diff --git a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence.output b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence.output new file mode 100644 index 000000000000..7ecd448f03b1 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence.output @@ -0,0 +1,100 @@ +func combine(_ a: Int, _ b: Int) { + _ = a .& b +} + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + functionDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + sequenceExpr + elements: + discardAssignmentExpr + wildcard: _ + assignmentExpr + equal: = + declReferenceExpr + baseName: identifier "a" + binaryOperatorExpr + operator: binaryOperator ".&" + declReferenceExpr + baseName: identifier "b" + name: identifier "combine" + modifiers: + signature: + functionSignature + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + functionParameter + colon: : + attributes: + modifiers: + trailingComma: , + type: + identifierType + name: identifier "Int" + firstName: _ + secondName: identifier "a" + functionParameter + colon: : + attributes: + modifiers: + type: + identifierType + name: identifier "Int" + firstName: _ + secondName: identifier "b" + funcKeyword: func + +--- + +top_level + body: + block + stmt: + function_declaration + name: identifier "combine" + parameter: + parameter + external_name: identifier "_" + type: + named_type_expr + name: identifier "Int" + pattern: + name_pattern + identifier: identifier "a" + parameter + external_name: identifier "_" + type: + named_type_expr + name: identifier "Int" + pattern: + name_pattern + identifier: identifier "b" + body: + block + stmt: + unresolved_operator_sequence + element: + name_expr + identifier: identifier "_" + unsupported_node "=" + name_expr + identifier: identifier "a" + infix_operator ".&" + name_expr + identifier: identifier "b" diff --git a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence.swift b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence.swift new file mode 100644 index 000000000000..6ab759752d28 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence.swift @@ -0,0 +1,3 @@ +func combine(_ a: Int, _ b: Int) { + _ = a .& b +} diff --git a/unified/extractor/tests/corpus/swift/types/actor-declaration.output b/unified/extractor/tests/corpus/swift/types/actor-declaration.output new file mode 100644 index 000000000000..b4fcd605b9e9 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/types/actor-declaration.output @@ -0,0 +1,45 @@ +actor Counter { + var value = 0 +} + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + actorDecl + attributes: + name: identifier "Counter" + actorKeyword: actor + memberBlock: + memberBlock + leftBrace: { + rightBrace: } + members: + memberBlockItem + decl: + variableDecl + attributes: + modifiers: + bindingSpecifier: var + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + integerLiteralExpr + literal: integerLiteral "0" + pattern: + identifierPattern + identifier: identifier "value" + modifiers: + +--- + +top_level + body: + block + stmt: unsupported_node "actor Counter {\n var value = 0\n}" diff --git a/unified/extractor/tests/corpus/swift/types/actor-declaration.swift b/unified/extractor/tests/corpus/swift/types/actor-declaration.swift new file mode 100644 index 000000000000..a4c13e4e8761 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/types/actor-declaration.swift @@ -0,0 +1,3 @@ +actor Counter { + var value = 0 +} diff --git a/unified/extractor/tests/corpus/swift/types/conditional-compilation-in-class-body.output b/unified/extractor/tests/corpus/swift/types/conditional-compilation-in-class-body.output new file mode 100644 index 000000000000..2c530111b9ca --- /dev/null +++ b/unified/extractor/tests/corpus/swift/types/conditional-compilation-in-class-body.output @@ -0,0 +1,87 @@ +// Conditional compilation is not yet supported: swift-syntax reports a +// structured `ifConfigDecl` (whose branches hold ordinary member items), but +// the mapping has no rule for it, so the whole block becomes one +// `unsupported_node` and its members are not extracted. +class C { +#if DEBUG + init(x: Int) {} + deinit {} +#endif +} + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + classDecl + attributes: + name: identifier "C" + memberBlock: + memberBlock + leftBrace: { + rightBrace: } + members: + memberBlockItem + decl: + ifConfigDecl + clauses: + ifConfigClause + elements: + memberBlockItem + decl: + initializerDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + modifiers: + signature: + functionSignature + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + functionParameter + colon: : + attributes: + modifiers: + type: + identifierType + name: identifier "Int" + firstName: identifier "x" + initKeyword: init + memberBlockItem + decl: + deinitializerDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + modifiers: + deinitKeyword: deinit + condition: + declReferenceExpr + baseName: identifier "DEBUG" + poundKeyword: #if + poundEndif: #endif + modifiers: + classKeyword: class + +--- + +top_level + body: + block + stmt: + class_like_declaration + modifier: modifier "class" + name: identifier "C" + member: unsupported_node "#if DEBUG\n init(x: Int) {}\n deinit {}\n#endif" diff --git a/unified/extractor/tests/corpus/swift/types/conditional-compilation-in-class-body.swift b/unified/extractor/tests/corpus/swift/types/conditional-compilation-in-class-body.swift new file mode 100644 index 000000000000..fe50583118c9 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/types/conditional-compilation-in-class-body.swift @@ -0,0 +1,10 @@ +// Conditional compilation is not yet supported: swift-syntax reports a +// structured `ifConfigDecl` (whose branches hold ordinary member items), but +// the mapping has no rule for it, so the whole block becomes one +// `unsupported_node` and its members are not extracted. +class C { +#if DEBUG + init(x: Int) {} + deinit {} +#endif +} diff --git a/unified/extractor/tests/corpus/swift/types/function-type-with-convention-attribute.output b/unified/extractor/tests/corpus/swift/types/function-type-with-convention-attribute.output new file mode 100644 index 000000000000..3d484d6f65d8 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/types/function-type-with-convention-attribute.output @@ -0,0 +1,73 @@ +let callback: @convention(c) () -> Void = {} + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + closureExpr + leftBrace: { + rightBrace: } + statements: + pattern: + identifierPattern + identifier: identifier "callback" + typeAnnotation: + typeAnnotation + colon: : + type: + attributedType + attributes: + attribute + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + declReferenceExpr + baseName: identifier "c" + atSign: @ + attributeName: + identifierType + name: identifier "convention" + baseType: + functionType + leftParen: ( + rightParen: ) + parameters: + returnClause: + returnClause + arrow: -> + type: + identifierType + name: identifier "Void" + lateSpecifiers: + specifiers: + +--- + +top_level + body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "callback" + type: unsupported_node "@convention(c) () -> Void" + value: + function_expr + body: block "{}" diff --git a/unified/extractor/tests/corpus/swift/types/function-type-with-convention-attribute.swift b/unified/extractor/tests/corpus/swift/types/function-type-with-convention-attribute.swift new file mode 100644 index 000000000000..f84fa5270093 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/types/function-type-with-convention-attribute.swift @@ -0,0 +1 @@ +let callback: @convention(c) () -> Void = {} diff --git a/unified/extractor/tests/corpus/swift/types/function-type-with-sendable-attribute.output b/unified/extractor/tests/corpus/swift/types/function-type-with-sendable-attribute.output new file mode 100644 index 000000000000..ef9f838dadbe --- /dev/null +++ b/unified/extractor/tests/corpus/swift/types/function-type-with-sendable-attribute.output @@ -0,0 +1,66 @@ +let handler: @Sendable () -> Void = {} + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + closureExpr + leftBrace: { + rightBrace: } + statements: + pattern: + identifierPattern + identifier: identifier "handler" + typeAnnotation: + typeAnnotation + colon: : + type: + attributedType + attributes: + attribute + atSign: @ + attributeName: + identifierType + name: identifier "Sendable" + baseType: + functionType + leftParen: ( + rightParen: ) + parameters: + returnClause: + returnClause + arrow: -> + type: + identifierType + name: identifier "Void" + lateSpecifiers: + specifiers: + +--- + +top_level + body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "handler" + type: unsupported_node "@Sendable () -> Void" + value: + function_expr + body: block "{}" diff --git a/unified/extractor/tests/corpus/swift/types/function-type-with-sendable-attribute.swift b/unified/extractor/tests/corpus/swift/types/function-type-with-sendable-attribute.swift new file mode 100644 index 000000000000..00810b921e84 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/types/function-type-with-sendable-attribute.swift @@ -0,0 +1 @@ +let handler: @Sendable () -> Void = {} diff --git a/unified/extractor/tests/corpus/swift/types/inline-array-type.output b/unified/extractor/tests/corpus/swift/types/inline-array-type.output new file mode 100644 index 000000000000..5f70d9d55168 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/types/inline-array-type.output @@ -0,0 +1,77 @@ +let triple: [3 of Int] = [1, 2, 3] + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + arrayExpr + elements: + arrayElement + expression: + integerLiteralExpr + literal: integerLiteral "1" + trailingComma: , + arrayElement + expression: + integerLiteralExpr + literal: integerLiteral "2" + trailingComma: , + arrayElement + expression: + integerLiteralExpr + literal: integerLiteral "3" + leftSquare: [ + rightSquare: ] + pattern: + identifierPattern + identifier: identifier "triple" + typeAnnotation: + typeAnnotation + colon: : + type: + inlineArrayType + leftSquare: [ + rightSquare: ] + element: + genericArgument + argument: + identifierType + name: identifier "Int" + count: + genericArgument + argument: + integerLiteralExpr + literal: integerLiteral "3" + separator: of + +--- + +top_level + body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "triple" + type: unsupported_node "[3 of Int]" + value: + array_literal + element: + int_literal "1" + int_literal "2" + int_literal "3" diff --git a/unified/extractor/tests/corpus/swift/types/inline-array-type.swift b/unified/extractor/tests/corpus/swift/types/inline-array-type.swift new file mode 100644 index 000000000000..3d27c8dca5c5 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/types/inline-array-type.swift @@ -0,0 +1 @@ +let triple: [3 of Int] = [1, 2, 3] diff --git a/unified/extractor/tests/corpus/swift/types/noncopyable-type.output b/unified/extractor/tests/corpus/swift/types/noncopyable-type.output new file mode 100644 index 000000000000..4fb13ca13ece --- /dev/null +++ b/unified/extractor/tests/corpus/swift/types/noncopyable-type.output @@ -0,0 +1,71 @@ +struct FileHandle: ~Copyable { + let descriptor: Int +} + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + structDecl + attributes: + name: identifier "FileHandle" + inheritanceClause: + inheritanceClause + colon: : + inheritedTypes: + inheritedType + type: + suppressedType + type: + identifierType + name: identifier "Copyable" + withoutTilde: prefixOperator "~" + memberBlock: + memberBlock + leftBrace: { + rightBrace: } + members: + memberBlockItem + decl: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + pattern: + identifierPattern + identifier: identifier "descriptor" + typeAnnotation: + typeAnnotation + colon: : + type: + identifierType + name: identifier "Int" + modifiers: + structKeyword: struct + +--- + +top_level + body: + block + stmt: + class_like_declaration + modifier: modifier "struct" + name: identifier "FileHandle" + base_type: + base_type + type: unsupported_node "~Copyable" + member: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "descriptor" + type: + named_type_expr + name: identifier "Int" diff --git a/unified/extractor/tests/corpus/swift/types/noncopyable-type.swift b/unified/extractor/tests/corpus/swift/types/noncopyable-type.swift new file mode 100644 index 000000000000..55390c9e6d13 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/types/noncopyable-type.swift @@ -0,0 +1,3 @@ +struct FileHandle: ~Copyable { + let descriptor: Int +} From c60900f573fceecd92c64c413d258f56e28ac9a9 Mon Sep 17 00:00:00 2001 From: Taus Date: Fri, 24 Jul 2026 19:45:29 +0000 Subject: [PATCH 098/188] unified: Handle assignment etc. in unresolved operator sequences Adds rules for mapping things like `=` and `as!` to `infix_operator`s, so that they are present in the output (which for unresolved operators expects an alternating sequence of values and `infix_operator`s). For ternary operators, we expand this into _two_ unresolved infix operators, `?` and `:` respectively. --- .../extractor/src/languages/swift/swift.rs | 22 +++ ...solved-operator-sequence-with-casts.output | 141 ++++++++++++++++ ...esolved-operator-sequence-with-casts.swift | 4 + ...lved-operator-sequence-with-ternary.output | 157 ++++++++++++++++++ ...olved-operator-sequence-with-ternary.swift | 3 + .../unresolved-operator-sequence.output | 2 +- 6 files changed, 328 insertions(+), 1 deletion(-) create mode 100644 unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-casts.output create mode 100644 unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-casts.swift create mode 100644 unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-ternary.output create mode 100644 unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-ternary.swift diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index 575c66733a51..a3b05cbdb1a9 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -205,6 +205,28 @@ fn translation_rules() -> Vec> { => (assign_expr target: {l} value: {r}) ), + // In an unresolved `sequenceExpr` (below) the operator positions are not + // only `binaryOperatorExpr`s: a plain assignment (`=`), an `as`/`is` cast + // and the ternary `?:` can also appear unfolded. Map each to an + // `infix_operator` (keeping its spelling) so the sequence stays a clean + // alternation of operands and operators instead of dropping the operator + // to an opaque `unsupported_node`. These bare nodes only occur inside an + // unresolved sequence — folded forms are handled by the dedicated rules + // above (assignment) and below (`ternaryExpr`). + rule!((assignmentExpr) @op => (infix_operator #{op})), + rule!((unresolvedAsExpr) @op => (infix_operator #{op})), + rule!((unresolvedIsExpr) @op => (infix_operator #{op})), + // The ternary is a three-part operator (`? thenExpr :`) that *wraps* a + // nested expression. Splice it into `?`, the then-expression, `:` so the + // then-expression survives as a real (traversable) operand rather than + // being buried in an opaque token. + rule!( + (unresolvedTernaryExpr questionMark: @@q thenExpression: @then colon: @@c) + => + expr_or_operator* { + vec![tree!((infix_operator #{q})), then, tree!((infix_operator #{c}))] + } + ), // Escape hatch: an operator chain the front-end could not resolve // (because it uses an operator of unknown precedence, e.g. imported from // another module) stays a flat `sequenceExpr`. Preserve it as an diff --git a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-casts.output b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-casts.output new file mode 100644 index 000000000000..a0563c7bc88b --- /dev/null +++ b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-casts.output @@ -0,0 +1,141 @@ +func casts(_ a: Any, _ b: Int) { + _ = a as Int .& b + _ = a is Int .& b +} + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + functionDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + sequenceExpr + elements: + discardAssignmentExpr + wildcard: _ + assignmentExpr + equal: = + declReferenceExpr + baseName: identifier "a" + unresolvedAsExpr + asKeyword: as + typeExpr + type: + identifierType + name: identifier "Int" + binaryOperatorExpr + operator: binaryOperator ".&" + declReferenceExpr + baseName: identifier "b" + codeBlockItem + item: + sequenceExpr + elements: + discardAssignmentExpr + wildcard: _ + assignmentExpr + equal: = + declReferenceExpr + baseName: identifier "a" + unresolvedIsExpr + isKeyword: is + typeExpr + type: + identifierType + name: identifier "Int" + binaryOperatorExpr + operator: binaryOperator ".&" + declReferenceExpr + baseName: identifier "b" + name: identifier "casts" + modifiers: + signature: + functionSignature + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + functionParameter + colon: : + attributes: + modifiers: + trailingComma: , + type: + identifierType + name: Any + firstName: _ + secondName: identifier "a" + functionParameter + colon: : + attributes: + modifiers: + type: + identifierType + name: identifier "Int" + firstName: _ + secondName: identifier "b" + funcKeyword: func + +--- + +top_level + body: + block + stmt: + function_declaration + name: identifier "casts" + parameter: + parameter + external_name: identifier "_" + type: + named_type_expr + name: identifier "Any" + pattern: + name_pattern + identifier: identifier "a" + parameter + external_name: identifier "_" + type: + named_type_expr + name: identifier "Int" + pattern: + name_pattern + identifier: identifier "b" + body: + block + stmt: + unresolved_operator_sequence + element: + name_expr + identifier: identifier "_" + infix_operator "=" + name_expr + identifier: identifier "a" + infix_operator "as" + unsupported_node "Int" + infix_operator ".&" + name_expr + identifier: identifier "b" + unresolved_operator_sequence + element: + name_expr + identifier: identifier "_" + infix_operator "=" + name_expr + identifier: identifier "a" + infix_operator "is" + unsupported_node "Int" + infix_operator ".&" + name_expr + identifier: identifier "b" diff --git a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-casts.swift b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-casts.swift new file mode 100644 index 000000000000..b22c93eb31e7 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-casts.swift @@ -0,0 +1,4 @@ +func casts(_ a: Any, _ b: Int) { + _ = a as Int .& b + _ = a is Int .& b +} diff --git a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-ternary.output b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-ternary.output new file mode 100644 index 000000000000..57274c32a9c2 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-ternary.output @@ -0,0 +1,157 @@ +func choose(_ c: Bool, _ a: Int, _ b: Int, _ d: Int) -> Int { + return c ? a : b .& d +} + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + functionDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + returnStmt + expression: + sequenceExpr + elements: + declReferenceExpr + baseName: identifier "c" + unresolvedTernaryExpr + colon: : + questionMark: ? + thenExpression: + declReferenceExpr + baseName: identifier "a" + declReferenceExpr + baseName: identifier "b" + binaryOperatorExpr + operator: binaryOperator ".&" + declReferenceExpr + baseName: identifier "d" + returnKeyword: return + name: identifier "choose" + modifiers: + signature: + functionSignature + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + functionParameter + colon: : + attributes: + modifiers: + trailingComma: , + type: + identifierType + name: identifier "Bool" + firstName: _ + secondName: identifier "c" + functionParameter + colon: : + attributes: + modifiers: + trailingComma: , + type: + identifierType + name: identifier "Int" + firstName: _ + secondName: identifier "a" + functionParameter + colon: : + attributes: + modifiers: + trailingComma: , + type: + identifierType + name: identifier "Int" + firstName: _ + secondName: identifier "b" + functionParameter + colon: : + attributes: + modifiers: + type: + identifierType + name: identifier "Int" + firstName: _ + secondName: identifier "d" + returnClause: + returnClause + arrow: -> + type: + identifierType + name: identifier "Int" + funcKeyword: func + +--- + +top_level + body: + block + stmt: + function_declaration + name: identifier "choose" + parameter: + parameter + external_name: identifier "_" + type: + named_type_expr + name: identifier "Bool" + pattern: + name_pattern + identifier: identifier "c" + parameter + external_name: identifier "_" + type: + named_type_expr + name: identifier "Int" + pattern: + name_pattern + identifier: identifier "a" + parameter + external_name: identifier "_" + type: + named_type_expr + name: identifier "Int" + pattern: + name_pattern + identifier: identifier "b" + parameter + external_name: identifier "_" + type: + named_type_expr + name: identifier "Int" + pattern: + name_pattern + identifier: identifier "d" + return_type: + named_type_expr + name: identifier "Int" + body: + block + stmt: + return_expr + value: + unresolved_operator_sequence + element: + name_expr + identifier: identifier "c" + infix_operator "?" + name_expr + identifier: identifier "a" + infix_operator ":" + name_expr + identifier: identifier "b" + infix_operator ".&" + name_expr + identifier: identifier "d" diff --git a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-ternary.swift b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-ternary.swift new file mode 100644 index 000000000000..54f164eee9a2 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-ternary.swift @@ -0,0 +1,3 @@ +func choose(_ c: Bool, _ a: Int, _ b: Int, _ d: Int) -> Int { + return c ? a : b .& d +} diff --git a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence.output b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence.output index 7ecd448f03b1..46dc8ca6ae89 100644 --- a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence.output +++ b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence.output @@ -92,7 +92,7 @@ top_level element: name_expr identifier: identifier "_" - unsupported_node "=" + infix_operator "=" name_expr identifier: identifier "a" infix_operator ".&" From a0dc89892e1002ffbe392484f6136e44eb07aacf Mon Sep 17 00:00:00 2001 From: Taus Date: Tue, 28 Jul 2026 13:57:37 +0000 Subject: [PATCH 099/188] yeast: Add optional fields to tree templates Wrapping an optional capture in a node meant building the wrapper inside an `Option::map`, which buried the shape of the output in a closure: (break_expr label: {lbl.map(|l| tree!((identifier #{l})))}) A field's value can now be marked with `?` instead. If a `#{expr}` anywhere beneath it interpolates an absent value, the subtree is abandoned and the field is left unset: (break_expr label: (identifier #{lbl})?) The marker follows the value, as quantifiers do in the query language (`label: _? @@lbl`). Absence propagates through as many levels as necessary, and a nested `?` catches first, so an inner absent value need not discard the outer node. Only `#{expr}` propagates absence, since it supplies a node's content: with no value there is no leaf to build. A `{expr}` splice supplies children, where yielding nothing already leaves the field unset, so `?` is rejected on one. Outside a `?`, interpolating an `Option` with `#{expr}` remains a compile error, keeping the choice between leaving a field unset and unwrapping explicit; `YeastDisplay` now carries an `on_unimplemented` note pointing at the new syntax. Inside a fallible field, interpolations route through a new `MaybeYeastValue` trait, whose impls are enumerated rather than blanket for the same coherence reason `YeastDisplay`'s are. Codegen outside a `?` is unchanged, so `tree!` and `trees!` keep their return types. Converting the ten `Option::map` sites in the Swift rules leaves the corpus byte-identical; four captures become `@@` now that their values are only ever interpolated. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- shared/yeast-macros/src/lib.rs | 27 ++++ shared/yeast-macros/src/parse.rs | 128 +++++++++++++++++- shared/yeast/doc/yeast.md | 47 +++++++ shared/yeast/src/lib.rs | 80 +++++++++++ shared/yeast/tests/test.rs | 111 +++++++++++++++ .../extractor/src/languages/swift/swift.rs | 34 +++-- 6 files changed, 403 insertions(+), 24 deletions(-) diff --git a/shared/yeast-macros/src/lib.rs b/shared/yeast-macros/src/lib.rs index 0df96c91d26b..82b0e3e7b408 100644 --- a/shared/yeast-macros/src/lib.rs +++ b/shared/yeast-macros/src/lib.rs @@ -47,8 +47,35 @@ pub fn query(input: TokenStream) -> TokenStream { /// `Option`, iterator chains) splice /// their elements /// field: {expr} - extend a named field with `{expr}`'s ids +/// field: (kind ...)? - set the field only if every `#{expr}` +/// beneath it has a value (see below) /// ``` /// +/// # Optional fields +/// +/// A `?` on a field's value makes that field fallible: if a `#{expr}` +/// anywhere beneath it interpolates an absent value — an `Option` that is +/// `None` — the subtree is abandoned and the field is left unset. This +/// replaces the surrounding `Option::map` that would otherwise be needed: +/// +/// ```text +/// (break_expr label: {lbl.map(|l| tree!((identifier #{l})))}) // before +/// (break_expr label: (identifier #{lbl})?) // after +/// ``` +/// +/// The value may be nested arbitrarily deeply, and a nested `?` catches +/// first, so an inner absent value need not discard the outer node: +/// +/// ```text +/// (parameter pattern: (name_pattern identifier: (identifier #{name}))? type: {ty}) +/// ``` +/// +/// Only `#{expr}` propagates absence. A `{expr}` splice is unaffected, since +/// yielding no ids already leaves a field unset, and `?` is rejected on one. +/// Outside a `?`, interpolating an `Option` with `#{expr}` remains a compile +/// error, so the choice between "unset the field" and "unwrap it" stays +/// explicit. +/// /// Can be called with an explicit context or using the implicit context /// from an enclosing `rule!`: /// diff --git a/shared/yeast-macros/src/parse.rs b/shared/yeast-macros/src/parse.rs index 55ada3588491..40f9dbce61c8 100644 --- a/shared/yeast-macros/src/parse.rs +++ b/shared/yeast-macros/src/parse.rs @@ -1,10 +1,44 @@ use proc_macro2::{Delimiter, Ident, Literal, Span, TokenStream, TokenTree}; use quote::quote; use std::iter::Peekable; +use std::sync::atomic::{AtomicUsize, Ordering}; +use syn::Lifetime; type Tokens = Peekable; type Result = std::result::Result; +/// Mints the block label a fallible field breaks out of. Labels must be unique +/// along a nesting chain, since a `?` nested inside another `?` has to break out +/// of the inner field only. +fn fresh_fallible_label() -> Lifetime { + static COUNTER: AtomicUsize = AtomicUsize::new(0); + let n = COUNTER.fetch_add(1, Ordering::Relaxed); + Lifetime::new(&format!("'__yeast_field_{n}"), Span::call_site()) +} + +/// Rejects a `?` in a position where there is no field for it to leave unset. +/// +/// The advice depends on what precedes it: on a `{...}` splice a `?` is +/// redundant, and anywhere else it belongs on a field's value. Other +/// quantifiers need no handling — `*` and `+` have never been valid in a +/// template, and the existing check for stray tokens already rejects them. +fn reject_stray_optional(tokens: &mut Tokens, after_splice: bool) -> Result<()> { + let Some(TokenTree::Punct(p)) = tokens.peek() else { + return Ok(()); + }; + if p.as_char() != '?' { + return Ok(()); + } + let msg = if after_splice { + "`?` is not valid on a `{...}` splice; a splice that yields no value \ + already leaves its field unset" + } else { + "`?` is only valid on the value of a named field, as in \ + `label: (identifier #{lbl})?`" + }; + Err(syn::Error::new_spanned(p.clone(), msg)) +} + // --------------------------------------------------------------------------- // Query parsing // --------------------------------------------------------------------------- @@ -318,8 +352,9 @@ pub fn parse_tree_top(input: TokenStream) -> Result { let mut tokens = input.into_iter().peekable(); let ctx = parse_ctx_or_implicit(&mut tokens); - let first = parse_direct_node(&mut tokens, &ctx)?; + let first = parse_direct_node(&mut tokens, &ctx, None)?; + reject_stray_optional(&mut tokens, false)?; if let Some(tok) = tokens.next() { return Err(syn::Error::new_spanned( tok, @@ -352,7 +387,15 @@ pub fn parse_trees_top(input: TokenStream) -> Result { /// Parse a single node template and generate code that returns an `Id`. /// Handles: `(kind fields... children...)` and `{expr}`. -fn parse_direct_node(tokens: &mut Tokens, ctx: &Ident) -> Result { +/// +/// `scope` is the enclosing fallible field's label, if any: inside one, a +/// `#{expr}` that interpolates an absent value breaks out to it, leaving that +/// field unset. See [`parse_direct_node_inner`]. +fn parse_direct_node( + tokens: &mut Tokens, + ctx: &Ident, + scope: Option<&Lifetime>, +) -> Result { match tokens.peek() { Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Brace => { let group = expect_group(tokens, Delimiter::Brace)?; @@ -362,7 +405,7 @@ fn parse_direct_node(tokens: &mut Tokens, ctx: &Ident) -> Result { Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Parenthesis => { let group = expect_group(tokens, Delimiter::Parenthesis)?; let mut inner = group.stream().into_iter().peekable(); - parse_direct_node_inner(&mut inner, ctx) + parse_direct_node_inner(&mut inner, ctx, scope) } Some(tok) => Err(syn::Error::new_spanned( tok.clone(), @@ -377,7 +420,11 @@ fn parse_direct_node(tokens: &mut Tokens, ctx: &Ident) -> Result { /// Parse the inside of a parenthesized node: `kind fields... children...` /// or `kind "literal"` or `kind $fresh`. -fn parse_direct_node_inner(tokens: &mut Tokens, ctx: &Ident) -> Result { +fn parse_direct_node_inner( + tokens: &mut Tokens, + ctx: &Ident, + scope: Option<&Lifetime>, +) -> Result { let kind = expect_ident(tokens, "expected node kind")?; let kind_str = kind.to_string(); @@ -392,6 +439,28 @@ fn parse_direct_node_inner(tokens: &mut Tokens, ctx: &Ident) -> Result Result = Vec::new(); @@ -446,7 +516,47 @@ fn parse_direct_node_inner(tokens: &mut Tokens, ctx: &Ident) -> Result = #label: { + ::std::option::Option::Some(#value) + }; + }); + field_args.push(quote! { + if let ::std::option::Option::Some(__id) = #temp { + __fields.push((#field_str, vec![__id])); + } + }); + } else { + // No `?` of its own, so failures beneath it belong to whichever + // fallible field encloses this one, if any. + let value = parse_direct_node_inner(&mut inner, ctx, scope)?; + stmts.push(quote! { let #temp: yeast::Id = #value; }); + field_args.push(quote! { __fields.push((#field_str, vec![#temp])); }); + } + continue; + } + + // Neither form matched; delegate for a consistent error message. + let value = parse_direct_node(tokens, ctx, scope)?; stmts.push(quote! { let #temp: yeast::Id = #value; }); field_args.push(quote! { __fields.push((#field_str, vec![#temp])); }); } @@ -486,7 +596,8 @@ fn parse_direct_list(tokens: &mut Tokens, ctx: &Ident) -> Result Result bool { matches!(tokens.peek(), Some(TokenTree::Group(g)) if g.delimiter() == delim) } +fn peek_is_punct(tokens: &mut Tokens, ch: char) -> bool { + matches!(tokens.peek(), Some(TokenTree::Punct(p)) if p.as_char() == ch) +} + fn peek_is_repetition(tokens: &mut Tokens) -> bool { matches!(tokens.peek(), Some(TokenTree::Punct(p)) if matches!(p.as_char(), '*' | '+' | '?')) } diff --git a/shared/yeast/doc/yeast.md b/shared/yeast/doc/yeast.md index 90edb510c1a1..be3bc913c700 100644 --- a/shared/yeast/doc/yeast.md +++ b/shared/yeast/doc/yeast.md @@ -235,6 +235,48 @@ yeast::trees!(ctx, (identifier #{name}) // an identifier from a Rust variable ``` +### Optional fields (`?`) + +A `?` on a field's value makes that field fallible. If a `#{expr}` anywhere +beneath it interpolates an absent value — an `Option` that is `None` — the +subtree is abandoned and the field is left unset: + +```rust +rule!((breakStmt label: _? @@lbl) => (break_expr label: (identifier #{lbl})?)) +``` + +Here an optional capture is being wrapped in a leaf, which without `?` needs +an `Option::map` to build the leaf only in the `Some` case: + +```rust +// Equivalent, but the intent is buried in the closure: +(break_expr label: {lbl.map(|l| tree!((identifier #{l})))}) +``` + +The marker mirrors the query language, where a quantifier likewise follows the +value it applies to (`label: _? @@lbl`). Note that the schema puts it on the +other side of the colon — `external_name?: identifier` — because it is +*declaring* a field's cardinality rather than supplying a value for it. + +Absence propagates outwards through as many levels as necessary, and a nested +`?` catches first, so an inner absent value need not discard the outer node: + +```rust +// If `name` is absent, `pattern` is left unset — but `type` is still set. +(parameter pattern: (name_pattern identifier: (identifier #{name}))? type: {ty}) +``` + +Only `#{expr}` propagates absence, because it supplies a node's *content*: with +no value there is no leaf to build. A `{expr}` splice supplies *children*, where +yielding nothing already leaves the field unset (see below), so `?` is rejected +on one. Repetition has no marker at all, in templates or elsewhere: how many +children a `{expr}` contributes is a property of the expression rather than of +the syntax. + +Outside a `?`, interpolating an `Option` with `#{expr}` remains a compile error. +That is deliberate: it keeps the choice between "leave the field unset" and +"unwrap it" explicit at every interpolation. + ### Fresh identifiers `(kind $name)` creates a leaf node with an auto-generated unique name. All @@ -279,6 +321,11 @@ yeast::trees!(ctx, ) ``` +Because an `Option` splices as zero or one id, `field: {opt}` already +leaves the field unset when `opt` is `None`. Use [`?`](#optional-fields-) +instead when the optional value has to be *wrapped* in a node first, so that +there is nothing to wrap when it is absent. + The contents of `{…}` are treated as a Rust block, so multi-statement expressions (with `let` bindings) work too: diff --git a/shared/yeast/src/lib.rs b/shared/yeast/src/lib.rs index 14a0ab055761..cf06d2d2c17b 100644 --- a/shared/yeast/src/lib.rs +++ b/shared/yeast/src/lib.rs @@ -117,6 +117,11 @@ where /// All standard primitive and string types implement [`YeastDisplay`] via /// the [`impl_yeast_display_via_display`] macro below. Coherence prevents a /// blanket `impl`, so additional types must be added explicitly. +#[diagnostic::on_unimplemented( + message = "`{Self}` cannot be interpolated with `#{{...}}`", + note = "if the value is optional, mark the enclosing field's value with `?` to leave \ + that field unset when it is absent, as in `label: (identifier #{{lbl}})?`" +)] pub trait YeastDisplay { fn yeast_to_string(&self, ast: &Ast) -> String; } @@ -183,6 +188,81 @@ impl YeastSourceRange for &T { } } +/// Normalizes a `#{expr}` interpolation to an optional value, so that a +/// fallible field — `field: (kind #{expr})?` — can tell "there is a value to +/// interpolate" apart from "there is none, so leave the field unset". +/// +/// Implemented for every [`YeastDisplay`] type, which always yields a value, +/// and for `Option` of the same, which yields one only when it is `Some`. +/// +/// The implementations are enumerated rather than blanket: a blanket +/// `impl` would overlap with the `Option` impl, since +/// coherence cannot rule out a future `impl YeastDisplay for Option`. +/// [`YeastDisplay`] itself is enumerated for the same reason. +/// +/// Note that this is used *only* inside a fallible field. Elsewhere `#{expr}` +/// still goes directly through [`YeastDisplay`], so interpolating an `Option` +/// without a `?` remains a compile error rather than silently dropping a node. +pub trait MaybeYeastValue { + /// The interpolated value's type, which knows how to render itself. + type Value: YeastDisplay + YeastSourceRange + ?Sized; + + /// Returns the value to interpolate, or `None` to leave the field unset. + fn maybe_yeast_value(&self) -> Option<&Self::Value>; +} + +macro_rules! impl_maybe_yeast_value { + ($($t:ty),* $(,)?) => { + $( + impl MaybeYeastValue for $t { + type Value = $t; + fn maybe_yeast_value(&self) -> Option<&$t> { + Some(self) + } + } + + impl MaybeYeastValue for Option<$t> { + type Value = $t; + fn maybe_yeast_value(&self) -> Option<&$t> { + self.as_ref() + } + } + )* + }; +} + +impl_maybe_yeast_value! { + Id, + i8, i16, i32, i64, i128, isize, + u8, u16, u32, u64, u128, usize, + f32, f64, + bool, char, + String, +} + +// `str` is unsized, so it has no `Option` counterpart; `Option<&str>` is +// covered by the reference impls below. +impl MaybeYeastValue for str { + type Value = str; + fn maybe_yeast_value(&self) -> Option<&str> { + Some(self) + } +} + +impl MaybeYeastValue for &T { + type Value = T::Value; + fn maybe_yeast_value(&self) -> Option<&T::Value> { + (**self).maybe_yeast_value() + } +} + +impl MaybeYeastValue for Option<&T> { + type Value = T::Value; + fn maybe_yeast_value(&self) -> Option<&T::Value> { + (*self).and_then(MaybeYeastValue::maybe_yeast_value) + } +} + #[derive(Debug)] pub struct AstCursor<'a> { ast: &'a Ast, diff --git a/shared/yeast/tests/test.rs b/shared/yeast/tests/test.rs index 756e219bd890..bdc17c7593dc 100644 --- a/shared/yeast/tests/test.rs +++ b/shared/yeast/tests/test.rs @@ -674,6 +674,117 @@ fn test_tree_builder() { ); } +/// Builds `(assignment left: … right: (integer #{value})?)`, where a `None` +/// `value` leaves `right` unset rather than producing an `integer` with no +/// content. +fn build_optional_right(ast: &mut Ast, value: Option) -> (yeast::Id, yeast::Id) { + let captures = yeast::captures::Captures::new(); + let fresh = yeast::tree_builder::FreshScope::new(); + let mut user_ctx = (); + let mut ctx = yeast::build::BuildCtx::new(ast, &captures, &fresh, &mut user_ctx); + let left = yeast::tree!(ctx, (identifier "x")); + let root = yeast::tree!(ctx, + (assignment + left: {left} + right: (integer #{value})? + ) + ); + (root, left) +} + +#[test] +fn test_optional_field_is_set_when_the_value_is_present() { + let runner: Runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), &[]); + let mut ast = runner.run("x = 1").unwrap(); + + // Any node will do as the interpolated value; `#{…}` renders its source text. + let mut cursor = AstCursor::new(&ast); + cursor.goto_first_child(); + let some = cursor.node_id(); + + let (root, _) = build_optional_right(&mut ast, Some(some)); + assert_dump_eq( + &dump_ast(&ast, root, "x = 1"), + r#" + assignment + left: identifier "x" + right: integer "x = 1" + "#, + ); +} + +#[test] +fn test_optional_field_is_unset_when_the_value_is_absent() { + let runner: Runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), &[]); + let mut ast = runner.run("x = 1").unwrap(); + + let (root, _) = build_optional_right(&mut ast, None); + assert_dump_eq( + &dump_ast(&ast, root, "x = 1"), + r#" + assignment + left: identifier "x" + "#, + ); +} + +#[test] +fn test_optional_field_propagates_through_nested_nodes() { + let runner: Runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), &[]); + let mut ast = runner.run("x = 1").unwrap(); + + let captures = yeast::captures::Captures::new(); + let fresh = yeast::tree_builder::FreshScope::new(); + let mut user_ctx = (); + let mut ctx = yeast::build::BuildCtx::new(&mut ast, &captures, &fresh, &mut user_ctx); + + // The absent value sits two levels below the `?`, so the whole + // `left_assignment_list` subtree is abandoned along with it. + let absent: Option = None; + let right = yeast::tree!(ctx, (integer "1")); + let root = yeast::tree!(ctx, + (assignment + left: (left_assignment_list child: (identifier #{absent}))? + right: {right} + ) + ); + + assert_dump_eq( + &dump_ast(&ast, root, "x = 1"), + r#" + assignment + right: integer "1" + "#, + ); +} + +#[test] +fn test_innermost_optional_field_catches_first() { + let runner: Runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), &[]); + let mut ast = runner.run("x = 1").unwrap(); + + let captures = yeast::captures::Captures::new(); + let fresh = yeast::tree_builder::FreshScope::new(); + let mut user_ctx = (); + let mut ctx = yeast::build::BuildCtx::new(&mut ast, &captures, &fresh, &mut user_ctx); + + // The inner `?` catches, so only `child` is dropped; `left` survives. + let absent: Option = None; + let root = yeast::tree!(ctx, + (assignment + left: (left_assignment_list child: (identifier #{absent})?)? + ) + ); + + assert_dump_eq( + &dump_ast(&ast, root, "x = 1"), + r#" + assignment + left: left_assignment_list + "#, + ); +} + // ---- Rule tests ---- // These rules use field names from node-types.yml, which extends the diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index a3b05cbdb1a9..bb421e776980 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -412,7 +412,7 @@ fn translation_rules() -> Vec> { rule!( (enumCaseParameter firstName: _? @@name type: @ty) => - (parameter pattern: {name.map(|name| tree!((name_pattern identifier: (identifier #{name}))))} type: {ty}) + (parameter pattern: (name_pattern identifier: (identifier #{name}))? type: {ty}) ), // An enum element with associated values (`case circle(radius: Double)`) // becomes a nested `class_like_declaration` whose constructor carries the @@ -508,9 +508,9 @@ fn translation_rules() -> Vec> { // key; unlabelled elements have no key. rule!((tuplePattern elements: _* @els) => (tuple_pattern element: {els})), rule!( - (tuplePatternElement label: _? @label pattern: @p) + (tuplePatternElement label: _? @@label pattern: @p) => - (pattern_element key: {label.map(|l| tree!((identifier #{l})))} pattern: {p}) + (pattern_element key: (identifier #{label})? pattern: {p}) ), // A type-casting pattern (`case is T`). Not yet supported, so it is // mapped to `unsupported_node` — an explicit reminder that this needs @@ -626,26 +626,25 @@ fn translation_rules() -> Vec> { // The pattern-only shapes (`patternExpr`, `discardAssignmentExpr`) are // matched first; they never occur as ordinary call arguments. rule!( - (labeledExpr label: _? @lbl expression: (patternExpr pattern: @p)) + (labeledExpr label: _? @@lbl expression: (patternExpr pattern: @p)) => - (pattern_element key: {lbl.map(|l| tree!((identifier #{l})))} pattern: {p}) + (pattern_element key: (identifier #{lbl})? pattern: {p}) ), rule!( - (labeledExpr label: _? @lbl expression: (discardAssignmentExpr) @@wildcard) + (labeledExpr label: _? @@lbl expression: (discardAssignmentExpr) @@wildcard) => - (pattern_element key: {lbl.map(|l| tree!((identifier #{l})))} pattern: (ignore_pattern #{wildcard})) + (pattern_element key: (identifier #{lbl})? pattern: (ignore_pattern #{wildcard})) ), rule!( - (labeledExpr label: _? @lbl expression: @val) + (labeledExpr label: _? @@lbl expression: @val) => argument { - let key = lbl.map(|l| tree!((identifier #{l}))); if ctx.in_pattern { tree!((pattern_element - key: {key} + key: (identifier #{lbl})? pattern: (expr_equality_pattern expr: {val}))) } else { - tree!((argument name: {key} value: {val})) + tree!((argument name: (identifier #{lbl})? value: {val})) } } ), @@ -667,8 +666,8 @@ fn translation_rules() -> Vec> { // value; `break` / `continue` an optional target label; `throw` its // thrown expression. rule!((returnStmt expression: _? @val) => (return_expr value: {val})), - rule!((breakStmt label: _? @@lbl) => (break_expr label: {lbl.map(|l| tree!((identifier #{l})))})), - rule!((continueStmt label: _? @@lbl) => (continue_expr label: {lbl.map(|l| tree!((identifier #{l})))})), + rule!((breakStmt label: _? @@lbl) => (break_expr label: (identifier #{lbl})?)), + rule!((continueStmt label: _? @@lbl) => (continue_expr label: (identifier #{lbl})?)), rule!((throwStmt expression: @val) => (throw_expr value: {val})), // ---- Closures ---- // A closure (`{ (x: Int) -> Int in … }`) becomes a `function_expr`. The @@ -704,7 +703,7 @@ fn translation_rules() -> Vec> { initializer: (initializerClause value: @val)?) => (variable_declaration - modifier: {spec.map(|s| tree!((modifier #{s})))} + modifier: (modifier #{spec})? pattern: (name_pattern identifier: (identifier #{name})) value: {val}) ), @@ -948,7 +947,7 @@ fn translation_rules() -> Vec> { None => tree!((bulk_importing_pattern)), }; tree!((import_declaration - modifier: {kind.map(|k| tree!((modifier #{k})))} + modifier: (modifier #{kind})? modifier: {attrs} modifier: {mods} pattern: {pattern} @@ -1037,11 +1036,10 @@ fn translation_rules() -> Vec> { (tupleTypeElement firstName: _? @@name type: @ty) => tuple_type_element { - let name = name.map(|n| tree!((identifier #{n}))); if ctx.in_function_type { - tree!((parameter external_name: {name} type: {ty})) + tree!((parameter external_name: (identifier #{name})? type: {ty})) } else { - tree!((tuple_type_element name: {name} type: {ty})) + tree!((tuple_type_element name: (identifier #{name})? type: {ty})) } } ), From 23fd0903ab403d10c88de3fffc2897dc881f60d3 Mon Sep 17 00:00:00 2001 From: Taus Date: Tue, 28 Jul 2026 15:50:46 +0000 Subject: [PATCH 100/188] Bazel: regenerate vendored cargo dependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dropping the tree-sitter-swift crate removed the last consumer of the tree-sitter grammar-generation dependencies, but the vendored Bazel deps still listed them, so `defs.bzl` disagreed with the Cargo manifests: `unified/extractor` was still given `tree-sitter` and `tree-sitter-embedded-template`, and `unified/extractor/tree-sitter-swift` remained as a package entry. Regenerated with `misc/bazel/3rdparty/update_tree_sitter_extractors_deps.sh`, which drops `cc`, `tree-sitter-generate` and `tree-sitter-language` along with their transitive closure. `tree-sitter` itself stays, as the Ruby and QL extractors still use it. This commit carries the regenerated `defs.bzl` and `MODULE.bazel`; the vendored BUILD files for the dropped crates are deleted in the following commit. This was drift rather than breakage — the extra entries were simply unused, so the build worked either way. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- MODULE.bazel | 3 - .../tree_sitter_extractors_deps/BUILD.bazel | 48 --- .../BUILD.toml_parser-1.1.2+spec-1.1.0.bazel | 49 +-- .../BUILD.winnow-1.0.2.bazel | 123 ------- .../tree_sitter_extractors_deps/defs.bzl | 330 ------------------ 5 files changed, 1 insertion(+), 552 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index b6d7319a13ce..24260271ecad 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -109,7 +109,6 @@ use_repo( tree_sitter_extractors_deps, "vendor_ts__anyhow-1.0.100", "vendor_ts__argfile-0.2.1", - "vendor_ts__cc-1.2.61", "vendor_ts__chalk-ir-0.104.0", "vendor_ts__chrono-0.4.42", "vendor_ts__clap-4.5.48", @@ -157,9 +156,7 @@ use_repo( "vendor_ts__tracing-subscriber-0.3.20", "vendor_ts__tree-sitter-0.26.8", "vendor_ts__tree-sitter-embedded-template-0.25.0", - "vendor_ts__tree-sitter-generate-0.26.8", "vendor_ts__tree-sitter-json-0.24.8", - "vendor_ts__tree-sitter-language-0.1.5", "vendor_ts__tree-sitter-python-0.23.6", "vendor_ts__tree-sitter-ql-0.23.1", "vendor_ts__tree-sitter-ruby-0.23.1", diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.bazel index ce1d79a772b9..e4e959491d45 100644 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.bazel +++ b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.bazel @@ -55,18 +55,6 @@ alias( tags = ["manual"], ) -alias( - name = "cc-1.2.61", - actual = "@vendor_ts__cc-1.2.61//:cc", - tags = ["manual"], -) - -alias( - name = "cc", - actual = "@vendor_ts__cc-1.2.61//:cc", - tags = ["manual"], -) - alias( name = "chalk-ir-0.104.0", actual = "@vendor_ts__chalk-ir-0.104.0//:chalk_ir", @@ -649,18 +637,6 @@ alias( tags = ["manual"], ) -alias( - name = "tree-sitter-generate-0.26.8", - actual = "@vendor_ts__tree-sitter-generate-0.26.8//:tree_sitter_generate", - tags = ["manual"], -) - -alias( - name = "tree-sitter-generate", - actual = "@vendor_ts__tree-sitter-generate-0.26.8//:tree_sitter_generate", - tags = ["manual"], -) - alias( name = "tree-sitter-json-0.24.8", actual = "@vendor_ts__tree-sitter-json-0.24.8//:tree_sitter_json", @@ -673,18 +649,6 @@ alias( tags = ["manual"], ) -alias( - name = "tree-sitter-language-0.1.5", - actual = "@vendor_ts__tree-sitter-language-0.1.5//:tree_sitter_language", - tags = ["manual"], -) - -alias( - name = "tree-sitter-language", - actual = "@vendor_ts__tree-sitter-language-0.1.5//:tree_sitter_language", - tags = ["manual"], -) - alias( name = "tree-sitter-python-0.23.6", actual = "@vendor_ts__tree-sitter-python-0.23.6//:tree_sitter_python", @@ -721,18 +685,6 @@ alias( tags = ["manual"], ) -alias( - name = "tree-sitter-swift-0.7.2", - actual = "@vendor_ts__tree-sitter-swift-0.7.2//:tree_sitter_swift", - tags = ["manual"], -) - -alias( - name = "tree-sitter-swift", - actual = "@vendor_ts__tree-sitter-swift-0.7.2//:tree_sitter_swift", - tags = ["manual"], -) - alias( name = "triomphe-0.1.14", actual = "@vendor_ts__triomphe-0.1.14//:triomphe", diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.toml_parser-1.1.2+spec-1.1.0.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.toml_parser-1.1.2+spec-1.1.0.bazel index 4504ea44e88a..3e9b84dd8a92 100644 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.toml_parser-1.1.2+spec-1.1.0.bazel +++ b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.toml_parser-1.1.2+spec-1.1.0.bazel @@ -37,54 +37,7 @@ rust_library( crate_features = [ "alloc", "std", - ] + select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [ - "default", # aarch64-apple-darwin - ], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [ - "default", # aarch64-pc-windows-msvc - ], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [ - "default", # aarch64-unknown-linux-gnu - ], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [ - "default", # aarch64-unknown-linux-gnu, aarch64-unknown-nixos-gnu - ], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [ - "default", # arm-unknown-linux-gnueabi - ], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [ - "default", # i686-pc-windows-msvc - ], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [ - "default", # i686-unknown-linux-gnu - ], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [ - "default", # powerpc-unknown-linux-gnu - ], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [ - "default", # riscv64gc-unknown-linux-gnu - ], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [ - "default", # s390x-unknown-linux-gnu - ], - "@rules_rust//rust/platform:x86_64-apple-darwin": [ - "default", # x86_64-apple-darwin - ], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [ - "default", # x86_64-pc-windows-msvc - ], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [ - "default", # x86_64-unknown-freebsd - ], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [ - "default", # x86_64-unknown-linux-gnu - ], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [ - "default", # x86_64-unknown-linux-gnu, x86_64-unknown-nixos-gnu - ], - "//conditions:default": [], - }), + ], crate_root = "src/lib.rs", edition = "2024", rustc_env_files = [ diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.winnow-1.0.2.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.winnow-1.0.2.bazel index e9d478c9c660..995dce1204f2 100644 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.winnow-1.0.2.bazel +++ b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.winnow-1.0.2.bazel @@ -34,129 +34,6 @@ rust_library( "WORKSPACE.bazel", ], ), - crate_features = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [ - "alloc", # aarch64-apple-darwin - "ascii", # aarch64-apple-darwin - "binary", # aarch64-apple-darwin - "default", # aarch64-apple-darwin - "parser", # aarch64-apple-darwin - "std", # aarch64-apple-darwin - ], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [ - "alloc", # aarch64-pc-windows-msvc - "ascii", # aarch64-pc-windows-msvc - "binary", # aarch64-pc-windows-msvc - "default", # aarch64-pc-windows-msvc - "parser", # aarch64-pc-windows-msvc - "std", # aarch64-pc-windows-msvc - ], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [ - "alloc", # aarch64-unknown-linux-gnu - "ascii", # aarch64-unknown-linux-gnu - "binary", # aarch64-unknown-linux-gnu - "default", # aarch64-unknown-linux-gnu - "parser", # aarch64-unknown-linux-gnu - "std", # aarch64-unknown-linux-gnu - ], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [ - "alloc", # aarch64-unknown-linux-gnu, aarch64-unknown-nixos-gnu - "ascii", # aarch64-unknown-linux-gnu, aarch64-unknown-nixos-gnu - "binary", # aarch64-unknown-linux-gnu, aarch64-unknown-nixos-gnu - "default", # aarch64-unknown-linux-gnu, aarch64-unknown-nixos-gnu - "parser", # aarch64-unknown-linux-gnu, aarch64-unknown-nixos-gnu - "std", # aarch64-unknown-linux-gnu, aarch64-unknown-nixos-gnu - ], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [ - "alloc", # arm-unknown-linux-gnueabi - "ascii", # arm-unknown-linux-gnueabi - "binary", # arm-unknown-linux-gnueabi - "default", # arm-unknown-linux-gnueabi - "parser", # arm-unknown-linux-gnueabi - "std", # arm-unknown-linux-gnueabi - ], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [ - "alloc", # i686-pc-windows-msvc - "ascii", # i686-pc-windows-msvc - "binary", # i686-pc-windows-msvc - "default", # i686-pc-windows-msvc - "parser", # i686-pc-windows-msvc - "std", # i686-pc-windows-msvc - ], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [ - "alloc", # i686-unknown-linux-gnu - "ascii", # i686-unknown-linux-gnu - "binary", # i686-unknown-linux-gnu - "default", # i686-unknown-linux-gnu - "parser", # i686-unknown-linux-gnu - "std", # i686-unknown-linux-gnu - ], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [ - "alloc", # powerpc-unknown-linux-gnu - "ascii", # powerpc-unknown-linux-gnu - "binary", # powerpc-unknown-linux-gnu - "default", # powerpc-unknown-linux-gnu - "parser", # powerpc-unknown-linux-gnu - "std", # powerpc-unknown-linux-gnu - ], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [ - "alloc", # riscv64gc-unknown-linux-gnu - "ascii", # riscv64gc-unknown-linux-gnu - "binary", # riscv64gc-unknown-linux-gnu - "default", # riscv64gc-unknown-linux-gnu - "parser", # riscv64gc-unknown-linux-gnu - "std", # riscv64gc-unknown-linux-gnu - ], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [ - "alloc", # s390x-unknown-linux-gnu - "ascii", # s390x-unknown-linux-gnu - "binary", # s390x-unknown-linux-gnu - "default", # s390x-unknown-linux-gnu - "parser", # s390x-unknown-linux-gnu - "std", # s390x-unknown-linux-gnu - ], - "@rules_rust//rust/platform:x86_64-apple-darwin": [ - "alloc", # x86_64-apple-darwin - "ascii", # x86_64-apple-darwin - "binary", # x86_64-apple-darwin - "default", # x86_64-apple-darwin - "parser", # x86_64-apple-darwin - "std", # x86_64-apple-darwin - ], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [ - "alloc", # x86_64-pc-windows-msvc - "ascii", # x86_64-pc-windows-msvc - "binary", # x86_64-pc-windows-msvc - "default", # x86_64-pc-windows-msvc - "parser", # x86_64-pc-windows-msvc - "std", # x86_64-pc-windows-msvc - ], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [ - "alloc", # x86_64-unknown-freebsd - "ascii", # x86_64-unknown-freebsd - "binary", # x86_64-unknown-freebsd - "default", # x86_64-unknown-freebsd - "parser", # x86_64-unknown-freebsd - "std", # x86_64-unknown-freebsd - ], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [ - "alloc", # x86_64-unknown-linux-gnu - "ascii", # x86_64-unknown-linux-gnu - "binary", # x86_64-unknown-linux-gnu - "default", # x86_64-unknown-linux-gnu - "parser", # x86_64-unknown-linux-gnu - "std", # x86_64-unknown-linux-gnu - ], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [ - "alloc", # x86_64-unknown-linux-gnu, x86_64-unknown-nixos-gnu - "ascii", # x86_64-unknown-linux-gnu, x86_64-unknown-nixos-gnu - "binary", # x86_64-unknown-linux-gnu, x86_64-unknown-nixos-gnu - "default", # x86_64-unknown-linux-gnu, x86_64-unknown-nixos-gnu - "parser", # x86_64-unknown-linux-gnu, x86_64-unknown-nixos-gnu - "std", # x86_64-unknown-linux-gnu, x86_64-unknown-nixos-gnu - ], - "//conditions:default": [], - }), crate_root = "src/lib.rs", edition = "2021", rustc_env_files = [ diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/defs.bzl b/misc/bazel/3rdparty/tree_sitter_extractors_deps/defs.bzl index f3b5edb59cd6..be869ecf7388 100644 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/defs.bzl +++ b/misc/bazel/3rdparty/tree_sitter_extractors_deps/defs.bzl @@ -420,13 +420,6 @@ _NORMAL_DEPENDENCIES = { "serde_json": Label("@vendor_ts__serde_json-1.0.145//:serde_json"), "tracing": Label("@vendor_ts__tracing-0.1.41//:tracing"), "tracing-subscriber": Label("@vendor_ts__tracing-subscriber-0.3.20//:tracing_subscriber"), - "tree-sitter": Label("@vendor_ts__tree-sitter-0.26.8//:tree_sitter"), - "tree-sitter-embedded-template": Label("@vendor_ts__tree-sitter-embedded-template-0.25.0//:tree_sitter_embedded_template"), - }, - }, - "unified/extractor/tree-sitter-swift": { - _COMMON_CONDITION: { - "tree-sitter-language": Label("@vendor_ts__tree-sitter-language-0.1.5//:tree_sitter_language"), }, }, "unified/swift-syntax-rs": { @@ -475,10 +468,6 @@ _NORMAL_ALIASES = { _COMMON_CONDITION: { }, }, - "unified/extractor/tree-sitter-swift": { - _COMMON_CONDITION: { - }, - }, "unified/swift-syntax-rs": { _COMMON_CONDITION: { }, @@ -511,8 +500,6 @@ _NORMAL_DEV_DEPENDENCIES = { }, "unified/extractor": { }, - "unified/extractor/tree-sitter-swift": { - }, "unified/swift-syntax-rs": { }, } @@ -540,8 +527,6 @@ _NORMAL_DEV_ALIASES = { }, "unified/extractor": { }, - "unified/extractor/tree-sitter-swift": { - }, "unified/swift-syntax-rs": { }, } @@ -567,8 +552,6 @@ _PROC_MACRO_DEPENDENCIES = { }, "unified/extractor": { }, - "unified/extractor/tree-sitter-swift": { - }, "unified/swift-syntax-rs": { }, } @@ -594,8 +577,6 @@ _PROC_MACRO_ALIASES = { }, "unified/extractor": { }, - "unified/extractor/tree-sitter-swift": { - }, "unified/swift-syntax-rs": { }, } @@ -621,8 +602,6 @@ _PROC_MACRO_DEV_DEPENDENCIES = { }, "unified/extractor": { }, - "unified/extractor/tree-sitter-swift": { - }, "unified/swift-syntax-rs": { }, } @@ -650,8 +629,6 @@ _PROC_MACRO_DEV_ALIASES = { }, "unified/extractor": { }, - "unified/extractor/tree-sitter-swift": { - }, "unified/swift-syntax-rs": { }, } @@ -677,12 +654,6 @@ _BUILD_DEPENDENCIES = { }, "unified/extractor": { }, - "unified/extractor/tree-sitter-swift": { - _COMMON_CONDITION: { - "cc": Label("@vendor_ts__cc-1.2.61//:cc"), - "tree-sitter-generate": Label("@vendor_ts__tree-sitter-generate-0.26.8//:tree_sitter_generate"), - }, - }, "unified/swift-syntax-rs": { }, } @@ -708,10 +679,6 @@ _BUILD_ALIASES = { }, "unified/extractor": { }, - "unified/extractor/tree-sitter-swift": { - _COMMON_CONDITION: { - }, - }, "unified/swift-syntax-rs": { }, } @@ -737,8 +704,6 @@ _BUILD_PROC_MACRO_DEPENDENCIES = { }, "unified/extractor": { }, - "unified/extractor/tree-sitter-swift": { - }, "unified/swift-syntax-rs": { }, } @@ -764,8 +729,6 @@ _BUILD_PROC_MACRO_ALIASES = { }, "unified/extractor": { }, - "unified/extractor/tree-sitter-swift": { - }, "unified/swift-syntax-rs": { }, } @@ -1009,16 +972,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.base64-0.22.1.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__bindgen-0.72.1", - sha256 = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895", - type = "tar.gz", - urls = ["https://static.crates.io/crates/bindgen/0.72.1/download"], - strip_prefix = "bindgen-0.72.1", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.bindgen-0.72.1.bazel"), - ) - maybe( http_archive, name = "vendor_ts__bitflags-1.3.2", @@ -1139,16 +1092,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.cc-1.2.61.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__cexpr-0.6.0", - sha256 = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766", - type = "tar.gz", - urls = ["https://static.crates.io/crates/cexpr/0.6.0/download"], - strip_prefix = "cexpr-0.6.0", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.cexpr-0.6.0.bazel"), - ) - maybe( http_archive, name = "vendor_ts__cfg-if-1.0.3", @@ -1239,16 +1182,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.chrono-0.4.42.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__clang-sys-1.8.1", - sha256 = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4", - type = "tar.gz", - urls = ["https://static.crates.io/crates/clang-sys/1.8.1/download"], - strip_prefix = "clang-sys-1.8.1", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.clang-sys-1.8.1.bazel"), - ) - maybe( http_archive, name = "vendor_ts__clap-4.5.48", @@ -1299,16 +1232,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.colorchoice-1.0.4.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__convert_case-0.8.0", - sha256 = "baaaa0ecca5b51987b9423ccdc971514dd8b0bb7b4060b983d3664dad3f1f89f", - type = "tar.gz", - urls = ["https://static.crates.io/crates/convert_case/0.8.0/download"], - strip_prefix = "convert_case-0.8.0", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.convert_case-0.8.0.bazel"), - ) - maybe( http_archive, name = "vendor_ts__core-foundation-sys-0.8.7", @@ -1599,16 +1522,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.erased-serde-0.4.6.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__fastrand-2.4.1", - sha256 = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6", - type = "tar.gz", - urls = ["https://static.crates.io/crates/fastrand/2.4.1/download"], - strip_prefix = "fastrand-2.4.1", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.fastrand-2.4.1.bazel"), - ) - maybe( http_archive, name = "vendor_ts__figment-0.10.19", @@ -1669,16 +1582,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.foldhash-0.1.5.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__foldhash-0.2.0", - sha256 = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb", - type = "tar.gz", - urls = ["https://static.crates.io/crates/foldhash/0.2.0/download"], - strip_prefix = "foldhash-0.2.0", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.foldhash-0.2.0.bazel"), - ) - maybe( http_archive, name = "vendor_ts__form_urlencoded-1.2.2", @@ -1779,16 +1682,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.hashbrown-0.15.5.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__hashbrown-0.16.1", - sha256 = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100", - type = "tar.gz", - urls = ["https://static.crates.io/crates/hashbrown/0.16.1/download"], - strip_prefix = "hashbrown-0.16.1", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.hashbrown-0.16.1.bazel"), - ) - maybe( http_archive, name = "vendor_ts__hashbrown-0.17.1", @@ -1989,16 +1882,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.indexmap-2.14.0.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__indoc-2.0.7", - sha256 = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706", - type = "tar.gz", - urls = ["https://static.crates.io/crates/indoc/2.0.7/download"], - strip_prefix = "indoc-2.0.7", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.indoc-2.0.7.bazel"), - ) - maybe( http_archive, name = "vendor_ts__inlinable_string-0.1.15", @@ -2159,16 +2042,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.libc-0.2.175.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__libloading-0.8.9", - sha256 = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55", - type = "tar.gz", - urls = ["https://static.crates.io/crates/libloading/0.8.9/download"], - strip_prefix = "libloading-0.8.9", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.libloading-0.8.9.bazel"), - ) - maybe( http_archive, name = "vendor_ts__line-index-0.1.2", @@ -2249,16 +2122,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.memoffset-0.9.1.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__minimal-lexical-0.2.1", - sha256 = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a", - type = "tar.gz", - urls = ["https://static.crates.io/crates/minimal-lexical/0.2.1/download"], - strip_prefix = "minimal-lexical-0.2.1", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.minimal-lexical-0.2.1.bazel"), - ) - maybe( http_archive, name = "vendor_ts__miniz_oxide-0.8.9", @@ -2309,16 +2172,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.nohash-hasher-0.2.0.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__nom-7.1.3", - sha256 = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a", - type = "tar.gz", - urls = ["https://static.crates.io/crates/nom/7.1.3/download"], - strip_prefix = "nom-7.1.3", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.nom-7.1.3.bazel"), - ) - maybe( http_archive, name = "vendor_ts__notify-8.2.0", @@ -2459,16 +2312,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.parking_lot_core-0.9.11.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__pathdiff-0.2.3", - sha256 = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3", - type = "tar.gz", - urls = ["https://static.crates.io/crates/pathdiff/0.2.3/download"], - strip_prefix = "pathdiff-0.2.3", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.pathdiff-0.2.3.bazel"), - ) - maybe( http_archive, name = "vendor_ts__pear-0.2.9", @@ -2529,36 +2372,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.petgraph-0.6.5.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__phf-0.13.1", - sha256 = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf", - type = "tar.gz", - urls = ["https://static.crates.io/crates/phf/0.13.1/download"], - strip_prefix = "phf-0.13.1", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.phf-0.13.1.bazel"), - ) - - maybe( - http_archive, - name = "vendor_ts__phf_generator-0.13.1", - sha256 = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737", - type = "tar.gz", - urls = ["https://static.crates.io/crates/phf_generator/0.13.1/download"], - strip_prefix = "phf_generator-0.13.1", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.phf_generator-0.13.1.bazel"), - ) - - maybe( - http_archive, - name = "vendor_ts__phf_shared-0.13.1", - sha256 = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266", - type = "tar.gz", - urls = ["https://static.crates.io/crates/phf_shared/0.13.1/download"], - strip_prefix = "phf_shared-0.13.1", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.phf_shared-0.13.1.bazel"), - ) - maybe( http_archive, name = "vendor_ts__pin-project-lite-0.2.16", @@ -2619,26 +2432,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.ppv-lite86-0.2.21.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__prettyplease-0.2.37", - sha256 = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b", - type = "tar.gz", - urls = ["https://static.crates.io/crates/prettyplease/0.2.37/download"], - strip_prefix = "prettyplease-0.2.37", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.prettyplease-0.2.37.bazel"), - ) - - maybe( - http_archive, - name = "vendor_ts__proc-macro-crate-3.5.0", - sha256 = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f", - type = "tar.gz", - urls = ["https://static.crates.io/crates/proc-macro-crate/3.5.0/download"], - strip_prefix = "proc-macro-crate-3.5.0", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.proc-macro-crate-3.5.0.bazel"), - ) - maybe( http_archive, name = "vendor_ts__proc-macro2-1.0.101", @@ -3119,16 +2912,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.regex-syntax-0.8.6.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__relative-path-2.0.1", - sha256 = "bca40a312222d8ba74837cb474edef44b37f561da5f773981007a10bbaa992b0", - type = "tar.gz", - urls = ["https://static.crates.io/crates/relative-path/2.0.1/download"], - strip_prefix = "relative-path-2.0.1", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.relative-path-2.0.1.bazel"), - ) - maybe( http_archive, name = "vendor_ts__rowan-0.15.15", @@ -3139,46 +2922,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.rowan-0.15.15.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__rquickjs-0.10.0", - sha256 = "a135375fbac5ba723bb6a48f432a72f81539cedde422f0121a86c7c4e96d8e0d", - type = "tar.gz", - urls = ["https://static.crates.io/crates/rquickjs/0.10.0/download"], - strip_prefix = "rquickjs-0.10.0", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.rquickjs-0.10.0.bazel"), - ) - - maybe( - http_archive, - name = "vendor_ts__rquickjs-core-0.10.0", - sha256 = "bccb7121a123865c8ace4dea42e7ed84d78b90cbaf4ca32c59849d8d210c9672", - type = "tar.gz", - urls = ["https://static.crates.io/crates/rquickjs-core/0.10.0/download"], - strip_prefix = "rquickjs-core-0.10.0", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.rquickjs-core-0.10.0.bazel"), - ) - - maybe( - http_archive, - name = "vendor_ts__rquickjs-macro-0.10.0", - sha256 = "89f93602cc3112c7f30bf5f29e722784232138692c7df4c52ebbac7e035d900d", - type = "tar.gz", - urls = ["https://static.crates.io/crates/rquickjs-macro/0.10.0/download"], - strip_prefix = "rquickjs-macro-0.10.0", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.rquickjs-macro-0.10.0.bazel"), - ) - - maybe( - http_archive, - name = "vendor_ts__rquickjs-sys-0.10.0", - sha256 = "57b1b6528590d4d65dc86b5159eae2d0219709546644c66408b2441696d1d725", - type = "tar.gz", - urls = ["https://static.crates.io/crates/rquickjs-sys/0.10.0/download"], - strip_prefix = "rquickjs-sys-0.10.0", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.rquickjs-sys-0.10.0.bazel"), - ) - maybe( http_archive, name = "vendor_ts__rustc-hash-1.1.0", @@ -3479,26 +3222,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.shlex-1.3.0.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__siphasher-1.0.3", - sha256 = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649", - type = "tar.gz", - urls = ["https://static.crates.io/crates/siphasher/1.0.3/download"], - strip_prefix = "siphasher-1.0.3", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.siphasher-1.0.3.bazel"), - ) - - maybe( - http_archive, - name = "vendor_ts__smallbitvec-2.6.1", - sha256 = "9b0e903ee191d8f7a8fbf0d712c3a1699d19e04ceba5ad1eb673053c7d938a09", - type = "tar.gz", - urls = ["https://static.crates.io/crates/smallbitvec/2.6.1/download"], - strip_prefix = "smallbitvec-2.6.1", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.smallbitvec-2.6.1.bazel"), - ) - maybe( http_archive, name = "vendor_ts__smallvec-1.15.1", @@ -3709,16 +3432,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.toml_datetime-0.7.2.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__toml_datetime-1.1.1-spec-1.1.0", - sha256 = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7", - type = "tar.gz", - urls = ["https://static.crates.io/crates/toml_datetime/1.1.1+spec-1.1.0/download"], - strip_prefix = "toml_datetime-1.1.1+spec-1.1.0", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.toml_datetime-1.1.1+spec-1.1.0.bazel"), - ) - maybe( http_archive, name = "vendor_ts__toml_edit-0.22.27", @@ -3729,16 +3442,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.toml_edit-0.22.27.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__toml_edit-0.25.11-spec-1.1.0", - sha256 = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b", - type = "tar.gz", - urls = ["https://static.crates.io/crates/toml_edit/0.25.11+spec-1.1.0/download"], - strip_prefix = "toml_edit-0.25.11+spec-1.1.0", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.toml_edit-0.25.11+spec-1.1.0.bazel"), - ) - maybe( http_archive, name = "vendor_ts__toml_parser-1.1.2-spec-1.1.0", @@ -3769,16 +3472,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.toml_writer-1.0.3.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__topological-sort-0.2.2", - sha256 = "ea68304e134ecd095ac6c3574494fc62b909f416c4fca77e440530221e549d3d", - type = "tar.gz", - urls = ["https://static.crates.io/crates/topological-sort/0.2.2/download"], - strip_prefix = "topological-sort-0.2.2", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.topological-sort-0.2.2.bazel"), - ) - maybe( http_archive, name = "vendor_ts__tracing-0.1.41", @@ -3859,16 +3552,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.tree-sitter-embedded-template-0.25.0.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__tree-sitter-generate-0.26.8", - sha256 = "c3fb2e1bdb1d5f9d23cd5fa68cf98b3bedbd223c92a2edd60bbcf30bcf7180a5", - type = "tar.gz", - urls = ["https://static.crates.io/crates/tree-sitter-generate/0.26.8/download"], - strip_prefix = "tree-sitter-generate-0.26.8", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.tree-sitter-generate-0.26.8.bazel"), - ) - maybe( http_archive, name = "vendor_ts__tree-sitter-json-0.24.8", @@ -3989,16 +3672,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.unicode-properties-0.1.3.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__unicode-segmentation-1.13.2", - sha256 = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c", - type = "tar.gz", - urls = ["https://static.crates.io/crates/unicode-segmentation/1.13.2/download"], - strip_prefix = "unicode-segmentation-1.13.2", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.unicode-segmentation-1.13.2.bazel"), - ) - maybe( http_archive, name = "vendor_ts__unicode-xid-0.2.6", @@ -4632,7 +4305,6 @@ def crate_repositories(): return [ struct(repo = "vendor_ts__anyhow-1.0.100", is_dev_dep = False), struct(repo = "vendor_ts__argfile-0.2.1", is_dev_dep = False), - struct(repo = "vendor_ts__cc-1.2.61", is_dev_dep = False), struct(repo = "vendor_ts__chalk-ir-0.104.0", is_dev_dep = False), struct(repo = "vendor_ts__chrono-0.4.42", is_dev_dep = False), struct(repo = "vendor_ts__clap-4.5.48", is_dev_dep = False), @@ -4679,8 +4351,6 @@ def crate_repositories(): struct(repo = "vendor_ts__tracing-subscriber-0.3.20", is_dev_dep = False), struct(repo = "vendor_ts__tree-sitter-0.26.8", is_dev_dep = False), struct(repo = "vendor_ts__tree-sitter-embedded-template-0.25.0", is_dev_dep = False), - struct(repo = "vendor_ts__tree-sitter-generate-0.26.8", is_dev_dep = False), - struct(repo = "vendor_ts__tree-sitter-language-0.1.5", is_dev_dep = False), struct(repo = "vendor_ts__tree-sitter-python-0.23.6", is_dev_dep = False), struct(repo = "vendor_ts__tree-sitter-ruby-0.23.1", is_dev_dep = False), struct(repo = "vendor_ts__triomphe-0.1.14", is_dev_dep = False), From b246cf6e6c5ca51c749c203106fc2797627d1476 Mon Sep 17 00:00:00 2001 From: Taus Date: Tue, 28 Jul 2026 15:50:47 +0000 Subject: [PATCH 101/188] Bazel: delete the vendored BUILD files for dropped crates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pure deletion of the generated `BUILD..bazel` files for the crates the previous commit removed from `defs.bzl` and `MODULE.bazel` — `cc`, `tree-sitter-generate`, `tree-sitter-language` and their transitive closure (bindgen, clang-sys, phf, rquickjs, …). Nothing instantiates the corresponding repositories any more, so the files are dead. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../BUILD.bindgen-0.72.1.bazel | 190 ---------------- .../BUILD.cexpr-0.6.0.bazel | 100 --------- .../BUILD.clang-sys-1.8.1.bazel | 203 ------------------ .../BUILD.convert_case-0.8.0.bazel | 100 --------- .../BUILD.fastrand-2.4.1.bazel | 97 --------- .../BUILD.foldhash-0.2.0.bazel | 97 --------- .../BUILD.hashbrown-0.16.1.bazel | 110 ---------- .../BUILD.indoc-2.0.7.bazel | 97 --------- .../BUILD.libloading-0.8.9.bazel | 190 ---------------- .../BUILD.minimal-lexical-0.2.1.bazel | 100 --------- .../BUILD.nom-7.1.3.bazel | 105 --------- .../BUILD.pathdiff-0.2.3.bazel | 97 --------- .../BUILD.phf-0.13.1.bazel | 104 --------- .../BUILD.phf_generator-0.13.1.bazel | 101 --------- .../BUILD.phf_shared-0.13.1.bazel | 104 --------- .../BUILD.prettyplease-0.2.37.bazel | 171 --------------- .../BUILD.proc-macro-crate-3.5.0.bazel | 100 --------- .../BUILD.relative-path-2.0.1.bazel | 101 --------- .../BUILD.rquickjs-0.10.0.bazel | 112 ---------- .../BUILD.rquickjs-core-0.10.0.bazel | 110 ---------- .../BUILD.rquickjs-macro-0.10.0.bazel | 116 ---------- .../BUILD.rquickjs-sys-0.10.0.bazel | 177 --------------- .../BUILD.siphasher-1.0.3.bazel | 101 --------- .../BUILD.smallbitvec-2.6.1.bazel | 97 --------- ...BUILD.toml_datetime-1.1.1+spec-1.1.0.bazel | 102 --------- .../BUILD.toml_edit-0.25.11+spec-1.1.0.bazel | 106 --------- .../BUILD.topological-sort-0.2.2.bazel | 97 --------- .../BUILD.tree-sitter-generate-0.26.8.bazel | 124 ----------- .../BUILD.unicode-segmentation-1.13.2.bazel | 97 --------- 29 files changed, 3406 deletions(-) delete mode 100644 misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.bindgen-0.72.1.bazel delete mode 100644 misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.cexpr-0.6.0.bazel delete mode 100644 misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.clang-sys-1.8.1.bazel delete mode 100644 misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.convert_case-0.8.0.bazel delete mode 100644 misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.fastrand-2.4.1.bazel delete mode 100644 misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.foldhash-0.2.0.bazel delete mode 100644 misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.hashbrown-0.16.1.bazel delete mode 100644 misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.indoc-2.0.7.bazel delete mode 100644 misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.libloading-0.8.9.bazel delete mode 100644 misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.minimal-lexical-0.2.1.bazel delete mode 100644 misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.nom-7.1.3.bazel delete mode 100644 misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.pathdiff-0.2.3.bazel delete mode 100644 misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.phf-0.13.1.bazel delete mode 100644 misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.phf_generator-0.13.1.bazel delete mode 100644 misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.phf_shared-0.13.1.bazel delete mode 100644 misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.prettyplease-0.2.37.bazel delete mode 100644 misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.proc-macro-crate-3.5.0.bazel delete mode 100644 misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.relative-path-2.0.1.bazel delete mode 100644 misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.rquickjs-0.10.0.bazel delete mode 100644 misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.rquickjs-core-0.10.0.bazel delete mode 100644 misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.rquickjs-macro-0.10.0.bazel delete mode 100644 misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.rquickjs-sys-0.10.0.bazel delete mode 100644 misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.siphasher-1.0.3.bazel delete mode 100644 misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.smallbitvec-2.6.1.bazel delete mode 100644 misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.toml_datetime-1.1.1+spec-1.1.0.bazel delete mode 100644 misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.toml_edit-0.25.11+spec-1.1.0.bazel delete mode 100644 misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.topological-sort-0.2.2.bazel delete mode 100644 misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.tree-sitter-generate-0.26.8.bazel delete mode 100644 misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.unicode-segmentation-1.13.2.bazel diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.bindgen-0.72.1.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.bindgen-0.72.1.bazel deleted file mode 100644 index 903b1c8fc773..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.bindgen-0.72.1.bazel +++ /dev/null @@ -1,190 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load( - "@rules_rust//cargo:defs.bzl", - "cargo_build_script", - "cargo_toml_env_vars", -) -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "bindgen", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_features = [ - "default", - "logging", - "prettyplease", - "runtime", - ], - crate_root = "lib.rs", - edition = "2021", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=bindgen", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "0.72.1", - deps = [ - "@vendor_ts__bindgen-0.72.1//:build_script_build", - "@vendor_ts__bitflags-2.9.4//:bitflags", - "@vendor_ts__cexpr-0.6.0//:cexpr", - "@vendor_ts__clang-sys-1.8.1//:clang_sys", - "@vendor_ts__itertools-0.12.1//:itertools", - "@vendor_ts__log-0.4.28//:log", - "@vendor_ts__prettyplease-0.2.37//:prettyplease", - "@vendor_ts__proc-macro2-1.0.101//:proc_macro2", - "@vendor_ts__quote-1.0.41//:quote", - "@vendor_ts__regex-1.11.3//:regex", - "@vendor_ts__rustc-hash-2.1.1//:rustc_hash", - "@vendor_ts__shlex-1.3.0//:shlex", - "@vendor_ts__syn-2.0.106//:syn", - ], -) - -cargo_build_script( - name = "_bs", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - "**/*.rs", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_features = [ - "default", - "logging", - "prettyplease", - "runtime", - ], - crate_name = "build_script_build", - crate_root = "build.rs", - data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - edition = "2021", - link_deps = [ - "@vendor_ts__clang-sys-1.8.1//:clang_sys", - "@vendor_ts__prettyplease-0.2.37//:prettyplease", - ], - pkg_name = "bindgen", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=bindgen", - "manual", - "noclippy", - "norustfmt", - ], - version = "0.72.1", - visibility = ["//visibility:private"], -) - -alias( - name = "build_script_build", - actual = ":_bs", - tags = ["manual"], -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.cexpr-0.6.0.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.cexpr-0.6.0.bazel deleted file mode 100644 index 500c657be108..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.cexpr-0.6.0.bazel +++ /dev/null @@ -1,100 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "cexpr", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_root = "src/lib.rs", - edition = "2018", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=cexpr", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "0.6.0", - deps = [ - "@vendor_ts__nom-7.1.3//:nom", - ], -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.clang-sys-1.8.1.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.clang-sys-1.8.1.bazel deleted file mode 100644 index b039f4c28e5b..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.clang-sys-1.8.1.bazel +++ /dev/null @@ -1,203 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load( - "@rules_rust//cargo:defs.bzl", - "cargo_build_script", - "cargo_toml_env_vars", -) -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "clang_sys", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_features = [ - "clang_10_0", - "clang_11_0", - "clang_3_5", - "clang_3_6", - "clang_3_7", - "clang_3_8", - "clang_3_9", - "clang_4_0", - "clang_5_0", - "clang_6_0", - "clang_7_0", - "clang_8_0", - "clang_9_0", - "libloading", - "runtime", - ], - crate_root = "src/lib.rs", - edition = "2021", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=clang-sys", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "1.8.1", - deps = [ - "@vendor_ts__clang-sys-1.8.1//:build_script_build", - "@vendor_ts__glob-0.3.3//:glob", - "@vendor_ts__libc-0.2.175//:libc", - "@vendor_ts__libloading-0.8.9//:libloading", - ], -) - -cargo_build_script( - name = "_bs", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - "**/*.rs", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_features = [ - "clang_10_0", - "clang_11_0", - "clang_3_5", - "clang_3_6", - "clang_3_7", - "clang_3_8", - "clang_3_9", - "clang_4_0", - "clang_5_0", - "clang_6_0", - "clang_7_0", - "clang_8_0", - "clang_9_0", - "libloading", - "runtime", - ], - crate_name = "build_script_build", - crate_root = "build.rs", - data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - edition = "2021", - links = "clang", - pkg_name = "clang-sys", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=clang-sys", - "manual", - "noclippy", - "norustfmt", - ], - version = "1.8.1", - visibility = ["//visibility:private"], - deps = [ - "@vendor_ts__glob-0.3.3//:glob", - ], -) - -alias( - name = "build_script_build", - actual = ":_bs", - tags = ["manual"], -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.convert_case-0.8.0.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.convert_case-0.8.0.bazel deleted file mode 100644 index a1a2df07bf1f..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.convert_case-0.8.0.bazel +++ /dev/null @@ -1,100 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "convert_case", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_root = "src/lib.rs", - edition = "2021", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=convert_case", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "0.8.0", - deps = [ - "@vendor_ts__unicode-segmentation-1.13.2//:unicode_segmentation", - ], -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.fastrand-2.4.1.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.fastrand-2.4.1.bazel deleted file mode 100644 index f6f016a9f467..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.fastrand-2.4.1.bazel +++ /dev/null @@ -1,97 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "fastrand", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_root = "src/lib.rs", - edition = "2018", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=fastrand", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "2.4.1", -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.foldhash-0.2.0.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.foldhash-0.2.0.bazel deleted file mode 100644 index 03940fb08ac2..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.foldhash-0.2.0.bazel +++ /dev/null @@ -1,97 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "foldhash", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_root = "src/lib.rs", - edition = "2021", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=foldhash", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "0.2.0", -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.hashbrown-0.16.1.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.hashbrown-0.16.1.bazel deleted file mode 100644 index 8090f6f8c7fc..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.hashbrown-0.16.1.bazel +++ /dev/null @@ -1,110 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "hashbrown", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_features = [ - "allocator-api2", - "default", - "default-hasher", - "equivalent", - "inline-more", - "raw-entry", - ], - crate_root = "src/lib.rs", - edition = "2021", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=hashbrown", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "0.16.1", - deps = [ - "@vendor_ts__allocator-api2-0.2.21//:allocator_api2", - "@vendor_ts__equivalent-1.0.2//:equivalent", - "@vendor_ts__foldhash-0.2.0//:foldhash", - ], -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.indoc-2.0.7.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.indoc-2.0.7.bazel deleted file mode 100644 index f3a9dea14d42..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.indoc-2.0.7.bazel +++ /dev/null @@ -1,97 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_proc_macro") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_proc_macro( - name = "indoc", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_root = "src/lib.rs", - edition = "2021", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=indoc", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "2.0.7", -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.libloading-0.8.9.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.libloading-0.8.9.bazel deleted file mode 100644 index e87fddeaaa5c..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.libloading-0.8.9.bazel +++ /dev/null @@ -1,190 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "libloading", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_root = "src/lib.rs", - edition = "2015", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=libloading", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "0.8.9", - deps = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:aarch64-apple-ios": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:aarch64-linux-android": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [ - "@vendor_ts__windows-link-0.2.0//:windows_link", # cfg(windows) - ], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:armv7-linux-androideabi": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:i686-apple-darwin": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:i686-linux-android": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [ - "@vendor_ts__windows-link-0.2.0//:windows_link", # cfg(windows) - ], - "@rules_rust//rust/platform:i686-unknown-freebsd": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:x86_64-apple-darwin": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:x86_64-apple-ios": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:x86_64-linux-android": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [ - "@vendor_ts__windows-link-0.2.0//:windows_link", # cfg(windows) - ], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "//conditions:default": [], - }), -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.minimal-lexical-0.2.1.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.minimal-lexical-0.2.1.bazel deleted file mode 100644 index 40e1e2259be6..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.minimal-lexical-0.2.1.bazel +++ /dev/null @@ -1,100 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "minimal_lexical", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_features = [ - "std", - ], - crate_root = "src/lib.rs", - edition = "2018", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=minimal-lexical", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "0.2.1", -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.nom-7.1.3.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.nom-7.1.3.bazel deleted file mode 100644 index b1524d8a86d9..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.nom-7.1.3.bazel +++ /dev/null @@ -1,105 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "nom", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_features = [ - "alloc", - "std", - ], - crate_root = "src/lib.rs", - edition = "2018", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=nom", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "7.1.3", - deps = [ - "@vendor_ts__memchr-2.7.5//:memchr", - "@vendor_ts__minimal-lexical-0.2.1//:minimal_lexical", - ], -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.pathdiff-0.2.3.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.pathdiff-0.2.3.bazel deleted file mode 100644 index 48df9a3c3d89..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.pathdiff-0.2.3.bazel +++ /dev/null @@ -1,97 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "pathdiff", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_root = "src/lib.rs", - edition = "2018", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=pathdiff", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "0.2.3", -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.phf-0.13.1.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.phf-0.13.1.bazel deleted file mode 100644 index 8c41939eb97f..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.phf-0.13.1.bazel +++ /dev/null @@ -1,104 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "phf", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_features = [ - "default", - "std", - ], - crate_root = "src/lib.rs", - edition = "2021", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=phf", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "0.13.1", - deps = [ - "@vendor_ts__phf_shared-0.13.1//:phf_shared", - ], -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.phf_generator-0.13.1.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.phf_generator-0.13.1.bazel deleted file mode 100644 index c270102428d2..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.phf_generator-0.13.1.bazel +++ /dev/null @@ -1,101 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "phf_generator", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_root = "src/lib.rs", - edition = "2021", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=phf_generator", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "0.13.1", - deps = [ - "@vendor_ts__fastrand-2.4.1//:fastrand", - "@vendor_ts__phf_shared-0.13.1//:phf_shared", - ], -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.phf_shared-0.13.1.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.phf_shared-0.13.1.bazel deleted file mode 100644 index 164cee335225..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.phf_shared-0.13.1.bazel +++ /dev/null @@ -1,104 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "phf_shared", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_features = [ - "default", - "std", - ], - crate_root = "src/lib.rs", - edition = "2021", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=phf_shared", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "0.13.1", - deps = [ - "@vendor_ts__siphasher-1.0.3//:siphasher", - ], -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.prettyplease-0.2.37.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.prettyplease-0.2.37.bazel deleted file mode 100644 index 5d0886807cb8..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.prettyplease-0.2.37.bazel +++ /dev/null @@ -1,171 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load( - "@rules_rust//cargo:defs.bzl", - "cargo_build_script", - "cargo_toml_env_vars", -) -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "prettyplease", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_features = [ - "verbatim", - ], - crate_root = "src/lib.rs", - edition = "2021", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=prettyplease", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "0.2.37", - deps = [ - "@vendor_ts__prettyplease-0.2.37//:build_script_build", - "@vendor_ts__proc-macro2-1.0.101//:proc_macro2", - "@vendor_ts__syn-2.0.106//:syn", - ], -) - -cargo_build_script( - name = "_bs", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - "**/*.rs", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_features = [ - "verbatim", - ], - crate_name = "build_script_build", - crate_root = "build.rs", - data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - edition = "2021", - links = "prettyplease02", - pkg_name = "prettyplease", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=prettyplease", - "manual", - "noclippy", - "norustfmt", - ], - version = "0.2.37", - visibility = ["//visibility:private"], -) - -alias( - name = "build_script_build", - actual = ":_bs", - tags = ["manual"], -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.proc-macro-crate-3.5.0.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.proc-macro-crate-3.5.0.bazel deleted file mode 100644 index 0ae50367face..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.proc-macro-crate-3.5.0.bazel +++ /dev/null @@ -1,100 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "proc_macro_crate", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_root = "src/lib.rs", - edition = "2021", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=proc-macro-crate", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "3.5.0", - deps = [ - "@vendor_ts__toml_edit-0.25.11-spec-1.1.0//:toml_edit", - ], -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.relative-path-2.0.1.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.relative-path-2.0.1.bazel deleted file mode 100644 index 67aef624737c..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.relative-path-2.0.1.bazel +++ /dev/null @@ -1,101 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "relative_path", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_features = [ - "alloc", - "std", - ], - crate_root = "src/lib.rs", - edition = "2021", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=relative-path", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "2.0.1", -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.rquickjs-0.10.0.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.rquickjs-0.10.0.bazel deleted file mode 100644 index 3c57513b3d3b..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.rquickjs-0.10.0.bazel +++ /dev/null @@ -1,112 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "rquickjs", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_features = [ - "bindgen", - "default", - "loader", - "macro", - "phf", - "rquickjs-macro", - "std", - ], - crate_root = "src/lib.rs", - edition = "2021", - proc_macro_deps = [ - "@vendor_ts__rquickjs-macro-0.10.0//:rquickjs_macro", - ], - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=rquickjs", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "0.10.0", - deps = [ - "@vendor_ts__rquickjs-core-0.10.0//:rquickjs_core", - ], -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.rquickjs-core-0.10.0.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.rquickjs-core-0.10.0.bazel deleted file mode 100644 index 415c9ee4e4b3..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.rquickjs-core-0.10.0.bazel +++ /dev/null @@ -1,110 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "rquickjs_core", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_features = [ - "bindgen", - "loader", - "phf", - "relative-path", - "std", - ], - crate_root = "src/lib.rs", - edition = "2021", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=rquickjs-core", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "0.10.0", - deps = [ - "@vendor_ts__hashbrown-0.16.1//:hashbrown", - "@vendor_ts__phf-0.13.1//:phf", - "@vendor_ts__relative-path-2.0.1//:relative_path", - "@vendor_ts__rquickjs-sys-0.10.0//:rquickjs_sys", - ], -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.rquickjs-macro-0.10.0.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.rquickjs-macro-0.10.0.bazel deleted file mode 100644 index 055e627f3bed..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.rquickjs-macro-0.10.0.bazel +++ /dev/null @@ -1,116 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_proc_macro") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_proc_macro( - name = "rquickjs_macro", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_features = [ - "bindgen", - "phf", - "phf_generator", - "phf_shared", - ], - crate_root = "src/lib.rs", - edition = "2021", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=rquickjs-macro", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "0.10.0", - deps = [ - "@vendor_ts__convert_case-0.8.0//:convert_case", - "@vendor_ts__fnv-1.0.7//:fnv", - "@vendor_ts__ident_case-1.0.1//:ident_case", - "@vendor_ts__indexmap-2.14.0//:indexmap", - "@vendor_ts__phf_generator-0.13.1//:phf_generator", - "@vendor_ts__phf_shared-0.13.1//:phf_shared", - "@vendor_ts__proc-macro-crate-3.5.0//:proc_macro_crate", - "@vendor_ts__proc-macro2-1.0.101//:proc_macro2", - "@vendor_ts__quote-1.0.41//:quote", - "@vendor_ts__rquickjs-core-0.10.0//:rquickjs_core", - "@vendor_ts__syn-2.0.106//:syn", - ], -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.rquickjs-sys-0.10.0.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.rquickjs-sys-0.10.0.bazel deleted file mode 100644 index 185637f6ba47..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.rquickjs-sys-0.10.0.bazel +++ /dev/null @@ -1,177 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load( - "@rules_rust//cargo:defs.bzl", - "cargo_build_script", - "cargo_toml_env_vars", -) -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "rquickjs_sys", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_features = [ - "bindgen", - "bindgen-rs", - ], - crate_root = "src/lib.rs", - edition = "2021", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=rquickjs-sys", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "0.10.0", - deps = [ - "@vendor_ts__rquickjs-sys-0.10.0//:build_script_build", - ], -) - -cargo_build_script( - name = "_bs", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - aliases = { - "@vendor_ts__bindgen-0.72.1//:bindgen": "bindgen_rs", - }, - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - "**/*.rs", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_features = [ - "bindgen", - "bindgen-rs", - ], - crate_name = "build_script_build", - crate_root = "build.rs", - data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - edition = "2021", - pkg_name = "rquickjs-sys", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=rquickjs-sys", - "manual", - "noclippy", - "norustfmt", - ], - version = "0.10.0", - visibility = ["//visibility:private"], - deps = [ - "@vendor_ts__bindgen-0.72.1//:bindgen", - "@vendor_ts__cc-1.2.61//:cc", - ], -) - -alias( - name = "build_script_build", - actual = ":_bs", - tags = ["manual"], -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.siphasher-1.0.3.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.siphasher-1.0.3.bazel deleted file mode 100644 index 472af635f83e..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.siphasher-1.0.3.bazel +++ /dev/null @@ -1,101 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "siphasher", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_features = [ - "default", - "std", - ], - crate_root = "src/lib.rs", - edition = "2018", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=siphasher", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "1.0.3", -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.smallbitvec-2.6.1.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.smallbitvec-2.6.1.bazel deleted file mode 100644 index 6dc39e352601..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.smallbitvec-2.6.1.bazel +++ /dev/null @@ -1,97 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "smallbitvec", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_root = "src/lib.rs", - edition = "2021", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=smallbitvec", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "2.6.1", -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.toml_datetime-1.1.1+spec-1.1.0.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.toml_datetime-1.1.1+spec-1.1.0.bazel deleted file mode 100644 index a4809f145b60..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.toml_datetime-1.1.1+spec-1.1.0.bazel +++ /dev/null @@ -1,102 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "toml_datetime", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_features = [ - "alloc", - "default", - "std", - ], - crate_root = "src/lib.rs", - edition = "2024", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=toml_datetime", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "1.1.1+spec-1.1.0", -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.toml_edit-0.25.11+spec-1.1.0.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.toml_edit-0.25.11+spec-1.1.0.bazel deleted file mode 100644 index 596127714520..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.toml_edit-0.25.11+spec-1.1.0.bazel +++ /dev/null @@ -1,106 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "toml_edit", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_features = [ - "parse", - ], - crate_root = "src/lib.rs", - edition = "2024", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=toml_edit", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "0.25.11+spec-1.1.0", - deps = [ - "@vendor_ts__indexmap-2.14.0//:indexmap", - "@vendor_ts__toml_datetime-1.1.1-spec-1.1.0//:toml_datetime", - "@vendor_ts__toml_parser-1.1.2-spec-1.1.0//:toml_parser", - "@vendor_ts__winnow-1.0.2//:winnow", - ], -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.topological-sort-0.2.2.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.topological-sort-0.2.2.bazel deleted file mode 100644 index 4cba2e919677..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.topological-sort-0.2.2.bazel +++ /dev/null @@ -1,97 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "topological_sort", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_root = "src/lib.rs", - edition = "2018", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=topological-sort", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "0.2.2", -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.tree-sitter-generate-0.26.8.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.tree-sitter-generate-0.26.8.bazel deleted file mode 100644 index 12951a955489..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.tree-sitter-generate-0.26.8.bazel +++ /dev/null @@ -1,124 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "tree_sitter_generate", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_features = [ - "default", - "load", - "pathdiff", - "qjs-rt", - "rquickjs", - ], - crate_root = "src/generate.rs", - edition = "2021", - proc_macro_deps = [ - "@vendor_ts__indoc-2.0.7//:indoc", - ], - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=tree-sitter-generate", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "0.26.8", - deps = [ - "@vendor_ts__bitflags-2.9.4//:bitflags", - "@vendor_ts__dunce-1.0.5//:dunce", - "@vendor_ts__indexmap-2.14.0//:indexmap", - "@vendor_ts__log-0.4.28//:log", - "@vendor_ts__pathdiff-0.2.3//:pathdiff", - "@vendor_ts__regex-1.11.3//:regex", - "@vendor_ts__regex-syntax-0.8.6//:regex_syntax", - "@vendor_ts__rquickjs-0.10.0//:rquickjs", - "@vendor_ts__rustc-hash-2.1.1//:rustc_hash", - "@vendor_ts__semver-1.0.28//:semver", - "@vendor_ts__serde-1.0.228//:serde", - "@vendor_ts__serde_json-1.0.145//:serde_json", - "@vendor_ts__smallbitvec-2.6.1//:smallbitvec", - "@vendor_ts__thiserror-2.0.18//:thiserror", - "@vendor_ts__topological-sort-0.2.2//:topological_sort", - ], -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.unicode-segmentation-1.13.2.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.unicode-segmentation-1.13.2.bazel deleted file mode 100644 index 020b1bf1a716..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.unicode-segmentation-1.13.2.bazel +++ /dev/null @@ -1,97 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "unicode_segmentation", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_root = "src/lib.rs", - edition = "2018", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=unicode-segmentation", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "1.13.2", -) From cb3a77fd09865689e8896fd4a31bdf1612893f33 Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 27 Jul 2026 15:11:47 +0200 Subject: [PATCH 102/188] unified: Remove predicate that is identical to the default --- unified/ql/lib/codeql/unified/internal/Variables.qll | 2 -- 1 file changed, 2 deletions(-) diff --git a/unified/ql/lib/codeql/unified/internal/Variables.qll b/unified/ql/lib/codeql/unified/internal/Variables.qll index 97629f2c57ff..a22cd9009dda 100644 --- a/unified/ql/lib/codeql/unified/internal/Variables.qll +++ b/unified/ql/lib/codeql/unified/internal/Variables.qll @@ -262,8 +262,6 @@ private module LocalNameBindingInput implements LocalNameBindingInputSig; From 320b906eeadf05a58d258b917c959ac38a7dda21 Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 27 Jul 2026 15:12:35 +0200 Subject: [PATCH 103/188] unified: Record missing variable binding --- unified/ql/test/library-tests/variables/test.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unified/ql/test/library-tests/variables/test.swift b/unified/ql/test/library-tests/variables/test.swift index 0e6c23782b0d..76130a76ffed 100644 --- a/unified/ql/test/library-tests/variables/test.swift +++ b/unified/ql/test/library-tests/variables/test.swift @@ -80,7 +80,7 @@ func t10(value: Int) { // name=value1 // Switch with multiple cases func t11(value: Int) { // name=value1 switch value { // $ access=value1 - case let x where x > 0: // name=x1 + case let x where x > 0: // $ MISSING: access=x1 // name=x1 print(x) // $ access=x1 case let x: // name=x2 print(x) // $ access=x2 From c55648ff7a7ef19cbb45735b938e96fc7f6899c4 Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 27 Jul 2026 15:16:07 +0200 Subject: [PATCH 104/188] unified: Add variable shadowing local function --- unified/ql/test/library-tests/variables/test.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/unified/ql/test/library-tests/variables/test.swift b/unified/ql/test/library-tests/variables/test.swift index 76130a76ffed..1583acd73928 100644 --- a/unified/ql/test/library-tests/variables/test.swift +++ b/unified/ql/test/library-tests/variables/test.swift @@ -187,6 +187,8 @@ func t22() { } inner() // $ access=inner1 print(x) // $ access=x1 + let inner = 2 // name=inner2 + print(inner) // $ access=inner2 } // Three levels of shadowing From 272492c2c796c1417c1c94fff7a940163808d373 Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 27 Jul 2026 15:16:54 +0200 Subject: [PATCH 105/188] unified: Fix a comment in test case --- unified/ql/test/library-tests/variables/test.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unified/ql/test/library-tests/variables/test.swift b/unified/ql/test/library-tests/variables/test.swift index 1583acd73928..58d3548b4c41 100644 --- a/unified/ql/test/library-tests/variables/test.swift +++ b/unified/ql/test/library-tests/variables/test.swift @@ -216,7 +216,7 @@ func t24(optional: Int?) { // name=optional1 } } -// Switch with same variable name in different cases +// Switch with variable shadowed within body of case func t25(value: Int) { // name=value1 switch value { // $ access=value1 case let x: // name=x1 From 7e1f6b98d4bd815d695f10cdf55e03a09d8b3e96 Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 29 Jul 2026 11:48:39 +0200 Subject: [PATCH 106/188] unified: Factor catch/case guards into conditional_pattern The where-clause needs to be attached to the individual pattern, not the catch/case. --- unified/extractor/ast_types.yml | 12 +++++++++--- unified/ql/lib/codeql/unified/Ast.qll | 28 +++++++++++++++++++++++++++ unified/ql/lib/unified.dbscheme | 15 +++++++++++++- 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/unified/extractor/ast_types.yml b/unified/extractor/ast_types.yml index 4fa1ff169428..99a8b62986f4 100644 --- a/unified/extractor/ast_types.yml +++ b/unified/extractor/ast_types.yml @@ -49,6 +49,7 @@ supertypes: - tuple_pattern - constructor_pattern - or_pattern + - conditional_pattern - ignore_pattern - expr_equality_pattern - bulk_importing_pattern @@ -369,7 +370,6 @@ named: catch_clause: modifier*: modifier pattern?: pattern - guard?: expr body: block # `switch value { case pattern: body case ...: default: body }` @@ -381,11 +381,9 @@ named: # A single `case ...:` (or `default:`) entry in a switch. # An entry with multiple `case p1, p2:` patterns uses an `or_pattern`. # A `default:` entry has no pattern. - # An optional `guard` corresponds to a `where`-clause on the case. switch_case: modifier*: modifier pattern?: pattern - guard?: expr body: block # Evaluate 'expr' and match its result against 'pattern', and return true if it matches. @@ -446,6 +444,14 @@ named: modifier*: modifier pattern*: pattern + # A pattern that matches against a nested pattern, and subsequently checks a condition. + # The match is rejected if the condition does not hold. + # Variables bound in the nested pattern are in scope within the condition. + conditional_pattern: + modifier*: modifier + condition: expr + pattern: pattern + # A pattern with an optional associated name. pattern_element: modifier*: modifier diff --git a/unified/ql/lib/codeql/unified/Ast.qll b/unified/ql/lib/codeql/unified/Ast.qll index e9a827269cc4..2f84aedd4128 100644 --- a/unified/ql/lib/codeql/unified/Ast.qll +++ b/unified/ql/lib/codeql/unified/Ast.qll @@ -427,6 +427,28 @@ module Unified { } } + /** A class representing `conditional_pattern` nodes. */ + final class ConditionalPattern extends @unified_conditional_pattern, AstNodeImpl { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ConditionalPattern" } + + /** Gets the node corresponding to the field `condition`. */ + final Expr getCondition() { unified_conditional_pattern_def(this, result, _) } + + /** Gets the node corresponding to the field `modifier`. */ + final Modifier getModifier(int i) { unified_conditional_pattern_modifier(this, i, result) } + + /** Gets the node corresponding to the field `pattern`. */ + final Pattern getPattern() { unified_conditional_pattern_def(this, _, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + unified_conditional_pattern_def(this, result, _) or + unified_conditional_pattern_modifier(this, _, result) or + unified_conditional_pattern_def(this, _, result) + } + } + /** A class representing `constructor_declaration` nodes. */ final class ConstructorDeclaration extends @unified_constructor_declaration, AstNodeImpl { /** Gets the name of the primary QL class for this element. */ @@ -1565,6 +1587,12 @@ module Unified { or result = node.(CompoundAssignExpr).getValue() and i = -1 and name = "getValue" or + result = node.(ConditionalPattern).getCondition() and i = -1 and name = "getCondition" + or + result = node.(ConditionalPattern).getModifier(i) and name = "getModifier" + or + result = node.(ConditionalPattern).getPattern() and i = -1 and name = "getPattern" + or result = node.(ConstructorDeclaration).getBody() and i = -1 and name = "getBody" or result = node.(ConstructorDeclaration).getModifier(i) and name = "getModifier" diff --git a/unified/ql/lib/unified.dbscheme b/unified/ql/lib/unified.dbscheme index 3aafb2a494f9..8ff0a75cc670 100644 --- a/unified/ql/lib/unified.dbscheme +++ b/unified/ql/lib/unified.dbscheme @@ -365,6 +365,19 @@ unified_compound_assign_expr_def( int value: @unified_expr ref ); +#keyset[unified_conditional_pattern, index] +unified_conditional_pattern_modifier( + int unified_conditional_pattern: @unified_conditional_pattern ref, + int index: int ref, + unique int modifier: @unified_token_modifier ref +); + +unified_conditional_pattern_def( + unique int id: @unified_conditional_pattern, + int condition: @unified_expr ref, + int pattern: @unified_pattern ref +); + #keyset[unified_constructor_declaration, index] unified_constructor_declaration_modifier( int unified_constructor_declaration: @unified_constructor_declaration ref, @@ -1085,7 +1098,7 @@ unified_trivia_tokeninfo( string value: string ref ); -@unified_ast_node = @unified_accessor_declaration | @unified_argument | @unified_array_literal | @unified_assign_expr | @unified_associated_type_declaration | @unified_base_type | @unified_binary_expr | @unified_block | @unified_bound_type_constraint | @unified_break_expr | @unified_bulk_importing_pattern | @unified_call_expr | @unified_catch_clause | @unified_class_like_declaration | @unified_compound_assign_expr | @unified_constructor_declaration | @unified_constructor_pattern | @unified_continue_expr | @unified_destructor_declaration | @unified_do_while_stmt | @unified_equality_type_constraint | @unified_expr_equality_pattern | @unified_for_each_stmt | @unified_function_declaration | @unified_function_expr | @unified_function_type_expr | @unified_generic_type_expr | @unified_guard_if_stmt | @unified_if_expr | @unified_import_declaration | @unified_initializer_declaration | @unified_key_value_pair | @unified_labeled_stmt | @unified_map_literal | @unified_member_access_expr | @unified_name_expr | @unified_name_pattern | @unified_named_type_expr | @unified_operator_syntax_declaration | @unified_or_pattern | @unified_parameter | @unified_pattern_element | @unified_pattern_guard_expr | @unified_return_expr | @unified_switch_case | @unified_switch_expr | @unified_throw_expr | @unified_token | @unified_top_level | @unified_trivia_token | @unified_try_expr | @unified_tuple_expr | @unified_tuple_pattern | @unified_tuple_type_element | @unified_tuple_type_expr | @unified_type_alias_declaration | @unified_type_cast_expr | @unified_type_parameter | @unified_type_test_expr | @unified_type_test_pattern | @unified_unary_expr | @unified_unresolved_operator_sequence | @unified_variable_declaration | @unified_while_stmt +@unified_ast_node = @unified_accessor_declaration | @unified_argument | @unified_array_literal | @unified_assign_expr | @unified_associated_type_declaration | @unified_base_type | @unified_binary_expr | @unified_block | @unified_bound_type_constraint | @unified_break_expr | @unified_bulk_importing_pattern | @unified_call_expr | @unified_catch_clause | @unified_class_like_declaration | @unified_compound_assign_expr | @unified_conditional_pattern | @unified_constructor_declaration | @unified_constructor_pattern | @unified_continue_expr | @unified_destructor_declaration | @unified_do_while_stmt | @unified_equality_type_constraint | @unified_expr_equality_pattern | @unified_for_each_stmt | @unified_function_declaration | @unified_function_expr | @unified_function_type_expr | @unified_generic_type_expr | @unified_guard_if_stmt | @unified_if_expr | @unified_import_declaration | @unified_initializer_declaration | @unified_key_value_pair | @unified_labeled_stmt | @unified_map_literal | @unified_member_access_expr | @unified_name_expr | @unified_name_pattern | @unified_named_type_expr | @unified_operator_syntax_declaration | @unified_or_pattern | @unified_parameter | @unified_pattern_element | @unified_pattern_guard_expr | @unified_return_expr | @unified_switch_case | @unified_switch_expr | @unified_throw_expr | @unified_token | @unified_top_level | @unified_trivia_token | @unified_try_expr | @unified_tuple_expr | @unified_tuple_pattern | @unified_tuple_type_element | @unified_tuple_type_expr | @unified_type_alias_declaration | @unified_type_cast_expr | @unified_type_parameter | @unified_type_test_expr | @unified_type_test_pattern | @unified_unary_expr | @unified_unresolved_operator_sequence | @unified_variable_declaration | @unified_while_stmt unified_ast_node_location( unique int node: @unified_ast_node ref, From 16466846356162c7a7475931726227d4c0372620 Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 29 Jul 2026 11:53:06 +0200 Subject: [PATCH 107/188] unified: Encode catch/case patterns with conditional_pattern and or_pattern --- .../extractor/src/languages/swift/swift.rs | 47 ++++++++++++------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index ef3672e1b91c..684f7565c6d1 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -94,6 +94,19 @@ fn and_chain( .expect("control-flow statement must have at least one condition") } +/// Return the only pattern unchanged when there is exactly one, otherwise +/// wrap the list in an `or_pattern`. +fn make_or_pattern( + ctx: &mut yeast::build::BuildCtx<'_, SwiftContext>, + items: Vec, +) -> yeast::Id { + if items.len() == 1 { + items[0] + } else { + tree!((or_pattern pattern: {items})) + } +} + /// Translate a multi-part identifier (for example `Foo.Bar.Baz`) into a /// `member_access_expr` chain rooted at a `name_expr` over the first /// part. Panics on an empty input because the grammar's `_+` quantifier @@ -746,22 +759,17 @@ fn translation_rules() -> Vec> { rule!( (switchCase label: (switchCaseLabel caseItems: _* @items) statements: _* @body) => - switch_case { - let pattern = if items.len() == 1 { - items[0] - } else { - tree!((or_pattern pattern: {items})) - }; - tree!((switch_case pattern: {pattern} body: (block stmt: {body}))) - } + (switch_case + pattern: {make_or_pattern(&mut ctx, items)} + body: (block stmt: {body})) ), rule!( (switchCase label: (switchDefaultLabel) statements: _* @body) => (switch_case body: (block stmt: {body})) ), - // A single case item unwraps to its pattern (used as an `or_pattern` - // element). + // A single case item unwraps to its pattern, possibly boxed in conditional_pattern + rule!((switchCaseItem pattern: @p whereClause: (whereClause condition: @cond)) => (conditional_pattern pattern: { p } condition: {cond})), rule!((switchCaseItem pattern: @p) => pattern { p }), // A pattern-matching condition (`if case let x = e`, `if case .foo(let x) // = e`) becomes a `pattern_guard_expr`: the matched pattern and the @@ -877,17 +885,24 @@ fn translation_rules() -> Vec> { body: {body} catch_clause: {catches}) ), - // Catch block with bound identifier; optional where-clause guard. + rule!( + (catchItem pattern: @pattern whereClause: (whereClause condition: @guard)) + => + (conditional_pattern pattern: {pattern} condition: {guard}) + ), + rule!( + (catchItem pattern: @pattern) + => + pattern {pattern} + ), + // Catch block with one or more patterns (which have been translated by the catchItem rules) rule!( (catchClause - catchItems: (catchItem - pattern: @pattern - whereClause: (whereClause condition: @guard)?) + catchItems: _+ @patterns body: @body) => (catch_clause - pattern: {pattern} - guard: {guard} + pattern: {make_or_pattern(&mut ctx, patterns)} body: {body}) ), // Catch block without error binding From d827417f22f5e5d6c43cd63a4d9e99005cbdf089 Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 29 Jul 2026 13:04:28 +0200 Subject: [PATCH 108/188] unified: Regenerate QL --- unified/ql/lib/codeql/unified/Ast.qll | 12 ------------ unified/ql/lib/unified.dbscheme | 12 +----------- 2 files changed, 1 insertion(+), 23 deletions(-) diff --git a/unified/ql/lib/codeql/unified/Ast.qll b/unified/ql/lib/codeql/unified/Ast.qll index 2f84aedd4128..4ad61ff353bf 100644 --- a/unified/ql/lib/codeql/unified/Ast.qll +++ b/unified/ql/lib/codeql/unified/Ast.qll @@ -349,9 +349,6 @@ module Unified { /** Gets the node corresponding to the field `body`. */ final Block getBody() { unified_catch_clause_def(this, result) } - /** Gets the node corresponding to the field `guard`. */ - final Expr getGuard() { unified_catch_clause_guard(this, result) } - /** Gets the node corresponding to the field `modifier`. */ final Modifier getModifier(int i) { unified_catch_clause_modifier(this, i, result) } @@ -361,7 +358,6 @@ module Unified { /** Gets a field or child node of this node. */ final override AstNode getAFieldOrChild() { unified_catch_clause_def(this, result) or - unified_catch_clause_guard(this, result) or unified_catch_clause_modifier(this, _, result) or unified_catch_clause_pattern(this, result) } @@ -1147,9 +1143,6 @@ module Unified { /** Gets the node corresponding to the field `body`. */ final Block getBody() { unified_switch_case_def(this, result) } - /** Gets the node corresponding to the field `guard`. */ - final Expr getGuard() { unified_switch_case_guard(this, result) } - /** Gets the node corresponding to the field `modifier`. */ final Modifier getModifier(int i) { unified_switch_case_modifier(this, i, result) } @@ -1159,7 +1152,6 @@ module Unified { /** Gets a field or child node of this node. */ final override AstNode getAFieldOrChild() { unified_switch_case_def(this, result) or - unified_switch_case_guard(this, result) or unified_switch_case_modifier(this, _, result) or unified_switch_case_pattern(this, result) } @@ -1563,8 +1555,6 @@ module Unified { or result = node.(CatchClause).getBody() and i = -1 and name = "getBody" or - result = node.(CatchClause).getGuard() and i = -1 and name = "getGuard" - or result = node.(CatchClause).getModifier(i) and name = "getModifier" or result = node.(CatchClause).getPattern() and i = -1 and name = "getPattern" @@ -1749,8 +1739,6 @@ module Unified { or result = node.(SwitchCase).getBody() and i = -1 and name = "getBody" or - result = node.(SwitchCase).getGuard() and i = -1 and name = "getGuard" - or result = node.(SwitchCase).getModifier(i) and name = "getModifier" or result = node.(SwitchCase).getPattern() and i = -1 and name = "getPattern" diff --git a/unified/ql/lib/unified.dbscheme b/unified/ql/lib/unified.dbscheme index 8ff0a75cc670..8306c3fcf0c7 100644 --- a/unified/ql/lib/unified.dbscheme +++ b/unified/ql/lib/unified.dbscheme @@ -292,11 +292,6 @@ unified_call_expr_def( int callee: @unified_expr_or_type ref ); -unified_catch_clause_guard( - unique int unified_catch_clause: @unified_catch_clause ref, - unique int guard: @unified_expr ref -); - #keyset[unified_catch_clause, index] unified_catch_clause_modifier( int unified_catch_clause: @unified_catch_clause ref, @@ -780,7 +775,7 @@ unified_parameter_def( unique int id: @unified_parameter ); -@unified_pattern = @unified_bulk_importing_pattern | @unified_constructor_pattern | @unified_expr_equality_pattern | @unified_name_pattern | @unified_or_pattern | @unified_token_ignore_pattern | @unified_token_unsupported_node | @unified_tuple_pattern +@unified_pattern = @unified_bulk_importing_pattern | @unified_conditional_pattern | @unified_constructor_pattern | @unified_expr_equality_pattern | @unified_name_pattern | @unified_or_pattern | @unified_token_ignore_pattern | @unified_token_unsupported_node | @unified_tuple_pattern unified_pattern_element_key( unique int unified_pattern_element: @unified_pattern_element ref, @@ -816,11 +811,6 @@ unified_return_expr_def( @unified_stmt = @unified_accessor_declaration | @unified_class_like_declaration | @unified_constructor_declaration | @unified_destructor_declaration | @unified_do_while_stmt | @unified_expr | @unified_for_each_stmt | @unified_function_declaration | @unified_guard_if_stmt | @unified_import_declaration | @unified_labeled_stmt | @unified_operator_syntax_declaration | @unified_type_alias_declaration | @unified_variable_declaration | @unified_while_stmt -unified_switch_case_guard( - unique int unified_switch_case: @unified_switch_case ref, - unique int guard: @unified_expr ref -); - #keyset[unified_switch_case, index] unified_switch_case_modifier( int unified_switch_case: @unified_switch_case ref, From 3923effe644a6c55c4c14448115fdec7062a40b6 Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 29 Jul 2026 13:07:56 +0200 Subject: [PATCH 109/188] unified: Add new MISSING marker in test --- unified/ql/test/library-tests/variables/test.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unified/ql/test/library-tests/variables/test.swift b/unified/ql/test/library-tests/variables/test.swift index 58d3548b4c41..608665b3bd52 100644 --- a/unified/ql/test/library-tests/variables/test.swift +++ b/unified/ql/test/library-tests/variables/test.swift @@ -81,7 +81,7 @@ func t10(value: Int) { // name=value1 func t11(value: Int) { // name=value1 switch value { // $ access=value1 case let x where x > 0: // $ MISSING: access=x1 // name=x1 - print(x) // $ access=x1 + print(x) // $ MISSING: access=x1 case let x: // name=x2 print(x) // $ access=x2 } From 5ba941e465430b0dd6984152da4fdb71d1e85d73 Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 29 Jul 2026 13:35:50 +0200 Subject: [PATCH 110/188] unified: Handle ConditionalPattern in local scoping --- unified/ql/lib/codeql/unified/internal/Variables.qll | 9 +++++++-- unified/ql/test/library-tests/variables/test.swift | 4 ++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/unified/ql/lib/codeql/unified/internal/Variables.qll b/unified/ql/lib/codeql/unified/internal/Variables.qll index a22cd9009dda..539f19930dc6 100644 --- a/unified/ql/lib/codeql/unified/internal/Variables.qll +++ b/unified/ql/lib/codeql/unified/internal/Variables.qll @@ -178,12 +178,12 @@ private module LocalNameBindingInput implements LocalNameBindingInputSig 0: // $ MISSING: access=x1 // name=x1 - print(x) // $ MISSING: access=x1 + case let x where x > 0: // $ access=x1 // name=x1 + print(x) // $ access=x1 case let x: // name=x2 print(x) // $ access=x2 } From 91c2d7251fa028213c80806fa756d166a6ddc9a2 Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 29 Jul 2026 13:37:25 +0200 Subject: [PATCH 111/188] unified: Add some corpus tests Output has not been generated yet (for reasons) --- .../control-flow/switch-case-item-where-clauses.swift | 8 ++++++++ .../swift/optionals-and-errors/catch-where-clauses.swift | 7 +++++++ 2 files changed, 15 insertions(+) create mode 100644 unified/extractor/tests/corpus/swift/control-flow/switch-case-item-where-clauses.swift create mode 100644 unified/extractor/tests/corpus/swift/optionals-and-errors/catch-where-clauses.swift diff --git a/unified/extractor/tests/corpus/swift/control-flow/switch-case-item-where-clauses.swift b/unified/extractor/tests/corpus/swift/control-flow/switch-case-item-where-clauses.swift new file mode 100644 index 000000000000..50003cb1fbca --- /dev/null +++ b/unified/extractor/tests/corpus/swift/control-flow/switch-case-item-where-clauses.swift @@ -0,0 +1,8 @@ +switch n { +case let x where x > 0: + print("positive") +case let y where y < 0, 0: + print("non-positive") +default: + print("other") +} diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/catch-where-clauses.swift b/unified/extractor/tests/corpus/swift/optionals-and-errors/catch-where-clauses.swift new file mode 100644 index 000000000000..48995b818e51 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/catch-where-clauses.swift @@ -0,0 +1,7 @@ +do { + try foo() +} catch let e where isNetworkError(e), let f where isTimeout(f) { + print("retry") +} catch { + print("fallback") +} From d0b6e96e5bb2914d1fb298daadbe1846d40a76f8 Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Wed, 29 Jul 2026 14:01:25 +0200 Subject: [PATCH 112/188] Make CODEQL_PLATFORM architecture-aware for linux-arm64 CODEQL_PLATFORM is OS-only today (linux->linux64, macos->osx64, windows->win64). ELF has no fat-binary equivalent, so Linux arm64 needs its own string. Add `linux-arm64` for os:linux AND cpu:arm64 while keeping every existing string byte-identical. - Add a public `//misc/bazel:linux_arm64` config_setting (os:linux + cpu:arm64). - Turn `os_select` into `codeql_platform_select`, a full selector over the four CodeQL platforms (`linux64`, `linux_arm64`, `osx64`, `win64`, plus `otherwise`), working in both macro (select) and rule (target_platform_has_constraint) contexts. There is deliberately no fallback between the two Linux slots. - Re-express `os_select` as a thin OS-only wrapper around it (Linux maps to both `linux64` and `linux_arm64`), so its existing swift/xcode callers keep working unchanged. - Add an `_arm64_constraint` entry to OS_DETECTION_ATTRS. - Drive the platform string from `codeql_platform_select` in pkg.bzl's `_detect_platform` and defs.bzl's `codeql_platform`. macOS keeps osx64 for both arch slices (universal binary): the linux_arm64 key requires both constraints, so the OS discriminator dominates. The new branch is dormant on existing CI (no job builds linux-on-arm64), so all current configs produce byte-identical outputs. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: c5c5b0bf-4afa-468c-b2dd-197d80932b4b --- defs.bzl | 13 +++++--- misc/bazel/BUILD.bazel | 11 ++++++ misc/bazel/os.bzl | 76 +++++++++++++++++++++++++++++++----------- misc/bazel/pkg.bzl | 10 ++++-- 4 files changed, 84 insertions(+), 26 deletions(-) diff --git a/defs.bzl b/defs.bzl index d6748d831761..d4c5ea5e2623 100644 --- a/defs.bzl +++ b/defs.bzl @@ -1,5 +1,8 @@ -codeql_platform = select({ - "@platforms//os:linux": "linux64", - "@platforms//os:macos": "osx64", - "@platforms//os:windows": "win64", -}) +load("//misc/bazel:os.bzl", "codeql_platform_select") + +codeql_platform = codeql_platform_select( + linux64 = "linux64", + linux_arm64 = "linux-arm64", + osx64 = "osx64", + win64 = "win64", +) diff --git a/misc/bazel/BUILD.bazel b/misc/bazel/BUILD.bazel index e00a6f7a64c7..b71a9b6ca6a3 100644 --- a/misc/bazel/BUILD.bazel +++ b/misc/bazel/BUILD.bazel @@ -1,5 +1,16 @@ load("@rules_shell//shell:sh_library.bzl", "sh_library") +# Matches the Linux arm64 target, used to give it a distinct `CODEQL_PLATFORM` string +# (`linux-arm64`). Every other configuration keeps its OS-only string. +config_setting( + name = "linux_arm64", + constraint_values = [ + "@platforms//os:linux", + "@platforms//cpu:arm64", + ], + visibility = ["//visibility:public"], +) + sh_library( name = "sh_runfiles", srcs = ["runfiles.sh"], diff --git a/misc/bazel/os.bzl b/misc/bazel/os.bzl index 34093e76331d..f8e5c13cfe10 100644 --- a/misc/bazel/os.bzl +++ b/misc/bazel/os.bzl @@ -1,38 +1,76 @@ """ Os detection facilities. """ -def os_select( +def codeql_platform_select( ctx = None, *, - linux = None, - windows = None, - macos = None, - default = None): + linux64 = None, + linux_arm64 = None, + osx64 = None, + win64 = None, + otherwise = None): """ - This can work both in a macro and a rule context to choose something based on the current OS. - If used in a rule implementation, you need to pass `ctx` and add `OS_DETECTION_ATTRS` to the - rule attributes. + Choose a value based on the target CodeQL platform, discriminating the four platforms CodeQL + knows about: `linux64` (Linux on x86_64), `linux_arm64` (Linux on arm64), `osx64` (macOS, any + architecture) and `win64` (Windows on x86_64). Any platform left unspecified uses `otherwise`. + + There is deliberately no fallback between `linux64` and `linux_arm64`: if you want the same value + for both (i.e. you only care about the OS, not the architecture), use `os_select` instead. + + This works both in a macro context (`ctx = None`, returning a `select`) and in a rule context + (passing `ctx`, which then needs `OS_DETECTION_ATTRS` on the rule attributes). """ choices = { - "linux": linux or default, - "windows": windows or default, - "macos": macos or default, + "//misc/bazel:linux_arm64": linux_arm64 or otherwise, + "@platforms//os:linux": linux64 or otherwise, + "@platforms//os:macos": osx64 or otherwise, + "@platforms//os:windows": win64 or otherwise, } if not ctx: return select({ - "@platforms//os:%s" % os: v - for os, v in choices.items() + setting: v + for setting, v in choices.items() if v != None }) - for os, v in choices.items(): - if ctx.target_platform_has_constraint(getattr(ctx.attr, "_%s_constraint" % os)[platform_common.ConstraintValueInfo]): - if v == None: - fail("%s not supported by %s" % (os, ctx.label)) - return v - fail("Unknown OS detected") + def has(constraint): + return ctx.target_platform_has_constraint(getattr(ctx.attr, "_%s_constraint" % constraint)[platform_common.ConstraintValueInfo]) + + if has("linux"): + result = choices["//misc/bazel:linux_arm64"] if has("arm64") else choices["@platforms//os:linux"] + elif has("macos"): + result = choices["@platforms//os:macos"] + elif has("windows"): + result = choices["@platforms//os:windows"] + else: + fail("Unknown OS detected") + if result == None: + fail("platform not supported by %s" % ctx.label) + return result + +def os_select( + ctx = None, + *, + linux = None, + windows = None, + macos = None, + default = None): + """ + Choose a value based on the target OS, ignoring the architecture. This is a thin, OS-only wrapper + around `codeql_platform_select` (Linux gets the same value on both x86_64 and arm64). + See `codeql_platform_select` for macro vs rule usage. + """ + return codeql_platform_select( + ctx, + linux64 = linux, + linux_arm64 = linux, + osx64 = macos, + win64 = windows, + otherwise = default, + ) OS_DETECTION_ATTRS = { "_windows_constraint": attr.label(default = "@platforms//os:windows"), "_macos_constraint": attr.label(default = "@platforms//os:macos"), "_linux_constraint": attr.label(default = "@platforms//os:linux"), + "_arm64_constraint": attr.label(default = "@platforms//cpu:arm64"), } diff --git a/misc/bazel/pkg.bzl b/misc/bazel/pkg.bzl index 25f2bf3577d0..efec21e761f9 100644 --- a/misc/bazel/pkg.bzl +++ b/misc/bazel/pkg.bzl @@ -8,7 +8,7 @@ load("@rules_pkg//pkg:mappings.bzl", "pkg_attributes", "pkg_filegroup", "pkg_fil load("@rules_pkg//pkg:pkg.bzl", "pkg_zip") load("@rules_pkg//pkg:providers.bzl", "PackageFilegroupInfo", "PackageFilesInfo") load("@rules_python//python:defs.bzl", "py_binary", "py_test") -load("//misc/bazel:os.bzl", "OS_DETECTION_ATTRS", "os_select") +load("//misc/bazel:os.bzl", "OS_DETECTION_ATTRS", "codeql_platform_select") def _make_internal(name): def internal(suffix = "internal", *args): @@ -26,7 +26,13 @@ def _expand_path(path, platform): return ("common", path) def _detect_platform(ctx = None): - return os_select(ctx, linux = "linux64", macos = "osx64", windows = "win64") + return codeql_platform_select( + ctx, + linux64 = "linux64", + linux_arm64 = "linux-arm64", + osx64 = "osx64", + win64 = "win64", + ) def codeql_pkg_files( *, From b6e7464da20bbb8b5d0c60cf993ff79f7bebeae2 Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Wed, 29 Jul 2026 14:25:13 +0200 Subject: [PATCH 113/188] Address review: linux-arm64 docs + None-vs-falsey fallback - codeql_pack docstring: include `linux-arm64` in the exhaustive list of values the `{CODEQL_PLATFORM}` placeholder expands to (both mentions). - codeql_platform_select: only fall back to `otherwise` on `None`, not on any falsey value, via a small `_or_otherwise` helper, matching the documented `None` defaults. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: c5c5b0bf-4afa-468c-b2dd-197d80932b4b --- misc/bazel/os.bzl | 12 ++++++++---- misc/bazel/pkg.bzl | 4 ++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/misc/bazel/os.bzl b/misc/bazel/os.bzl index f8e5c13cfe10..a3fee479dbcd 100644 --- a/misc/bazel/os.bzl +++ b/misc/bazel/os.bzl @@ -19,11 +19,15 @@ def codeql_platform_select( This works both in a macro context (`ctx = None`, returning a `select`) and in a rule context (passing `ctx`, which then needs `OS_DETECTION_ATTRS` on the rule attributes). """ + + def _or_otherwise(value): + return value if value != None else otherwise + choices = { - "//misc/bazel:linux_arm64": linux_arm64 or otherwise, - "@platforms//os:linux": linux64 or otherwise, - "@platforms//os:macos": osx64 or otherwise, - "@platforms//os:windows": win64 or otherwise, + "//misc/bazel:linux_arm64": _or_otherwise(linux_arm64), + "@platforms//os:linux": _or_otherwise(linux64), + "@platforms//os:macos": _or_otherwise(osx64), + "@platforms//os:windows": _or_otherwise(win64), } if not ctx: return select({ diff --git a/misc/bazel/pkg.bzl b/misc/bazel/pkg.bzl index efec21e761f9..684bcbb8c3ba 100644 --- a/misc/bazel/pkg.bzl +++ b/misc/bazel/pkg.bzl @@ -464,12 +464,12 @@ def codeql_pack( `zips` is a map from `.zip` files to prefixes to import. The distinction between arch-specific and common contents is made based on whether the paths (including possible prefixes added by rules) contain the special `{CODEQL_PLATFORM}` placeholder, which in case it is present will also - be replaced by the appropriate platform (`linux64`, `win64` or `osx64`). + be replaced by the appropriate platform (`linux64`, `linux-arm64`, `win64` or `osx64`). Specific file paths can be placed in the arch-specific package by adding them to `arch_overrides`, even if their path doesn't contain the `CODEQL_PLATFORM` placeholder. The codeql pack rules will expand the `{CODEQL_PLATFORM}` marker in paths, and use that to split the files into a common and an arch-specific part. - This placeholder will be replaced by the appropriate platform (`linux64`, `win64` or `osx64`). + This placeholder will be replaced by the appropriate platform (`linux64`, `linux-arm64`, `win64` or `osx64`). `arch_overrides` is a list of files that should be included in the arch-specific bits of the pack, even if their path doesn't contain the `{CODEQL_PLATFORM}` marker. All files in the pack will be prefixed with `name`, unless `pack_prefix` is set, then is used instead. From ba3fce17df72408e8289ddc7f07ef607be1b426e Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Wed, 29 Jul 2026 14:50:21 +0200 Subject: [PATCH 114/188] Add `posix` convenience to os_select `posix` sets the shared value for both `linux` and `macos`. It is mutually exclusive with either of them and fails if supplied together with `linux` or `macos`. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: c5c5b0bf-4afa-468c-b2dd-197d80932b4b --- misc/bazel/os.bzl | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/misc/bazel/os.bzl b/misc/bazel/os.bzl index a3fee479dbcd..6b9b71cb0167 100644 --- a/misc/bazel/os.bzl +++ b/misc/bazel/os.bzl @@ -57,12 +57,19 @@ def os_select( linux = None, windows = None, macos = None, + posix = None, default = None): """ Choose a value based on the target OS, ignoring the architecture. This is a thin, OS-only wrapper around `codeql_platform_select` (Linux gets the same value on both x86_64 and arm64). - See `codeql_platform_select` for macro vs rule usage. + `posix` is a convenience for the value shared by `linux` and `macos`; it is mutually exclusive + with both. See `codeql_platform_select` for macro vs rule usage. """ + if posix != None: + if linux != None or macos != None: + fail("`posix` is mutually exclusive with `linux` and `macos`") + linux = posix + macos = posix return codeql_platform_select( ctx, linux64 = linux, From 0c20a33bc249698b47af059c9c57b497e569f09d Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Wed, 29 Jul 2026 16:03:39 +0200 Subject: [PATCH 115/188] Anchor linux_arm64 select key to the codeql repo When `codeql_platform_select` builds its `select` from a macro invoked in another workspace (e.g. semmle-code consuming this repo as `@codeql`), a bare `//misc/bazel:linux_arm64` string key resolves against the consuming repo and fails with "no such package 'misc/bazel'". Use `Label(...)`, which resolves relative to this file's own repo, so the key always binds to `@codeql//misc/bazel:linux_arm64` regardless of the calling workspace. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: c5c5b0bf-4afa-468c-b2dd-197d80932b4b --- misc/bazel/os.bzl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/misc/bazel/os.bzl b/misc/bazel/os.bzl index 6b9b71cb0167..39b12773c780 100644 --- a/misc/bazel/os.bzl +++ b/misc/bazel/os.bzl @@ -23,8 +23,9 @@ def codeql_platform_select( def _or_otherwise(value): return value if value != None else otherwise + linux_arm64_setting = Label("//misc/bazel:linux_arm64") choices = { - "//misc/bazel:linux_arm64": _or_otherwise(linux_arm64), + linux_arm64_setting: _or_otherwise(linux_arm64), "@platforms//os:linux": _or_otherwise(linux64), "@platforms//os:macos": _or_otherwise(osx64), "@platforms//os:windows": _or_otherwise(win64), @@ -40,7 +41,7 @@ def codeql_platform_select( return ctx.target_platform_has_constraint(getattr(ctx.attr, "_%s_constraint" % constraint)[platform_common.ConstraintValueInfo]) if has("linux"): - result = choices["//misc/bazel:linux_arm64"] if has("arm64") else choices["@platforms//os:linux"] + result = choices[linux_arm64_setting] if has("arm64") else choices["@platforms//os:linux"] elif has("macos"): result = choices["@platforms//os:macos"] elif has("windows"): From d2faab7fab03d7d7d154e1f1f55d859916a79ef1 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 29 Jul 2026 15:29:22 +0100 Subject: [PATCH 116/188] Python: Use fastTC explicitly in 'localFlow' to avoid relying on the optimizer to always do this transformation. --- .../lib/semmle/python/dataflow/new/internal/DataFlowUtil.qll | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowUtil.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowUtil.qll index ad007c6f6fe3..e61fc15c754a 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowUtil.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowUtil.qll @@ -20,9 +20,11 @@ predicate localFlowStep(Node nodeFrom, Node nodeTo) { FlowSummaryImpl::Private::Steps::summaryThroughStepValue(nodeFrom, nodeTo, _) } +private predicate localFlowStepPlus(Node node1, Node node2) = fastTC(localFlowStep/2)(node1, node2) + /** * Holds if data flows from `source` to `sink` in zero or more local * (intra-procedural) steps. */ pragma[inline] -predicate localFlow(Node source, Node sink) { localFlowStep*(source, sink) } +predicate localFlow(Node source, Node sink) { source = sink or localFlowStepPlus(source, sink) } From 73ccefff888e7adc4b3577ab420eb21c04662b2e Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Wed, 29 Jul 2026 17:31:32 +0100 Subject: [PATCH 117/188] Go: Reduce package processing log messages to `debug` level --- go/extractor/extractor.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/go/extractor/extractor.go b/go/extractor/extractor.go index 4efa1daac569..7f8ae557e3c4 100644 --- a/go/extractor/extractor.go +++ b/go/extractor/extractor.go @@ -232,13 +232,13 @@ func ExtractWithFlags(buildFlags []string, patterns []string, extractTests bool, // This should only cause some wasted time and not inconsistency because the names for // objects seen in this process should be the same each time. - log.Printf("Processing package %s.", pkg.PkgPath) + slog.Debug("Processing package", "package", pkg.PkgPath) if _, ok := pkgInfos[pkg.PkgPath]; !ok { pkgInfos[pkg.PkgPath] = toolchain.GetPkgInfo(pkg.PkgPath, modFlags...) } - log.Printf("Extracting types for package %s.", pkg.PkgPath) + slog.Debug("Extracting types for package", "package", pkg.PkgPath) tw, err := trap.NewWriter(pkg.PkgPath, pkg) if err != nil { From e70ba7df2e18e33722b9860419e0f953423c8588 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20Loba=C4=8Devski?= Date: Sun, 19 Jul 2026 18:30:45 +0000 Subject: [PATCH 118/188] Improve clobbering query message and documentation --- .../2026-07-29-output-clobbering-messages.md | 4 + .../Security/CWE-074/OutputClobberingHigh.md | 88 +++++++++++++++++++ .../Security/CWE-074/OutputClobberingHigh.ql | 39 +++++++- actions/ql/test/output-clobbering.model.yml | 6 ++ actions/ql/test/qlpack.yml | 2 + .../CWE-074/.github/workflows/output3.yml | 10 +++ .../CWE-074/OutputClobberingHigh.expected | 18 ++-- 7 files changed, 157 insertions(+), 10 deletions(-) create mode 100644 actions/ql/src/change-notes/2026-07-29-output-clobbering-messages.md create mode 100644 actions/ql/src/experimental/Security/CWE-074/OutputClobberingHigh.md create mode 100644 actions/ql/test/output-clobbering.model.yml create mode 100644 actions/ql/test/query-tests/Security/CWE-074/.github/workflows/output3.yml diff --git a/actions/ql/src/change-notes/2026-07-29-output-clobbering-messages.md b/actions/ql/src/change-notes/2026-07-29-output-clobbering-messages.md new file mode 100644 index 000000000000..4abb7a029762 --- /dev/null +++ b/actions/ql/src/change-notes/2026-07-29-output-clobbering-messages.md @@ -0,0 +1,4 @@ +--- +category: fix +--- +* The `actions/output-clobbering/high` query now provides messages tailored to the affected output channel and includes expanded documentation and recommendations. diff --git a/actions/ql/src/experimental/Security/CWE-074/OutputClobberingHigh.md b/actions/ql/src/experimental/Security/CWE-074/OutputClobberingHigh.md new file mode 100644 index 000000000000..cf8c086e097c --- /dev/null +++ b/actions/ql/src/experimental/Security/CWE-074/OutputClobberingHigh.md @@ -0,0 +1,88 @@ +## Overview + +GitHub Actions steps communicate output values to the runner through a line-oriented command format. A step normally sets an output by appending a `name=value` record to the file referenced by `GITHUB_OUTPUT`. Multiline values use a delimiter-based form. Older workflows may instead emit `set-output` workflow commands to standard output. + +If attacker-controlled data is written to one of these command channels without validation, the data may be interpreted as command syntax rather than as a single value. An attacker can use newline characters, a matching multiline delimiter, or a forged workflow command to create additional outputs or overwrite output values that later steps expect to be trusted. + +The attacker-controlled data may come directly from an event, or indirectly from an untrusted checkout, downloaded artifact, file, or action output. Clobbered outputs can alter conditions and arguments in later steps. If a later step interpolates an injected output into a script, this issue may contribute to arbitrary code execution. + +## Recommendation + +Treat values from events, pull requests, artifacts, untrusted files, and third-party actions as untrusted. + +Before writing an untrusted value to `GITHUB_OUTPUT`, validate it against the narrow format required by the workflow. For example, require a pull request number to contain only decimal digits. For a single-line output, reject carriage-return and newline characters. Do not append an untrusted file directly to `GITHUB_OUTPUT`. + +Do not use the deprecated `set-output` workflow command. Migrate to `GITHUB_OUTPUT`, and avoid printing untrusted data while legacy workflow-command processing is enabled. + +For multiline values, use a random delimiter that cannot occur on a line by itself in the value. If the value is arbitrary, store it in a normal file instead of using the multiline command format, and pass only the validated file path as an output. + +Review the documentation and implementation of actions that consume untrusted inputs. Use only inputs that the action handles as data rather than as output-command syntax. + +## Example + +### Incorrect Usage + +The following step reads an attacker-controlled artifact file and writes its contents directly to `GITHUB_OUTPUT`. A newline in `pr-number.txt` can add another output record and overwrite `approved`. + +```yaml +- id: metadata + run: | + echo "approved=false" >> "$GITHUB_OUTPUT" + echo "pr_number=$(cat pr-number.txt)" >> "$GITHUB_OUTPUT" +``` + +For example, an attacker can provide a `pr-number.txt` artifact with the following contents: + +```text +123 +approved=true +``` + +The step appends the following records to `GITHUB_OUTPUT`: + +```text +approved=false +pr_number=123 +approved=true +``` + +The injected record replaces the expected `approved` output with the attacker-controlled value +`true`. + +Likewise, printing untrusted data to standard output can forge a legacy workflow command: + +```yaml +- id: metadata + env: + BODY: ${{ github.event.comment.body }} + run: | + echo "$BODY" + echo "::set-output name=approved::false" +``` + +### Correct Usage + +Validate the value before writing it to `GITHUB_OUTPUT`, and use a fixed output name with a single-line value: + +```yaml +- id: metadata + run: | + pr_number="$(cat pr-number.txt)" + if [[ ! "$pr_number" =~ ^[0-9]+$ ]]; then + echo "Invalid pull request number" >&2 + exit 1 + fi + printf 'pr_number=%s\n' "$pr_number" >> "$GITHUB_OUTPUT" +``` + +## References + +- GitHub Docs: [Workflow commands for GitHub Actions](https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-commands). +- GitHub Docs: [Setting an output parameter](https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-commands#setting-an-output-parameter). +- GitHub Docs: [Multiline strings](https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-commands#multiline-strings). +- GitHub Changelog: [Deprecating `save-state` and `set-output` commands](https://github.blog/changelog/2022-10-10-github-actions-deprecating-save-state-and-set-output-commands/). +- GitHub Actions Toolkit: [`add-path` and `set-env` runner commands are processed via stdout](https://github.com/actions/toolkit/security/advisories/GHSA-mfwh-5m23-j46w). +- GitHub Security Lab: [New vulnerability patterns and mitigation strategies](https://securitylab.github.com/resources/github-actions-new-patterns-and-mitigations/). +- GitHub Security Lab: [Actions expression injection in Ant Design](https://securitylab.github.com/advisories/GHSL-2024-121_GHSL-2024-122_ant-design/). +- GitHub Security Lab: [Poisoned Pipeline Execution via code injection in SymPy](https://securitylab.github.com/advisories/GHSL-2024-322_Sympy/). +- Common Weakness Enumeration: [CWE-74](https://cwe.mitre.org/data/definitions/74.html). diff --git a/actions/ql/src/experimental/Security/CWE-074/OutputClobberingHigh.ql b/actions/ql/src/experimental/Security/CWE-074/OutputClobberingHigh.ql index 9c9c2e4d139a..a197ee2b244a 100644 --- a/actions/ql/src/experimental/Security/CWE-074/OutputClobberingHigh.ql +++ b/actions/ql/src/experimental/Security/CWE-074/OutputClobberingHigh.ql @@ -19,6 +19,42 @@ import codeql.actions.dataflow.FlowSources import OutputClobberingFlow::PathGraph import codeql.actions.security.ControlChecks +private predicate isEnvironmentFileSink(OutputClobberingFlow::PathNode sink) { + sink.getNode() instanceof OutputClobberingFromFileReadSink or + sink.getNode() instanceof OutputClobberingFromEnvVarSink +} + +private predicate isWorkflowCommandSink(OutputClobberingFlow::PathNode sink) { + sink.getNode() instanceof WorkflowCommandClobberingFromFileReadSink or + sink.getNode() instanceof WorkflowCommandClobberingFromEnvVarSink +} + +private string getMessage(OutputClobberingFlow::PathNode sink) { + isEnvironmentFileSink(sink) and + result = + "Attacker-controlled data may inject or overwrite step outputs written through " + + "`$GITHUB_OUTPUT` in $@." + or + not isEnvironmentFileSink(sink) and + isWorkflowCommandSink(sink) and + result = + "Attacker-controlled data printed to standard output may forge a `set-output` " + + "workflow command and overwrite step outputs in $@." + or + not isEnvironmentFileSink(sink) and + not isWorkflowCommandSink(sink) and + result = "Attacker-controlled data may inject or overwrite step outputs in $@." +} + +private string getSinkLabel(OutputClobberingFlow::PathNode sink) { + (isEnvironmentFileSink(sink) or isWorkflowCommandSink(sink)) and + result = "this step" + or + not isEnvironmentFileSink(sink) and + not isWorkflowCommandSink(sink) and + result = "this action" +} + from OutputClobberingFlow::PathNode source, OutputClobberingFlow::PathNode sink, Event event where OutputClobberingFlow::flowPath(source, sink) and @@ -40,5 +76,4 @@ where madSink(sink.getNode(), "output-clobbering") ) ) -select sink.getNode(), source, sink, "Potential clobbering of a step output in $@.", sink, - sink.getNode().toString() +select sink.getNode(), source, sink, getMessage(sink), sink, getSinkLabel(sink) diff --git a/actions/ql/test/output-clobbering.model.yml b/actions/ql/test/output-clobbering.model.yml new file mode 100644 index 000000000000..ef94ac69ac41 --- /dev/null +++ b/actions/ql/test/output-clobbering.model.yml @@ -0,0 +1,6 @@ +extensions: + - addsTo: + pack: codeql/actions-all + extensible: actionsSinkModel + data: + - ["actions/github-script", "*", "input.script", "output-clobbering", "manual"] diff --git a/actions/ql/test/qlpack.yml b/actions/ql/test/qlpack.yml index 139e8e57c62e..9c9e714fc67a 100644 --- a/actions/ql/test/qlpack.yml +++ b/actions/ql/test/qlpack.yml @@ -10,3 +10,5 @@ dependencies: extractor: actions tests: . warnOnImplicitThis: true +dataExtensions: + - output-clobbering.model.yml diff --git a/actions/ql/test/query-tests/Security/CWE-074/.github/workflows/output3.yml b/actions/ql/test/query-tests/Security/CWE-074/.github/workflows/output3.yml new file mode 100644 index 000000000000..15d31880422c --- /dev/null +++ b/actions/ql/test/query-tests/Security/CWE-074/.github/workflows/output3.yml @@ -0,0 +1,10 @@ +on: + issue_comment: {} + +jobs: + modeled-action: + runs-on: ubuntu-latest + steps: + - uses: actions/github-script@v7 + with: + script: ${{ github.event.comment.body }} diff --git a/actions/ql/test/query-tests/Security/CWE-074/OutputClobberingHigh.expected b/actions/ql/test/query-tests/Security/CWE-074/OutputClobberingHigh.expected index af792f1ab65e..44d18652adf5 100644 --- a/actions/ql/test/query-tests/Security/CWE-074/OutputClobberingHigh.expected +++ b/actions/ql/test/query-tests/Security/CWE-074/OutputClobberingHigh.expected @@ -21,13 +21,15 @@ nodes | .github/workflows/output2.yml:48:14:51:48 | # VULNERABLE\ncat pr-number\necho "::set-output name=OUTPUT::SAFE"\n | semmle.label | # VULNERABLE\ncat pr-number\necho "::set-output name=OUTPUT::SAFE"\n | | .github/workflows/output2.yml:53:14:56:19 | # VULNERABLE\necho "::set-output name=OUTPUT::SAFE"\nls *.txt\n | semmle.label | # VULNERABLE\necho "::set-output name=OUTPUT::SAFE"\nls *.txt\n | | .github/workflows/output2.yml:58:14:62:48 | # VULNERABLE\nCURRENT_VERSION=$(cat gradle.properties \| sed -n '/^version=/ { s/^version=//;p }')\necho "$CURRENT_VERSION"\necho "::set-output name=OUTPUT::SAFE"\n | semmle.label | # VULNERABLE\nCURRENT_VERSION=$(cat gradle.properties \| sed -n '/^version=/ { s/^version=//;p }')\necho "$CURRENT_VERSION"\necho "::set-output name=OUTPUT::SAFE"\n | +| .github/workflows/output3.yml:10:20:10:51 | github.event.comment.body | semmle.label | github.event.comment.body | subpaths #select -| .github/workflows/output1.yml:10:14:13:50 | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$BODY" >> $GITHUB_OUTPUT\n | .github/workflows/output1.yml:9:18:9:49 | github.event.comment.body | .github/workflows/output1.yml:10:14:13:50 | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$BODY" >> $GITHUB_OUTPUT\n | Potential clobbering of a step output in $@. | .github/workflows/output1.yml:10:14:13:50 | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$BODY" >> $GITHUB_OUTPUT\n | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$BODY" >> $GITHUB_OUTPUT\n | -| .github/workflows/output1.yml:36:14:39:58 | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$(> $GITHUB_OUTPUT\n | .github/workflows/output1.yml:30:9:35:6 | Uses Step | .github/workflows/output1.yml:36:14:39:58 | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$(> $GITHUB_OUTPUT\n | Potential clobbering of a step output in $@. | .github/workflows/output1.yml:36:14:39:58 | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$(> $GITHUB_OUTPUT\n | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$(> $GITHUB_OUTPUT\n | -| .github/workflows/output2.yml:10:14:13:48 | # VULNERABLE\necho $BODY\necho "::set-output name=OUTPUT::SAFE"\n | .github/workflows/output2.yml:9:18:9:49 | github.event.comment.body | .github/workflows/output2.yml:10:14:13:48 | # VULNERABLE\necho $BODY\necho "::set-output name=OUTPUT::SAFE"\n | Potential clobbering of a step output in $@. | .github/workflows/output2.yml:10:14:13:48 | # VULNERABLE\necho $BODY\necho "::set-output name=OUTPUT::SAFE"\n | # VULNERABLE\necho $BODY\necho "::set-output name=OUTPUT::SAFE"\n | -| .github/workflows/output2.yml:17:14:20:21 | # VULNERABLE\necho "::set-output name=OUTPUT::SAFE"\necho $BODY\n | .github/workflows/output2.yml:16:18:16:49 | github.event.comment.body | .github/workflows/output2.yml:17:14:20:21 | # VULNERABLE\necho "::set-output name=OUTPUT::SAFE"\necho $BODY\n | Potential clobbering of a step output in $@. | .github/workflows/output2.yml:17:14:20:21 | # VULNERABLE\necho "::set-output name=OUTPUT::SAFE"\necho $BODY\n | # VULNERABLE\necho "::set-output name=OUTPUT::SAFE"\necho $BODY\n | -| .github/workflows/output2.yml:42:14:46:48 | # VULNERABLE\nPR="$(> $GITHUB_OUTPUT\necho "OUTPUT_2=$BODY" >> $GITHUB_OUTPUT\n | .github/workflows/output1.yml:9:18:9:49 | github.event.comment.body | .github/workflows/output1.yml:10:14:13:50 | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$BODY" >> $GITHUB_OUTPUT\n | Attacker-controlled data may inject or overwrite step outputs written through `$GITHUB_OUTPUT` in $@. | .github/workflows/output1.yml:10:14:13:50 | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$BODY" >> $GITHUB_OUTPUT\n | this step | +| .github/workflows/output1.yml:36:14:39:58 | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$(> $GITHUB_OUTPUT\n | .github/workflows/output1.yml:30:9:35:6 | Uses Step | .github/workflows/output1.yml:36:14:39:58 | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$(> $GITHUB_OUTPUT\n | Attacker-controlled data may inject or overwrite step outputs written through `$GITHUB_OUTPUT` in $@. | .github/workflows/output1.yml:36:14:39:58 | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$(> $GITHUB_OUTPUT\n | this step | +| .github/workflows/output2.yml:10:14:13:48 | # VULNERABLE\necho $BODY\necho "::set-output name=OUTPUT::SAFE"\n | .github/workflows/output2.yml:9:18:9:49 | github.event.comment.body | .github/workflows/output2.yml:10:14:13:48 | # VULNERABLE\necho $BODY\necho "::set-output name=OUTPUT::SAFE"\n | Attacker-controlled data printed to standard output may forge a `set-output` workflow command and overwrite step outputs in $@. | .github/workflows/output2.yml:10:14:13:48 | # VULNERABLE\necho $BODY\necho "::set-output name=OUTPUT::SAFE"\n | this step | +| .github/workflows/output2.yml:17:14:20:21 | # VULNERABLE\necho "::set-output name=OUTPUT::SAFE"\necho $BODY\n | .github/workflows/output2.yml:16:18:16:49 | github.event.comment.body | .github/workflows/output2.yml:17:14:20:21 | # VULNERABLE\necho "::set-output name=OUTPUT::SAFE"\necho $BODY\n | Attacker-controlled data printed to standard output may forge a `set-output` workflow command and overwrite step outputs in $@. | .github/workflows/output2.yml:17:14:20:21 | # VULNERABLE\necho "::set-output name=OUTPUT::SAFE"\necho $BODY\n | this step | +| .github/workflows/output2.yml:42:14:46:48 | # VULNERABLE\nPR="$( Date: Sun, 19 Jul 2026 20:37:35 +0000 Subject: [PATCH 119/188] Reduce false positives in the clobbering query --- .../security/OutputClobberingQuery.qll | 18 ++++++++++++- ...26-07-29-output-clobbering-jq-precision.md | 4 +++ .../CWE-074/.github/workflows/output2.yml | 26 +++++++++++++++++++ .../CWE-074/OutputClobberingHigh.expected | 12 +++++++++ 4 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 actions/ql/src/change-notes/2026-07-29-output-clobbering-jq-precision.md diff --git a/actions/ql/lib/codeql/actions/security/OutputClobberingQuery.qll b/actions/ql/lib/codeql/actions/security/OutputClobberingQuery.qll index 22b4879df126..9e0122a05391 100644 --- a/actions/ql/lib/codeql/actions/security/OutputClobberingQuery.qll +++ b/actions/ql/lib/codeql/actions/security/OutputClobberingQuery.qll @@ -111,6 +111,21 @@ class WorkflowCommandClobberingFromEnvVarSink extends OutputClobberingSink { } } +bindingset[command] +private predicate jqUsesRawOutput(string command) { + exists( + command + .regexpFind("(^|\\s)(--raw-output0?|--join-output)(\\s|$)|(^|\\s)-[A-Za-z0-9]*[rj][A-Za-z0-9]*(\\s|$)", + _, _) + ) +} + +bindingset[command] +private predicate jqProducesJsonEncodedOutput(string command) { + command.regexpMatch("jq\\s+((\\.[^\\s]*)|('[^']*')|(\"[^\"]*\"))(\\s+.*)?") and + not jqUsesRawOutput(command) +} + /** * - id: clob1 * run: | @@ -165,7 +180,8 @@ class WorkflowCommandClobberingFromFileReadSink extends OutputClobberingSink { // - run: cat pr-id.txt clobbering_stmt.indexOf(clobbering_cmd) = 0 ) - ) + ) and + not jqProducesJsonEncodedOutput(clobbering_cmd) ) } } diff --git a/actions/ql/src/change-notes/2026-07-29-output-clobbering-jq-precision.md b/actions/ql/src/change-notes/2026-07-29-output-clobbering-jq-precision.md new file mode 100644 index 000000000000..e8cddde06823 --- /dev/null +++ b/actions/ql/src/change-notes/2026-07-29-output-clobbering-jq-precision.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* The `actions/output-clobbering/high` query no longer reports JSON-encoded `jq` output unless raw output is enabled. diff --git a/actions/ql/test/query-tests/Security/CWE-074/.github/workflows/output2.yml b/actions/ql/test/query-tests/Security/CWE-074/.github/workflows/output2.yml index 614de61b0cb7..42d411460abe 100644 --- a/actions/ql/test/query-tests/Security/CWE-074/.github/workflows/output2.yml +++ b/actions/ql/test/query-tests/Security/CWE-074/.github/workflows/output2.yml @@ -60,3 +60,29 @@ jobs: CURRENT_VERSION=$(cat gradle.properties | sed -n '/^version=/ { s/^version=//;p }') echo "$CURRENT_VERSION" echo "::set-output name=OUTPUT::SAFE" + - id: clob5 + run: | + # NOT VULNERABLE: jq emits JSON-encoded strings by default + jq '.value' pr-number.json + - id: clob6 + run: | + # VULNERABLE: raw output can begin with a workflow command + jq -r '.value' pr-number.json + - id: clob7 + run: | + # VULNERABLE: long raw-output option after the filter + jq '.value' --raw-output pr-number.json + - id: clob8 + run: | + # VULNERABLE: combined short options include raw output + jq -Mcr '.value' pr-number.json + - id: clob9 + run: | + # NOT VULNERABLE: assigned jq output remains JSON encoded + VALUE=$(jq '.value' pr-number.json) + echo "$VALUE" + - id: clob10 + run: | + # VULNERABLE: assigned raw output can begin with a workflow command + VALUE=$(jq --raw-output '.value' pr-number.json) + echo "$VALUE" diff --git a/actions/ql/test/query-tests/Security/CWE-074/OutputClobberingHigh.expected b/actions/ql/test/query-tests/Security/CWE-074/OutputClobberingHigh.expected index af792f1ab65e..9eb4cb075cac 100644 --- a/actions/ql/test/query-tests/Security/CWE-074/OutputClobberingHigh.expected +++ b/actions/ql/test/query-tests/Security/CWE-074/OutputClobberingHigh.expected @@ -7,6 +7,10 @@ edges | .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:48:14:51:48 | # VULNERABLE\ncat pr-number\necho "::set-output name=OUTPUT::SAFE"\n | provenance | Config | | .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:53:14:56:19 | # VULNERABLE\necho "::set-output name=OUTPUT::SAFE"\nls *.txt\n | provenance | Config | | .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:58:14:62:48 | # VULNERABLE\nCURRENT_VERSION=$(cat gradle.properties \| sed -n '/^version=/ { s/^version=//;p }')\necho "$CURRENT_VERSION"\necho "::set-output name=OUTPUT::SAFE"\n | provenance | Config | +| .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:68:14:70:40 | # VULNERABLE: raw output can begin with a workflow command\njq -r '.value' pr-number.json\n | provenance | Config | +| .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:72:14:74:50 | # VULNERABLE: long raw-output option after the filter\njq '.value' --raw-output pr-number.json\n | provenance | Config | +| .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:76:14:78:42 | # VULNERABLE: combined short options include raw output\njq -Mcr '.value' pr-number.json\n | provenance | Config | +| .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:85:14:88:24 | # VULNERABLE: assigned raw output can begin with a workflow command\nVALUE=$(jq --raw-output '.value' pr-number.json)\necho "$VALUE"\n | provenance | Config | nodes | .github/workflows/output1.yml:9:18:9:49 | github.event.comment.body | semmle.label | github.event.comment.body | | .github/workflows/output1.yml:10:14:13:50 | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$BODY" >> $GITHUB_OUTPUT\n | semmle.label | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$BODY" >> $GITHUB_OUTPUT\n | @@ -21,6 +25,10 @@ nodes | .github/workflows/output2.yml:48:14:51:48 | # VULNERABLE\ncat pr-number\necho "::set-output name=OUTPUT::SAFE"\n | semmle.label | # VULNERABLE\ncat pr-number\necho "::set-output name=OUTPUT::SAFE"\n | | .github/workflows/output2.yml:53:14:56:19 | # VULNERABLE\necho "::set-output name=OUTPUT::SAFE"\nls *.txt\n | semmle.label | # VULNERABLE\necho "::set-output name=OUTPUT::SAFE"\nls *.txt\n | | .github/workflows/output2.yml:58:14:62:48 | # VULNERABLE\nCURRENT_VERSION=$(cat gradle.properties \| sed -n '/^version=/ { s/^version=//;p }')\necho "$CURRENT_VERSION"\necho "::set-output name=OUTPUT::SAFE"\n | semmle.label | # VULNERABLE\nCURRENT_VERSION=$(cat gradle.properties \| sed -n '/^version=/ { s/^version=//;p }')\necho "$CURRENT_VERSION"\necho "::set-output name=OUTPUT::SAFE"\n | +| .github/workflows/output2.yml:68:14:70:40 | # VULNERABLE: raw output can begin with a workflow command\njq -r '.value' pr-number.json\n | semmle.label | # VULNERABLE: raw output can begin with a workflow command\njq -r '.value' pr-number.json\n | +| .github/workflows/output2.yml:72:14:74:50 | # VULNERABLE: long raw-output option after the filter\njq '.value' --raw-output pr-number.json\n | semmle.label | # VULNERABLE: long raw-output option after the filter\njq '.value' --raw-output pr-number.json\n | +| .github/workflows/output2.yml:76:14:78:42 | # VULNERABLE: combined short options include raw output\njq -Mcr '.value' pr-number.json\n | semmle.label | # VULNERABLE: combined short options include raw output\njq -Mcr '.value' pr-number.json\n | +| .github/workflows/output2.yml:85:14:88:24 | # VULNERABLE: assigned raw output can begin with a workflow command\nVALUE=$(jq --raw-output '.value' pr-number.json)\necho "$VALUE"\n | semmle.label | # VULNERABLE: assigned raw output can begin with a workflow command\nVALUE=$(jq --raw-output '.value' pr-number.json)\necho "$VALUE"\n | subpaths #select | .github/workflows/output1.yml:10:14:13:50 | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$BODY" >> $GITHUB_OUTPUT\n | .github/workflows/output1.yml:9:18:9:49 | github.event.comment.body | .github/workflows/output1.yml:10:14:13:50 | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$BODY" >> $GITHUB_OUTPUT\n | Potential clobbering of a step output in $@. | .github/workflows/output1.yml:10:14:13:50 | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$BODY" >> $GITHUB_OUTPUT\n | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$BODY" >> $GITHUB_OUTPUT\n | @@ -31,3 +39,7 @@ subpaths | .github/workflows/output2.yml:48:14:51:48 | # VULNERABLE\ncat pr-number\necho "::set-output name=OUTPUT::SAFE"\n | .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:48:14:51:48 | # VULNERABLE\ncat pr-number\necho "::set-output name=OUTPUT::SAFE"\n | Potential clobbering of a step output in $@. | .github/workflows/output2.yml:48:14:51:48 | # VULNERABLE\ncat pr-number\necho "::set-output name=OUTPUT::SAFE"\n | # VULNERABLE\ncat pr-number\necho "::set-output name=OUTPUT::SAFE"\n | | .github/workflows/output2.yml:53:14:56:19 | # VULNERABLE\necho "::set-output name=OUTPUT::SAFE"\nls *.txt\n | .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:53:14:56:19 | # VULNERABLE\necho "::set-output name=OUTPUT::SAFE"\nls *.txt\n | Potential clobbering of a step output in $@. | .github/workflows/output2.yml:53:14:56:19 | # VULNERABLE\necho "::set-output name=OUTPUT::SAFE"\nls *.txt\n | # VULNERABLE\necho "::set-output name=OUTPUT::SAFE"\nls *.txt\n | | .github/workflows/output2.yml:58:14:62:48 | # VULNERABLE\nCURRENT_VERSION=$(cat gradle.properties \| sed -n '/^version=/ { s/^version=//;p }')\necho "$CURRENT_VERSION"\necho "::set-output name=OUTPUT::SAFE"\n | .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:58:14:62:48 | # VULNERABLE\nCURRENT_VERSION=$(cat gradle.properties \| sed -n '/^version=/ { s/^version=//;p }')\necho "$CURRENT_VERSION"\necho "::set-output name=OUTPUT::SAFE"\n | Potential clobbering of a step output in $@. | .github/workflows/output2.yml:58:14:62:48 | # VULNERABLE\nCURRENT_VERSION=$(cat gradle.properties \| sed -n '/^version=/ { s/^version=//;p }')\necho "$CURRENT_VERSION"\necho "::set-output name=OUTPUT::SAFE"\n | # VULNERABLE\nCURRENT_VERSION=$(cat gradle.properties \| sed -n '/^version=/ { s/^version=//;p }')\necho "$CURRENT_VERSION"\necho "::set-output name=OUTPUT::SAFE"\n | +| .github/workflows/output2.yml:68:14:70:40 | # VULNERABLE: raw output can begin with a workflow command\njq -r '.value' pr-number.json\n | .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:68:14:70:40 | # VULNERABLE: raw output can begin with a workflow command\njq -r '.value' pr-number.json\n | Potential clobbering of a step output in $@. | .github/workflows/output2.yml:68:14:70:40 | # VULNERABLE: raw output can begin with a workflow command\njq -r '.value' pr-number.json\n | # VULNERABLE: raw output can begin with a workflow command\njq -r '.value' pr-number.json\n | +| .github/workflows/output2.yml:72:14:74:50 | # VULNERABLE: long raw-output option after the filter\njq '.value' --raw-output pr-number.json\n | .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:72:14:74:50 | # VULNERABLE: long raw-output option after the filter\njq '.value' --raw-output pr-number.json\n | Potential clobbering of a step output in $@. | .github/workflows/output2.yml:72:14:74:50 | # VULNERABLE: long raw-output option after the filter\njq '.value' --raw-output pr-number.json\n | # VULNERABLE: long raw-output option after the filter\njq '.value' --raw-output pr-number.json\n | +| .github/workflows/output2.yml:76:14:78:42 | # VULNERABLE: combined short options include raw output\njq -Mcr '.value' pr-number.json\n | .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:76:14:78:42 | # VULNERABLE: combined short options include raw output\njq -Mcr '.value' pr-number.json\n | Potential clobbering of a step output in $@. | .github/workflows/output2.yml:76:14:78:42 | # VULNERABLE: combined short options include raw output\njq -Mcr '.value' pr-number.json\n | # VULNERABLE: combined short options include raw output\njq -Mcr '.value' pr-number.json\n | +| .github/workflows/output2.yml:85:14:88:24 | # VULNERABLE: assigned raw output can begin with a workflow command\nVALUE=$(jq --raw-output '.value' pr-number.json)\necho "$VALUE"\n | .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:85:14:88:24 | # VULNERABLE: assigned raw output can begin with a workflow command\nVALUE=$(jq --raw-output '.value' pr-number.json)\necho "$VALUE"\n | Potential clobbering of a step output in $@. | .github/workflows/output2.yml:85:14:88:24 | # VULNERABLE: assigned raw output can begin with a workflow command\nVALUE=$(jq --raw-output '.value' pr-number.json)\necho "$VALUE"\n | # VULNERABLE: assigned raw output can begin with a workflow command\nVALUE=$(jq --raw-output '.value' pr-number.json)\necho "$VALUE"\n | From 5b96fcc9cb436277ffedf416a84b32d5e68c4d46 Mon Sep 17 00:00:00 2001 From: JarLob Date: Wed, 29 Jul 2026 22:38:46 +0300 Subject: [PATCH 120/188] Restrict jq output-clobbering suppression --- .../security/OutputClobberingQuery.qll | 40 ++++++++++++++----- ...26-07-29-output-clobbering-jq-precision.md | 2 +- .../CWE-074/.github/workflows/output2.yml | 28 +++++++++++++ .../CWE-074/OutputClobberingHigh.expected | 15 +++++++ 4 files changed, 75 insertions(+), 10 deletions(-) diff --git a/actions/ql/lib/codeql/actions/security/OutputClobberingQuery.qll b/actions/ql/lib/codeql/actions/security/OutputClobberingQuery.qll index 9e0122a05391..7d560f8b6242 100644 --- a/actions/ql/lib/codeql/actions/security/OutputClobberingQuery.qll +++ b/actions/ql/lib/codeql/actions/security/OutputClobberingQuery.qll @@ -111,19 +111,41 @@ class WorkflowCommandClobberingFromEnvVarSink extends OutputClobberingSink { } } -bindingset[command] -private predicate jqUsesRawOutput(string command) { - exists( - command - .regexpFind("(^|\\s)(--raw-output0?|--join-output)(\\s|$)|(^|\\s)-[A-Za-z0-9]*[rj][A-Za-z0-9]*(\\s|$)", - _, _) - ) +private string jqSafeOptionRegexp() { + result = "-[acCMeRnSs]+" + or + result = + "--(ascii-output|color-output|compact-output|exit-status|monochrome-output|null-input|" + + "raw-input|slurp|sort-keys|unbuffered)" +} + +private string jqSimpleFilterRegexp() { + result = "\\." + or + result = "\\.[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z_][A-Za-z0-9_]*|\\[[0-9]+\\])*" +} + +private string jqSimpleFilterArgumentRegexp() { + result = jqSimpleFilterRegexp() + or + result = "'" + jqSimpleFilterRegexp() + "'" + or + result = "\"" + jqSimpleFilterRegexp() + "\"" +} + +private string jqLiteralInputRegexp() { + result = "[A-Za-z0-9_./][A-Za-z0-9_./-]*" + or + result = "\\$GITHUB_EVENT_PATH" + or + result = "\\$\\{GITHUB_EVENT_PATH\\}" } bindingset[command] private predicate jqProducesJsonEncodedOutput(string command) { - command.regexpMatch("jq\\s+((\\.[^\\s]*)|('[^']*')|(\"[^\"]*\"))(\\s+.*)?") and - not jqUsesRawOutput(command) + command + .regexpMatch("jq(\\s+" + jqSafeOptionRegexp() + ")*\\s+" + jqSimpleFilterArgumentRegexp() + + "(\\s+" + jqSafeOptionRegexp() + ")*(\\s+" + jqLiteralInputRegexp() + ")*") } /** diff --git a/actions/ql/src/change-notes/2026-07-29-output-clobbering-jq-precision.md b/actions/ql/src/change-notes/2026-07-29-output-clobbering-jq-precision.md index e8cddde06823..9fba403a5715 100644 --- a/actions/ql/src/change-notes/2026-07-29-output-clobbering-jq-precision.md +++ b/actions/ql/src/change-notes/2026-07-29-output-clobbering-jq-precision.md @@ -1,4 +1,4 @@ --- category: minorAnalysis --- -* The `actions/output-clobbering/high` query no longer reports JSON-encoded `jq` output unless raw output is enabled. +* The `actions/output-clobbering/high` query no longer reports simple `jq` path filters when their output remains JSON-encoded. Raw-output modes, complex filters, and unrecognized options remain reportable. diff --git a/actions/ql/test/query-tests/Security/CWE-074/.github/workflows/output2.yml b/actions/ql/test/query-tests/Security/CWE-074/.github/workflows/output2.yml index 42d411460abe..896f6c820152 100644 --- a/actions/ql/test/query-tests/Security/CWE-074/.github/workflows/output2.yml +++ b/actions/ql/test/query-tests/Security/CWE-074/.github/workflows/output2.yml @@ -86,3 +86,31 @@ jobs: # VULNERABLE: assigned raw output can begin with a workflow command VALUE=$(jq --raw-output '.value' pr-number.json) echo "$VALUE" + - id: clob11 + run: | + # NOT VULNERABLE: combined options preserve JSON encoding + jq -Mc '.value' pr-number.json + - id: clob12 + run: | + # NOT VULNERABLE: safe long options may follow a simple filter + jq '.value' --compact-output pr-number.json + - id: clob13 + run: | + # VULNERABLE: join output emits strings without JSON encoding + jq -j '.value' pr-number.json + - id: clob14 + run: | + # VULNERABLE: the long join-output option also emits raw strings + jq '.value' --join-output pr-number.json + - id: clob15 + run: | + # VULNERABLE: raw-output0 emits strings without JSON encoding + jq '.value' --raw-output0 pr-number.json + - id: clob16 + run: | + # VULNERABLE: stderr emits its input without JSON encoding + jq '.value | stderr' pr-number.json + - id: clob17 + run: | + # VULNERABLE: halt_error emits its input without JSON encoding + jq '.value | halt_error(1)' pr-number.json diff --git a/actions/ql/test/query-tests/Security/CWE-074/OutputClobberingHigh.expected b/actions/ql/test/query-tests/Security/CWE-074/OutputClobberingHigh.expected index 9eb4cb075cac..58b0df462e48 100644 --- a/actions/ql/test/query-tests/Security/CWE-074/OutputClobberingHigh.expected +++ b/actions/ql/test/query-tests/Security/CWE-074/OutputClobberingHigh.expected @@ -11,6 +11,11 @@ edges | .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:72:14:74:50 | # VULNERABLE: long raw-output option after the filter\njq '.value' --raw-output pr-number.json\n | provenance | Config | | .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:76:14:78:42 | # VULNERABLE: combined short options include raw output\njq -Mcr '.value' pr-number.json\n | provenance | Config | | .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:85:14:88:24 | # VULNERABLE: assigned raw output can begin with a workflow command\nVALUE=$(jq --raw-output '.value' pr-number.json)\necho "$VALUE"\n | provenance | Config | +| .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:98:14:100:40 | # VULNERABLE: join output emits strings without JSON encoding\njq -j '.value' pr-number.json\n | provenance | Config | +| .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:102:14:104:51 | # VULNERABLE: the long join-output option also emits raw strings\njq '.value' --join-output pr-number.json\n | provenance | Config | +| .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:106:14:108:51 | # VULNERABLE: raw-output0 emits strings without JSON encoding\njq '.value' --raw-output0 pr-number.json\n | provenance | Config | +| .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:110:14:112:46 | # VULNERABLE: stderr emits its input without JSON encoding\njq '.value \| stderr' pr-number.json\n | provenance | Config | +| .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:114:14:116:53 | # VULNERABLE: halt_error emits its input without JSON encoding\njq '.value \| halt_error(1)' pr-number.json\n | provenance | Config | nodes | .github/workflows/output1.yml:9:18:9:49 | github.event.comment.body | semmle.label | github.event.comment.body | | .github/workflows/output1.yml:10:14:13:50 | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$BODY" >> $GITHUB_OUTPUT\n | semmle.label | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$BODY" >> $GITHUB_OUTPUT\n | @@ -29,6 +34,11 @@ nodes | .github/workflows/output2.yml:72:14:74:50 | # VULNERABLE: long raw-output option after the filter\njq '.value' --raw-output pr-number.json\n | semmle.label | # VULNERABLE: long raw-output option after the filter\njq '.value' --raw-output pr-number.json\n | | .github/workflows/output2.yml:76:14:78:42 | # VULNERABLE: combined short options include raw output\njq -Mcr '.value' pr-number.json\n | semmle.label | # VULNERABLE: combined short options include raw output\njq -Mcr '.value' pr-number.json\n | | .github/workflows/output2.yml:85:14:88:24 | # VULNERABLE: assigned raw output can begin with a workflow command\nVALUE=$(jq --raw-output '.value' pr-number.json)\necho "$VALUE"\n | semmle.label | # VULNERABLE: assigned raw output can begin with a workflow command\nVALUE=$(jq --raw-output '.value' pr-number.json)\necho "$VALUE"\n | +| .github/workflows/output2.yml:98:14:100:40 | # VULNERABLE: join output emits strings without JSON encoding\njq -j '.value' pr-number.json\n | semmle.label | # VULNERABLE: join output emits strings without JSON encoding\njq -j '.value' pr-number.json\n | +| .github/workflows/output2.yml:102:14:104:51 | # VULNERABLE: the long join-output option also emits raw strings\njq '.value' --join-output pr-number.json\n | semmle.label | # VULNERABLE: the long join-output option also emits raw strings\njq '.value' --join-output pr-number.json\n | +| .github/workflows/output2.yml:106:14:108:51 | # VULNERABLE: raw-output0 emits strings without JSON encoding\njq '.value' --raw-output0 pr-number.json\n | semmle.label | # VULNERABLE: raw-output0 emits strings without JSON encoding\njq '.value' --raw-output0 pr-number.json\n | +| .github/workflows/output2.yml:110:14:112:46 | # VULNERABLE: stderr emits its input without JSON encoding\njq '.value \| stderr' pr-number.json\n | semmle.label | # VULNERABLE: stderr emits its input without JSON encoding\njq '.value \| stderr' pr-number.json\n | +| .github/workflows/output2.yml:114:14:116:53 | # VULNERABLE: halt_error emits its input without JSON encoding\njq '.value \| halt_error(1)' pr-number.json\n | semmle.label | # VULNERABLE: halt_error emits its input without JSON encoding\njq '.value \| halt_error(1)' pr-number.json\n | subpaths #select | .github/workflows/output1.yml:10:14:13:50 | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$BODY" >> $GITHUB_OUTPUT\n | .github/workflows/output1.yml:9:18:9:49 | github.event.comment.body | .github/workflows/output1.yml:10:14:13:50 | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$BODY" >> $GITHUB_OUTPUT\n | Potential clobbering of a step output in $@. | .github/workflows/output1.yml:10:14:13:50 | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$BODY" >> $GITHUB_OUTPUT\n | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$BODY" >> $GITHUB_OUTPUT\n | @@ -43,3 +53,8 @@ subpaths | .github/workflows/output2.yml:72:14:74:50 | # VULNERABLE: long raw-output option after the filter\njq '.value' --raw-output pr-number.json\n | .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:72:14:74:50 | # VULNERABLE: long raw-output option after the filter\njq '.value' --raw-output pr-number.json\n | Potential clobbering of a step output in $@. | .github/workflows/output2.yml:72:14:74:50 | # VULNERABLE: long raw-output option after the filter\njq '.value' --raw-output pr-number.json\n | # VULNERABLE: long raw-output option after the filter\njq '.value' --raw-output pr-number.json\n | | .github/workflows/output2.yml:76:14:78:42 | # VULNERABLE: combined short options include raw output\njq -Mcr '.value' pr-number.json\n | .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:76:14:78:42 | # VULNERABLE: combined short options include raw output\njq -Mcr '.value' pr-number.json\n | Potential clobbering of a step output in $@. | .github/workflows/output2.yml:76:14:78:42 | # VULNERABLE: combined short options include raw output\njq -Mcr '.value' pr-number.json\n | # VULNERABLE: combined short options include raw output\njq -Mcr '.value' pr-number.json\n | | .github/workflows/output2.yml:85:14:88:24 | # VULNERABLE: assigned raw output can begin with a workflow command\nVALUE=$(jq --raw-output '.value' pr-number.json)\necho "$VALUE"\n | .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:85:14:88:24 | # VULNERABLE: assigned raw output can begin with a workflow command\nVALUE=$(jq --raw-output '.value' pr-number.json)\necho "$VALUE"\n | Potential clobbering of a step output in $@. | .github/workflows/output2.yml:85:14:88:24 | # VULNERABLE: assigned raw output can begin with a workflow command\nVALUE=$(jq --raw-output '.value' pr-number.json)\necho "$VALUE"\n | # VULNERABLE: assigned raw output can begin with a workflow command\nVALUE=$(jq --raw-output '.value' pr-number.json)\necho "$VALUE"\n | +| .github/workflows/output2.yml:98:14:100:40 | # VULNERABLE: join output emits strings without JSON encoding\njq -j '.value' pr-number.json\n | .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:98:14:100:40 | # VULNERABLE: join output emits strings without JSON encoding\njq -j '.value' pr-number.json\n | Potential clobbering of a step output in $@. | .github/workflows/output2.yml:98:14:100:40 | # VULNERABLE: join output emits strings without JSON encoding\njq -j '.value' pr-number.json\n | # VULNERABLE: join output emits strings without JSON encoding\njq -j '.value' pr-number.json\n | +| .github/workflows/output2.yml:102:14:104:51 | # VULNERABLE: the long join-output option also emits raw strings\njq '.value' --join-output pr-number.json\n | .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:102:14:104:51 | # VULNERABLE: the long join-output option also emits raw strings\njq '.value' --join-output pr-number.json\n | Potential clobbering of a step output in $@. | .github/workflows/output2.yml:102:14:104:51 | # VULNERABLE: the long join-output option also emits raw strings\njq '.value' --join-output pr-number.json\n | # VULNERABLE: the long join-output option also emits raw strings\njq '.value' --join-output pr-number.json\n | +| .github/workflows/output2.yml:106:14:108:51 | # VULNERABLE: raw-output0 emits strings without JSON encoding\njq '.value' --raw-output0 pr-number.json\n | .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:106:14:108:51 | # VULNERABLE: raw-output0 emits strings without JSON encoding\njq '.value' --raw-output0 pr-number.json\n | Potential clobbering of a step output in $@. | .github/workflows/output2.yml:106:14:108:51 | # VULNERABLE: raw-output0 emits strings without JSON encoding\njq '.value' --raw-output0 pr-number.json\n | # VULNERABLE: raw-output0 emits strings without JSON encoding\njq '.value' --raw-output0 pr-number.json\n | +| .github/workflows/output2.yml:110:14:112:46 | # VULNERABLE: stderr emits its input without JSON encoding\njq '.value \| stderr' pr-number.json\n | .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:110:14:112:46 | # VULNERABLE: stderr emits its input without JSON encoding\njq '.value \| stderr' pr-number.json\n | Potential clobbering of a step output in $@. | .github/workflows/output2.yml:110:14:112:46 | # VULNERABLE: stderr emits its input without JSON encoding\njq '.value \| stderr' pr-number.json\n | # VULNERABLE: stderr emits its input without JSON encoding\njq '.value \| stderr' pr-number.json\n | +| .github/workflows/output2.yml:114:14:116:53 | # VULNERABLE: halt_error emits its input without JSON encoding\njq '.value \| halt_error(1)' pr-number.json\n | .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:114:14:116:53 | # VULNERABLE: halt_error emits its input without JSON encoding\njq '.value \| halt_error(1)' pr-number.json\n | Potential clobbering of a step output in $@. | .github/workflows/output2.yml:114:14:116:53 | # VULNERABLE: halt_error emits its input without JSON encoding\njq '.value \| halt_error(1)' pr-number.json\n | # VULNERABLE: halt_error emits its input without JSON encoding\njq '.value \| halt_error(1)' pr-number.json\n | From 761de929ca15540ff4e9c200a0e94a273904f5ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20Loba=C4=8Devski?= Date: Sun, 19 Jul 2026 07:01:24 +0000 Subject: [PATCH 121/188] Account cache poisoning queries for read-only access on low-trust triggers --- .../actions/security/CachePoisoningQuery.qll | 31 ++++++++- .../actions/security/CodeInjectionQuery.qll | 14 +--- .../CWE-349/CachePoisoningViaCodeInjection.md | 31 +++++---- .../CWE-349/CachePoisoningViaCodeInjection.ql | 1 + .../CWE-349/CachePoisoningViaDirectCache.md | 66 ++++++------------- .../CWE-349/CachePoisoningViaDirectCache.ql | 12 +--- .../CachePoisoningViaPoisonableStep.md | 28 +++++--- .../CachePoisoningViaPoisonableStep.ql | 12 +--- ...26-07-18-read-only-default-branch-cache.md | 4 ++ .../workflows/cache_write_capable_push.yml | 10 +++ .../cache_write_capable_workflow_dispatch.yml | 17 +++++ .../CachePoisoningViaCodeInjection.expected | 3 +- .../CachePoisoningViaDirectCache.expected | 9 +-- .../CachePoisoningViaPoisonableStep.expected | 10 +-- 14 files changed, 131 insertions(+), 117 deletions(-) create mode 100644 actions/ql/src/change-notes/2026-07-18-read-only-default-branch-cache.md create mode 100644 actions/ql/test/query-tests/Security/CWE-349/.github/workflows/cache_write_capable_push.yml create mode 100644 actions/ql/test/query-tests/Security/CWE-349/.github/workflows/cache_write_capable_workflow_dispatch.yml diff --git a/actions/ql/lib/codeql/actions/security/CachePoisoningQuery.qll b/actions/ql/lib/codeql/actions/security/CachePoisoningQuery.qll index e5c5a3655101..52ceb9a94e0c 100644 --- a/actions/ql/lib/codeql/actions/security/CachePoisoningQuery.qll +++ b/actions/ql/lib/codeql/actions/security/CachePoisoningQuery.qll @@ -5,8 +5,8 @@ string defaultBranchTriggerEvent() { [ "check_run", "check_suite", "delete", "discussion", "discussion_comment", "fork", "gollum", "issue_comment", "issues", "label", "milestone", "project", "project_card", "project_column", - "public", "pull_request_comment", "pull_request_target", "repository_dispatch", "schedule", - "watch", "workflow_run" + "public", "pull_request_comment", "pull_request_target", "repository_dispatch", + "registry_package", "page_build", "schedule", "watch", "workflow_dispatch", "workflow_run" ] } @@ -42,6 +42,33 @@ predicate runsOnDefaultBranch(Event e) { ) } +private string defaultBranchCacheWriteEvent() { + result = + [ + "push", "workflow_dispatch", "repository_dispatch", "delete", "registry_package", + "page_build", "schedule" + ] +} + +private predicate eventHasDefaultBranchCacheWriteAccess(Event event) { + runsOnDefaultBranch(event) and event.getName() = defaultBranchCacheWriteEvent() +} + +/** Holds if `job` can write to the cache scope of the default branch for `event`. */ +predicate hasDefaultBranchCacheWriteAccess(LocalJob job, Event event) { + job.getATriggerEvent() = event and + ( + eventHasDefaultBranchCacheWriteAccess(event) + or + // the workflow caller runs in the context of the default branch + event.getName() = "workflow_call" and + exists(ExternalJob caller | + job.getEnclosingWorkflow().(ReusableWorkflow).getACaller() = caller and + eventHasDefaultBranchCacheWriteAccess(caller.getATriggerEvent()) + ) + ) +} + abstract class CacheWritingStep extends Step { abstract string getPath(); } diff --git a/actions/ql/lib/codeql/actions/security/CodeInjectionQuery.qll b/actions/ql/lib/codeql/actions/security/CodeInjectionQuery.qll index 3d5b8852b850..2afa68244091 100644 --- a/actions/ql/lib/codeql/actions/security/CodeInjectionQuery.qll +++ b/actions/ql/lib/codeql/actions/security/CodeInjectionQuery.qll @@ -29,22 +29,10 @@ Event getRelevantCachePoisoningEventForSink(DataFlow::Node sink) { exists(LocalJob job | job = sink.asExpr().getEnclosingJob() and job.getATriggerEvent() = result and - // job can be triggered by an external user - result.isExternallyTriggerable() and // excluding privileged workflows since they can be exploited in easier circumstances // which is covered by `actions/code-injection/critical` not job.isPrivilegedExternallyTriggerable(result) and - ( - // the workflow runs in the context of the default branch - runsOnDefaultBranch(result) - or - // the workflow caller runs in the context of the default branch - result.getName() = "workflow_call" and - exists(ExternalJob caller | - caller.getCallee() = job.getLocation().getFile().getRelativePath() and - runsOnDefaultBranch(caller.getATriggerEvent()) - ) - ) + hasDefaultBranchCacheWriteAccess(job, result) ) } diff --git a/actions/ql/src/Security/CWE-349/CachePoisoningViaCodeInjection.md b/actions/ql/src/Security/CWE-349/CachePoisoningViaCodeInjection.md index f75028a27e61..0ef3199e0fd9 100644 --- a/actions/ql/src/Security/CWE-349/CachePoisoningViaCodeInjection.md +++ b/actions/ql/src/Security/CWE-349/CachePoisoningViaCodeInjection.md @@ -34,48 +34,55 @@ Due to the above design, if something is cached in the context of the default br ## Example +GitHub gives workflows triggered by low-trust events, such as `issue_comment`, +`pull_request_target`, and `workflow_run`, read-only access to the default branch cache scope. +This query therefore reports only workflows whose trigger can write to that scope. + ### Incorrect Usage -The following workflow is vulnerable to code injection in a non-privileged job but in the context of the default branch. +The following workflow interpolates a commit message directly into a script on a push to the +default branch. A commit message originating from a merged contribution may contain shell syntax, +which can expose the cache write token and allow the default branch cache to be poisoned. ```yaml name: Vulnerable Workflow on: - issue_comment: - types: [created] + push: + branches: [main] jobs: - pr-comment: + build: permissions: {} runs-on: ubuntu-latest steps: - run: | - echo ${{ github.event.comment.body }} + echo ${{ github.event.head_commit.message }} ``` ### Correct Usage -The following workflow is not vulnerable to code injections even if it runs in the context of the default branch. +The following workflow passes the commit message through an environment variable, so the shell +does not interpret its contents as code. ```yaml name: Secure Workflow on: - issue_comment: - types: [created] + push: + branches: [main] jobs: - pr-comment: + build: permissions: {} runs-on: ubuntu-latest steps: - env: - BODY: ${{ github.event.comment.body }} + MESSAGE: ${{ github.event.head_commit.message }} run: | - echo "$BODY" + echo "$MESSAGE" ``` ## References - Adnan Khan's Blog: [The Monsters in Your Build Cache – GitHub Actions Cache Poisoning](https://adnanthekhan.com/2024/05/06/the-monsters-in-your-build-cache-github-actions-cache-poisoning/). -- GitHub Docs: [GitHub Actions Caching Documentation](https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows). +- GitHub Docs: [Cache access for low-trust workflow triggers](https://docs.github.com/actions/reference/workflows-and-actions/dependency-caching#cache-access-for-low-trust-workflow-triggers). - Scribe Security Blog: [Cache Poisoning in GitHub Actions](https://scribesecurity.com/blog/github-cache-poisoning/). diff --git a/actions/ql/src/Security/CWE-349/CachePoisoningViaCodeInjection.ql b/actions/ql/src/Security/CWE-349/CachePoisoningViaCodeInjection.ql index 2fe792aba1e6..b970288ac31b 100644 --- a/actions/ql/src/Security/CWE-349/CachePoisoningViaCodeInjection.ql +++ b/actions/ql/src/Security/CWE-349/CachePoisoningViaCodeInjection.ql @@ -22,6 +22,7 @@ from CodeInjectionFlow::PathNode source, CodeInjectionFlow::PathNode sink, Event where CodeInjectionFlow::flowPath(source, sink) and event = getRelevantCachePoisoningEventForSink(sink.getNode()) and + source.getNode().(RemoteFlowSource).getEventName() = event.getName() and // the checkout is not controlled by an access check not exists(ControlCheck check | check.protects(source.getNode().asExpr(), event, "code-injection") diff --git a/actions/ql/src/Security/CWE-349/CachePoisoningViaDirectCache.md b/actions/ql/src/Security/CWE-349/CachePoisoningViaDirectCache.md index 849b771a8ff0..a22c41ad3e3a 100644 --- a/actions/ql/src/Security/CWE-349/CachePoisoningViaDirectCache.md +++ b/actions/ql/src/Security/CWE-349/CachePoisoningViaDirectCache.md @@ -34,35 +34,39 @@ Due to the above design, if something is cached in the context of the default br ## Example +GitHub gives workflows triggered by low-trust events, such as `issue_comment`, +`pull_request_target`, and `workflow_run`, read-only access to the default branch cache scope. +This query therefore reports only workflows whose trigger can write to that scope. + ### Incorrect Usage -The following workflow is caching an attacker-controlled file (`large_file`) in the context of the default branch. +The following write-capable manually dispatched workflow accepts a revision without validation, +fetches files from it, and saves those files in the default branch cache. This is unsafe if an +untrusted integration or automation can influence the dispatch input. ```yaml name: Vulnerable Workflow on: - issue_comment: - types: [created] + workflow_dispatch: + inputs: + head_sha: + required: true jobs: - pr-comment: + cache: permissions: read-all runs-on: ubuntu-latest steps: - - uses: xt0rted/pull-request-comment-branch@v2 - id: comment-branch - - uses: actions/checkout@v3 - with: - ref: ${{ steps.comment-branch.outputs.head_sha }} - - name: Set up Python 3.10 - uses: actions/setup-python@v5 - - name: Cache pip dependencies + - env: + HEAD_SHA: ${{ github.event.inputs.head_sha }} + run: | + git fetch origin "$HEAD_SHA" + git checkout "$HEAD_SHA" + - name: Cache fetched files uses: actions/cache@v4 - id: cache-pip with: - path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('**/pyproject.toml') }} - restore-keys: ${{ runner.os }}-pip- + path: . + key: dispatched-${{ github.event.inputs.head_sha }} ``` ### Correct Usage @@ -91,36 +95,8 @@ jobs: restore-keys: ${{ runner.os }}-pip- ``` -Note, that the example above doesn't allow using secrets if the Pull Request originates from a fork. In case secrets are needed, `pull_request_target` with labels as `safe to test` can be used, but the code in Pull Request must be manually reviewed before applying the label. - -```yaml -name: Secure Workflow -on: - pull_request_target: - types: [labeled] - -jobs: - pr-comment: - if: contains(github.event.pull_request.labels.*.name, 'safe to test') - permissions: read-all - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - with: - ref: ${{ github.event.pull_request.head.sha}} - - name: Set up Python 3.10 - uses: actions/setup-python@v5 - - name: Cache pip dependencies - uses: actions/cache@v4 - id: cache-pip - with: - path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('**/pyproject.toml') }} - restore-keys: ${{ runner.os }}-pip- -``` - ## References - Adnan Khan's Blog: [The Monsters in Your Build Cache – GitHub Actions Cache Poisoning](https://adnanthekhan.com/2024/05/06/the-monsters-in-your-build-cache-github-actions-cache-poisoning/). -- GitHub Docs: [GitHub Actions Caching Documentation](https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows). +- GitHub Docs: [Cache access for low-trust workflow triggers](https://docs.github.com/actions/reference/workflows-and-actions/dependency-caching#cache-access-for-low-trust-workflow-triggers). - Scribe Security Blog: [Cache Poisoning in GitHub Actions](https://scribesecurity.com/blog/github-cache-poisoning/). diff --git a/actions/ql/src/Security/CWE-349/CachePoisoningViaDirectCache.ql b/actions/ql/src/Security/CWE-349/CachePoisoningViaDirectCache.ql index 85a0f53df1dc..b410f92b68a1 100644 --- a/actions/ql/src/Security/CWE-349/CachePoisoningViaDirectCache.ql +++ b/actions/ql/src/Security/CWE-349/CachePoisoningViaDirectCache.ql @@ -40,17 +40,7 @@ where job.getATriggerEvent() = event and // job can be triggered by an external user event.isExternallyTriggerable() and - ( - // the workflow runs in the context of the default branch - runsOnDefaultBranch(event) - or - // the workflow's caller runs in the context of the default branch - event.getName() = "workflow_call" and - exists(ExternalJob caller | - caller.getCallee() = job.getLocation().getFile().getRelativePath() and - runsOnDefaultBranch(caller.getATriggerEvent()) - ) - ) and + hasDefaultBranchCacheWriteAccess(job, event) and // the job writes to the cache // (No need to follow the checkout/download step since the cache is normally write after the job completes) job.getAStep() = step and diff --git a/actions/ql/src/Security/CWE-349/CachePoisoningViaPoisonableStep.md b/actions/ql/src/Security/CWE-349/CachePoisoningViaPoisonableStep.md index fefd6d61a44d..e5fd868609c4 100644 --- a/actions/ql/src/Security/CWE-349/CachePoisoningViaPoisonableStep.md +++ b/actions/ql/src/Security/CWE-349/CachePoisoningViaPoisonableStep.md @@ -34,25 +34,35 @@ Due to the above design, if something is cached in the context of the default br ## Example +GitHub gives workflows triggered by low-trust events, such as `issue_comment`, +`pull_request_target`, and `workflow_run`, read-only access to the default branch cache scope. +This query therefore reports only workflows whose trigger can write to that scope. + ### Incorrect Usage -The following workflow runs untrusted code in a non-privileged job but in the context of the default branch. +The following write-capable manually dispatched workflow fetches an unvalidated revision and then +executes code from it. The executed code can use the cache token to poison the default branch cache +if an untrusted integration or automation can influence the dispatch input. ```yaml name: Vulnerable Workflow on: - pull_request_target: - branches: [main] -permissions: {} + workflow_dispatch: + inputs: + head_sha: + required: true jobs: test: + permissions: {} runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - with: - ref: ${{ github.event.pull_request.head.sha }} + - env: + HEAD_SHA: ${{ github.event.inputs.head_sha }} + run: | + git fetch origin "$HEAD_SHA" + git checkout "$HEAD_SHA" - name: Run tests - run: ./run_tests.sh + run: npm install ``` ### Correct Usage @@ -79,5 +89,5 @@ jobs: ## References - Adnan Khan's Blog: [The Monsters in Your Build Cache – GitHub Actions Cache Poisoning](https://adnanthekhan.com/2024/05/06/the-monsters-in-your-build-cache-github-actions-cache-poisoning/). -- GitHub Docs: [GitHub Actions Caching Documentation](https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows). +- GitHub Docs: [Cache access for low-trust workflow triggers](https://docs.github.com/actions/reference/workflows-and-actions/dependency-caching#cache-access-for-low-trust-workflow-triggers). - Scribe Security Blog: [Cache Poisoning in GitHub Actions](https://scribesecurity.com/blog/github-cache-poisoning/). diff --git a/actions/ql/src/Security/CWE-349/CachePoisoningViaPoisonableStep.ql b/actions/ql/src/Security/CWE-349/CachePoisoningViaPoisonableStep.ql index 95adcfaf78ec..f8466179caeb 100644 --- a/actions/ql/src/Security/CWE-349/CachePoisoningViaPoisonableStep.ql +++ b/actions/ql/src/Security/CWE-349/CachePoisoningViaPoisonableStep.ql @@ -40,17 +40,7 @@ where job.getATriggerEvent() = event and // job can be triggered by an external user event.isExternallyTriggerable() and - ( - // the workflow runs in the context of the default branch - runsOnDefaultBranch(event) - or - // the workflow's caller runs in the context of the default branch - event.getName() = "workflow_call" and - exists(ExternalJob caller | - caller.getCallee() = job.getLocation().getFile().getRelativePath() and - runsOnDefaultBranch(caller.getATriggerEvent()) - ) - ) and + hasDefaultBranchCacheWriteAccess(job, event) and // the job executes checked-out code // (The cache specific token can be leaked even for non-privileged workflows) source.getAFollowingStep() = step and diff --git a/actions/ql/src/change-notes/2026-07-18-read-only-default-branch-cache.md b/actions/ql/src/change-notes/2026-07-18-read-only-default-branch-cache.md new file mode 100644 index 000000000000..9952be542003 --- /dev/null +++ b/actions/ql/src/change-notes/2026-07-18-read-only-default-branch-cache.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* The `actions/cache-poisoning/code-injection`, `actions/cache-poisoning/direct-cache`, and `actions/cache-poisoning/poisonable-step` queries now account for read-only cache access on low-trust triggers that run in the default branch scope. Results are retained for triggers that GitHub allows to write to that cache scope. diff --git a/actions/ql/test/query-tests/Security/CWE-349/.github/workflows/cache_write_capable_push.yml b/actions/ql/test/query-tests/Security/CWE-349/.github/workflows/cache_write_capable_push.yml new file mode 100644 index 000000000000..b9fbe2d2d0b4 --- /dev/null +++ b/actions/ql/test/query-tests/Security/CWE-349/.github/workflows/cache_write_capable_push.yml @@ -0,0 +1,10 @@ +on: + push: + branches: [main] + +jobs: + injection: + permissions: {} + runs-on: ubuntu-latest + steps: + - run: echo "${{ github.event.head_commit.message }}" \ No newline at end of file diff --git a/actions/ql/test/query-tests/Security/CWE-349/.github/workflows/cache_write_capable_workflow_dispatch.yml b/actions/ql/test/query-tests/Security/CWE-349/.github/workflows/cache_write_capable_workflow_dispatch.yml new file mode 100644 index 000000000000..74695bc76942 --- /dev/null +++ b/actions/ql/test/query-tests/Security/CWE-349/.github/workflows/cache_write_capable_workflow_dispatch.yml @@ -0,0 +1,17 @@ +on: workflow_dispatch + +jobs: + cache: + permissions: {} + runs-on: ubuntu-latest + steps: + - env: + HEAD_SHA: ${{ github.event.inputs.head_sha }} + run: | + git fetch origin "$HEAD_SHA" + git checkout "$HEAD_SHA" + - run: npm install + - uses: actions/cache@v4 + with: + path: .npm + key: workflow-dispatch diff --git a/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaCodeInjection.expected b/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaCodeInjection.expected index 9cfac091f675..8cfbf6c2965c 100644 --- a/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaCodeInjection.expected +++ b/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaCodeInjection.expected @@ -1,10 +1,11 @@ edges | .github/workflows/code_injection2.yml:12:9:16:6 | Uses Step: modified_files | .github/workflows/code_injection2.yml:16:21:16:70 | steps.modified_files.outputs.files_modified | provenance | | nodes +| .github/workflows/cache_write_capable_push.yml:10:21:10:59 | github.event.head_commit.message | semmle.label | github.event.head_commit.message | | .github/workflows/code_injection1.yml:11:17:11:48 | github.event.comment.body | semmle.label | github.event.comment.body | | .github/workflows/code_injection2.yml:12:9:16:6 | Uses Step: modified_files | semmle.label | Uses Step: modified_files | | .github/workflows/code_injection2.yml:16:21:16:70 | steps.modified_files.outputs.files_modified | semmle.label | steps.modified_files.outputs.files_modified | | .github/workflows/neg_code_injection1.yml:11:17:11:48 | github.event.comment.body | semmle.label | github.event.comment.body | subpaths #select -| .github/workflows/code_injection1.yml:11:17:11:48 | github.event.comment.body | .github/workflows/code_injection1.yml:11:17:11:48 | github.event.comment.body | .github/workflows/code_injection1.yml:11:17:11:48 | github.event.comment.body | Unprivileged code injection in $@, which may lead to cache poisoning ($@). | .github/workflows/code_injection1.yml:11:17:11:48 | github.event.comment.body | ${{ github.event.comment.body }} | .github/workflows/code_injection1.yml:2:3:2:15 | issue_comment | issue_comment | +| .github/workflows/cache_write_capable_push.yml:10:21:10:59 | github.event.head_commit.message | .github/workflows/cache_write_capable_push.yml:10:21:10:59 | github.event.head_commit.message | .github/workflows/cache_write_capable_push.yml:10:21:10:59 | github.event.head_commit.message | Unprivileged code injection in $@, which may lead to cache poisoning ($@). | .github/workflows/cache_write_capable_push.yml:10:21:10:59 | github.event.head_commit.message | ${{ github.event.head_commit.message }} | .github/workflows/cache_write_capable_push.yml:2:3:2:6 | push | push | diff --git a/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaDirectCache.expected b/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaDirectCache.expected index 4cc8536b5943..8d0b858d0035 100644 --- a/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaDirectCache.expected +++ b/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaDirectCache.expected @@ -1,4 +1,6 @@ edges +| .github/workflows/cache_write_capable_workflow_dispatch.yml:8:9:13:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:13:9:14:6 | Run Step | +| .github/workflows/cache_write_capable_workflow_dispatch.yml:13:9:14:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:14:9:17:33 | Uses Step | | .github/workflows/code_injection2.yml:12:9:16:6 | Uses Step: modified_files | .github/workflows/code_injection2.yml:16:9:16:71 | Run Step | | .github/workflows/direct_cache1.yml:10:9:13:6 | Uses Step: comment-branch | .github/workflows/direct_cache1.yml:13:9:18:6 | Uses Step | | .github/workflows/direct_cache1.yml:13:9:18:6 | Uses Step | .github/workflows/direct_cache1.yml:18:9:22:6 | Uses Step | @@ -44,9 +46,4 @@ edges | .github/workflows/poisonable_step5.yml:17:9:22:6 | Uses Step | .github/workflows/poisonable_step5.yml:22:9:24:6 | Uses Step | | .github/workflows/poisonable_step5.yml:22:9:24:6 | Uses Step | .github/workflows/poisonable_step5.yml:24:9:28:31 | Uses Step | #select -| .github/workflows/direct_cache1.yml:18:9:22:6 | Uses Step | .github/workflows/direct_cache1.yml:13:9:18:6 | Uses Step | .github/workflows/direct_cache1.yml:18:9:22:6 | Uses Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/direct_cache1.yml:2:3:2:15 | issue_comment | issue_comment | -| .github/workflows/direct_cache2.yml:14:9:18:6 | Uses Step | .github/workflows/direct_cache2.yml:11:9:14:6 | Uses Step | .github/workflows/direct_cache2.yml:14:9:18:6 | Uses Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/direct_cache2.yml:3:5:3:23 | pull_request_target | pull_request_target | -| .github/workflows/direct_cache3.yml:19:9:23:6 | Uses Step | .github/workflows/direct_cache3.yml:14:9:19:6 | Uses Step | .github/workflows/direct_cache3.yml:19:9:23:6 | Uses Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/direct_cache3.yml:2:3:2:15 | issue_comment | issue_comment | -| .github/workflows/direct_cache4.yml:17:9:21:6 | Uses Step | .github/workflows/direct_cache4.yml:14:9:17:6 | Uses Step | .github/workflows/direct_cache4.yml:17:9:21:6 | Uses Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/direct_cache4.yml:4:3:4:21 | pull_request_target | pull_request_target | -| .github/workflows/direct_cache5.yml:17:9:21:6 | Uses Step | .github/workflows/direct_cache5.yml:14:9:17:6 | Uses Step | .github/workflows/direct_cache5.yml:17:9:21:6 | Uses Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/direct_cache5.yml:4:3:4:21 | pull_request_target | pull_request_target | -| .github/workflows/direct_cache6.yml:20:9:26:46 | Uses Step: cache-pip | .github/workflows/direct_cache6.yml:13:9:16:6 | Uses Step | .github/workflows/direct_cache6.yml:20:9:26:46 | Uses Step: cache-pip | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/direct_cache6.yml:4:3:4:21 | pull_request_target | pull_request_target | +| .github/workflows/cache_write_capable_workflow_dispatch.yml:14:9:17:33 | Uses Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:8:9:13:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:14:9:17:33 | Uses Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/cache_write_capable_workflow_dispatch.yml:1:5:1:21 | workflow_dispatch | workflow_dispatch | diff --git a/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaPoisonableStep.expected b/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaPoisonableStep.expected index 6b1a3e873134..ba48d939eda7 100644 --- a/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaPoisonableStep.expected +++ b/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaPoisonableStep.expected @@ -1,4 +1,6 @@ edges +| .github/workflows/cache_write_capable_workflow_dispatch.yml:8:9:13:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:13:9:14:6 | Run Step | +| .github/workflows/cache_write_capable_workflow_dispatch.yml:13:9:14:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:14:9:17:33 | Uses Step | | .github/workflows/code_injection2.yml:12:9:16:6 | Uses Step: modified_files | .github/workflows/code_injection2.yml:16:9:16:71 | Run Step | | .github/workflows/direct_cache1.yml:10:9:13:6 | Uses Step: comment-branch | .github/workflows/direct_cache1.yml:13:9:18:6 | Uses Step | | .github/workflows/direct_cache1.yml:13:9:18:6 | Uses Step | .github/workflows/direct_cache1.yml:18:9:22:6 | Uses Step | @@ -44,10 +46,4 @@ edges | .github/workflows/poisonable_step5.yml:17:9:22:6 | Uses Step | .github/workflows/poisonable_step5.yml:22:9:24:6 | Uses Step | | .github/workflows/poisonable_step5.yml:22:9:24:6 | Uses Step | .github/workflows/poisonable_step5.yml:24:9:28:31 | Uses Step | #select -| .github/workflows/poisonable_step1.yml:15:9:17:2 | Run Step | .github/workflows/poisonable_step1.yml:12:9:15:6 | Uses Step | .github/workflows/poisonable_step1.yml:15:9:17:2 | Run Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/poisonable_step1.yml:2:3:2:15 | issue_comment | issue_comment | -| .github/workflows/poisonable_step1.yml:26:9:28:2 | Uses Step | .github/workflows/poisonable_step1.yml:23:9:26:6 | Uses Step | .github/workflows/poisonable_step1.yml:26:9:28:2 | Uses Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/poisonable_step1.yml:2:3:2:15 | issue_comment | issue_comment | -| .github/workflows/poisonable_step1.yml:37:9:37:75 | Run Step | .github/workflows/poisonable_step1.yml:34:9:37:6 | Uses Step | .github/workflows/poisonable_step1.yml:37:9:37:75 | Run Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/poisonable_step1.yml:2:3:2:15 | issue_comment | issue_comment | -| .github/workflows/poisonable_step2.yml:22:9:26:31 | Uses Step | .github/workflows/poisonable_step2.yml:15:9:20:6 | Uses Step | .github/workflows/poisonable_step2.yml:22:9:26:31 | Uses Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/poisonable_step2.yml:5:3:5:21 | pull_request_target | pull_request_target | -| .github/workflows/poisonable_step3.yml:19:7:19:32 | Run Step | .github/workflows/poisonable_step3.yml:13:7:19:4 | Uses Step | .github/workflows/poisonable_step3.yml:19:7:19:32 | Run Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/poisonable_step3.yml:4:3:4:21 | pull_request_target | pull_request_target | -| .github/workflows/poisonable_step4.yml:18:9:18:19 | Run Step | .github/workflows/poisonable_step4.yml:13:9:18:6 | Uses Step | .github/workflows/poisonable_step4.yml:18:9:18:19 | Run Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/poisonable_step4.yml:3:3:3:21 | pull_request_target | pull_request_target | -| .github/workflows/poisonable_step5.yml:24:9:28:31 | Uses Step | .github/workflows/poisonable_step5.yml:17:9:22:6 | Uses Step | .github/workflows/poisonable_step5.yml:24:9:28:31 | Uses Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/poisonable_step5.yml:3:3:3:21 | pull_request_target | pull_request_target | +| .github/workflows/cache_write_capable_workflow_dispatch.yml:13:9:14:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:8:9:13:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:13:9:14:6 | Run Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/cache_write_capable_workflow_dispatch.yml:1:5:1:21 | workflow_dispatch | workflow_dispatch | From 6e0d62c004d98b7890b07db37047c2eb7cb78c28 Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 30 Jul 2026 10:06:52 +0200 Subject: [PATCH 122/188] unified: Generate corpus output --- .../switch-case-item-where-clauses.output | 222 ++++++++++++++++++ .../catch-where-clauses.output | 207 ++++++++++++++++ 2 files changed, 429 insertions(+) create mode 100644 unified/extractor/tests/corpus/swift/control-flow/switch-case-item-where-clauses.output create mode 100644 unified/extractor/tests/corpus/swift/optionals-and-errors/catch-where-clauses.output diff --git a/unified/extractor/tests/corpus/swift/control-flow/switch-case-item-where-clauses.output b/unified/extractor/tests/corpus/swift/control-flow/switch-case-item-where-clauses.output new file mode 100644 index 000000000000..9d2041aa2ad1 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/control-flow/switch-case-item-where-clauses.output @@ -0,0 +1,222 @@ +switch n { +case let x where x > 0: + print("positive") +case let y where y < 0, 0: + print("non-positive") +default: + print("other") +} + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + expressionStmt + expression: + switchExpr + leftBrace: { + rightBrace: } + cases: + switchCase + label: + switchCaseLabel + colon: : + caseKeyword: case + caseItems: + switchCaseItem + pattern: + valueBindingPattern + pattern: + identifierPattern + identifier: identifier "x" + bindingSpecifier: let + whereClause: + whereClause + condition: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator ">" + leftOperand: + declReferenceExpr + baseName: identifier "x" + rightOperand: + integerLiteralExpr + literal: integerLiteral "0" + whereKeyword: where + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment "positive" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + switchCase + label: + switchCaseLabel + colon: : + caseKeyword: case + caseItems: + switchCaseItem + trailingComma: , + pattern: + valueBindingPattern + pattern: + identifierPattern + identifier: identifier "y" + bindingSpecifier: let + whereClause: + whereClause + condition: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "<" + leftOperand: + declReferenceExpr + baseName: identifier "y" + rightOperand: + integerLiteralExpr + literal: integerLiteral "0" + whereKeyword: where + switchCaseItem + pattern: + expressionPattern + expression: + integerLiteralExpr + literal: integerLiteral "0" + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment "non-positive" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + switchCase + label: + switchDefaultLabel + colon: : + defaultKeyword: default + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment "other" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + subject: + declReferenceExpr + baseName: identifier "n" + switchKeyword: switch + +--- + +top_level + body: + block + stmt: + switch_expr + value: + name_expr + identifier: identifier "n" + case: + switch_case + pattern: + conditional_pattern + condition: + binary_expr + left: + name_expr + identifier: identifier "x" + operator: infix_operator ">" + right: int_literal "0" + pattern: + name_pattern + identifier: identifier "x" + body: + block + stmt: + call_expr + callee: + name_expr + identifier: identifier "print" + argument: + argument + value: string_literal "\"positive\"" + switch_case + pattern: + or_pattern + pattern: + conditional_pattern + condition: + binary_expr + left: + name_expr + identifier: identifier "y" + operator: infix_operator "<" + right: int_literal "0" + pattern: + name_pattern + identifier: identifier "y" + expr_equality_pattern + expr: int_literal "0" + body: + block + stmt: + call_expr + callee: + name_expr + identifier: identifier "print" + argument: + argument + value: string_literal "\"non-positive\"" + switch_case + body: + block + stmt: + call_expr + callee: + name_expr + identifier: identifier "print" + argument: + argument + value: string_literal "\"other\"" diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/catch-where-clauses.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/catch-where-clauses.output new file mode 100644 index 000000000000..79b7879d35fa --- /dev/null +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/catch-where-clauses.output @@ -0,0 +1,207 @@ +do { + try foo() +} catch let e where isNetworkError(e), let f where isTimeout(f) { + print("retry") +} catch { + print("fallback") +} + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + doStmt + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + tryExpr + expression: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "foo" + tryKeyword: try + catchClauses: + catchClause + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment "retry" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + catchItems: + catchItem + trailingComma: , + pattern: + valueBindingPattern + pattern: + identifierPattern + identifier: identifier "e" + bindingSpecifier: let + whereClause: + whereClause + condition: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + declReferenceExpr + baseName: identifier "e" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "isNetworkError" + whereKeyword: where + catchItem + pattern: + valueBindingPattern + pattern: + identifierPattern + identifier: identifier "f" + bindingSpecifier: let + whereClause: + whereClause + condition: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + declReferenceExpr + baseName: identifier "f" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "isTimeout" + whereKeyword: where + catchKeyword: catch + catchClause + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment "fallback" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + catchItems: + catchKeyword: catch + doKeyword: do + +--- + +top_level + body: + block + stmt: + try_expr + body: + block + stmt: + unary_expr + operand: + call_expr + callee: + name_expr + identifier: identifier "foo" + operator: prefix_operator "try" + catch_clause: + catch_clause + pattern: + or_pattern + pattern: + conditional_pattern + condition: + call_expr + callee: + name_expr + identifier: identifier "isNetworkError" + argument: + argument + value: + name_expr + identifier: identifier "e" + pattern: + name_pattern + identifier: identifier "e" + conditional_pattern + condition: + call_expr + callee: + name_expr + identifier: identifier "isTimeout" + argument: + argument + value: + name_expr + identifier: identifier "f" + pattern: + name_pattern + identifier: identifier "f" + body: + block + stmt: + call_expr + callee: + name_expr + identifier: identifier "print" + argument: + argument + value: string_literal "\"retry\"" + catch_clause + body: + block + stmt: + call_expr + callee: + name_expr + identifier: identifier "print" + argument: + argument + value: string_literal "\"fallback\"" From 5613a25e84ddaf4eb76e0bae2df607b6f728bdbf Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 30 Jul 2026 09:23:55 +0000 Subject: [PATCH 123/188] update codeql documentation --- .../codeql-changelog/codeql-cli-2.26.2.rst | 79 +++++++++++++++++++ .../codeql-changelog/index.rst | 1 + 2 files changed, 80 insertions(+) create mode 100644 docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.26.2.rst diff --git a/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.26.2.rst b/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.26.2.rst new file mode 100644 index 000000000000..845988894f0a --- /dev/null +++ b/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.26.2.rst @@ -0,0 +1,79 @@ +.. _codeql-cli-2.26.2: + +========================== +CodeQL 2.26.2 (2026-07-23) +========================== + +.. contents:: Contents + :depth: 2 + :local: + :backlinks: none + +This is an overview of changes in the CodeQL CLI and relevant CodeQL query and library packs. For additional updates on changes to the CodeQL code scanning experience, check out the `code scanning section on the GitHub blog `__, `relevant GitHub Changelog updates `__, `changes in the CodeQL extension for Visual Studio Code `__, and the `CodeQL Action changelog `__. + +Security Coverage +----------------- + +CodeQL 2.26.2 runs a total of 497 security queries when configured with the Default suite (covering 170 CWE). The Extended suite enables an additional 131 queries (covering 32 more CWE). + +CodeQL CLI +---------- + +Breaking Changes +~~~~~~~~~~~~~~~~ + +* Removed support for parsing :code:`[[`\ -style links in alert messages. This was an undocumented legacy feature that allowed query authors to embed links inline in select clause message strings using :code:`[["text"|"url"]]` syntax. Queries should use :code:`$@` placeholder pairs instead. + +Query Packs +----------- + +Minor Analysis Improvements +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +C# +"" + +* :code:`System.Web.HttpRequest.RawUrl` is no longer treated as a sanitizer for :code:`cs/web/unvalidated-url-redirection`, since it contains the un-normalized request line. This may lead to more results. + +Query Metadata Changes +~~~~~~~~~~~~~~~~~~~~~~ + +C/C++ +""""" + +* Added the tag :code:`external/cwe/cwe-762` to :code:`cpp/new-free-mismatch`, and removed the tag :code:`external/cwe/cwe-401`. This better matches the behavior of the query. + +C# +"" + +* The query :code:`cs/useless-assignment-to-local` has been removed from the :code:`code-quality` suite, but it remains in the :code:`code-quality-extended` suite. + +Language Libraries +------------------ + +Major Analysis Improvements +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Swift +""""" + +* Upgraded to allow analysis of Swift 6.3.3. + +Minor Analysis Improvements +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Golang +"""""" + +* The function :code:`Rel` in :code:`path/filepath` was incorrectly considered a sanitizer for :code:`go/path-injection` and :code:`go/zipslip`. This has now been fixed, which may lead to more results for those queries. + +Java/Kotlin +""""""""""" + +* Kotlin versions up to 2.4.10 are now supported. +* :code:`java.io.File.getName()` is no longer treated as a complete sanitizer for :code:`java/path-injection`, since it does not remove a :code:`..` path component (for example :code:`new File("..").getName()` returns :code:`".."`). It is now only recognized as a sanitizer when combined with a subsequent check for :code:`..` components, which may result in new alerts. + +GitHub Actions +"""""""""""""" + +* Altered the logic of :code:`EnvironmentCheck` to make sure it is a check that protects only for non-toctou. This change will result in more results being found by the queries: :code:`actions/untrusted-checkout-toctou/high` and :code:`actions/untrusted-checkout-toctou/critical`. diff --git a/docs/codeql/codeql-overview/codeql-changelog/index.rst b/docs/codeql/codeql-overview/codeql-changelog/index.rst index 837fa757368d..a0a2e1832d83 100644 --- a/docs/codeql/codeql-overview/codeql-changelog/index.rst +++ b/docs/codeql/codeql-overview/codeql-changelog/index.rst @@ -11,6 +11,7 @@ A list of queries for each suite and language `is available here Date: Thu, 30 Jul 2026 13:13:17 +0100 Subject: [PATCH 124/188] C++: Add missing flow models. --- .../dataflow/external-models/windows.cpp | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp b/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp index 5afa72723d64..f4ed4d909f6c 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp +++ b/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp @@ -987,6 +987,16 @@ LONG RegQueryMultipleValuesW( HKEY hKey, PVALENTW valList, DWORD numVals, LPWSTR valueBuffer, LPDWORD totalSize ); +LONG RegEnumValueA( + HKEY hKey, DWORD dwIndex, LPSTR lpValueName, LPDWORD lpcchValueName, LPDWORD lpReserved, + LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData +); + +LONG RegEnumValueW( + HKEY hKey, DWORD dwIndex, LPWSTR lpValueName, LPDWORD lpcchValueName, LPDWORD lpReserved, + LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData +); + void test_registry_queries(HKEY hKey) { { char data[256]; @@ -1042,4 +1052,33 @@ void test_registry_queries(HKEY hKey) { sink(data); // clean sink(*data); // $ ir } + + { + BYTE data[256]; + DWORD dataSize = sizeof(data); + DWORD type; + RegGetValueA(hKey, "subkey", "value", 0, &type, data, &dataSize); + sink(data); // clean + sink(*data); // $ MISSING: ir + } + { + char valueName[256]; + DWORD valueNameSize = sizeof(valueName); + BYTE data[256]; + DWORD dataSize = sizeof(data); + DWORD type; + RegEnumValueA(hKey, 0, valueName, &valueNameSize, nullptr, &type, data, &dataSize); + sink(data); // clean + sink(*data); // $ MISSING: ir + } + { + wchar_t valueName[256]; + DWORD valueNameSize = sizeof(valueName) / sizeof(*valueName); + BYTE data[256]; + DWORD dataSize = sizeof(data); + DWORD type; + RegEnumValueW(hKey, 0, valueName, &valueNameSize, nullptr, &type, data, &dataSize); + sink(data); // clean + sink(*data); // $ MISSING: ir + } } \ No newline at end of file From 5256b9545cdabf032171b0654f9c8124eaa42d8e Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 30 Jul 2026 13:15:17 +0100 Subject: [PATCH 125/188] C++: Add models and accept test changes. --- cpp/ql/lib/ext/Windows.model.yml | 2 + .../dataflow/external-models/flow.expected | 293 +++++++++--------- .../dataflow/external-models/sources.expected | 17 +- .../dataflow/external-models/windows.cpp | 6 +- 4 files changed, 167 insertions(+), 151 deletions(-) diff --git a/cpp/ql/lib/ext/Windows.model.yml b/cpp/ql/lib/ext/Windows.model.yml index e9f6dfd7fbfd..8c25b874ccff 100644 --- a/cpp/ql/lib/ext/Windows.model.yml +++ b/cpp/ql/lib/ext/Windows.model.yml @@ -45,6 +45,8 @@ extensions: - ["", "", False, "RegQueryMultipleValuesA", "", "", "Argument[*3]", "local", "manual"] # TODO: Once we support access paths at sources we should also mark Argument[*1].Field[*ve_valueptr] - ["", "", False, "RegQueryMultipleValuesW", "", "", "Argument[*3]", "local", "manual"] + - ["", "", False, "RegEnumValueA", "", "", "Argument[*6]", "local", "manual"] + - ["", "", False, "RegEnumValueW", "", "", "Argument[*6]", "local", "manual"] - addsTo: pack: codeql/cpp-all extensible: summaryModel diff --git a/cpp/ql/test/library-tests/dataflow/external-models/flow.expected b/cpp/ql/test/library-tests/dataflow/external-models/flow.expected index df453de8e1d3..a14376b044e7 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/flow.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/flow.expected @@ -17,111 +17,113 @@ models | 16 | Source: ; ; false; NtReadFile; ; ; Argument[*5]; local; manual | | 17 | Source: ; ; false; ReadFile; ; ; Argument[*1]; local; manual | | 18 | Source: ; ; false; ReadFileEx; ; ; Argument[*1]; local; manual | -| 19 | Source: ; ; false; RegGetValueA; ; ; Argument[*5]; local; manual | -| 20 | Source: ; ; false; RegQueryMultipleValuesA; ; ; Argument[*3]; local; manual | -| 21 | Source: ; ; false; RegQueryMultipleValuesW; ; ; Argument[*3]; local; manual | -| 22 | Source: ; ; false; RegQueryValueA; ; ; Argument[*2]; local; manual | -| 23 | Source: ; ; false; RegQueryValueExA; ; ; Argument[*4]; local; manual | -| 24 | Source: ; ; false; RegQueryValueExW; ; ; Argument[*4]; local; manual | -| 25 | Source: ; ; false; RegQueryValueW; ; ; Argument[*2]; local; manual | -| 26 | Source: ; ; false; WinHttpQueryHeaders; ; ; Argument[*3]; remote; manual | -| 27 | Source: ; ; false; WinHttpQueryHeadersEx; ; ; Argument[**8]; remote; manual | -| 28 | Source: ; ; false; WinHttpQueryHeadersEx; ; ; Argument[*5]; remote; manual | -| 29 | Source: ; ; false; WinHttpQueryHeadersEx; ; ; Argument[*6]; remote; manual | -| 30 | Source: ; ; false; WinHttpReadData; ; ; Argument[*1]; remote; manual | -| 31 | Source: ; ; false; WinHttpReadDataEx; ; ; Argument[*1]; remote; manual | -| 32 | Source: ; ; false; ymlSource; ; ; ReturnValue; local; manual | -| 33 | Source: Azure::Core::Http; RawResponse; true; ExtractBodyStream; ; ; ReturnValue[*]; remote; manual | -| 34 | Source: Azure::Core::Http; RawResponse; true; GetBody; ; ; ReturnValue[*]; remote; manual | -| 35 | Source: Azure::Core::Http; RawResponse; true; GetHeaders; ; ; ReturnValue[*]; remote; manual | -| 36 | Source: Azure::Core::Http; Request; true; GetBodyStream; ; ; ReturnValue[*]; remote; manual | -| 37 | Source: Azure::Core::Http; Request; true; GetHeader; ; ; ReturnValue; remote; manual | -| 38 | Source: Azure::Core::Http; Request; true; GetHeaders; ; ; ReturnValue; remote; manual | -| 39 | Source: boost::asio; ; false; read_until; ; ; Argument[*1]; remote; manual | -| 40 | Summary: ; ; false; CommandLineToArgvA; ; ; Argument[*0]; ReturnValue[**]; taint; manual | -| 41 | Summary: ; ; false; CreateRemoteThread; ; ; Argument[@4]; Argument[3].Parameter[@0]; value; manual | -| 42 | Summary: ; ; false; CreateRemoteThreadEx; ; ; Argument[@4]; Argument[3].Parameter[@0]; value; manual | -| 43 | Summary: ; ; false; CreateThread; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual | -| 44 | Summary: ; ; false; ReadFileEx; ; ; Argument[*3].Field[@hEvent]; Argument[4].Parameter[*2].Field[@hEvent]; value; manual | -| 45 | Summary: ; ; false; RtlCopyDeviceMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | -| 46 | Summary: ; ; false; RtlCopyMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | -| 47 | Summary: ; ; false; RtlCopyMemoryNonTemporal; ; ; Argument[*@1]; Argument[*@0]; value; manual | -| 48 | Summary: ; ; false; RtlCopyUnicodeString; ; ; Argument[*1].Field[*Buffer]; Argument[*0].Field[*Buffer]; value; manual | -| 49 | Summary: ; ; false; RtlCopyVolatileMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | -| 50 | Summary: ; ; false; RtlInitUnicodeString; ; ; Argument[*1]; Argument[*0].Field[*Buffer]; value; manual | -| 51 | Summary: ; ; false; RtlMoveMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | -| 52 | Summary: ; ; false; RtlMoveVolatileMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | -| 53 | Summary: ; ; false; WinHttpCrackUrl; ; ; Argument[*0]; Argument[*3]; taint; manual | -| 54 | Summary: ; ; false; callWithArgument; ; ; Argument[1]; Argument[0].Parameter[0]; value; manual | -| 55 | Summary: ; ; false; callWithNonTypeTemplate; (const T &); ; Argument[*0]; ReturnValue; value; manual | -| 56 | Summary: ; ; false; pthread_create; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual | -| 57 | Summary: ; ; false; read_field_from_struct; ; ; Argument[*0].Field[MyNamespace::MyStructInNamespace::myField]; ReturnValue; value; manual | -| 58 | Summary: ; ; false; read_field_from_struct_2; ; ; Argument[*0].Field[MyGlobalStruct::myField]; ReturnValue; value; manual | -| 59 | Summary: ; ; false; ymlStepGenerated; ; ; Argument[0]; ReturnValue; taint; df-generated | -| 60 | Summary: ; ; false; ymlStepManual; ; ; Argument[0]; ReturnValue; taint; manual | -| 61 | Summary: ; ; false; ymlStepManual_with_body; ; ; Argument[0]; ReturnValue; taint; manual | -| 62 | Summary: ; MyString; true; operator[]; ; ; Argument[-1]; ReturnValue[*]; taint; manual | -| 63 | Summary: ; MyString; true; operator[]; ; ; ReturnValue[*]; Argument[-1]; taint; manual | -| 64 | Summary: ; ReverseFlow; true; get_ptr; ; ; ReturnValue[*]; Argument[-1].Field[ReverseFlow::value]; value; manual | -| 65 | Summary: ; TemplateClass1; true; templateFunction2; (U,V); ; Argument[1]; ReturnValue; value; manual | -| 66 | Summary: ; TemplateClass1; false; templateFunction; (T,U); ; Argument[0]; ReturnValue; value; manual | -| 67 | Summary: ; TemplateClass2; true; function; (U,T); ; Argument[1]; ReturnValue; value; manual | -| 68 | Summary: Azure::Core::IO; BodyStream; true; Read; ; ; Argument[-1]; Argument[*0]; taint; manual | -| 69 | Summary: Azure::Core::IO; BodyStream; true; ReadToCount; ; ; Argument[-1]; Argument[*0]; taint; manual | -| 70 | Summary: Azure::Core::IO; BodyStream; true; ReadToEnd; ; ; Argument[-1]; ReturnValue.Element; taint; manual | -| 71 | Summary: Azure; Nullable; true; Value; ; ; Argument[-1]; ReturnValue[*]; taint; manual | -| 72 | Summary: boost::asio; ; false; buffer; ; ; Argument[*0]; ReturnValue; taint; manual | +| 19 | Source: ; ; false; RegEnumValueA; ; ; Argument[*6]; local; manual | +| 20 | Source: ; ; false; RegEnumValueW; ; ; Argument[*6]; local; manual | +| 21 | Source: ; ; false; RegGetValueA; ; ; Argument[*5]; local; manual | +| 22 | Source: ; ; false; RegQueryMultipleValuesA; ; ; Argument[*3]; local; manual | +| 23 | Source: ; ; false; RegQueryMultipleValuesW; ; ; Argument[*3]; local; manual | +| 24 | Source: ; ; false; RegQueryValueA; ; ; Argument[*2]; local; manual | +| 25 | Source: ; ; false; RegQueryValueExA; ; ; Argument[*4]; local; manual | +| 26 | Source: ; ; false; RegQueryValueExW; ; ; Argument[*4]; local; manual | +| 27 | Source: ; ; false; RegQueryValueW; ; ; Argument[*2]; local; manual | +| 28 | Source: ; ; false; WinHttpQueryHeaders; ; ; Argument[*3]; remote; manual | +| 29 | Source: ; ; false; WinHttpQueryHeadersEx; ; ; Argument[**8]; remote; manual | +| 30 | Source: ; ; false; WinHttpQueryHeadersEx; ; ; Argument[*5]; remote; manual | +| 31 | Source: ; ; false; WinHttpQueryHeadersEx; ; ; Argument[*6]; remote; manual | +| 32 | Source: ; ; false; WinHttpReadData; ; ; Argument[*1]; remote; manual | +| 33 | Source: ; ; false; WinHttpReadDataEx; ; ; Argument[*1]; remote; manual | +| 34 | Source: ; ; false; ymlSource; ; ; ReturnValue; local; manual | +| 35 | Source: Azure::Core::Http; RawResponse; true; ExtractBodyStream; ; ; ReturnValue[*]; remote; manual | +| 36 | Source: Azure::Core::Http; RawResponse; true; GetBody; ; ; ReturnValue[*]; remote; manual | +| 37 | Source: Azure::Core::Http; RawResponse; true; GetHeaders; ; ; ReturnValue[*]; remote; manual | +| 38 | Source: Azure::Core::Http; Request; true; GetBodyStream; ; ; ReturnValue[*]; remote; manual | +| 39 | Source: Azure::Core::Http; Request; true; GetHeader; ; ; ReturnValue; remote; manual | +| 40 | Source: Azure::Core::Http; Request; true; GetHeaders; ; ; ReturnValue; remote; manual | +| 41 | Source: boost::asio; ; false; read_until; ; ; Argument[*1]; remote; manual | +| 42 | Summary: ; ; false; CommandLineToArgvA; ; ; Argument[*0]; ReturnValue[**]; taint; manual | +| 43 | Summary: ; ; false; CreateRemoteThread; ; ; Argument[@4]; Argument[3].Parameter[@0]; value; manual | +| 44 | Summary: ; ; false; CreateRemoteThreadEx; ; ; Argument[@4]; Argument[3].Parameter[@0]; value; manual | +| 45 | Summary: ; ; false; CreateThread; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual | +| 46 | Summary: ; ; false; ReadFileEx; ; ; Argument[*3].Field[@hEvent]; Argument[4].Parameter[*2].Field[@hEvent]; value; manual | +| 47 | Summary: ; ; false; RtlCopyDeviceMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | +| 48 | Summary: ; ; false; RtlCopyMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | +| 49 | Summary: ; ; false; RtlCopyMemoryNonTemporal; ; ; Argument[*@1]; Argument[*@0]; value; manual | +| 50 | Summary: ; ; false; RtlCopyUnicodeString; ; ; Argument[*1].Field[*Buffer]; Argument[*0].Field[*Buffer]; value; manual | +| 51 | Summary: ; ; false; RtlCopyVolatileMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | +| 52 | Summary: ; ; false; RtlInitUnicodeString; ; ; Argument[*1]; Argument[*0].Field[*Buffer]; value; manual | +| 53 | Summary: ; ; false; RtlMoveMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | +| 54 | Summary: ; ; false; RtlMoveVolatileMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | +| 55 | Summary: ; ; false; WinHttpCrackUrl; ; ; Argument[*0]; Argument[*3]; taint; manual | +| 56 | Summary: ; ; false; callWithArgument; ; ; Argument[1]; Argument[0].Parameter[0]; value; manual | +| 57 | Summary: ; ; false; callWithNonTypeTemplate; (const T &); ; Argument[*0]; ReturnValue; value; manual | +| 58 | Summary: ; ; false; pthread_create; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual | +| 59 | Summary: ; ; false; read_field_from_struct; ; ; Argument[*0].Field[MyNamespace::MyStructInNamespace::myField]; ReturnValue; value; manual | +| 60 | Summary: ; ; false; read_field_from_struct_2; ; ; Argument[*0].Field[MyGlobalStruct::myField]; ReturnValue; value; manual | +| 61 | Summary: ; ; false; ymlStepGenerated; ; ; Argument[0]; ReturnValue; taint; df-generated | +| 62 | Summary: ; ; false; ymlStepManual; ; ; Argument[0]; ReturnValue; taint; manual | +| 63 | Summary: ; ; false; ymlStepManual_with_body; ; ; Argument[0]; ReturnValue; taint; manual | +| 64 | Summary: ; MyString; true; operator[]; ; ; Argument[-1]; ReturnValue[*]; taint; manual | +| 65 | Summary: ; MyString; true; operator[]; ; ; ReturnValue[*]; Argument[-1]; taint; manual | +| 66 | Summary: ; ReverseFlow; true; get_ptr; ; ; ReturnValue[*]; Argument[-1].Field[ReverseFlow::value]; value; manual | +| 67 | Summary: ; TemplateClass1; true; templateFunction2; (U,V); ; Argument[1]; ReturnValue; value; manual | +| 68 | Summary: ; TemplateClass1; false; templateFunction; (T,U); ; Argument[0]; ReturnValue; value; manual | +| 69 | Summary: ; TemplateClass2; true; function; (U,T); ; Argument[1]; ReturnValue; value; manual | +| 70 | Summary: Azure::Core::IO; BodyStream; true; Read; ; ; Argument[-1]; Argument[*0]; taint; manual | +| 71 | Summary: Azure::Core::IO; BodyStream; true; ReadToCount; ; ; Argument[-1]; Argument[*0]; taint; manual | +| 72 | Summary: Azure::Core::IO; BodyStream; true; ReadToEnd; ; ; Argument[-1]; ReturnValue.Element; taint; manual | +| 73 | Summary: Azure; Nullable; true; Value; ; ; Argument[-1]; ReturnValue[*]; taint; manual | +| 74 | Summary: boost::asio; ; false; buffer; ; ; Argument[*0]; ReturnValue; taint; manual | edges -| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:91:7:91:17 | recv_buffer | provenance | Src:MaD:39 | -| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:93:29:93:39 | *recv_buffer | provenance | Src:MaD:39 Sink:MaD:2 | +| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:91:7:91:17 | recv_buffer | provenance | Src:MaD:41 | +| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:93:29:93:39 | *recv_buffer | provenance | Src:MaD:41 Sink:MaD:2 | | asio_streams.cpp:97:37:97:44 | call to source | asio_streams.cpp:98:7:98:14 | send_str | provenance | TaintFunction | | asio_streams.cpp:97:37:97:44 | call to source | asio_streams.cpp:100:64:100:71 | *send_str | provenance | TaintFunction | | asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | | | asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:101:7:101:17 | send_buffer | provenance | | | asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:103:29:103:39 | *send_buffer | provenance | Sink:MaD:2 | -| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:72 | -| azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:253:48:253:60 | *call to GetBodyStream | provenance | Src:MaD:36 | +| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:74 | +| azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:253:48:253:60 | *call to GetBodyStream | provenance | Src:MaD:38 | | azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:257:5:257:8 | *resp | provenance | | | azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:262:5:262:8 | *resp | provenance | | | azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:266:38:266:41 | *resp | provenance | | -| azure.cpp:257:5:257:8 | *resp | azure.cpp:257:16:257:21 | Read output argument | provenance | MaD:68 | +| azure.cpp:257:5:257:8 | *resp | azure.cpp:257:16:257:21 | Read output argument | provenance | MaD:70 | | azure.cpp:257:16:257:21 | Read output argument | azure.cpp:258:10:258:16 | * ... | provenance | | -| azure.cpp:262:5:262:8 | *resp | azure.cpp:262:23:262:28 | ReadToCount output argument | provenance | MaD:69 | +| azure.cpp:262:5:262:8 | *resp | azure.cpp:262:23:262:28 | ReadToCount output argument | provenance | MaD:71 | | azure.cpp:262:23:262:28 | ReadToCount output argument | azure.cpp:263:10:263:16 | * ... | provenance | | -| azure.cpp:266:38:266:41 | *resp | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | provenance | MaD:70 | +| azure.cpp:266:38:266:41 | *resp | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | provenance | MaD:72 | | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | provenance | | | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | azure.cpp:267:10:267:12 | vec [element] | provenance | | | azure.cpp:267:10:267:12 | vec [element] | azure.cpp:267:10:267:12 | vec | provenance | | -| azure.cpp:273:62:273:64 | call to GetHeaders | azure.cpp:273:62:273:64 | call to GetHeaders | provenance | Src:MaD:35 | +| azure.cpp:273:62:273:64 | call to GetHeaders | azure.cpp:273:62:273:64 | call to GetHeaders | provenance | Src:MaD:37 | | azure.cpp:273:62:273:64 | call to GetHeaders | azure.cpp:274:14:274:29 | call to operator[] | provenance | TaintFunction | | azure.cpp:273:62:273:64 | call to GetHeaders | azure.cpp:274:14:274:29 | call to operator[] | provenance | TaintFunction | | azure.cpp:273:62:273:64 | call to GetHeaders | azure.cpp:274:14:274:29 | call to operator[] | provenance | TaintFunction | | azure.cpp:274:14:274:29 | call to operator[] | azure.cpp:274:10:274:29 | call to operator[] | provenance | | | azure.cpp:274:14:274:29 | call to operator[] | azure.cpp:274:14:274:29 | call to operator[] | provenance | | -| azure.cpp:277:45:277:47 | call to GetBody | azure.cpp:277:45:277:47 | call to GetBody | provenance | Src:MaD:34 | +| azure.cpp:277:45:277:47 | call to GetBody | azure.cpp:277:45:277:47 | call to GetBody | provenance | Src:MaD:36 | | azure.cpp:277:45:277:47 | call to GetBody | azure.cpp:278:10:278:13 | body | provenance | | | azure.cpp:277:45:277:47 | call to GetBody | azure.cpp:278:10:278:13 | body | provenance | | | azure.cpp:278:10:278:13 | body | azure.cpp:278:10:278:13 | body | provenance | | -| azure.cpp:281:68:281:84 | *call to ExtractBodyStream | azure.cpp:281:68:281:84 | *call to ExtractBodyStream | provenance | Src:MaD:33 | +| azure.cpp:281:68:281:84 | *call to ExtractBodyStream | azure.cpp:281:68:281:84 | *call to ExtractBodyStream | provenance | Src:MaD:35 | | azure.cpp:281:68:281:84 | *call to ExtractBodyStream | azure.cpp:282:21:282:23 | *call to get | provenance | | -| azure.cpp:282:21:282:23 | *call to get | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | provenance | MaD:70 | +| azure.cpp:282:21:282:23 | *call to get | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | provenance | MaD:72 | | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | azure.cpp:282:10:282:38 | call to ReadToEnd | provenance | | | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | provenance | | -| azure.cpp:289:24:289:56 | call to GetHeader | azure.cpp:289:63:289:65 | call to Value | provenance | MaD:71 | +| azure.cpp:289:24:289:56 | call to GetHeader | azure.cpp:289:63:289:65 | call to Value | provenance | MaD:73 | | azure.cpp:289:32:289:40 | call to GetHeader | azure.cpp:289:24:289:56 | call to GetHeader | provenance | | -| azure.cpp:289:32:289:40 | call to GetHeader | azure.cpp:289:32:289:40 | call to GetHeader | provenance | Src:MaD:37 | +| azure.cpp:289:32:289:40 | call to GetHeader | azure.cpp:289:32:289:40 | call to GetHeader | provenance | Src:MaD:39 | | azure.cpp:289:63:289:65 | call to Value | azure.cpp:289:63:289:65 | call to Value | provenance | | | azure.cpp:289:63:289:65 | call to Value | azure.cpp:290:10:290:20 | headerValue | provenance | | | azure.cpp:289:63:289:65 | call to Value | azure.cpp:290:10:290:20 | headerValue | provenance | | | azure.cpp:290:10:290:20 | headerValue | azure.cpp:290:10:290:20 | headerValue | provenance | | -| azure.cpp:293:58:293:67 | call to GetHeaders | azure.cpp:293:58:293:67 | call to GetHeaders | provenance | Src:MaD:38 | +| azure.cpp:293:58:293:67 | call to GetHeaders | azure.cpp:293:58:293:67 | call to GetHeaders | provenance | Src:MaD:40 | | azure.cpp:293:58:293:67 | call to GetHeaders | azure.cpp:294:38:294:53 | call to operator[] | provenance | TaintFunction | | azure.cpp:294:38:294:53 | call to operator[] | azure.cpp:295:10:295:20 | contentType | provenance | | | azure.cpp:294:38:294:53 | call to operator[] | azure.cpp:295:10:295:20 | contentType | provenance | | | azure.cpp:295:10:295:20 | contentType | azure.cpp:295:10:295:20 | contentType | provenance | | | test.cpp:7:47:7:52 | value2 | test.cpp:7:64:7:69 | value2 | provenance | | | test.cpp:7:64:7:69 | value2 | test.cpp:7:5:7:30 | *ymlStepGenerated_with_body | provenance | | -| test.cpp:10:10:10:18 | call to ymlSource | test.cpp:10:10:10:18 | call to ymlSource | provenance | Src:MaD:32 | +| test.cpp:10:10:10:18 | call to ymlSource | test.cpp:10:10:10:18 | call to ymlSource | provenance | Src:MaD:34 | | test.cpp:10:10:10:18 | call to ymlSource | test.cpp:14:10:14:10 | x | provenance | Sink:MaD:1 | | test.cpp:10:10:10:18 | call to ymlSource | test.cpp:17:24:17:24 | x | provenance | | | test.cpp:10:10:10:18 | call to ymlSource | test.cpp:21:27:21:27 | x | provenance | | @@ -129,13 +131,13 @@ edges | test.cpp:10:10:10:18 | call to ymlSource | test.cpp:32:41:32:41 | x | provenance | | | test.cpp:17:10:17:22 | call to ymlStepManual | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | | | test.cpp:17:10:17:22 | call to ymlStepManual | test.cpp:18:10:18:10 | y | provenance | Sink:MaD:1 | -| test.cpp:17:24:17:24 | x | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | MaD:60 | +| test.cpp:17:24:17:24 | x | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | MaD:62 | | test.cpp:21:10:21:25 | call to ymlStepGenerated | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | | | test.cpp:21:10:21:25 | call to ymlStepGenerated | test.cpp:22:10:22:10 | z | provenance | Sink:MaD:1 | -| test.cpp:21:27:21:27 | x | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | MaD:59 | +| test.cpp:21:27:21:27 | x | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | MaD:61 | | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | | | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | test.cpp:26:10:26:11 | y2 | provenance | Sink:MaD:1 | -| test.cpp:25:35:25:35 | x | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | MaD:61 | +| test.cpp:25:35:25:35 | x | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | MaD:63 | | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | provenance | | | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | test.cpp:33:10:33:11 | z2 | provenance | Sink:MaD:1 | | test.cpp:32:41:32:41 | x | test.cpp:7:47:7:52 | value2 | provenance | | @@ -145,73 +147,73 @@ edges | test.cpp:48:13:48:13 | *s [x] | test.cpp:48:16:48:16 | x | provenance | Sink:MaD:1 | | test.cpp:56:2:56:2 | *s [post update] [x] | test.cpp:59:55:59:64 | *& ... [x] | provenance | | | test.cpp:56:2:56:18 | ... = ... | test.cpp:56:2:56:2 | *s [post update] [x] | provenance | | -| test.cpp:56:8:56:16 | call to ymlSource | test.cpp:56:2:56:18 | ... = ... | provenance | Src:MaD:32 | -| test.cpp:59:55:59:64 | *& ... [x] | test.cpp:46:30:46:32 | *arg [x] | provenance | MaD:56 | +| test.cpp:56:8:56:16 | call to ymlSource | test.cpp:56:2:56:18 | ... = ... | provenance | Src:MaD:34 | +| test.cpp:59:55:59:64 | *& ... [x] | test.cpp:46:30:46:32 | *arg [x] | provenance | MaD:58 | | test.cpp:68:22:68:22 | y | test.cpp:69:11:69:11 | y | provenance | Sink:MaD:1 | | test.cpp:74:22:74:22 | y | test.cpp:75:11:75:11 | y | provenance | Sink:MaD:1 | | test.cpp:82:22:82:22 | y | test.cpp:83:11:83:11 | y | provenance | Sink:MaD:1 | | test.cpp:88:22:88:22 | y | test.cpp:89:11:89:11 | y | provenance | Sink:MaD:1 | -| test.cpp:94:10:94:18 | call to ymlSource | test.cpp:94:10:94:18 | call to ymlSource | provenance | Src:MaD:32 | +| test.cpp:94:10:94:18 | call to ymlSource | test.cpp:94:10:94:18 | call to ymlSource | provenance | Src:MaD:34 | | test.cpp:94:10:94:18 | call to ymlSource | test.cpp:97:26:97:26 | x | provenance | | | test.cpp:94:10:94:18 | call to ymlSource | test.cpp:101:26:101:26 | x | provenance | | | test.cpp:94:10:94:18 | call to ymlSource | test.cpp:103:63:103:63 | x | provenance | | | test.cpp:94:10:94:18 | call to ymlSource | test.cpp:104:62:104:62 | x | provenance | | -| test.cpp:97:26:97:26 | x | test.cpp:68:22:68:22 | y | provenance | MaD:54 | -| test.cpp:101:26:101:26 | x | test.cpp:74:22:74:22 | y | provenance | MaD:54 | -| test.cpp:103:63:103:63 | x | test.cpp:82:22:82:22 | y | provenance | MaD:54 | -| test.cpp:104:62:104:62 | x | test.cpp:88:22:88:22 | y | provenance | MaD:54 | -| test.cpp:114:10:114:18 | call to ymlSource | test.cpp:114:10:114:18 | call to ymlSource | provenance | Src:MaD:32 | +| test.cpp:97:26:97:26 | x | test.cpp:68:22:68:22 | y | provenance | MaD:56 | +| test.cpp:101:26:101:26 | x | test.cpp:74:22:74:22 | y | provenance | MaD:56 | +| test.cpp:103:63:103:63 | x | test.cpp:82:22:82:22 | y | provenance | MaD:56 | +| test.cpp:104:62:104:62 | x | test.cpp:88:22:88:22 | y | provenance | MaD:56 | +| test.cpp:114:10:114:18 | call to ymlSource | test.cpp:114:10:114:18 | call to ymlSource | provenance | Src:MaD:34 | | test.cpp:114:10:114:18 | call to ymlSource | test.cpp:118:44:118:44 | *x | provenance | | | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | provenance | | | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | test.cpp:119:10:119:11 | y2 | provenance | Sink:MaD:1 | -| test.cpp:118:44:118:44 | *x | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | provenance | MaD:55 | -| test.cpp:133:10:133:18 | call to ymlSource | test.cpp:133:10:133:18 | call to ymlSource | provenance | Src:MaD:32 | +| test.cpp:118:44:118:44 | *x | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | provenance | MaD:57 | +| test.cpp:133:10:133:18 | call to ymlSource | test.cpp:133:10:133:18 | call to ymlSource | provenance | Src:MaD:34 | | test.cpp:133:10:133:18 | call to ymlSource | test.cpp:134:45:134:45 | x | provenance | | | test.cpp:134:13:134:43 | call to templateFunction | test.cpp:134:13:134:43 | call to templateFunction | provenance | | | test.cpp:134:13:134:43 | call to templateFunction | test.cpp:135:10:135:10 | y | provenance | Sink:MaD:1 | -| test.cpp:134:45:134:45 | x | test.cpp:134:13:134:43 | call to templateFunction | provenance | MaD:66 | -| test.cpp:146:10:146:18 | call to ymlSource | test.cpp:146:10:146:18 | call to ymlSource | provenance | Src:MaD:32 | +| test.cpp:134:45:134:45 | x | test.cpp:134:13:134:43 | call to templateFunction | provenance | MaD:68 | +| test.cpp:146:10:146:18 | call to ymlSource | test.cpp:146:10:146:18 | call to ymlSource | provenance | Src:MaD:34 | | test.cpp:146:10:146:18 | call to ymlSource | test.cpp:148:26:148:26 | x | provenance | | | test.cpp:148:10:148:27 | call to function | test.cpp:148:10:148:27 | call to function | provenance | | | test.cpp:148:10:148:27 | call to function | test.cpp:149:10:149:10 | z | provenance | Sink:MaD:1 | -| test.cpp:148:26:148:26 | x | test.cpp:148:10:148:27 | call to function | provenance | MaD:67 | -| test.cpp:155:10:155:18 | call to ymlSource | test.cpp:155:10:155:18 | call to ymlSource | provenance | Src:MaD:32 | +| test.cpp:148:26:148:26 | x | test.cpp:148:10:148:27 | call to function | provenance | MaD:69 | +| test.cpp:155:10:155:18 | call to ymlSource | test.cpp:155:10:155:18 | call to ymlSource | provenance | Src:MaD:34 | | test.cpp:155:10:155:18 | call to ymlSource | test.cpp:157:26:157:26 | x | provenance | | | test.cpp:157:13:157:20 | call to function | test.cpp:157:13:157:20 | call to function | provenance | | | test.cpp:157:13:157:20 | call to function | test.cpp:158:10:158:10 | z | provenance | Sink:MaD:1 | -| test.cpp:157:26:157:26 | x | test.cpp:157:13:157:20 | call to function | provenance | MaD:67 | +| test.cpp:157:26:157:26 | x | test.cpp:157:13:157:20 | call to function | provenance | MaD:69 | | test.cpp:164:34:164:34 | x | test.cpp:165:69:165:69 | x | provenance | | | test.cpp:165:12:165:64 | call to templateFunction2 | test.cpp:164:7:164:7 | *templateFunction3 | provenance | | | test.cpp:165:12:165:64 | call to templateFunction2 | test.cpp:165:12:165:64 | call to templateFunction2 | provenance | | -| test.cpp:165:69:165:69 | x | test.cpp:165:12:165:64 | call to templateFunction2 | provenance | MaD:65 | -| test.cpp:170:10:170:18 | call to ymlSource | test.cpp:170:10:170:18 | call to ymlSource | provenance | Src:MaD:32 | +| test.cpp:165:69:165:69 | x | test.cpp:165:12:165:64 | call to templateFunction2 | provenance | MaD:67 | +| test.cpp:170:10:170:18 | call to ymlSource | test.cpp:170:10:170:18 | call to ymlSource | provenance | Src:MaD:34 | | test.cpp:170:10:170:18 | call to ymlSource | test.cpp:172:51:172:51 | x | provenance | | | test.cpp:172:13:172:44 | call to templateFunction3 | test.cpp:172:13:172:44 | call to templateFunction3 | provenance | | | test.cpp:172:13:172:44 | call to templateFunction3 | test.cpp:173:10:173:10 | y | provenance | Sink:MaD:1 | | test.cpp:172:51:172:51 | x | test.cpp:164:34:164:34 | x | provenance | | -| test.cpp:172:51:172:51 | x | test.cpp:172:13:172:44 | call to templateFunction3 | provenance | MaD:65 | +| test.cpp:172:51:172:51 | x | test.cpp:172:13:172:44 | call to templateFunction3 | provenance | MaD:67 | | test.cpp:186:2:186:2 | *s [post update] [myField] | test.cpp:187:33:187:34 | *& ... [myField] | provenance | | | test.cpp:186:2:186:24 | ... = ... | test.cpp:186:2:186:2 | *s [post update] [myField] | provenance | | -| test.cpp:186:14:186:22 | call to ymlSource | test.cpp:186:2:186:24 | ... = ... | provenance | Src:MaD:32 | +| test.cpp:186:14:186:22 | call to ymlSource | test.cpp:186:2:186:24 | ... = ... | provenance | Src:MaD:34 | | test.cpp:187:10:187:31 | call to read_field_from_struct | test.cpp:187:10:187:31 | call to read_field_from_struct | provenance | | | test.cpp:187:10:187:31 | call to read_field_from_struct | test.cpp:188:10:188:10 | x | provenance | Sink:MaD:1 | -| test.cpp:187:33:187:34 | *& ... [myField] | test.cpp:187:10:187:31 | call to read_field_from_struct | provenance | MaD:57 | +| test.cpp:187:33:187:34 | *& ... [myField] | test.cpp:187:10:187:31 | call to read_field_from_struct | provenance | MaD:59 | | test.cpp:199:2:199:2 | *s [post update] [myField] | test.cpp:200:35:200:36 | *& ... [myField] | provenance | | | test.cpp:199:2:199:24 | ... = ... | test.cpp:199:2:199:2 | *s [post update] [myField] | provenance | | -| test.cpp:199:14:199:22 | call to ymlSource | test.cpp:199:2:199:24 | ... = ... | provenance | Src:MaD:32 | +| test.cpp:199:14:199:22 | call to ymlSource | test.cpp:199:2:199:24 | ... = ... | provenance | Src:MaD:34 | | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | provenance | | | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | test.cpp:201:10:201:10 | x | provenance | Sink:MaD:1 | -| test.cpp:200:35:200:36 | *& ... [myField] | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | provenance | MaD:58 | +| test.cpp:200:35:200:36 | *& ... [myField] | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | provenance | MaD:60 | | test.cpp:216:3:216:4 | get_ptr output argument [value] | test.cpp:217:11:217:12 | *rf [value] | provenance | | -| test.cpp:216:3:216:28 | ... = ... | test.cpp:216:3:216:4 | get_ptr output argument [value] | provenance | MaD:64 | -| test.cpp:216:18:216:26 | call to ymlSource | test.cpp:216:3:216:28 | ... = ... | provenance | Src:MaD:32 | +| test.cpp:216:3:216:28 | ... = ... | test.cpp:216:3:216:4 | get_ptr output argument [value] | provenance | MaD:66 | +| test.cpp:216:18:216:26 | call to ymlSource | test.cpp:216:3:216:28 | ... = ... | provenance | Src:MaD:34 | | test.cpp:217:11:217:12 | *rf [value] | test.cpp:217:14:217:18 | value | provenance | | | test.cpp:217:14:217:18 | value | test.cpp:217:14:217:18 | value | provenance | | | test.cpp:217:14:217:18 | value | test.cpp:218:11:218:11 | x | provenance | Sink:MaD:1 | | test.cpp:222:3:222:3 | operator[] output argument | test.cpp:223:12:223:12 | *s | provenance | | -| test.cpp:222:3:222:20 | ... = ... | test.cpp:222:3:222:3 | operator[] output argument | provenance | MaD:63 | -| test.cpp:222:10:222:20 | call to ymlSource | test.cpp:222:3:222:20 | ... = ... | provenance | Src:MaD:32 | -| test.cpp:223:12:223:12 | *s | test.cpp:223:13:223:15 | call to operator[] | provenance | MaD:62 | +| test.cpp:222:3:222:20 | ... = ... | test.cpp:222:3:222:3 | operator[] output argument | provenance | MaD:65 | +| test.cpp:222:10:222:20 | call to ymlSource | test.cpp:222:3:222:20 | ... = ... | provenance | Src:MaD:34 | +| test.cpp:223:12:223:12 | *s | test.cpp:223:13:223:15 | call to operator[] | provenance | MaD:64 | | test.cpp:223:13:223:15 | call to operator[] | test.cpp:223:13:223:15 | call to operator[] | provenance | | | test.cpp:223:13:223:15 | call to operator[] | test.cpp:224:11:224:11 | c | provenance | Sink:MaD:1 | | windows.cpp:22:15:22:29 | *call to GetCommandLineA | windows.cpp:22:15:22:29 | *call to GetCommandLineA | provenance | Src:MaD:3 | @@ -219,7 +221,7 @@ edges | windows.cpp:22:15:22:29 | *call to GetCommandLineA | windows.cpp:27:36:27:38 | *cmd | provenance | | | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | provenance | | | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | windows.cpp:30:8:30:15 | * ... | provenance | | -| windows.cpp:27:36:27:38 | *cmd | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | provenance | MaD:40 | +| windows.cpp:27:36:27:38 | *cmd | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | provenance | MaD:42 | | windows.cpp:34:17:34:38 | *call to GetEnvironmentStringsA | windows.cpp:34:17:34:38 | *call to GetEnvironmentStringsA | provenance | Src:MaD:4 | | windows.cpp:34:17:34:38 | *call to GetEnvironmentStringsA | windows.cpp:36:10:36:13 | * ... | provenance | | | windows.cpp:39:36:39:38 | GetEnvironmentVariableA output argument | windows.cpp:41:10:41:13 | * ... | provenance | Src:MaD:5 | @@ -239,11 +241,11 @@ edges | windows.cpp:189:21:189:26 | ReadFile output argument | windows.cpp:190:5:190:56 | *... = ... | provenance | Src:MaD:17 | | windows.cpp:190:5:190:14 | *overlapped [post update] [*hEvent] | windows.cpp:192:53:192:63 | *& ... [*hEvent] | provenance | | | windows.cpp:190:5:190:56 | *... = ... | windows.cpp:190:5:190:14 | *overlapped [post update] [*hEvent] | provenance | | -| windows.cpp:192:53:192:63 | *& ... [*hEvent] | windows.cpp:147:16:147:27 | *lpOverlapped [*hEvent] | provenance | MaD:44 | +| windows.cpp:192:53:192:63 | *& ... [*hEvent] | windows.cpp:147:16:147:27 | *lpOverlapped [*hEvent] | provenance | MaD:46 | | windows.cpp:198:21:198:26 | ReadFile output argument | windows.cpp:199:5:199:57 | ... = ... | provenance | Src:MaD:17 | | windows.cpp:199:5:199:14 | *overlapped [post update] [hEvent] | windows.cpp:201:53:201:63 | *& ... [hEvent] | provenance | | | windows.cpp:199:5:199:57 | ... = ... | windows.cpp:199:5:199:14 | *overlapped [post update] [hEvent] | provenance | | -| windows.cpp:201:53:201:63 | *& ... [hEvent] | windows.cpp:157:16:157:27 | *lpOverlapped [hEvent] | provenance | MaD:44 | +| windows.cpp:201:53:201:63 | *& ... [hEvent] | windows.cpp:157:16:157:27 | *lpOverlapped [hEvent] | provenance | MaD:46 | | windows.cpp:209:84:209:89 | NtReadFile output argument | windows.cpp:211:10:211:16 | * ... | provenance | Src:MaD:16 | | windows.cpp:286:23:286:35 | *call to MapViewOfFile | windows.cpp:286:23:286:35 | *call to MapViewOfFile | provenance | Src:MaD:12 | | windows.cpp:286:23:286:35 | *call to MapViewOfFile | windows.cpp:287:20:287:52 | *pMapView | provenance | | @@ -280,9 +282,9 @@ edges | windows.cpp:431:3:431:3 | *s [post update] [x] | windows.cpp:464:7:464:8 | *& ... [x] | provenance | | | windows.cpp:431:3:431:16 | ... = ... | windows.cpp:431:3:431:3 | *s [post update] [x] | provenance | | | windows.cpp:431:9:431:14 | call to source | windows.cpp:431:3:431:16 | ... = ... | provenance | | -| windows.cpp:439:7:439:8 | *& ... [x] | windows.cpp:403:26:403:36 | *lpParameter [x] | provenance | MaD:43 | -| windows.cpp:451:7:451:8 | *& ... [x] | windows.cpp:410:26:410:36 | *lpParameter [x] | provenance | MaD:41 | -| windows.cpp:464:7:464:8 | *& ... [x] | windows.cpp:417:26:417:36 | *lpParameter [x] | provenance | MaD:42 | +| windows.cpp:439:7:439:8 | *& ... [x] | windows.cpp:403:26:403:36 | *lpParameter [x] | provenance | MaD:45 | +| windows.cpp:451:7:451:8 | *& ... [x] | windows.cpp:410:26:410:36 | *lpParameter [x] | provenance | MaD:43 | +| windows.cpp:464:7:464:8 | *& ... [x] | windows.cpp:417:26:417:36 | *lpParameter [x] | provenance | MaD:44 | | windows.cpp:533:11:533:16 | call to source | windows.cpp:533:11:533:16 | call to source | provenance | | | windows.cpp:533:11:533:16 | call to source | windows.cpp:537:40:537:41 | *& ... | provenance | | | windows.cpp:533:11:533:16 | call to source | windows.cpp:542:38:542:39 | *& ... | provenance | | @@ -291,39 +293,39 @@ edges | windows.cpp:533:11:533:16 | call to source | windows.cpp:568:32:568:33 | *& ... | provenance | | | windows.cpp:533:11:533:16 | call to source | windows.cpp:573:40:573:41 | *& ... | provenance | | | windows.cpp:537:27:537:37 | RtlCopyVolatileMemory output argument | windows.cpp:538:10:538:23 | access to array | provenance | | -| windows.cpp:537:40:537:41 | *& ... | windows.cpp:537:27:537:37 | RtlCopyVolatileMemory output argument | provenance | MaD:49 | +| windows.cpp:537:40:537:41 | *& ... | windows.cpp:537:27:537:37 | RtlCopyVolatileMemory output argument | provenance | MaD:51 | | windows.cpp:542:25:542:35 | RtlCopyDeviceMemory output argument | windows.cpp:543:10:543:23 | access to array | provenance | | -| windows.cpp:542:38:542:39 | *& ... | windows.cpp:542:25:542:35 | RtlCopyDeviceMemory output argument | provenance | MaD:45 | +| windows.cpp:542:38:542:39 | *& ... | windows.cpp:542:25:542:35 | RtlCopyDeviceMemory output argument | provenance | MaD:47 | | windows.cpp:547:19:547:29 | RtlCopyMemory output argument | windows.cpp:548:10:548:23 | access to array | provenance | | -| windows.cpp:547:32:547:33 | *& ... | windows.cpp:547:19:547:29 | RtlCopyMemory output argument | provenance | MaD:46 | +| windows.cpp:547:32:547:33 | *& ... | windows.cpp:547:19:547:29 | RtlCopyMemory output argument | provenance | MaD:48 | | windows.cpp:552:30:552:40 | RtlCopyMemoryNonTemporal output argument | windows.cpp:553:10:553:23 | access to array | provenance | | -| windows.cpp:552:43:552:44 | *& ... | windows.cpp:552:30:552:40 | RtlCopyMemoryNonTemporal output argument | provenance | MaD:47 | +| windows.cpp:552:43:552:44 | *& ... | windows.cpp:552:30:552:40 | RtlCopyMemoryNonTemporal output argument | provenance | MaD:49 | | windows.cpp:559:5:559:24 | ... = ... | windows.cpp:561:39:561:44 | *buffer | provenance | | | windows.cpp:559:17:559:24 | call to source | windows.cpp:559:5:559:24 | ... = ... | provenance | | | windows.cpp:561:26:561:36 | RtlInitUnicodeString output argument [*Buffer] | windows.cpp:562:10:562:19 | *src_string [*Buffer] | provenance | | | windows.cpp:561:26:561:36 | RtlInitUnicodeString output argument [*Buffer] | windows.cpp:563:40:563:50 | *& ... [*Buffer] | provenance | | -| windows.cpp:561:39:561:44 | *buffer | windows.cpp:561:26:561:36 | RtlInitUnicodeString output argument [*Buffer] | provenance | MaD:50 | +| windows.cpp:561:39:561:44 | *buffer | windows.cpp:561:26:561:36 | RtlInitUnicodeString output argument [*Buffer] | provenance | MaD:52 | | windows.cpp:562:10:562:19 | *src_string [*Buffer] | windows.cpp:562:10:562:29 | access to array | provenance | | | windows.cpp:562:10:562:19 | *src_string [*Buffer] | windows.cpp:562:21:562:26 | *Buffer | provenance | | | windows.cpp:562:21:562:26 | *Buffer | windows.cpp:562:10:562:29 | access to array | provenance | | | windows.cpp:563:26:563:37 | RtlCopyUnicodeString output argument [*Buffer] | windows.cpp:564:10:564:20 | *dest_string [*Buffer] | provenance | | -| windows.cpp:563:40:563:50 | *& ... [*Buffer] | windows.cpp:563:26:563:37 | RtlCopyUnicodeString output argument [*Buffer] | provenance | MaD:48 | +| windows.cpp:563:40:563:50 | *& ... [*Buffer] | windows.cpp:563:26:563:37 | RtlCopyUnicodeString output argument [*Buffer] | provenance | MaD:50 | | windows.cpp:564:10:564:20 | *dest_string [*Buffer] | windows.cpp:564:10:564:30 | access to array | provenance | | | windows.cpp:564:10:564:20 | *dest_string [*Buffer] | windows.cpp:564:22:564:27 | *Buffer | provenance | | | windows.cpp:564:22:564:27 | *Buffer | windows.cpp:564:10:564:30 | access to array | provenance | | | windows.cpp:568:19:568:29 | RtlMoveMemory output argument | windows.cpp:569:10:569:23 | access to array | provenance | | -| windows.cpp:568:32:568:33 | *& ... | windows.cpp:568:19:568:29 | RtlMoveMemory output argument | provenance | MaD:51 | +| windows.cpp:568:32:568:33 | *& ... | windows.cpp:568:19:568:29 | RtlMoveMemory output argument | provenance | MaD:53 | | windows.cpp:573:27:573:37 | RtlMoveVolatileMemory output argument | windows.cpp:574:10:574:23 | access to array | provenance | | -| windows.cpp:573:40:573:41 | *& ... | windows.cpp:573:27:573:37 | RtlMoveVolatileMemory output argument | provenance | MaD:52 | -| windows.cpp:645:45:645:50 | WinHttpReadData output argument | windows.cpp:647:10:647:16 | * ... | provenance | Src:MaD:30 | -| windows.cpp:652:48:652:53 | WinHttpReadDataEx output argument | windows.cpp:654:10:654:16 | * ... | provenance | Src:MaD:31 | -| windows.cpp:659:47:659:52 | WinHttpQueryHeaders output argument | windows.cpp:661:10:661:16 | * ... | provenance | Src:MaD:26 | -| windows.cpp:669:70:669:79 | WinHttpQueryHeadersEx output argument | windows.cpp:673:10:673:29 | * ... | provenance | Src:MaD:28 | -| windows.cpp:669:82:669:87 | WinHttpQueryHeadersEx output argument | windows.cpp:671:10:671:16 | * ... | provenance | Src:MaD:29 | -| windows.cpp:669:105:669:112 | WinHttpQueryHeadersEx output argument | windows.cpp:675:10:675:27 | * ... | provenance | Src:MaD:27 | +| windows.cpp:573:40:573:41 | *& ... | windows.cpp:573:27:573:37 | RtlMoveVolatileMemory output argument | provenance | MaD:54 | +| windows.cpp:645:45:645:50 | WinHttpReadData output argument | windows.cpp:647:10:647:16 | * ... | provenance | Src:MaD:32 | +| windows.cpp:652:48:652:53 | WinHttpReadDataEx output argument | windows.cpp:654:10:654:16 | * ... | provenance | Src:MaD:33 | +| windows.cpp:659:47:659:52 | WinHttpQueryHeaders output argument | windows.cpp:661:10:661:16 | * ... | provenance | Src:MaD:28 | +| windows.cpp:669:70:669:79 | WinHttpQueryHeadersEx output argument | windows.cpp:673:10:673:29 | * ... | provenance | Src:MaD:30 | +| windows.cpp:669:82:669:87 | WinHttpQueryHeadersEx output argument | windows.cpp:671:10:671:16 | * ... | provenance | Src:MaD:31 | +| windows.cpp:669:105:669:112 | WinHttpQueryHeadersEx output argument | windows.cpp:675:10:675:27 | * ... | provenance | Src:MaD:29 | | windows.cpp:728:5:728:28 | ... = ... | windows.cpp:729:35:729:35 | *x | provenance | | | windows.cpp:728:12:728:28 | call to source | windows.cpp:728:5:728:28 | ... = ... | provenance | | -| windows.cpp:729:35:729:35 | *x | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | provenance | MaD:53 | +| windows.cpp:729:35:729:35 | *x | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | provenance | MaD:55 | | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | windows.cpp:731:10:731:36 | * ... | provenance | | | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | windows.cpp:733:10:733:35 | * ... | provenance | | | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | windows.cpp:735:10:735:37 | * ... | provenance | | @@ -344,13 +346,16 @@ edges | windows.cpp:936:70:936:78 | HttpReceiveClientCertificate output argument | windows.cpp:937:15:937:48 | *& ... | provenance | Src:MaD:6 | | windows.cpp:936:70:936:78 | HttpReceiveClientCertificate output argument | windows.cpp:941:10:941:31 | * ... | provenance | Src:MaD:6 | | windows.cpp:937:15:937:48 | *& ... | windows.cpp:939:10:939:11 | * ... | provenance | | -| windows.cpp:994:35:994:38 | RegQueryValueA output argument | windows.cpp:996:10:996:14 | * ... | provenance | Src:MaD:22 | -| windows.cpp:1001:36:1001:39 | RegQueryValueW output argument | windows.cpp:1003:10:1003:14 | * ... | provenance | Src:MaD:25 | -| windows.cpp:1009:53:1009:56 | RegQueryValueExA output argument | windows.cpp:1011:10:1011:14 | * ... | provenance | Src:MaD:23 | -| windows.cpp:1017:54:1017:57 | RegQueryValueExW output argument | windows.cpp:1019:10:1019:14 | * ... | provenance | Src:MaD:24 | -| windows.cpp:1025:46:1025:49 | RegQueryMultipleValuesA output argument | windows.cpp:1027:10:1027:14 | * ... | provenance | Src:MaD:20 | -| windows.cpp:1033:46:1033:49 | RegQueryMultipleValuesW output argument | windows.cpp:1035:10:1035:14 | * ... | provenance | Src:MaD:21 | -| windows.cpp:1041:53:1041:56 | RegGetValueA output argument | windows.cpp:1043:10:1043:14 | * ... | provenance | Src:MaD:19 | +| windows.cpp:1004:35:1004:38 | RegQueryValueA output argument | windows.cpp:1006:10:1006:14 | * ... | provenance | Src:MaD:24 | +| windows.cpp:1011:36:1011:39 | RegQueryValueW output argument | windows.cpp:1013:10:1013:14 | * ... | provenance | Src:MaD:27 | +| windows.cpp:1019:53:1019:56 | RegQueryValueExA output argument | windows.cpp:1021:10:1021:14 | * ... | provenance | Src:MaD:25 | +| windows.cpp:1027:54:1027:57 | RegQueryValueExW output argument | windows.cpp:1029:10:1029:14 | * ... | provenance | Src:MaD:26 | +| windows.cpp:1035:46:1035:49 | RegQueryMultipleValuesA output argument | windows.cpp:1037:10:1037:14 | * ... | provenance | Src:MaD:22 | +| windows.cpp:1043:46:1043:49 | RegQueryMultipleValuesW output argument | windows.cpp:1045:10:1045:14 | * ... | provenance | Src:MaD:23 | +| windows.cpp:1051:53:1051:56 | RegGetValueA output argument | windows.cpp:1053:10:1053:14 | * ... | provenance | Src:MaD:21 | +| windows.cpp:1060:53:1060:56 | RegGetValueA output argument | windows.cpp:1062:10:1062:14 | * ... | provenance | Src:MaD:21 | +| windows.cpp:1070:71:1070:74 | RegEnumValueA output argument | windows.cpp:1072:10:1072:14 | * ... | provenance | Src:MaD:19 | +| windows.cpp:1080:71:1080:74 | RegEnumValueW output argument | windows.cpp:1082:10:1082:14 | * ... | provenance | Src:MaD:20 | nodes | asio_streams.cpp:87:34:87:44 | read_until output argument | semmle.label | read_until output argument | | asio_streams.cpp:91:7:91:17 | recv_buffer | semmle.label | recv_buffer | @@ -667,20 +672,26 @@ nodes | windows.cpp:937:15:937:48 | *& ... | semmle.label | *& ... | | windows.cpp:939:10:939:11 | * ... | semmle.label | * ... | | windows.cpp:941:10:941:31 | * ... | semmle.label | * ... | -| windows.cpp:994:35:994:38 | RegQueryValueA output argument | semmle.label | RegQueryValueA output argument | -| windows.cpp:996:10:996:14 | * ... | semmle.label | * ... | -| windows.cpp:1001:36:1001:39 | RegQueryValueW output argument | semmle.label | RegQueryValueW output argument | -| windows.cpp:1003:10:1003:14 | * ... | semmle.label | * ... | -| windows.cpp:1009:53:1009:56 | RegQueryValueExA output argument | semmle.label | RegQueryValueExA output argument | -| windows.cpp:1011:10:1011:14 | * ... | semmle.label | * ... | -| windows.cpp:1017:54:1017:57 | RegQueryValueExW output argument | semmle.label | RegQueryValueExW output argument | -| windows.cpp:1019:10:1019:14 | * ... | semmle.label | * ... | -| windows.cpp:1025:46:1025:49 | RegQueryMultipleValuesA output argument | semmle.label | RegQueryMultipleValuesA output argument | -| windows.cpp:1027:10:1027:14 | * ... | semmle.label | * ... | -| windows.cpp:1033:46:1033:49 | RegQueryMultipleValuesW output argument | semmle.label | RegQueryMultipleValuesW output argument | -| windows.cpp:1035:10:1035:14 | * ... | semmle.label | * ... | -| windows.cpp:1041:53:1041:56 | RegGetValueA output argument | semmle.label | RegGetValueA output argument | -| windows.cpp:1043:10:1043:14 | * ... | semmle.label | * ... | +| windows.cpp:1004:35:1004:38 | RegQueryValueA output argument | semmle.label | RegQueryValueA output argument | +| windows.cpp:1006:10:1006:14 | * ... | semmle.label | * ... | +| windows.cpp:1011:36:1011:39 | RegQueryValueW output argument | semmle.label | RegQueryValueW output argument | +| windows.cpp:1013:10:1013:14 | * ... | semmle.label | * ... | +| windows.cpp:1019:53:1019:56 | RegQueryValueExA output argument | semmle.label | RegQueryValueExA output argument | +| windows.cpp:1021:10:1021:14 | * ... | semmle.label | * ... | +| windows.cpp:1027:54:1027:57 | RegQueryValueExW output argument | semmle.label | RegQueryValueExW output argument | +| windows.cpp:1029:10:1029:14 | * ... | semmle.label | * ... | +| windows.cpp:1035:46:1035:49 | RegQueryMultipleValuesA output argument | semmle.label | RegQueryMultipleValuesA output argument | +| windows.cpp:1037:10:1037:14 | * ... | semmle.label | * ... | +| windows.cpp:1043:46:1043:49 | RegQueryMultipleValuesW output argument | semmle.label | RegQueryMultipleValuesW output argument | +| windows.cpp:1045:10:1045:14 | * ... | semmle.label | * ... | +| windows.cpp:1051:53:1051:56 | RegGetValueA output argument | semmle.label | RegGetValueA output argument | +| windows.cpp:1053:10:1053:14 | * ... | semmle.label | * ... | +| windows.cpp:1060:53:1060:56 | RegGetValueA output argument | semmle.label | RegGetValueA output argument | +| windows.cpp:1062:10:1062:14 | * ... | semmle.label | * ... | +| windows.cpp:1070:71:1070:74 | RegEnumValueA output argument | semmle.label | RegEnumValueA output argument | +| windows.cpp:1072:10:1072:14 | * ... | semmle.label | * ... | +| windows.cpp:1080:71:1080:74 | RegEnumValueW output argument | semmle.label | RegEnumValueW output argument | +| windows.cpp:1082:10:1082:14 | * ... | semmle.label | * ... | subpaths | test.cpp:32:41:32:41 | x | test.cpp:7:47:7:52 | value2 | test.cpp:7:5:7:30 | *ymlStepGenerated_with_body | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | | test.cpp:172:51:172:51 | x | test.cpp:164:34:164:34 | x | test.cpp:164:7:164:7 | *templateFunction3 | test.cpp:172:13:172:44 | call to templateFunction3 | diff --git a/cpp/ql/test/library-tests/dataflow/external-models/sources.expected b/cpp/ql/test/library-tests/dataflow/external-models/sources.expected index 54320be20331..1e60cc73dcfa 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/sources.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/sources.expected @@ -43,10 +43,13 @@ | windows.cpp:900:64:900:77 | HttpReceiveHttpRequest output argument | remote | | windows.cpp:929:70:929:75 | HttpReceiveRequestEntityBody output argument | remote | | windows.cpp:936:70:936:78 | HttpReceiveClientCertificate output argument | remote | -| windows.cpp:994:35:994:38 | RegQueryValueA output argument | local | -| windows.cpp:1001:36:1001:39 | RegQueryValueW output argument | local | -| windows.cpp:1009:53:1009:56 | RegQueryValueExA output argument | local | -| windows.cpp:1017:54:1017:57 | RegQueryValueExW output argument | local | -| windows.cpp:1025:46:1025:49 | RegQueryMultipleValuesA output argument | local | -| windows.cpp:1033:46:1033:49 | RegQueryMultipleValuesW output argument | local | -| windows.cpp:1041:53:1041:56 | RegGetValueA output argument | local | +| windows.cpp:1004:35:1004:38 | RegQueryValueA output argument | local | +| windows.cpp:1011:36:1011:39 | RegQueryValueW output argument | local | +| windows.cpp:1019:53:1019:56 | RegQueryValueExA output argument | local | +| windows.cpp:1027:54:1027:57 | RegQueryValueExW output argument | local | +| windows.cpp:1035:46:1035:49 | RegQueryMultipleValuesA output argument | local | +| windows.cpp:1043:46:1043:49 | RegQueryMultipleValuesW output argument | local | +| windows.cpp:1051:53:1051:56 | RegGetValueA output argument | local | +| windows.cpp:1060:53:1060:56 | RegGetValueA output argument | local | +| windows.cpp:1070:71:1070:74 | RegEnumValueA output argument | local | +| windows.cpp:1080:71:1080:74 | RegEnumValueW output argument | local | diff --git a/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp b/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp index f4ed4d909f6c..aaa06105c915 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp +++ b/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp @@ -1059,7 +1059,7 @@ void test_registry_queries(HKEY hKey) { DWORD type; RegGetValueA(hKey, "subkey", "value", 0, &type, data, &dataSize); sink(data); // clean - sink(*data); // $ MISSING: ir + sink(*data); // $ ir } { char valueName[256]; @@ -1069,7 +1069,7 @@ void test_registry_queries(HKEY hKey) { DWORD type; RegEnumValueA(hKey, 0, valueName, &valueNameSize, nullptr, &type, data, &dataSize); sink(data); // clean - sink(*data); // $ MISSING: ir + sink(*data); // $ ir } { wchar_t valueName[256]; @@ -1079,6 +1079,6 @@ void test_registry_queries(HKEY hKey) { DWORD type; RegEnumValueW(hKey, 0, valueName, &valueNameSize, nullptr, &type, data, &dataSize); sink(data); // clean - sink(*data); // $ MISSING: ir + sink(*data); // $ ir } } \ No newline at end of file From 68f197335265abad546d2454f0f0540e555e4f8b Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 30 Jul 2026 13:04:25 +0200 Subject: [PATCH 126/188] tree-sitter-extractor: Support facade AST --- ql/extractor/src/generator.rs | 1 + ruby/extractor/src/generator.rs | 1 + shared/tree-sitter-extractor/src/generator/mod.rs | 13 +++++++++++++ shared/tree-sitter-extractor/src/generator/ql.rs | 8 ++++++++ .../tree-sitter-extractor/src/generator/ql_gen.rs | 10 +++++----- unified/extractor/src/generator.rs | 1 + 6 files changed, 29 insertions(+), 5 deletions(-) diff --git a/ql/extractor/src/generator.rs b/ql/extractor/src/generator.rs index 96ce5319dd19..7f8ca718344c 100644 --- a/ql/extractor/src/generator.rs +++ b/ql/extractor/src/generator.rs @@ -44,6 +44,7 @@ pub fn run(options: Options) -> std::io::Result<()> { languages, options.dbscheme, options.library, + false, // do not use facade AST "run 'scripts/create-extractor-pack.sh' in ql/", ) } diff --git a/ruby/extractor/src/generator.rs b/ruby/extractor/src/generator.rs index 0430afd103e7..0fc6f9d5cc74 100644 --- a/ruby/extractor/src/generator.rs +++ b/ruby/extractor/src/generator.rs @@ -34,6 +34,7 @@ pub fn run(options: Options) -> std::io::Result<()> { languages, options.dbscheme, options.library, + false, // do not use facade AST "run 'make dbscheme' in ql/ruby/", ) } diff --git a/shared/tree-sitter-extractor/src/generator/mod.rs b/shared/tree-sitter-extractor/src/generator/mod.rs index dbecf62569af..bc1d6fc34aab 100644 --- a/shared/tree-sitter-extractor/src/generator/mod.rs +++ b/shared/tree-sitter-extractor/src/generator/mod.rs @@ -18,6 +18,7 @@ pub fn generate( languages: Vec, dbscheme_path: PathBuf, ql_library_path: PathBuf, + use_facade_ast: bool, regenerate_instructions: &str, ) -> std::io::Result<()> { let dbscheme_file = File::create(dbscheme_path).map_err(|e| { @@ -47,6 +48,7 @@ pub fn generate( ql::write( &mut ql_writer, &[ql::TopLevel::Import(ql::Import { + is_private: false, module: "codeql.Locations", alias: Some("L"), })], @@ -122,6 +124,17 @@ pub fn generate( let mut body = vec![]; + let facade_import_name = if use_facade_ast { + format!("FacadeAst::{}", &language.name) + } else { + language.name.clone() // If not using a facade AST, treat the module itself as the facade module. + }; + body.push(ql::TopLevel::Import(ql::Import { + is_private: true, + module: &facade_import_name, + alias: Some("F"), + })); + for c in ql_gen::create_ast_node_class( &ast_node_name, &node_location_table_name, diff --git a/shared/tree-sitter-extractor/src/generator/ql.rs b/shared/tree-sitter-extractor/src/generator/ql.rs index 6a78a4f95f09..5991cab4a6c1 100644 --- a/shared/tree-sitter-extractor/src/generator/ql.rs +++ b/shared/tree-sitter-extractor/src/generator/ql.rs @@ -22,12 +22,16 @@ impl fmt::Display for TopLevel<'_> { #[derive(Clone, Eq, PartialEq, Hash)] pub struct Import<'a> { + pub is_private: bool, pub module: &'a str, pub alias: Option<&'a str>, } impl fmt::Display for Import<'_> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.is_private { + write!(f, "private ")?; + } write!(f, "import {}", &self.module)?; if let Some(name) = &self.alias { write!(f, " as {name}")?; @@ -146,6 +150,9 @@ pub enum Type<'a> { /// A user-defined type. Normal(&'a str), + + /// A normal type with an `F::` prefix. + Facade(&'a str), } impl fmt::Display for Type<'_> { @@ -155,6 +162,7 @@ impl fmt::Display for Type<'_> { Type::String => write!(f, "string"), Type::Normal(name) => write!(f, "{name}"), Type::At(name) => write!(f, "@{name}"), + Type::Facade(name) => write!(f, "F::{name}"), } } } diff --git a/shared/tree-sitter-extractor/src/generator/ql_gen.rs b/shared/tree-sitter-extractor/src/generator/ql_gen.rs index 8f37bf5dff45..73fc5bc0e975 100644 --- a/shared/tree-sitter-extractor/src/generator/ql_gen.rs +++ b/shared/tree-sitter-extractor/src/generator/ql_gen.rs @@ -48,7 +48,7 @@ pub fn create_ast_node_class<'a>( Some(String::from("Gets a field or child node of this node.")), "getAFieldOrChild", false, - Some(ql::Type::Normal("AstNode")), + Some(ql::Type::Facade("AstNode")), ); let get_parent = ql::Predicate { qldoc: Some(String::from("Gets the parent of this element.")), @@ -56,7 +56,7 @@ pub fn create_ast_node_class<'a>( overridden: false, is_private: false, is_final: true, - return_type: Some(ql::Type::Normal("AstNode")), + return_type: Some(ql::Type::Facade("AstNode")), formal_parameters: vec![], body: ql::Expression::Pred( node_parent_table, @@ -659,13 +659,13 @@ fn create_field_getters<'a>( ) -> (ql::Predicate<'a>, Option>) { let return_type = match &field.type_info { node_types::FieldTypeInfo::Single(t) => { - Some(ql::Type::Normal(&nodes.get(t).unwrap().ql_class_name)) + Some(ql::Type::Facade(&nodes.get(t).unwrap().ql_class_name)) } node_types::FieldTypeInfo::Multiple { types: _, dbscheme_union: _, ql_class, - } => Some(ql::Type::Normal(ql_class)), + } => Some(ql::Type::Facade(ql_class)), node_types::FieldTypeInfo::ReservedWordInt(_) => Some(ql::Type::String), }; let formal_parameters = match &field.storage { @@ -911,7 +911,7 @@ pub fn convert_nodes(nodes: &node_types::NodeTypeMap) -> Vec> { overridden: true, is_private: false, is_final: true, - return_type: Some(ql::Type::Normal("AstNode")), + return_type: Some(ql::Type::Facade("AstNode")), formal_parameters: vec![], body: ql::Expression::Or(get_child_exprs), overlay: None, diff --git a/unified/extractor/src/generator.rs b/unified/extractor/src/generator.rs index 974de5dbca97..f1f8a34ca84d 100644 --- a/unified/extractor/src/generator.rs +++ b/unified/extractor/src/generator.rs @@ -35,6 +35,7 @@ pub fn run(options: Options) -> std::io::Result<()> { languages, options.dbscheme, options.library, + true, // use facade AST "run unified/scripts/create-extractor-pack.sh", ) } From eba3f20411a8614dccfff6250715dc3fa1e479e5 Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 30 Jul 2026 13:05:51 +0200 Subject: [PATCH 127/188] Regenerate AST classes --- .../src/codeql_ql/ast/internal/TreeSitter.qll | 506 +++++++-------- .../codeql/ruby/ast/internal/TreeSitter.qll | 576 +++++++++--------- unified/ql/lib/codeql/unified/Ast.qll | 478 ++++++++------- 3 files changed, 804 insertions(+), 756 deletions(-) diff --git a/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll b/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll index e2aedc401f7a..7452f7b290b2 100644 --- a/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll +++ b/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll @@ -25,6 +25,8 @@ private predicate discardLocation(@location_default loc) { overlay[local] module QL { + private import QL as F + /** The base class for all AST nodes */ private class AstNodeImpl extends @ql_ast_node { /** Gets a string representation of this element. */ @@ -34,13 +36,13 @@ module QL { final L::Location getLocation() { ql_ast_node_location(this, result) } /** Gets the parent of this element. */ - final AstNode getParent() { ql_ast_node_parent(this, result, _) } + final F::AstNode getParent() { ql_ast_node_parent(this, result, _) } /** Gets the index of this node among the children of its parent. */ final int getParentIndex() { ql_ast_node_parent(this, _, result) } /** Gets a field or child node of this node. */ - AstNode getAFieldOrChild() { none() } + F::AstNode getAFieldOrChild() { none() } /** Gets the name of the primary QL class for this element. */ string getAPrimaryQlClass() { result = "???" } @@ -97,16 +99,16 @@ module QL { final override string getAPrimaryQlClass() { result = "AddExpr" } /** Gets the node corresponding to the field `left`. */ - final AstNode getLeft() { ql_add_expr_def(this, result, _, _) } + final F::AstNode getLeft() { ql_add_expr_def(this, result, _, _) } /** Gets the node corresponding to the field `right`. */ - final AstNode getRight() { ql_add_expr_def(this, _, result, _) } + final F::AstNode getRight() { ql_add_expr_def(this, _, result, _) } /** Gets the child of this node. */ - final Addop getChild() { ql_add_expr_def(this, _, _, result) } + final F::Addop getChild() { ql_add_expr_def(this, _, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_add_expr_def(this, result, _, _) or ql_add_expr_def(this, _, result, _) or ql_add_expr_def(this, _, _, result) @@ -131,10 +133,10 @@ module QL { final override string getAPrimaryQlClass() { result = "Aggregate" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_aggregate_child(this, i, result) } + final F::AstNode getChild(int i) { ql_aggregate_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_aggregate_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ql_aggregate_child(this, _, result) } } /** A class representing `annotArg` nodes. */ @@ -143,10 +145,10 @@ module QL { final override string getAPrimaryQlClass() { result = "AnnotArg" } /** Gets the child of this node. */ - final AstNode getChild() { ql_annot_arg_def(this, result) } + final F::AstNode getChild() { ql_annot_arg_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_annot_arg_def(this, result) } + final override F::AstNode getAFieldOrChild() { ql_annot_arg_def(this, result) } } /** A class representing `annotName` tokens. */ @@ -161,13 +163,13 @@ module QL { final override string getAPrimaryQlClass() { result = "Annotation" } /** Gets the node corresponding to the field `args`. */ - final AstNode getArgs(int i) { ql_annotation_args(this, i, result) } + final F::AstNode getArgs(int i) { ql_annotation_args(this, i, result) } /** Gets the node corresponding to the field `name`. */ - final AnnotName getName() { ql_annotation_def(this, result) } + final F::AnnotName getName() { ql_annotation_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_annotation_args(this, _, result) or ql_annotation_def(this, result) } } @@ -178,13 +180,13 @@ module QL { final override string getAPrimaryQlClass() { result = "AritylessPredicateExpr" } /** Gets the node corresponding to the field `name`. */ - final LiteralId getName() { ql_arityless_predicate_expr_def(this, result) } + final F::LiteralId getName() { ql_arityless_predicate_expr_def(this, result) } /** Gets the node corresponding to the field `qualifier`. */ - final ModuleExpr getQualifier() { ql_arityless_predicate_expr_qualifier(this, result) } + final F::ModuleExpr getQualifier() { ql_arityless_predicate_expr_qualifier(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_arityless_predicate_expr_def(this, result) or ql_arityless_predicate_expr_qualifier(this, result) } @@ -196,10 +198,10 @@ module QL { final override string getAPrimaryQlClass() { result = "AsExpr" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_as_expr_child(this, i, result) } + final F::AstNode getChild(int i) { ql_as_expr_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_as_expr_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ql_as_expr_child(this, _, result) } } /** A class representing `asExprs` nodes. */ @@ -208,10 +210,10 @@ module QL { final override string getAPrimaryQlClass() { result = "AsExprs" } /** Gets the `i`th child of this node. */ - final AsExpr getChild(int i) { ql_as_exprs_child(this, i, result) } + final F::AsExpr getChild(int i) { ql_as_exprs_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_as_exprs_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ql_as_exprs_child(this, _, result) } } /** A class representing `block_comment` tokens. */ @@ -226,10 +228,10 @@ module QL { final override string getAPrimaryQlClass() { result = "Body" } /** Gets the child of this node. */ - final AstNode getChild() { ql_body_def(this, result) } + final F::AstNode getChild() { ql_body_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_body_def(this, result) } + final override F::AstNode getAFieldOrChild() { ql_body_def(this, result) } } /** A class representing `bool` nodes. */ @@ -238,10 +240,10 @@ module QL { final override string getAPrimaryQlClass() { result = "Bool" } /** Gets the child of this node. */ - final AstNode getChild() { ql_bool_def(this, result) } + final F::AstNode getChild() { ql_bool_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_bool_def(this, result) } + final override F::AstNode getAFieldOrChild() { ql_bool_def(this, result) } } /** A class representing `call_body` nodes. */ @@ -250,10 +252,10 @@ module QL { final override string getAPrimaryQlClass() { result = "CallBody" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_call_body_child(this, i, result) } + final F::AstNode getChild(int i) { ql_call_body_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_call_body_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ql_call_body_child(this, _, result) } } /** A class representing `call_or_unqual_agg_expr` nodes. */ @@ -262,10 +264,12 @@ module QL { final override string getAPrimaryQlClass() { result = "CallOrUnqualAggExpr" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_call_or_unqual_agg_expr_child(this, i, result) } + final F::AstNode getChild(int i) { ql_call_or_unqual_agg_expr_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_call_or_unqual_agg_expr_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { + ql_call_or_unqual_agg_expr_child(this, _, result) + } } /** A class representing `charpred` nodes. */ @@ -274,13 +278,13 @@ module QL { final override string getAPrimaryQlClass() { result = "Charpred" } /** Gets the node corresponding to the field `body`. */ - final AstNode getBody() { ql_charpred_def(this, result, _) } + final F::AstNode getBody() { ql_charpred_def(this, result, _) } /** Gets the child of this node. */ - final ClassName getChild() { ql_charpred_def(this, _, result) } + final F::ClassName getChild() { ql_charpred_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_charpred_def(this, result, _) or ql_charpred_def(this, _, result) } } @@ -291,10 +295,10 @@ module QL { final override string getAPrimaryQlClass() { result = "ClassMember" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_class_member_child(this, i, result) } + final F::AstNode getChild(int i) { ql_class_member_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_class_member_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ql_class_member_child(this, _, result) } } /** A class representing `className` tokens. */ @@ -309,16 +313,16 @@ module QL { final override string getAPrimaryQlClass() { result = "ClasslessPredicate" } /** Gets the node corresponding to the field `name`. */ - final PredicateName getName() { ql_classless_predicate_def(this, result, _) } + final F::PredicateName getName() { ql_classless_predicate_def(this, result, _) } /** Gets the node corresponding to the field `returnType`. */ - final AstNode getReturnType() { ql_classless_predicate_def(this, _, result) } + final F::AstNode getReturnType() { ql_classless_predicate_def(this, _, result) } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_classless_predicate_child(this, i, result) } + final F::AstNode getChild(int i) { ql_classless_predicate_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_classless_predicate_def(this, result, _) or ql_classless_predicate_def(this, _, result) or ql_classless_predicate_child(this, _, result) @@ -337,16 +341,16 @@ module QL { final override string getAPrimaryQlClass() { result = "CompTerm" } /** Gets the node corresponding to the field `left`. */ - final AstNode getLeft() { ql_comp_term_def(this, result, _, _) } + final F::AstNode getLeft() { ql_comp_term_def(this, result, _, _) } /** Gets the node corresponding to the field `right`. */ - final AstNode getRight() { ql_comp_term_def(this, _, result, _) } + final F::AstNode getRight() { ql_comp_term_def(this, _, result, _) } /** Gets the child of this node. */ - final Compop getChild() { ql_comp_term_def(this, _, _, result) } + final F::Compop getChild() { ql_comp_term_def(this, _, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_comp_term_def(this, result, _, _) or ql_comp_term_def(this, _, result, _) or ql_comp_term_def(this, _, _, result) @@ -365,13 +369,13 @@ module QL { final override string getAPrimaryQlClass() { result = "Conjunction" } /** Gets the node corresponding to the field `left`. */ - final AstNode getLeft() { ql_conjunction_def(this, result, _) } + final F::AstNode getLeft() { ql_conjunction_def(this, result, _) } /** Gets the node corresponding to the field `right`. */ - final AstNode getRight() { ql_conjunction_def(this, _, result) } + final F::AstNode getRight() { ql_conjunction_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_conjunction_def(this, result, _) or ql_conjunction_def(this, _, result) } } @@ -382,19 +386,19 @@ module QL { final override string getAPrimaryQlClass() { result = "Dataclass" } /** Gets the node corresponding to the field `extends`. */ - final AstNode getExtends(int i) { ql_dataclass_extends(this, i, result) } + final F::AstNode getExtends(int i) { ql_dataclass_extends(this, i, result) } /** Gets the node corresponding to the field `instanceof`. */ - final AstNode getInstanceof(int i) { ql_dataclass_instanceof(this, i, result) } + final F::AstNode getInstanceof(int i) { ql_dataclass_instanceof(this, i, result) } /** Gets the node corresponding to the field `name`. */ - final ClassName getName() { ql_dataclass_def(this, result) } + final F::ClassName getName() { ql_dataclass_def(this, result) } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_dataclass_child(this, i, result) } + final F::AstNode getChild(int i) { ql_dataclass_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_dataclass_extends(this, _, result) or ql_dataclass_instanceof(this, _, result) or ql_dataclass_def(this, result) or @@ -408,13 +412,13 @@ module QL { final override string getAPrimaryQlClass() { result = "Datatype" } /** Gets the node corresponding to the field `name`. */ - final ClassName getName() { ql_datatype_def(this, result, _) } + final F::ClassName getName() { ql_datatype_def(this, result, _) } /** Gets the child of this node. */ - final DatatypeBranches getChild() { ql_datatype_def(this, _, result) } + final F::DatatypeBranches getChild() { ql_datatype_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_datatype_def(this, result, _) or ql_datatype_def(this, _, result) } } @@ -425,13 +429,13 @@ module QL { final override string getAPrimaryQlClass() { result = "DatatypeBranch" } /** Gets the node corresponding to the field `name`. */ - final ClassName getName() { ql_datatype_branch_def(this, result) } + final F::ClassName getName() { ql_datatype_branch_def(this, result) } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_datatype_branch_child(this, i, result) } + final F::AstNode getChild(int i) { ql_datatype_branch_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_datatype_branch_def(this, result) or ql_datatype_branch_child(this, _, result) } } @@ -442,10 +446,10 @@ module QL { final override string getAPrimaryQlClass() { result = "DatatypeBranches" } /** Gets the `i`th child of this node. */ - final DatatypeBranch getChild(int i) { ql_datatype_branches_child(this, i, result) } + final F::DatatypeBranch getChild(int i) { ql_datatype_branches_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_datatype_branches_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ql_datatype_branches_child(this, _, result) } } /** A class representing `dbtype` tokens. */ @@ -466,13 +470,13 @@ module QL { final override string getAPrimaryQlClass() { result = "Disjunction" } /** Gets the node corresponding to the field `left`. */ - final AstNode getLeft() { ql_disjunction_def(this, result, _) } + final F::AstNode getLeft() { ql_disjunction_def(this, result, _) } /** Gets the node corresponding to the field `right`. */ - final AstNode getRight() { ql_disjunction_def(this, _, result) } + final F::AstNode getRight() { ql_disjunction_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_disjunction_def(this, result, _) or ql_disjunction_def(this, _, result) } } @@ -489,13 +493,13 @@ module QL { final override string getAPrimaryQlClass() { result = "ExprAggregateBody" } /** Gets the node corresponding to the field `asExprs`. */ - final AsExprs getAsExprs() { ql_expr_aggregate_body_def(this, result) } + final F::AsExprs getAsExprs() { ql_expr_aggregate_body_def(this, result) } /** Gets the node corresponding to the field `orderBys`. */ - final OrderBys getOrderBys() { ql_expr_aggregate_body_order_bys(this, result) } + final F::OrderBys getOrderBys() { ql_expr_aggregate_body_order_bys(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_expr_aggregate_body_def(this, result) or ql_expr_aggregate_body_order_bys(this, result) } } @@ -506,16 +510,16 @@ module QL { final override string getAPrimaryQlClass() { result = "ExprAnnotation" } /** Gets the node corresponding to the field `annot_arg`. */ - final AnnotName getAnnotArg() { ql_expr_annotation_def(this, result, _, _) } + final F::AnnotName getAnnotArg() { ql_expr_annotation_def(this, result, _, _) } /** Gets the node corresponding to the field `name`. */ - final AnnotName getName() { ql_expr_annotation_def(this, _, result, _) } + final F::AnnotName getName() { ql_expr_annotation_def(this, _, result, _) } /** Gets the child of this node. */ - final AstNode getChild() { ql_expr_annotation_def(this, _, _, result) } + final F::AstNode getChild() { ql_expr_annotation_def(this, _, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_expr_annotation_def(this, result, _, _) or ql_expr_annotation_def(this, _, result, _) or ql_expr_annotation_def(this, _, _, result) @@ -534,10 +538,10 @@ module QL { final override string getAPrimaryQlClass() { result = "Field" } /** Gets the child of this node. */ - final VarDecl getChild() { ql_field_def(this, result) } + final F::VarDecl getChild() { ql_field_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_field_def(this, result) } + final override F::AstNode getAFieldOrChild() { ql_field_def(this, result) } } /** A class representing `float` tokens. */ @@ -552,19 +556,19 @@ module QL { final override string getAPrimaryQlClass() { result = "FullAggregateBody" } /** Gets the node corresponding to the field `asExprs`. */ - final AsExprs getAsExprs() { ql_full_aggregate_body_as_exprs(this, result) } + final F::AsExprs getAsExprs() { ql_full_aggregate_body_as_exprs(this, result) } /** Gets the node corresponding to the field `guard`. */ - final AstNode getGuard() { ql_full_aggregate_body_guard(this, result) } + final F::AstNode getGuard() { ql_full_aggregate_body_guard(this, result) } /** Gets the node corresponding to the field `orderBys`. */ - final OrderBys getOrderBys() { ql_full_aggregate_body_order_bys(this, result) } + final F::OrderBys getOrderBys() { ql_full_aggregate_body_order_bys(this, result) } /** Gets the `i`th child of this node. */ - final VarDecl getChild(int i) { ql_full_aggregate_body_child(this, i, result) } + final F::VarDecl getChild(int i) { ql_full_aggregate_body_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_full_aggregate_body_as_exprs(this, result) or ql_full_aggregate_body_guard(this, result) or ql_full_aggregate_body_order_bys(this, result) or @@ -578,13 +582,13 @@ module QL { final override string getAPrimaryQlClass() { result = "HigherOrderTerm" } /** Gets the node corresponding to the field `name`. */ - final LiteralId getName() { ql_higher_order_term_def(this, result) } + final F::LiteralId getName() { ql_higher_order_term_def(this, result) } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_higher_order_term_child(this, i, result) } + final F::AstNode getChild(int i) { ql_higher_order_term_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_higher_order_term_def(this, result) or ql_higher_order_term_child(this, _, result) } } @@ -595,16 +599,16 @@ module QL { final override string getAPrimaryQlClass() { result = "IfTerm" } /** Gets the node corresponding to the field `cond`. */ - final AstNode getCond() { ql_if_term_def(this, result, _, _) } + final F::AstNode getCond() { ql_if_term_def(this, result, _, _) } /** Gets the node corresponding to the field `first`. */ - final AstNode getFirst() { ql_if_term_def(this, _, result, _) } + final F::AstNode getFirst() { ql_if_term_def(this, _, result, _) } /** Gets the node corresponding to the field `second`. */ - final AstNode getSecond() { ql_if_term_def(this, _, _, result) } + final F::AstNode getSecond() { ql_if_term_def(this, _, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_if_term_def(this, result, _, _) or ql_if_term_def(this, _, result, _) or ql_if_term_def(this, _, _, result) @@ -617,13 +621,13 @@ module QL { final override string getAPrimaryQlClass() { result = "Implication" } /** Gets the node corresponding to the field `left`. */ - final AstNode getLeft() { ql_implication_def(this, result, _) } + final F::AstNode getLeft() { ql_implication_def(this, result, _) } /** Gets the node corresponding to the field `right`. */ - final AstNode getRight() { ql_implication_def(this, _, result) } + final F::AstNode getRight() { ql_implication_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_implication_def(this, result, _) or ql_implication_def(this, _, result) } } @@ -634,10 +638,10 @@ module QL { final override string getAPrimaryQlClass() { result = "ImportDirective" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_import_directive_child(this, i, result) } + final F::AstNode getChild(int i) { ql_import_directive_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_import_directive_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ql_import_directive_child(this, _, result) } } /** A class representing `importModuleExpr` nodes. */ @@ -646,13 +650,13 @@ module QL { final override string getAPrimaryQlClass() { result = "ImportModuleExpr" } /** Gets the node corresponding to the field `qualName`. */ - final SimpleId getQualName(int i) { ql_import_module_expr_qual_name(this, i, result) } + final F::SimpleId getQualName(int i) { ql_import_module_expr_qual_name(this, i, result) } /** Gets the child of this node. */ - final ModuleExpr getChild() { ql_import_module_expr_def(this, result) } + final F::ModuleExpr getChild() { ql_import_module_expr_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_import_module_expr_qual_name(this, _, result) or ql_import_module_expr_def(this, result) } } @@ -663,13 +667,13 @@ module QL { final override string getAPrimaryQlClass() { result = "InExpr" } /** Gets the node corresponding to the field `left`. */ - final AstNode getLeft() { ql_in_expr_def(this, result, _) } + final F::AstNode getLeft() { ql_in_expr_def(this, result, _) } /** Gets the node corresponding to the field `right`. */ - final AstNode getRight() { ql_in_expr_def(this, _, result) } + final F::AstNode getRight() { ql_in_expr_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_in_expr_def(this, result, _) or ql_in_expr_def(this, _, result) } } @@ -680,10 +684,10 @@ module QL { final override string getAPrimaryQlClass() { result = "InstanceOf" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_instance_of_child(this, i, result) } + final F::AstNode getChild(int i) { ql_instance_of_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_instance_of_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ql_instance_of_child(this, _, result) } } /** A class representing `integer` tokens. */ @@ -704,10 +708,10 @@ module QL { final override string getAPrimaryQlClass() { result = "Literal" } /** Gets the child of this node. */ - final AstNode getChild() { ql_literal_def(this, result) } + final F::AstNode getChild() { ql_literal_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_literal_def(this, result) } + final override F::AstNode getAFieldOrChild() { ql_literal_def(this, result) } } /** A class representing `literalId` tokens. */ @@ -722,16 +726,16 @@ module QL { final override string getAPrimaryQlClass() { result = "MemberPredicate" } /** Gets the node corresponding to the field `name`. */ - final PredicateName getName() { ql_member_predicate_def(this, result, _) } + final F::PredicateName getName() { ql_member_predicate_def(this, result, _) } /** Gets the node corresponding to the field `returnType`. */ - final AstNode getReturnType() { ql_member_predicate_def(this, _, result) } + final F::AstNode getReturnType() { ql_member_predicate_def(this, _, result) } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_member_predicate_child(this, i, result) } + final F::AstNode getChild(int i) { ql_member_predicate_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_member_predicate_def(this, result, _) or ql_member_predicate_def(this, _, result) or ql_member_predicate_child(this, _, result) @@ -744,19 +748,19 @@ module QL { final override string getAPrimaryQlClass() { result = "Module" } /** Gets the node corresponding to the field `implements`. */ - final SignatureExpr getImplements(int i) { ql_module_implements(this, i, result) } + final F::SignatureExpr getImplements(int i) { ql_module_implements(this, i, result) } /** Gets the node corresponding to the field `name`. */ - final ModuleName getName() { ql_module_def(this, result) } + final F::ModuleName getName() { ql_module_def(this, result) } /** Gets the node corresponding to the field `parameter`. */ - final ModuleParam getParameter(int i) { ql_module_parameter(this, i, result) } + final F::ModuleParam getParameter(int i) { ql_module_parameter(this, i, result) } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_module_child(this, i, result) } + final F::AstNode getChild(int i) { ql_module_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_module_implements(this, _, result) or ql_module_def(this, result) or ql_module_parameter(this, _, result) or @@ -770,10 +774,10 @@ module QL { final override string getAPrimaryQlClass() { result = "ModuleAliasBody" } /** Gets the child of this node. */ - final ModuleExpr getChild() { ql_module_alias_body_def(this, result) } + final F::ModuleExpr getChild() { ql_module_alias_body_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_module_alias_body_def(this, result) } + final override F::AstNode getAFieldOrChild() { ql_module_alias_body_def(this, result) } } /** A class representing `moduleExpr` nodes. */ @@ -782,13 +786,13 @@ module QL { final override string getAPrimaryQlClass() { result = "ModuleExpr" } /** Gets the node corresponding to the field `name`. */ - final AstNode getName() { ql_module_expr_name(this, result) } + final F::AstNode getName() { ql_module_expr_name(this, result) } /** Gets the child of this node. */ - final AstNode getChild() { ql_module_expr_def(this, result) } + final F::AstNode getChild() { ql_module_expr_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_module_expr_name(this, result) or ql_module_expr_def(this, result) } } @@ -799,13 +803,13 @@ module QL { final override string getAPrimaryQlClass() { result = "ModuleInstantiation" } /** Gets the node corresponding to the field `name`. */ - final ModuleName getName() { ql_module_instantiation_def(this, result) } + final F::ModuleName getName() { ql_module_instantiation_def(this, result) } /** Gets the `i`th child of this node. */ - final SignatureExpr getChild(int i) { ql_module_instantiation_child(this, i, result) } + final F::SignatureExpr getChild(int i) { ql_module_instantiation_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_module_instantiation_def(this, result) or ql_module_instantiation_child(this, _, result) } } @@ -816,10 +820,10 @@ module QL { final override string getAPrimaryQlClass() { result = "ModuleMember" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_module_member_child(this, i, result) } + final F::AstNode getChild(int i) { ql_module_member_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_module_member_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ql_module_member_child(this, _, result) } } /** A class representing `moduleName` nodes. */ @@ -828,10 +832,10 @@ module QL { final override string getAPrimaryQlClass() { result = "ModuleName" } /** Gets the child of this node. */ - final SimpleId getChild() { ql_module_name_def(this, result) } + final F::SimpleId getChild() { ql_module_name_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_module_name_def(this, result) } + final override F::AstNode getAFieldOrChild() { ql_module_name_def(this, result) } } /** A class representing `moduleParam` nodes. */ @@ -840,13 +844,13 @@ module QL { final override string getAPrimaryQlClass() { result = "ModuleParam" } /** Gets the node corresponding to the field `parameter`. */ - final SimpleId getParameter() { ql_module_param_def(this, result, _) } + final F::SimpleId getParameter() { ql_module_param_def(this, result, _) } /** Gets the node corresponding to the field `signature`. */ - final SignatureExpr getSignature() { ql_module_param_def(this, _, result) } + final F::SignatureExpr getSignature() { ql_module_param_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_module_param_def(this, result, _) or ql_module_param_def(this, _, result) } } @@ -857,16 +861,16 @@ module QL { final override string getAPrimaryQlClass() { result = "MulExpr" } /** Gets the node corresponding to the field `left`. */ - final AstNode getLeft() { ql_mul_expr_def(this, result, _, _) } + final F::AstNode getLeft() { ql_mul_expr_def(this, result, _, _) } /** Gets the node corresponding to the field `right`. */ - final AstNode getRight() { ql_mul_expr_def(this, _, result, _) } + final F::AstNode getRight() { ql_mul_expr_def(this, _, result, _) } /** Gets the child of this node. */ - final Mulop getChild() { ql_mul_expr_def(this, _, _, result) } + final F::Mulop getChild() { ql_mul_expr_def(this, _, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_mul_expr_def(this, result, _, _) or ql_mul_expr_def(this, _, result, _) or ql_mul_expr_def(this, _, _, result) @@ -885,10 +889,10 @@ module QL { final override string getAPrimaryQlClass() { result = "Negation" } /** Gets the child of this node. */ - final AstNode getChild() { ql_negation_def(this, result) } + final F::AstNode getChild() { ql_negation_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_negation_def(this, result) } + final override F::AstNode getAFieldOrChild() { ql_negation_def(this, result) } } /** A class representing `orderBy` nodes. */ @@ -897,10 +901,10 @@ module QL { final override string getAPrimaryQlClass() { result = "OrderBy" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_order_by_child(this, i, result) } + final F::AstNode getChild(int i) { ql_order_by_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_order_by_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ql_order_by_child(this, _, result) } } /** A class representing `orderBys` nodes. */ @@ -909,10 +913,10 @@ module QL { final override string getAPrimaryQlClass() { result = "OrderBys" } /** Gets the `i`th child of this node. */ - final OrderBy getChild(int i) { ql_order_bys_child(this, i, result) } + final F::OrderBy getChild(int i) { ql_order_bys_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_order_bys_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ql_order_bys_child(this, _, result) } } /** A class representing `par_expr` nodes. */ @@ -921,10 +925,10 @@ module QL { final override string getAPrimaryQlClass() { result = "ParExpr" } /** Gets the child of this node. */ - final AstNode getChild() { ql_par_expr_def(this, result) } + final F::AstNode getChild() { ql_par_expr_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_par_expr_def(this, result) } + final override F::AstNode getAFieldOrChild() { ql_par_expr_def(this, result) } } /** A class representing `predicate` tokens. */ @@ -939,10 +943,10 @@ module QL { final override string getAPrimaryQlClass() { result = "PredicateAliasBody" } /** Gets the child of this node. */ - final PredicateExpr getChild() { ql_predicate_alias_body_def(this, result) } + final F::PredicateExpr getChild() { ql_predicate_alias_body_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_predicate_alias_body_def(this, result) } + final override F::AstNode getAFieldOrChild() { ql_predicate_alias_body_def(this, result) } } /** A class representing `predicateExpr` nodes. */ @@ -951,10 +955,10 @@ module QL { final override string getAPrimaryQlClass() { result = "PredicateExpr" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_predicate_expr_child(this, i, result) } + final F::AstNode getChild(int i) { ql_predicate_expr_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_predicate_expr_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ql_predicate_expr_child(this, _, result) } } /** A class representing `predicateName` tokens. */ @@ -969,10 +973,10 @@ module QL { final override string getAPrimaryQlClass() { result = "PrefixCast" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_prefix_cast_child(this, i, result) } + final F::AstNode getChild(int i) { ql_prefix_cast_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_prefix_cast_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ql_prefix_cast_child(this, _, result) } } /** A class representing `primitiveType` tokens. */ @@ -987,10 +991,10 @@ module QL { final override string getAPrimaryQlClass() { result = "Ql" } /** Gets the `i`th child of this node. */ - final ModuleMember getChild(int i) { ql_ql_child(this, i, result) } + final F::ModuleMember getChild(int i) { ql_ql_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_ql_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ql_ql_child(this, _, result) } } /** A class representing `qldoc` tokens. */ @@ -1005,13 +1009,13 @@ module QL { final override string getAPrimaryQlClass() { result = "QualifiedRhs" } /** Gets the node corresponding to the field `name`. */ - final PredicateName getName() { ql_qualified_rhs_name(this, result) } + final F::PredicateName getName() { ql_qualified_rhs_name(this, result) } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_qualified_rhs_child(this, i, result) } + final F::AstNode getChild(int i) { ql_qualified_rhs_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_qualified_rhs_name(this, result) or ql_qualified_rhs_child(this, _, result) } } @@ -1022,10 +1026,10 @@ module QL { final override string getAPrimaryQlClass() { result = "QualifiedExpr" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_qualified_expr_child(this, i, result) } + final F::AstNode getChild(int i) { ql_qualified_expr_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_qualified_expr_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ql_qualified_expr_child(this, _, result) } } /** A class representing `quantified` nodes. */ @@ -1034,19 +1038,19 @@ module QL { final override string getAPrimaryQlClass() { result = "Quantified" } /** Gets the node corresponding to the field `expr`. */ - final AstNode getExpr() { ql_quantified_expr(this, result) } + final F::AstNode getExpr() { ql_quantified_expr(this, result) } /** Gets the node corresponding to the field `formula`. */ - final AstNode getFormula() { ql_quantified_formula(this, result) } + final F::AstNode getFormula() { ql_quantified_formula(this, result) } /** Gets the node corresponding to the field `range`. */ - final AstNode getRange() { ql_quantified_range(this, result) } + final F::AstNode getRange() { ql_quantified_range(this, result) } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_quantified_child(this, i, result) } + final F::AstNode getChild(int i) { ql_quantified_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_quantified_expr(this, result) or ql_quantified_formula(this, result) or ql_quantified_range(this, result) or @@ -1066,13 +1070,13 @@ module QL { final override string getAPrimaryQlClass() { result = "Range" } /** Gets the node corresponding to the field `lower`. */ - final AstNode getLower() { ql_range_def(this, result, _) } + final F::AstNode getLower() { ql_range_def(this, result, _) } /** Gets the node corresponding to the field `upper`. */ - final AstNode getUpper() { ql_range_def(this, _, result) } + final F::AstNode getUpper() { ql_range_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_range_def(this, result, _) or ql_range_def(this, _, result) } } @@ -1089,10 +1093,10 @@ module QL { final override string getAPrimaryQlClass() { result = "Select" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_select_child(this, i, result) } + final F::AstNode getChild(int i) { ql_select_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_select_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ql_select_child(this, _, result) } } /** A class representing `set_literal` nodes. */ @@ -1101,10 +1105,10 @@ module QL { final override string getAPrimaryQlClass() { result = "SetLiteral" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_set_literal_child(this, i, result) } + final F::AstNode getChild(int i) { ql_set_literal_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_set_literal_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ql_set_literal_child(this, _, result) } } /** A class representing `signatureExpr` nodes. */ @@ -1113,16 +1117,16 @@ module QL { final override string getAPrimaryQlClass() { result = "SignatureExpr" } /** Gets the node corresponding to the field `mod_expr`. */ - final ModuleExpr getModExpr() { ql_signature_expr_mod_expr(this, result) } + final F::ModuleExpr getModExpr() { ql_signature_expr_mod_expr(this, result) } /** Gets the node corresponding to the field `predicate`. */ - final PredicateExpr getPredicate() { ql_signature_expr_predicate(this, result) } + final F::PredicateExpr getPredicate() { ql_signature_expr_predicate(this, result) } /** Gets the node corresponding to the field `type_expr`. */ - final TypeExpr getTypeExpr() { ql_signature_expr_type_expr(this, result) } + final F::TypeExpr getTypeExpr() { ql_signature_expr_type_expr(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_signature_expr_mod_expr(this, result) or ql_signature_expr_predicate(this, result) or ql_signature_expr_type_expr(this, result) @@ -1147,10 +1151,10 @@ module QL { final override string getAPrimaryQlClass() { result = "SpecialCall" } /** Gets the child of this node. */ - final SpecialId getChild() { ql_special_call_def(this, result) } + final F::SpecialId getChild() { ql_special_call_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_special_call_def(this, result) } + final override F::AstNode getAFieldOrChild() { ql_special_call_def(this, result) } } /** A class representing `string` tokens. */ @@ -1171,10 +1175,10 @@ module QL { final override string getAPrimaryQlClass() { result = "SuperRef" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_super_ref_child(this, i, result) } + final F::AstNode getChild(int i) { ql_super_ref_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_super_ref_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ql_super_ref_child(this, _, result) } } /** A class representing `this` tokens. */ @@ -1195,10 +1199,10 @@ module QL { final override string getAPrimaryQlClass() { result = "TypeAliasBody" } /** Gets the child of this node. */ - final TypeExpr getChild() { ql_type_alias_body_def(this, result) } + final F::TypeExpr getChild() { ql_type_alias_body_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_type_alias_body_def(this, result) } + final override F::AstNode getAFieldOrChild() { ql_type_alias_body_def(this, result) } } /** A class representing `typeExpr` nodes. */ @@ -1207,16 +1211,16 @@ module QL { final override string getAPrimaryQlClass() { result = "TypeExpr" } /** Gets the node corresponding to the field `name`. */ - final ClassName getName() { ql_type_expr_name(this, result) } + final F::ClassName getName() { ql_type_expr_name(this, result) } /** Gets the node corresponding to the field `qualifier`. */ - final ModuleExpr getQualifier() { ql_type_expr_qualifier(this, result) } + final F::ModuleExpr getQualifier() { ql_type_expr_qualifier(this, result) } /** Gets the child of this node. */ - final AstNode getChild() { ql_type_expr_child(this, result) } + final F::AstNode getChild() { ql_type_expr_child(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_type_expr_name(this, result) or ql_type_expr_qualifier(this, result) or ql_type_expr_child(this, result) @@ -1229,10 +1233,10 @@ module QL { final override string getAPrimaryQlClass() { result = "TypeUnionBody" } /** Gets the `i`th child of this node. */ - final TypeExpr getChild(int i) { ql_type_union_body_child(this, i, result) } + final F::TypeExpr getChild(int i) { ql_type_union_body_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_type_union_body_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ql_type_union_body_child(this, _, result) } } /** A class representing `unary_expr` nodes. */ @@ -1241,10 +1245,10 @@ module QL { final override string getAPrimaryQlClass() { result = "UnaryExpr" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_unary_expr_child(this, i, result) } + final F::AstNode getChild(int i) { ql_unary_expr_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_unary_expr_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ql_unary_expr_child(this, _, result) } } /** A class representing `underscore` tokens. */ @@ -1265,16 +1269,16 @@ module QL { final override string getAPrimaryQlClass() { result = "UnqualAggBody" } /** Gets the node corresponding to the field `asExprs`. */ - final AstNode getAsExprs(int i) { ql_unqual_agg_body_as_exprs(this, i, result) } + final F::AstNode getAsExprs(int i) { ql_unqual_agg_body_as_exprs(this, i, result) } /** Gets the node corresponding to the field `guard`. */ - final AstNode getGuard() { ql_unqual_agg_body_guard(this, result) } + final F::AstNode getGuard() { ql_unqual_agg_body_guard(this, result) } /** Gets the `i`th child of this node. */ - final VarDecl getChild(int i) { ql_unqual_agg_body_child(this, i, result) } + final F::VarDecl getChild(int i) { ql_unqual_agg_body_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_unqual_agg_body_as_exprs(this, _, result) or ql_unqual_agg_body_guard(this, result) or ql_unqual_agg_body_child(this, _, result) @@ -1287,10 +1291,10 @@ module QL { final override string getAPrimaryQlClass() { result = "VarDecl" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_var_decl_child(this, i, result) } + final F::AstNode getChild(int i) { ql_var_decl_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_var_decl_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ql_var_decl_child(this, _, result) } } /** A class representing `varName` nodes. */ @@ -1299,10 +1303,10 @@ module QL { final override string getAPrimaryQlClass() { result = "VarName" } /** Gets the child of this node. */ - final SimpleId getChild() { ql_var_name_def(this, result) } + final F::SimpleId getChild() { ql_var_name_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_var_name_def(this, result) } + final override F::AstNode getAFieldOrChild() { ql_var_name_def(this, result) } } /** A class representing `variable` nodes. */ @@ -1311,10 +1315,10 @@ module QL { final override string getAPrimaryQlClass() { result = "Variable" } /** Gets the child of this node. */ - final AstNode getChild() { ql_variable_def(this, result) } + final F::AstNode getChild() { ql_variable_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_variable_def(this, result) } + final override F::AstNode getAFieldOrChild() { ql_variable_def(this, result) } } /** Provides predicates for mapping AST nodes to their named children. */ @@ -1558,6 +1562,8 @@ module QL { overlay[local] module Dbscheme { + private import Dbscheme as F + /** The base class for all AST nodes */ private class AstNodeImpl extends @dbscheme_ast_node { /** Gets a string representation of this element. */ @@ -1567,13 +1573,13 @@ module Dbscheme { final L::Location getLocation() { dbscheme_ast_node_location(this, result) } /** Gets the parent of this element. */ - final AstNode getParent() { dbscheme_ast_node_parent(this, result, _) } + final F::AstNode getParent() { dbscheme_ast_node_parent(this, result, _) } /** Gets the index of this node among the children of its parent. */ final int getParentIndex() { dbscheme_ast_node_parent(this, _, result) } /** Gets a field or child node of this node. */ - AstNode getAFieldOrChild() { none() } + F::AstNode getAFieldOrChild() { none() } /** Gets the name of the primary QL class for this element. */ string getAPrimaryQlClass() { result = "???" } @@ -1636,13 +1642,15 @@ module Dbscheme { final override string getAPrimaryQlClass() { result = "Annotation" } /** Gets the node corresponding to the field `argsAnnotation`. */ - final ArgsAnnotation getArgsAnnotation() { dbscheme_annotation_args_annotation(this, result) } + final F::ArgsAnnotation getArgsAnnotation() { + dbscheme_annotation_args_annotation(this, result) + } /** Gets the node corresponding to the field `simpleAnnotation`. */ - final AnnotName getSimpleAnnotation() { dbscheme_annotation_simple_annotation(this, result) } + final F::AnnotName getSimpleAnnotation() { dbscheme_annotation_simple_annotation(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { dbscheme_annotation_args_annotation(this, result) or dbscheme_annotation_simple_annotation(this, result) } @@ -1654,13 +1662,13 @@ module Dbscheme { final override string getAPrimaryQlClass() { result = "ArgsAnnotation" } /** Gets the node corresponding to the field `name`. */ - final AnnotName getName() { dbscheme_args_annotation_def(this, result) } + final F::AnnotName getName() { dbscheme_args_annotation_def(this, result) } /** Gets the `i`th child of this node. */ - final SimpleId getChild(int i) { dbscheme_args_annotation_child(this, i, result) } + final F::SimpleId getChild(int i) { dbscheme_args_annotation_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { dbscheme_args_annotation_def(this, result) or dbscheme_args_annotation_child(this, _, result) } } @@ -1683,13 +1691,13 @@ module Dbscheme { final override string getAPrimaryQlClass() { result = "Branch" } /** Gets the node corresponding to the field `qldoc`. */ - final Qldoc getQldoc() { dbscheme_branch_qldoc(this, result) } + final F::Qldoc getQldoc() { dbscheme_branch_qldoc(this, result) } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { dbscheme_branch_child(this, i, result) } + final F::AstNode getChild(int i) { dbscheme_branch_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { dbscheme_branch_qldoc(this, result) or dbscheme_branch_child(this, _, result) } } @@ -1700,16 +1708,16 @@ module Dbscheme { final override string getAPrimaryQlClass() { result = "CaseDecl" } /** Gets the node corresponding to the field `base`. */ - final Dbtype getBase() { dbscheme_case_decl_def(this, result, _) } + final F::Dbtype getBase() { dbscheme_case_decl_def(this, result, _) } /** Gets the node corresponding to the field `discriminator`. */ - final SimpleId getDiscriminator() { dbscheme_case_decl_def(this, _, result) } + final F::SimpleId getDiscriminator() { dbscheme_case_decl_def(this, _, result) } /** Gets the `i`th child of this node. */ - final Branch getChild(int i) { dbscheme_case_decl_child(this, i, result) } + final F::Branch getChild(int i) { dbscheme_case_decl_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { dbscheme_case_decl_def(this, result, _) or dbscheme_case_decl_def(this, _, result) or dbscheme_case_decl_child(this, _, result) @@ -1722,10 +1730,10 @@ module Dbscheme { final override string getAPrimaryQlClass() { result = "ColType" } /** Gets the child of this node. */ - final AstNode getChild() { dbscheme_col_type_def(this, result) } + final F::AstNode getChild() { dbscheme_col_type_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { dbscheme_col_type_def(this, result) } + final override F::AstNode getAFieldOrChild() { dbscheme_col_type_def(this, result) } } /** A class representing `column` nodes. */ @@ -1734,25 +1742,25 @@ module Dbscheme { final override string getAPrimaryQlClass() { result = "Column" } /** Gets the node corresponding to the field `colName`. */ - final SimpleId getColName() { dbscheme_column_def(this, result, _, _) } + final F::SimpleId getColName() { dbscheme_column_def(this, result, _, _) } /** Gets the node corresponding to the field `colType`. */ - final ColType getColType() { dbscheme_column_def(this, _, result, _) } + final F::ColType getColType() { dbscheme_column_def(this, _, result, _) } /** Gets the node corresponding to the field `isRef`. */ - final Ref getIsRef() { dbscheme_column_is_ref(this, result) } + final F::Ref getIsRef() { dbscheme_column_is_ref(this, result) } /** Gets the node corresponding to the field `isUnique`. */ - final Unique getIsUnique() { dbscheme_column_is_unique(this, result) } + final F::Unique getIsUnique() { dbscheme_column_is_unique(this, result) } /** Gets the node corresponding to the field `qldoc`. */ - final Qldoc getQldoc() { dbscheme_column_qldoc(this, result) } + final F::Qldoc getQldoc() { dbscheme_column_qldoc(this, result) } /** Gets the node corresponding to the field `reprType`. */ - final ReprType getReprType() { dbscheme_column_def(this, _, _, result) } + final F::ReprType getReprType() { dbscheme_column_def(this, _, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { dbscheme_column_def(this, result, _, _) or dbscheme_column_def(this, _, result, _) or dbscheme_column_is_ref(this, result) or @@ -1774,10 +1782,10 @@ module Dbscheme { final override string getAPrimaryQlClass() { result = "Dbscheme" } /** Gets the `i`th child of this node. */ - final Entry getChild(int i) { dbscheme_dbscheme_child(this, i, result) } + final F::Entry getChild(int i) { dbscheme_dbscheme_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { dbscheme_dbscheme_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { dbscheme_dbscheme_child(this, _, result) } } /** A class representing `dbtype` tokens. */ @@ -1792,10 +1800,10 @@ module Dbscheme { final override string getAPrimaryQlClass() { result = "Entry" } /** Gets the child of this node. */ - final AstNode getChild() { dbscheme_entry_def(this, result) } + final F::AstNode getChild() { dbscheme_entry_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { dbscheme_entry_def(this, result) } + final override F::AstNode getAFieldOrChild() { dbscheme_entry_def(this, result) } } /** A class representing `float` tokens. */ @@ -1840,10 +1848,10 @@ module Dbscheme { final override string getAPrimaryQlClass() { result = "ReprType" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { dbscheme_repr_type_child(this, i, result) } + final F::AstNode getChild(int i) { dbscheme_repr_type_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { dbscheme_repr_type_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { dbscheme_repr_type_child(this, _, result) } } /** A class representing `simpleId` tokens. */ @@ -1864,13 +1872,13 @@ module Dbscheme { final override string getAPrimaryQlClass() { result = "Table" } /** Gets the node corresponding to the field `tableName`. */ - final TableName getTableName() { dbscheme_table_def(this, result) } + final F::TableName getTableName() { dbscheme_table_def(this, result) } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { dbscheme_table_child(this, i, result) } + final F::AstNode getChild(int i) { dbscheme_table_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { dbscheme_table_def(this, result) or dbscheme_table_child(this, _, result) } } @@ -1881,10 +1889,10 @@ module Dbscheme { final override string getAPrimaryQlClass() { result = "TableName" } /** Gets the child of this node. */ - final SimpleId getChild() { dbscheme_table_name_def(this, result) } + final F::SimpleId getChild() { dbscheme_table_name_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { dbscheme_table_name_def(this, result) } + final override F::AstNode getAFieldOrChild() { dbscheme_table_name_def(this, result) } } /** A class representing `unionDecl` nodes. */ @@ -1893,13 +1901,13 @@ module Dbscheme { final override string getAPrimaryQlClass() { result = "UnionDecl" } /** Gets the node corresponding to the field `base`. */ - final Dbtype getBase() { dbscheme_union_decl_def(this, result) } + final F::Dbtype getBase() { dbscheme_union_decl_def(this, result) } /** Gets the `i`th child of this node. */ - final Dbtype getChild(int i) { dbscheme_union_decl_child(this, i, result) } + final F::Dbtype getChild(int i) { dbscheme_union_decl_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { dbscheme_union_decl_def(this, result) or dbscheme_union_decl_child(this, _, result) } } @@ -1973,6 +1981,8 @@ module Dbscheme { overlay[local] module Blame { + private import Blame as F + /** The base class for all AST nodes */ private class AstNodeImpl extends @blame_ast_node { /** Gets a string representation of this element. */ @@ -1982,13 +1992,13 @@ module Blame { final L::Location getLocation() { blame_ast_node_location(this, result) } /** Gets the parent of this element. */ - final AstNode getParent() { blame_ast_node_parent(this, result, _) } + final F::AstNode getParent() { blame_ast_node_parent(this, result, _) } /** Gets the index of this node among the children of its parent. */ final int getParentIndex() { blame_ast_node_parent(this, _, result) } /** Gets a field or child node of this node. */ - AstNode getAFieldOrChild() { none() } + F::AstNode getAFieldOrChild() { none() } /** Gets the name of the primary QL class for this element. */ string getAPrimaryQlClass() { result = "???" } @@ -2045,13 +2055,13 @@ module Blame { final override string getAPrimaryQlClass() { result = "BlameEntry" } /** Gets the node corresponding to the field `date`. */ - final Date getDate() { blame_blame_entry_def(this, result) } + final F::Date getDate() { blame_blame_entry_def(this, result) } /** Gets the node corresponding to the field `line`. */ - final Number getLine(int i) { blame_blame_entry_line(this, i, result) } + final F::Number getLine(int i) { blame_blame_entry_line(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { blame_blame_entry_def(this, result) or blame_blame_entry_line(this, _, result) } } @@ -2062,13 +2072,13 @@ module Blame { final override string getAPrimaryQlClass() { result = "BlameInfo" } /** Gets the node corresponding to the field `file_entry`. */ - final FileEntry getFileEntry(int i) { blame_blame_info_file_entry(this, i, result) } + final F::FileEntry getFileEntry(int i) { blame_blame_info_file_entry(this, i, result) } /** Gets the node corresponding to the field `today`. */ - final Date getToday() { blame_blame_info_def(this, result) } + final F::Date getToday() { blame_blame_info_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { blame_blame_info_file_entry(this, _, result) or blame_blame_info_def(this, result) } } @@ -2085,13 +2095,13 @@ module Blame { final override string getAPrimaryQlClass() { result = "FileEntry" } /** Gets the node corresponding to the field `blame_entry`. */ - final BlameEntry getBlameEntry(int i) { blame_file_entry_blame_entry(this, i, result) } + final F::BlameEntry getBlameEntry(int i) { blame_file_entry_blame_entry(this, i, result) } /** Gets the node corresponding to the field `file_name`. */ - final Filename getFileName() { blame_file_entry_def(this, result) } + final F::Filename getFileName() { blame_file_entry_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { blame_file_entry_blame_entry(this, _, result) or blame_file_entry_def(this, result) } } @@ -2129,6 +2139,8 @@ module Blame { overlay[local] module JSON { + private import JSON as F + /** The base class for all AST nodes */ private class AstNodeImpl extends @json_ast_node { /** Gets a string representation of this element. */ @@ -2138,13 +2150,13 @@ module JSON { final L::Location getLocation() { json_ast_node_location(this, result) } /** Gets the parent of this element. */ - final AstNode getParent() { json_ast_node_parent(this, result, _) } + final F::AstNode getParent() { json_ast_node_parent(this, result, _) } /** Gets the index of this node among the children of its parent. */ final int getParentIndex() { json_ast_node_parent(this, _, result) } /** Gets a field or child node of this node. */ - AstNode getAFieldOrChild() { none() } + F::AstNode getAFieldOrChild() { none() } /** Gets the name of the primary QL class for this element. */ string getAPrimaryQlClass() { result = "???" } @@ -2203,10 +2215,10 @@ module JSON { final override string getAPrimaryQlClass() { result = "Array" } /** Gets the `i`th child of this node. */ - final UnderscoreValue getChild(int i) { json_array_child(this, i, result) } + final F::UnderscoreValue getChild(int i) { json_array_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { json_array_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { json_array_child(this, _, result) } } /** A class representing `comment` tokens. */ @@ -2221,10 +2233,10 @@ module JSON { final override string getAPrimaryQlClass() { result = "Document" } /** Gets the `i`th child of this node. */ - final UnderscoreValue getChild(int i) { json_document_child(this, i, result) } + final F::UnderscoreValue getChild(int i) { json_document_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { json_document_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { json_document_child(this, _, result) } } /** A class representing `escape_sequence` tokens. */ @@ -2257,10 +2269,10 @@ module JSON { final override string getAPrimaryQlClass() { result = "Object" } /** Gets the `i`th child of this node. */ - final Pair getChild(int i) { json_object_child(this, i, result) } + final F::Pair getChild(int i) { json_object_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { json_object_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { json_object_child(this, _, result) } } /** A class representing `pair` nodes. */ @@ -2269,13 +2281,13 @@ module JSON { final override string getAPrimaryQlClass() { result = "Pair" } /** Gets the node corresponding to the field `key`. */ - final String getKey() { json_pair_def(this, result, _) } + final F::String getKey() { json_pair_def(this, result, _) } /** Gets the node corresponding to the field `value`. */ - final UnderscoreValue getValue() { json_pair_def(this, _, result) } + final F::UnderscoreValue getValue() { json_pair_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { json_pair_def(this, result, _) or json_pair_def(this, _, result) } } @@ -2286,10 +2298,10 @@ module JSON { final override string getAPrimaryQlClass() { result = "String" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { json_string_child(this, i, result) } + final F::AstNode getChild(int i) { json_string_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { json_string_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { json_string_child(this, _, result) } } /** A class representing `string_content` tokens. */ diff --git a/ruby/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll b/ruby/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll index 13ae1923b105..db5360ef5d58 100644 --- a/ruby/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll +++ b/ruby/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll @@ -25,6 +25,8 @@ private predicate discardLocation(@location_default loc) { overlay[local] module Ruby { + private import Ruby as F + /** The base class for all AST nodes */ private class AstNodeImpl extends @ruby_ast_node { /** Gets a string representation of this element. */ @@ -34,13 +36,13 @@ module Ruby { final L::Location getLocation() { ruby_ast_node_location(this, result) } /** Gets the parent of this element. */ - final AstNode getParent() { ruby_ast_node_parent(this, result, _) } + final F::AstNode getParent() { ruby_ast_node_parent(this, result, _) } /** Gets the index of this node among the children of its parent. */ final int getParentIndex() { ruby_ast_node_parent(this, _, result) } /** Gets a field or child node of this node. */ - AstNode getAFieldOrChild() { none() } + F::AstNode getAFieldOrChild() { none() } /** Gets the name of the primary QL class for this element. */ string getAPrimaryQlClass() { result = "???" } @@ -130,13 +132,13 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Alias" } /** Gets the node corresponding to the field `alias`. */ - final UnderscoreMethodName getAlias() { ruby_alias_def(this, result, _) } + final F::UnderscoreMethodName getAlias() { ruby_alias_def(this, result, _) } /** Gets the node corresponding to the field `name`. */ - final UnderscoreMethodName getName() { ruby_alias_def(this, _, result) } + final F::UnderscoreMethodName getName() { ruby_alias_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_alias_def(this, result, _) or ruby_alias_def(this, _, result) } } @@ -147,12 +149,12 @@ module Ruby { final override string getAPrimaryQlClass() { result = "AlternativePattern" } /** Gets the node corresponding to the field `alternatives`. */ - final UnderscorePatternExprBasic getAlternatives(int i) { + final F::UnderscorePatternExprBasic getAlternatives(int i) { ruby_alternative_pattern_alternatives(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_alternative_pattern_alternatives(this, _, result) } } @@ -163,10 +165,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "ArgumentList" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_argument_list_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_argument_list_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_argument_list_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_argument_list_child(this, _, result) } } /** A class representing `array` nodes. */ @@ -175,10 +177,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Array" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_array_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_array_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_array_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_array_child(this, _, result) } } /** A class representing `array_pattern` nodes. */ @@ -187,13 +189,13 @@ module Ruby { final override string getAPrimaryQlClass() { result = "ArrayPattern" } /** Gets the node corresponding to the field `class`. */ - final UnderscorePatternConstant getClass() { ruby_array_pattern_class(this, result) } + final F::UnderscorePatternConstant getClass() { ruby_array_pattern_class(this, result) } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_array_pattern_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_array_pattern_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_array_pattern_class(this, result) or ruby_array_pattern_child(this, _, result) } } @@ -204,13 +206,13 @@ module Ruby { final override string getAPrimaryQlClass() { result = "AsPattern" } /** Gets the node corresponding to the field `name`. */ - final Identifier getName() { ruby_as_pattern_def(this, result, _) } + final F::Identifier getName() { ruby_as_pattern_def(this, result, _) } /** Gets the node corresponding to the field `value`. */ - final UnderscorePatternExpr getValue() { ruby_as_pattern_def(this, _, result) } + final F::UnderscorePatternExpr getValue() { ruby_as_pattern_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_as_pattern_def(this, result, _) or ruby_as_pattern_def(this, _, result) } } @@ -221,13 +223,13 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Assignment" } /** Gets the node corresponding to the field `left`. */ - final AstNode getLeft() { ruby_assignment_def(this, result, _) } + final F::AstNode getLeft() { ruby_assignment_def(this, result, _) } /** Gets the node corresponding to the field `right`. */ - final AstNode getRight() { ruby_assignment_def(this, _, result) } + final F::AstNode getRight() { ruby_assignment_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_assignment_def(this, result, _) or ruby_assignment_def(this, _, result) } } @@ -238,10 +240,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "BareString" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_bare_string_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_bare_string_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_bare_string_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_bare_string_child(this, _, result) } } /** A class representing `bare_symbol` nodes. */ @@ -250,10 +252,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "BareSymbol" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_bare_symbol_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_bare_symbol_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_bare_symbol_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_bare_symbol_child(this, _, result) } } /** A class representing `begin` nodes. */ @@ -262,10 +264,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Begin" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_begin_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_begin_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_begin_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_begin_child(this, _, result) } } /** A class representing `begin_block` nodes. */ @@ -274,10 +276,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "BeginBlock" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_begin_block_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_begin_block_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_begin_block_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_begin_block_child(this, _, result) } } /** A class representing `binary` nodes. */ @@ -286,7 +288,7 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Binary" } /** Gets the node corresponding to the field `left`. */ - final AstNode getLeft() { ruby_binary_def(this, result, _, _) } + final F::AstNode getLeft() { ruby_binary_def(this, result, _, _) } /** Gets the node corresponding to the field `operator`. */ final string getOperator() { @@ -344,10 +346,10 @@ module Ruby { } /** Gets the node corresponding to the field `right`. */ - final UnderscoreExpression getRight() { ruby_binary_def(this, _, _, result) } + final F::UnderscoreExpression getRight() { ruby_binary_def(this, _, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_binary_def(this, result, _, _) or ruby_binary_def(this, _, _, result) } } @@ -358,13 +360,13 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Block" } /** Gets the node corresponding to the field `body`. */ - final BlockBody getBody() { ruby_block_body(this, result) } + final F::BlockBody getBody() { ruby_block_body(this, result) } /** Gets the node corresponding to the field `parameters`. */ - final BlockParameters getParameters() { ruby_block_parameters(this, result) } + final F::BlockParameters getParameters() { ruby_block_parameters(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_block_body(this, result) or ruby_block_parameters(this, result) } } @@ -375,10 +377,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "BlockArgument" } /** Gets the child of this node. */ - final UnderscoreArg getChild() { ruby_block_argument_child(this, result) } + final F::UnderscoreArg getChild() { ruby_block_argument_child(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_block_argument_child(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_block_argument_child(this, result) } } /** A class representing `block_body` nodes. */ @@ -387,10 +389,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "BlockBody" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_block_body_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_block_body_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_block_body_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_block_body_child(this, _, result) } } /** A class representing `block_parameter` nodes. */ @@ -399,10 +401,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "BlockParameter" } /** Gets the node corresponding to the field `name`. */ - final Identifier getName() { ruby_block_parameter_name(this, result) } + final F::Identifier getName() { ruby_block_parameter_name(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_block_parameter_name(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_block_parameter_name(this, result) } } /** A class representing `block_parameters` nodes. */ @@ -411,13 +413,13 @@ module Ruby { final override string getAPrimaryQlClass() { result = "BlockParameters" } /** Gets the node corresponding to the field `locals`. */ - final Identifier getLocals(int i) { ruby_block_parameters_locals(this, i, result) } + final F::Identifier getLocals(int i) { ruby_block_parameters_locals(this, i, result) } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_block_parameters_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_block_parameters_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_block_parameters_locals(this, _, result) or ruby_block_parameters_child(this, _, result) } } @@ -428,10 +430,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "BodyStatement" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_body_statement_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_body_statement_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_body_statement_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_body_statement_child(this, _, result) } } /** A class representing `break` nodes. */ @@ -440,10 +442,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Break" } /** Gets the child of this node. */ - final ArgumentList getChild() { ruby_break_child(this, result) } + final F::ArgumentList getChild() { ruby_break_child(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_break_child(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_break_child(this, result) } } /** A class representing `call` nodes. */ @@ -452,22 +454,22 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Call" } /** Gets the node corresponding to the field `arguments`. */ - final ArgumentList getArguments() { ruby_call_arguments(this, result) } + final F::ArgumentList getArguments() { ruby_call_arguments(this, result) } /** Gets the node corresponding to the field `block`. */ - final AstNode getBlock() { ruby_call_block(this, result) } + final F::AstNode getBlock() { ruby_call_block(this, result) } /** Gets the node corresponding to the field `method`. */ - final AstNode getMethod() { ruby_call_method(this, result) } + final F::AstNode getMethod() { ruby_call_method(this, result) } /** Gets the node corresponding to the field `operator`. */ - final UnderscoreCallOperator getOperator() { ruby_call_operator(this, result) } + final F::UnderscoreCallOperator getOperator() { ruby_call_operator(this, result) } /** Gets the node corresponding to the field `receiver`. */ - final UnderscorePrimary getReceiver() { ruby_call_receiver(this, result) } + final F::UnderscorePrimary getReceiver() { ruby_call_receiver(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_call_arguments(this, result) or ruby_call_block(this, result) or ruby_call_method(this, result) or @@ -482,13 +484,13 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Case" } /** Gets the node corresponding to the field `value`. */ - final UnderscoreStatement getValue() { ruby_case_value(this, result) } + final F::UnderscoreStatement getValue() { ruby_case_value(this, result) } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_case_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_case_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_case_value(this, result) or ruby_case_child(this, _, result) } } @@ -499,16 +501,16 @@ module Ruby { final override string getAPrimaryQlClass() { result = "CaseMatch" } /** Gets the node corresponding to the field `clauses`. */ - final InClause getClauses(int i) { ruby_case_match_clauses(this, i, result) } + final F::InClause getClauses(int i) { ruby_case_match_clauses(this, i, result) } /** Gets the node corresponding to the field `else`. */ - final Else getElse() { ruby_case_match_else(this, result) } + final F::Else getElse() { ruby_case_match_else(this, result) } /** Gets the node corresponding to the field `value`. */ - final UnderscoreStatement getValue() { ruby_case_match_def(this, result) } + final F::UnderscoreStatement getValue() { ruby_case_match_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_case_match_clauses(this, _, result) or ruby_case_match_else(this, result) or ruby_case_match_def(this, result) @@ -521,10 +523,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "ChainedString" } /** Gets the `i`th child of this node. */ - final String getChild(int i) { ruby_chained_string_child(this, i, result) } + final F::String getChild(int i) { ruby_chained_string_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_chained_string_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_chained_string_child(this, _, result) } } /** A class representing `character` tokens. */ @@ -539,16 +541,16 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Class" } /** Gets the node corresponding to the field `body`. */ - final BodyStatement getBody() { ruby_class_body(this, result) } + final F::BodyStatement getBody() { ruby_class_body(this, result) } /** Gets the node corresponding to the field `name`. */ - final AstNode getName() { ruby_class_def(this, result) } + final F::AstNode getName() { ruby_class_def(this, result) } /** Gets the node corresponding to the field `superclass`. */ - final Superclass getSuperclass() { ruby_class_superclass(this, result) } + final F::Superclass getSuperclass() { ruby_class_superclass(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_class_body(this, result) or ruby_class_def(this, result) or ruby_class_superclass(this, result) @@ -573,10 +575,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Complex" } /** Gets the child of this node. */ - final AstNode getChild() { ruby_complex_def(this, result) } + final F::AstNode getChild() { ruby_complex_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_complex_def(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_complex_def(this, result) } } /** A class representing `conditional` nodes. */ @@ -585,16 +587,16 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Conditional" } /** Gets the node corresponding to the field `alternative`. */ - final UnderscoreArg getAlternative() { ruby_conditional_def(this, result, _, _) } + final F::UnderscoreArg getAlternative() { ruby_conditional_def(this, result, _, _) } /** Gets the node corresponding to the field `condition`. */ - final UnderscoreArg getCondition() { ruby_conditional_def(this, _, result, _) } + final F::UnderscoreArg getCondition() { ruby_conditional_def(this, _, result, _) } /** Gets the node corresponding to the field `consequence`. */ - final UnderscoreArg getConsequence() { ruby_conditional_def(this, _, _, result) } + final F::UnderscoreArg getConsequence() { ruby_conditional_def(this, _, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_conditional_def(this, result, _, _) or ruby_conditional_def(this, _, result, _) or ruby_conditional_def(this, _, _, result) @@ -613,10 +615,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "DelimitedSymbol" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_delimited_symbol_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_delimited_symbol_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_delimited_symbol_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_delimited_symbol_child(this, _, result) } } /** A class representing `destructured_left_assignment` nodes. */ @@ -625,10 +627,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "DestructuredLeftAssignment" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_destructured_left_assignment_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_destructured_left_assignment_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_destructured_left_assignment_child(this, _, result) } } @@ -639,10 +641,12 @@ module Ruby { final override string getAPrimaryQlClass() { result = "DestructuredParameter" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_destructured_parameter_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_destructured_parameter_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_destructured_parameter_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { + ruby_destructured_parameter_child(this, _, result) + } } /** A class representing `do` nodes. */ @@ -651,10 +655,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Do" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_do_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_do_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_do_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_do_child(this, _, result) } } /** A class representing `do_block` nodes. */ @@ -663,13 +667,13 @@ module Ruby { final override string getAPrimaryQlClass() { result = "DoBlock" } /** Gets the node corresponding to the field `body`. */ - final BodyStatement getBody() { ruby_do_block_body(this, result) } + final F::BodyStatement getBody() { ruby_do_block_body(this, result) } /** Gets the node corresponding to the field `parameters`. */ - final BlockParameters getParameters() { ruby_do_block_parameters(this, result) } + final F::BlockParameters getParameters() { ruby_do_block_parameters(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_do_block_body(this, result) or ruby_do_block_parameters(this, result) } } @@ -680,16 +684,16 @@ module Ruby { final override string getAPrimaryQlClass() { result = "ElementReference" } /** Gets the node corresponding to the field `block`. */ - final AstNode getBlock() { ruby_element_reference_block(this, result) } + final F::AstNode getBlock() { ruby_element_reference_block(this, result) } /** Gets the node corresponding to the field `object`. */ - final UnderscorePrimary getObject() { ruby_element_reference_def(this, result) } + final F::UnderscorePrimary getObject() { ruby_element_reference_def(this, result) } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_element_reference_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_element_reference_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_element_reference_block(this, result) or ruby_element_reference_def(this, result) or ruby_element_reference_child(this, _, result) @@ -702,10 +706,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Else" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_else_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_else_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_else_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_else_child(this, _, result) } } /** A class representing `elsif` nodes. */ @@ -714,16 +718,16 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Elsif" } /** Gets the node corresponding to the field `alternative`. */ - final AstNode getAlternative() { ruby_elsif_alternative(this, result) } + final F::AstNode getAlternative() { ruby_elsif_alternative(this, result) } /** Gets the node corresponding to the field `condition`. */ - final UnderscoreStatement getCondition() { ruby_elsif_def(this, result) } + final F::UnderscoreStatement getCondition() { ruby_elsif_def(this, result) } /** Gets the node corresponding to the field `consequence`. */ - final Then getConsequence() { ruby_elsif_consequence(this, result) } + final F::Then getConsequence() { ruby_elsif_consequence(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_elsif_alternative(this, result) or ruby_elsif_def(this, result) or ruby_elsif_consequence(this, result) @@ -748,10 +752,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "EndBlock" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_end_block_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_end_block_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_end_block_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_end_block_child(this, _, result) } } /** A class representing `ensure` nodes. */ @@ -760,10 +764,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Ensure" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_ensure_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_ensure_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_ensure_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_ensure_child(this, _, result) } } /** A class representing `escape_sequence` tokens. */ @@ -778,10 +782,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "ExceptionVariable" } /** Gets the child of this node. */ - final UnderscoreLhs getChild() { ruby_exception_variable_def(this, result) } + final F::UnderscoreLhs getChild() { ruby_exception_variable_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_exception_variable_def(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_exception_variable_def(this, result) } } /** A class representing `exceptions` nodes. */ @@ -790,10 +794,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Exceptions" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_exceptions_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_exceptions_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_exceptions_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_exceptions_child(this, _, result) } } /** A class representing `expression_reference_pattern` nodes. */ @@ -802,10 +806,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "ExpressionReferencePattern" } /** Gets the node corresponding to the field `value`. */ - final UnderscoreExpression getValue() { ruby_expression_reference_pattern_def(this, result) } + final F::UnderscoreExpression getValue() { ruby_expression_reference_pattern_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_expression_reference_pattern_def(this, result) } } @@ -828,13 +832,13 @@ module Ruby { final override string getAPrimaryQlClass() { result = "FindPattern" } /** Gets the node corresponding to the field `class`. */ - final UnderscorePatternConstant getClass() { ruby_find_pattern_class(this, result) } + final F::UnderscorePatternConstant getClass() { ruby_find_pattern_class(this, result) } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_find_pattern_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_find_pattern_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_find_pattern_class(this, result) or ruby_find_pattern_child(this, _, result) } } @@ -851,16 +855,16 @@ module Ruby { final override string getAPrimaryQlClass() { result = "For" } /** Gets the node corresponding to the field `body`. */ - final Do getBody() { ruby_for_def(this, result, _, _) } + final F::Do getBody() { ruby_for_def(this, result, _, _) } /** Gets the node corresponding to the field `pattern`. */ - final AstNode getPattern() { ruby_for_def(this, _, result, _) } + final F::AstNode getPattern() { ruby_for_def(this, _, result, _) } /** Gets the node corresponding to the field `value`. */ - final In getValue() { ruby_for_def(this, _, _, result) } + final F::In getValue() { ruby_for_def(this, _, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_for_def(this, result, _, _) or ruby_for_def(this, _, result, _) or ruby_for_def(this, _, _, result) @@ -891,10 +895,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Hash" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_hash_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_hash_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_hash_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_hash_child(this, _, result) } } /** A class representing `hash_key_symbol` tokens. */ @@ -909,13 +913,13 @@ module Ruby { final override string getAPrimaryQlClass() { result = "HashPattern" } /** Gets the node corresponding to the field `class`. */ - final UnderscorePatternConstant getClass() { ruby_hash_pattern_class(this, result) } + final F::UnderscorePatternConstant getClass() { ruby_hash_pattern_class(this, result) } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_hash_pattern_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_hash_pattern_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_hash_pattern_class(this, result) or ruby_hash_pattern_child(this, _, result) } } @@ -926,10 +930,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "HashSplatArgument" } /** Gets the child of this node. */ - final UnderscoreArg getChild() { ruby_hash_splat_argument_child(this, result) } + final F::UnderscoreArg getChild() { ruby_hash_splat_argument_child(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_hash_splat_argument_child(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_hash_splat_argument_child(this, result) } } /** A class representing `hash_splat_nil` tokens. */ @@ -944,10 +948,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "HashSplatParameter" } /** Gets the node corresponding to the field `name`. */ - final Identifier getName() { ruby_hash_splat_parameter_name(this, result) } + final F::Identifier getName() { ruby_hash_splat_parameter_name(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_hash_splat_parameter_name(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_hash_splat_parameter_name(this, result) } } /** A class representing `heredoc_beginning` tokens. */ @@ -962,10 +966,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "HeredocBody" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_heredoc_body_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_heredoc_body_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_heredoc_body_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_heredoc_body_child(this, _, result) } } /** A class representing `heredoc_content` tokens. */ @@ -992,16 +996,16 @@ module Ruby { final override string getAPrimaryQlClass() { result = "If" } /** Gets the node corresponding to the field `alternative`. */ - final AstNode getAlternative() { ruby_if_alternative(this, result) } + final F::AstNode getAlternative() { ruby_if_alternative(this, result) } /** Gets the node corresponding to the field `condition`. */ - final UnderscoreStatement getCondition() { ruby_if_def(this, result) } + final F::UnderscoreStatement getCondition() { ruby_if_def(this, result) } /** Gets the node corresponding to the field `consequence`. */ - final Then getConsequence() { ruby_if_consequence(this, result) } + final F::Then getConsequence() { ruby_if_consequence(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_if_alternative(this, result) or ruby_if_def(this, result) or ruby_if_consequence(this, result) @@ -1014,10 +1018,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "IfGuard" } /** Gets the node corresponding to the field `condition`. */ - final UnderscoreExpression getCondition() { ruby_if_guard_def(this, result) } + final F::UnderscoreExpression getCondition() { ruby_if_guard_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_if_guard_def(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_if_guard_def(this, result) } } /** A class representing `if_modifier` nodes. */ @@ -1026,13 +1030,13 @@ module Ruby { final override string getAPrimaryQlClass() { result = "IfModifier" } /** Gets the node corresponding to the field `body`. */ - final UnderscoreStatement getBody() { ruby_if_modifier_def(this, result, _) } + final F::UnderscoreStatement getBody() { ruby_if_modifier_def(this, result, _) } /** Gets the node corresponding to the field `condition`. */ - final UnderscoreExpression getCondition() { ruby_if_modifier_def(this, _, result) } + final F::UnderscoreExpression getCondition() { ruby_if_modifier_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_if_modifier_def(this, result, _) or ruby_if_modifier_def(this, _, result) } } @@ -1043,10 +1047,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "In" } /** Gets the child of this node. */ - final UnderscoreArg getChild() { ruby_in_def(this, result) } + final F::UnderscoreArg getChild() { ruby_in_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_in_def(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_in_def(this, result) } } /** A class representing `in_clause` nodes. */ @@ -1055,16 +1059,16 @@ module Ruby { final override string getAPrimaryQlClass() { result = "InClause" } /** Gets the node corresponding to the field `body`. */ - final Then getBody() { ruby_in_clause_body(this, result) } + final F::Then getBody() { ruby_in_clause_body(this, result) } /** Gets the node corresponding to the field `guard`. */ - final AstNode getGuard() { ruby_in_clause_guard(this, result) } + final F::AstNode getGuard() { ruby_in_clause_guard(this, result) } /** Gets the node corresponding to the field `pattern`. */ - final UnderscorePatternTopExprBody getPattern() { ruby_in_clause_def(this, result) } + final F::UnderscorePatternTopExprBody getPattern() { ruby_in_clause_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_in_clause_body(this, result) or ruby_in_clause_guard(this, result) or ruby_in_clause_def(this, result) @@ -1089,10 +1093,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Interpolation" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_interpolation_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_interpolation_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_interpolation_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_interpolation_child(this, _, result) } } /** A class representing `keyword_parameter` nodes. */ @@ -1101,13 +1105,13 @@ module Ruby { final override string getAPrimaryQlClass() { result = "KeywordParameter" } /** Gets the node corresponding to the field `name`. */ - final Identifier getName() { ruby_keyword_parameter_def(this, result) } + final F::Identifier getName() { ruby_keyword_parameter_def(this, result) } /** Gets the node corresponding to the field `value`. */ - final UnderscoreArg getValue() { ruby_keyword_parameter_value(this, result) } + final F::UnderscoreArg getValue() { ruby_keyword_parameter_value(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_keyword_parameter_def(this, result) or ruby_keyword_parameter_value(this, result) } } @@ -1118,13 +1122,13 @@ module Ruby { final override string getAPrimaryQlClass() { result = "KeywordPattern" } /** Gets the node corresponding to the field `key`. */ - final AstNode getKey() { ruby_keyword_pattern_def(this, result) } + final F::AstNode getKey() { ruby_keyword_pattern_def(this, result) } /** Gets the node corresponding to the field `value`. */ - final UnderscorePatternExpr getValue() { ruby_keyword_pattern_value(this, result) } + final F::UnderscorePatternExpr getValue() { ruby_keyword_pattern_value(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_keyword_pattern_def(this, result) or ruby_keyword_pattern_value(this, result) } } @@ -1135,13 +1139,13 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Lambda" } /** Gets the node corresponding to the field `body`. */ - final AstNode getBody() { ruby_lambda_def(this, result) } + final F::AstNode getBody() { ruby_lambda_def(this, result) } /** Gets the node corresponding to the field `parameters`. */ - final LambdaParameters getParameters() { ruby_lambda_parameters(this, result) } + final F::LambdaParameters getParameters() { ruby_lambda_parameters(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_lambda_def(this, result) or ruby_lambda_parameters(this, result) } } @@ -1152,10 +1156,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "LambdaParameters" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_lambda_parameters_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_lambda_parameters_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_lambda_parameters_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_lambda_parameters_child(this, _, result) } } /** A class representing `left_assignment_list` nodes. */ @@ -1164,10 +1168,12 @@ module Ruby { final override string getAPrimaryQlClass() { result = "LeftAssignmentList" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_left_assignment_list_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_left_assignment_list_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_left_assignment_list_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { + ruby_left_assignment_list_child(this, _, result) + } } /** A class representing `line` tokens. */ @@ -1182,13 +1188,13 @@ module Ruby { final override string getAPrimaryQlClass() { result = "MatchPattern" } /** Gets the node corresponding to the field `pattern`. */ - final UnderscorePatternTopExprBody getPattern() { ruby_match_pattern_def(this, result, _) } + final F::UnderscorePatternTopExprBody getPattern() { ruby_match_pattern_def(this, result, _) } /** Gets the node corresponding to the field `value`. */ - final UnderscoreArg getValue() { ruby_match_pattern_def(this, _, result) } + final F::UnderscoreArg getValue() { ruby_match_pattern_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_match_pattern_def(this, result, _) or ruby_match_pattern_def(this, _, result) } } @@ -1199,16 +1205,16 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Method" } /** Gets the node corresponding to the field `body`. */ - final AstNode getBody() { ruby_method_body(this, result) } + final F::AstNode getBody() { ruby_method_body(this, result) } /** Gets the node corresponding to the field `name`. */ - final UnderscoreMethodName getName() { ruby_method_def(this, result) } + final F::UnderscoreMethodName getName() { ruby_method_def(this, result) } /** Gets the node corresponding to the field `parameters`. */ - final MethodParameters getParameters() { ruby_method_parameters(this, result) } + final F::MethodParameters getParameters() { ruby_method_parameters(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_method_body(this, result) or ruby_method_def(this, result) or ruby_method_parameters(this, result) @@ -1221,10 +1227,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "MethodParameters" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_method_parameters_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_method_parameters_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_method_parameters_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_method_parameters_child(this, _, result) } } /** A class representing `module` nodes. */ @@ -1233,13 +1239,13 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Module" } /** Gets the node corresponding to the field `body`. */ - final BodyStatement getBody() { ruby_module_body(this, result) } + final F::BodyStatement getBody() { ruby_module_body(this, result) } /** Gets the node corresponding to the field `name`. */ - final AstNode getName() { ruby_module_def(this, result) } + final F::AstNode getName() { ruby_module_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_module_body(this, result) or ruby_module_def(this, result) } } @@ -1250,10 +1256,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Next" } /** Gets the child of this node. */ - final ArgumentList getChild() { ruby_next_child(this, result) } + final F::ArgumentList getChild() { ruby_next_child(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_next_child(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_next_child(this, result) } } /** A class representing `nil` tokens. */ @@ -1274,7 +1280,7 @@ module Ruby { final override string getAPrimaryQlClass() { result = "OperatorAssignment" } /** Gets the node corresponding to the field `left`. */ - final UnderscoreLhs getLeft() { ruby_operator_assignment_def(this, result, _, _) } + final F::UnderscoreLhs getLeft() { ruby_operator_assignment_def(this, result, _, _) } /** Gets the node corresponding to the field `operator`. */ final string getOperator() { @@ -1308,10 +1314,10 @@ module Ruby { } /** Gets the node corresponding to the field `right`. */ - final AstNode getRight() { ruby_operator_assignment_def(this, _, _, result) } + final F::AstNode getRight() { ruby_operator_assignment_def(this, _, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_operator_assignment_def(this, result, _, _) or ruby_operator_assignment_def(this, _, _, result) } @@ -1323,13 +1329,13 @@ module Ruby { final override string getAPrimaryQlClass() { result = "OptionalParameter" } /** Gets the node corresponding to the field `name`. */ - final Identifier getName() { ruby_optional_parameter_def(this, result, _) } + final F::Identifier getName() { ruby_optional_parameter_def(this, result, _) } /** Gets the node corresponding to the field `value`. */ - final UnderscoreArg getValue() { ruby_optional_parameter_def(this, _, result) } + final F::UnderscoreArg getValue() { ruby_optional_parameter_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_optional_parameter_def(this, result, _) or ruby_optional_parameter_def(this, _, result) } } @@ -1340,13 +1346,13 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Pair" } /** Gets the node corresponding to the field `key`. */ - final AstNode getKey() { ruby_pair_def(this, result) } + final F::AstNode getKey() { ruby_pair_def(this, result) } /** Gets the node corresponding to the field `value`. */ - final UnderscoreArg getValue() { ruby_pair_value(this, result) } + final F::UnderscoreArg getValue() { ruby_pair_value(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_pair_def(this, result) or ruby_pair_value(this, result) } } @@ -1357,10 +1363,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "ParenthesizedPattern" } /** Gets the child of this node. */ - final UnderscorePatternExpr getChild() { ruby_parenthesized_pattern_def(this, result) } + final F::UnderscorePatternExpr getChild() { ruby_parenthesized_pattern_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_parenthesized_pattern_def(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_parenthesized_pattern_def(this, result) } } /** A class representing `parenthesized_statements` nodes. */ @@ -1369,10 +1375,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "ParenthesizedStatements" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_parenthesized_statements_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_parenthesized_statements_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_parenthesized_statements_child(this, _, result) } } @@ -1383,10 +1389,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Pattern" } /** Gets the child of this node. */ - final AstNode getChild() { ruby_pattern_def(this, result) } + final F::AstNode getChild() { ruby_pattern_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_pattern_def(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_pattern_def(this, result) } } /** A class representing `program` nodes. */ @@ -1395,10 +1401,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Program" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_program_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_program_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_program_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_program_child(this, _, result) } } /** A class representing `range` nodes. */ @@ -1407,10 +1413,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Range" } /** Gets the node corresponding to the field `begin`. */ - final AstNode getBegin() { ruby_range_begin(this, result) } + final F::AstNode getBegin() { ruby_range_begin(this, result) } /** Gets the node corresponding to the field `end`. */ - final AstNode getEnd() { ruby_range_end(this, result) } + final F::AstNode getEnd() { ruby_range_end(this, result) } /** Gets the node corresponding to the field `operator`. */ final string getOperator() { @@ -1422,7 +1428,7 @@ module Ruby { } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_range_begin(this, result) or ruby_range_end(this, result) } } @@ -1433,10 +1439,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Rational" } /** Gets the child of this node. */ - final AstNode getChild() { ruby_rational_def(this, result) } + final F::AstNode getChild() { ruby_rational_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_rational_def(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_rational_def(this, result) } } /** A class representing `redo` nodes. */ @@ -1445,10 +1451,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Redo" } /** Gets the child of this node. */ - final ArgumentList getChild() { ruby_redo_child(this, result) } + final F::ArgumentList getChild() { ruby_redo_child(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_redo_child(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_redo_child(this, result) } } /** A class representing `regex` nodes. */ @@ -1457,10 +1463,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Regex" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_regex_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_regex_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_regex_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_regex_child(this, _, result) } } /** A class representing `rescue` nodes. */ @@ -1469,16 +1475,16 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Rescue" } /** Gets the node corresponding to the field `body`. */ - final Then getBody() { ruby_rescue_body(this, result) } + final F::Then getBody() { ruby_rescue_body(this, result) } /** Gets the node corresponding to the field `exceptions`. */ - final Exceptions getExceptions() { ruby_rescue_exceptions(this, result) } + final F::Exceptions getExceptions() { ruby_rescue_exceptions(this, result) } /** Gets the node corresponding to the field `variable`. */ - final ExceptionVariable getVariable() { ruby_rescue_variable(this, result) } + final F::ExceptionVariable getVariable() { ruby_rescue_variable(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_rescue_body(this, result) or ruby_rescue_exceptions(this, result) or ruby_rescue_variable(this, result) @@ -1491,13 +1497,13 @@ module Ruby { final override string getAPrimaryQlClass() { result = "RescueModifier" } /** Gets the node corresponding to the field `body`. */ - final AstNode getBody() { ruby_rescue_modifier_def(this, result, _) } + final F::AstNode getBody() { ruby_rescue_modifier_def(this, result, _) } /** Gets the node corresponding to the field `handler`. */ - final UnderscoreExpression getHandler() { ruby_rescue_modifier_def(this, _, result) } + final F::UnderscoreExpression getHandler() { ruby_rescue_modifier_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_rescue_modifier_def(this, result, _) or ruby_rescue_modifier_def(this, _, result) } } @@ -1508,10 +1514,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "RestAssignment" } /** Gets the child of this node. */ - final UnderscoreLhs getChild() { ruby_rest_assignment_child(this, result) } + final F::UnderscoreLhs getChild() { ruby_rest_assignment_child(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_rest_assignment_child(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_rest_assignment_child(this, result) } } /** A class representing `retry` nodes. */ @@ -1520,10 +1526,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Retry" } /** Gets the child of this node. */ - final ArgumentList getChild() { ruby_retry_child(this, result) } + final F::ArgumentList getChild() { ruby_retry_child(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_retry_child(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_retry_child(this, result) } } /** A class representing `return` nodes. */ @@ -1532,10 +1538,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Return" } /** Gets the child of this node. */ - final ArgumentList getChild() { ruby_return_child(this, result) } + final F::ArgumentList getChild() { ruby_return_child(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_return_child(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_return_child(this, result) } } /** A class representing `right_assignment_list` nodes. */ @@ -1544,10 +1550,12 @@ module Ruby { final override string getAPrimaryQlClass() { result = "RightAssignmentList" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_right_assignment_list_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_right_assignment_list_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_right_assignment_list_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { + ruby_right_assignment_list_child(this, _, result) + } } /** A class representing `scope_resolution` nodes. */ @@ -1556,13 +1564,13 @@ module Ruby { final override string getAPrimaryQlClass() { result = "ScopeResolution" } /** Gets the node corresponding to the field `name`. */ - final Constant getName() { ruby_scope_resolution_def(this, result) } + final F::Constant getName() { ruby_scope_resolution_def(this, result) } /** Gets the node corresponding to the field `scope`. */ - final AstNode getScope() { ruby_scope_resolution_scope(this, result) } + final F::AstNode getScope() { ruby_scope_resolution_scope(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_scope_resolution_def(this, result) or ruby_scope_resolution_scope(this, result) } } @@ -1579,10 +1587,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Setter" } /** Gets the node corresponding to the field `name`. */ - final Identifier getName() { ruby_setter_def(this, result) } + final F::Identifier getName() { ruby_setter_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_setter_def(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_setter_def(this, result) } } /** A class representing `simple_symbol` tokens. */ @@ -1597,13 +1605,13 @@ module Ruby { final override string getAPrimaryQlClass() { result = "SingletonClass" } /** Gets the node corresponding to the field `body`. */ - final BodyStatement getBody() { ruby_singleton_class_body(this, result) } + final F::BodyStatement getBody() { ruby_singleton_class_body(this, result) } /** Gets the node corresponding to the field `value`. */ - final UnderscoreArg getValue() { ruby_singleton_class_def(this, result) } + final F::UnderscoreArg getValue() { ruby_singleton_class_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_singleton_class_body(this, result) or ruby_singleton_class_def(this, result) } } @@ -1614,19 +1622,19 @@ module Ruby { final override string getAPrimaryQlClass() { result = "SingletonMethod" } /** Gets the node corresponding to the field `body`. */ - final AstNode getBody() { ruby_singleton_method_body(this, result) } + final F::AstNode getBody() { ruby_singleton_method_body(this, result) } /** Gets the node corresponding to the field `name`. */ - final UnderscoreMethodName getName() { ruby_singleton_method_def(this, result, _) } + final F::UnderscoreMethodName getName() { ruby_singleton_method_def(this, result, _) } /** Gets the node corresponding to the field `object`. */ - final AstNode getObject() { ruby_singleton_method_def(this, _, result) } + final F::AstNode getObject() { ruby_singleton_method_def(this, _, result) } /** Gets the node corresponding to the field `parameters`. */ - final MethodParameters getParameters() { ruby_singleton_method_parameters(this, result) } + final F::MethodParameters getParameters() { ruby_singleton_method_parameters(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_singleton_method_body(this, result) or ruby_singleton_method_def(this, result, _) or ruby_singleton_method_def(this, _, result) or @@ -1640,10 +1648,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "SplatArgument" } /** Gets the child of this node. */ - final UnderscoreArg getChild() { ruby_splat_argument_child(this, result) } + final F::UnderscoreArg getChild() { ruby_splat_argument_child(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_splat_argument_child(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_splat_argument_child(this, result) } } /** A class representing `splat_parameter` nodes. */ @@ -1652,10 +1660,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "SplatParameter" } /** Gets the node corresponding to the field `name`. */ - final Identifier getName() { ruby_splat_parameter_name(this, result) } + final F::Identifier getName() { ruby_splat_parameter_name(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_splat_parameter_name(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_splat_parameter_name(this, result) } } /** A class representing `string` nodes. */ @@ -1664,10 +1672,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "String" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_string_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_string_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_string_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_string_child(this, _, result) } } /** A class representing `string_array` nodes. */ @@ -1676,10 +1684,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "StringArray" } /** Gets the `i`th child of this node. */ - final BareString getChild(int i) { ruby_string_array_child(this, i, result) } + final F::BareString getChild(int i) { ruby_string_array_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_string_array_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_string_array_child(this, _, result) } } /** A class representing `string_content` tokens. */ @@ -1694,10 +1702,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Subshell" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_subshell_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_subshell_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_subshell_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_subshell_child(this, _, result) } } /** A class representing `super` tokens. */ @@ -1712,10 +1720,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Superclass" } /** Gets the child of this node. */ - final UnderscoreExpression getChild() { ruby_superclass_def(this, result) } + final F::UnderscoreExpression getChild() { ruby_superclass_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_superclass_def(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_superclass_def(this, result) } } /** A class representing `symbol_array` nodes. */ @@ -1724,10 +1732,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "SymbolArray" } /** Gets the `i`th child of this node. */ - final BareSymbol getChild(int i) { ruby_symbol_array_child(this, i, result) } + final F::BareSymbol getChild(int i) { ruby_symbol_array_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_symbol_array_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_symbol_array_child(this, _, result) } } /** A class representing `test_pattern` nodes. */ @@ -1736,13 +1744,13 @@ module Ruby { final override string getAPrimaryQlClass() { result = "TestPattern" } /** Gets the node corresponding to the field `pattern`. */ - final UnderscorePatternTopExprBody getPattern() { ruby_test_pattern_def(this, result, _) } + final F::UnderscorePatternTopExprBody getPattern() { ruby_test_pattern_def(this, result, _) } /** Gets the node corresponding to the field `value`. */ - final UnderscoreArg getValue() { ruby_test_pattern_def(this, _, result) } + final F::UnderscoreArg getValue() { ruby_test_pattern_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_test_pattern_def(this, result, _) or ruby_test_pattern_def(this, _, result) } } @@ -1753,10 +1761,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Then" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_then_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_then_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_then_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_then_child(this, _, result) } } /** A class representing `true` tokens. */ @@ -1771,7 +1779,7 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Unary" } /** Gets the node corresponding to the field `operand`. */ - final AstNode getOperand() { ruby_unary_def(this, result, _) } + final F::AstNode getOperand() { ruby_unary_def(this, result, _) } /** Gets the node corresponding to the field `operator`. */ final string getOperator() { @@ -1791,7 +1799,7 @@ module Ruby { } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_unary_def(this, result, _) } + final override F::AstNode getAFieldOrChild() { ruby_unary_def(this, result, _) } } /** A class representing `undef` nodes. */ @@ -1800,10 +1808,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Undef" } /** Gets the `i`th child of this node. */ - final UnderscoreMethodName getChild(int i) { ruby_undef_child(this, i, result) } + final F::UnderscoreMethodName getChild(int i) { ruby_undef_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_undef_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_undef_child(this, _, result) } } /** A class representing `uninterpreted` tokens. */ @@ -1818,16 +1826,16 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Unless" } /** Gets the node corresponding to the field `alternative`. */ - final AstNode getAlternative() { ruby_unless_alternative(this, result) } + final F::AstNode getAlternative() { ruby_unless_alternative(this, result) } /** Gets the node corresponding to the field `condition`. */ - final UnderscoreStatement getCondition() { ruby_unless_def(this, result) } + final F::UnderscoreStatement getCondition() { ruby_unless_def(this, result) } /** Gets the node corresponding to the field `consequence`. */ - final Then getConsequence() { ruby_unless_consequence(this, result) } + final F::Then getConsequence() { ruby_unless_consequence(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_unless_alternative(this, result) or ruby_unless_def(this, result) or ruby_unless_consequence(this, result) @@ -1840,10 +1848,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "UnlessGuard" } /** Gets the node corresponding to the field `condition`. */ - final UnderscoreExpression getCondition() { ruby_unless_guard_def(this, result) } + final F::UnderscoreExpression getCondition() { ruby_unless_guard_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_unless_guard_def(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_unless_guard_def(this, result) } } /** A class representing `unless_modifier` nodes. */ @@ -1852,13 +1860,13 @@ module Ruby { final override string getAPrimaryQlClass() { result = "UnlessModifier" } /** Gets the node corresponding to the field `body`. */ - final UnderscoreStatement getBody() { ruby_unless_modifier_def(this, result, _) } + final F::UnderscoreStatement getBody() { ruby_unless_modifier_def(this, result, _) } /** Gets the node corresponding to the field `condition`. */ - final UnderscoreExpression getCondition() { ruby_unless_modifier_def(this, _, result) } + final F::UnderscoreExpression getCondition() { ruby_unless_modifier_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_unless_modifier_def(this, result, _) or ruby_unless_modifier_def(this, _, result) } } @@ -1869,13 +1877,13 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Until" } /** Gets the node corresponding to the field `body`. */ - final Do getBody() { ruby_until_def(this, result, _) } + final F::Do getBody() { ruby_until_def(this, result, _) } /** Gets the node corresponding to the field `condition`. */ - final UnderscoreStatement getCondition() { ruby_until_def(this, _, result) } + final F::UnderscoreStatement getCondition() { ruby_until_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_until_def(this, result, _) or ruby_until_def(this, _, result) } } @@ -1886,13 +1894,13 @@ module Ruby { final override string getAPrimaryQlClass() { result = "UntilModifier" } /** Gets the node corresponding to the field `body`. */ - final UnderscoreStatement getBody() { ruby_until_modifier_def(this, result, _) } + final F::UnderscoreStatement getBody() { ruby_until_modifier_def(this, result, _) } /** Gets the node corresponding to the field `condition`. */ - final UnderscoreExpression getCondition() { ruby_until_modifier_def(this, _, result) } + final F::UnderscoreExpression getCondition() { ruby_until_modifier_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_until_modifier_def(this, result, _) or ruby_until_modifier_def(this, _, result) } } @@ -1903,10 +1911,12 @@ module Ruby { final override string getAPrimaryQlClass() { result = "VariableReferencePattern" } /** Gets the node corresponding to the field `name`. */ - final AstNode getName() { ruby_variable_reference_pattern_def(this, result) } + final F::AstNode getName() { ruby_variable_reference_pattern_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_variable_reference_pattern_def(this, result) } + final override F::AstNode getAFieldOrChild() { + ruby_variable_reference_pattern_def(this, result) + } } /** A class representing `when` nodes. */ @@ -1915,13 +1925,13 @@ module Ruby { final override string getAPrimaryQlClass() { result = "When" } /** Gets the node corresponding to the field `body`. */ - final Then getBody() { ruby_when_body(this, result) } + final F::Then getBody() { ruby_when_body(this, result) } /** Gets the node corresponding to the field `pattern`. */ - final Pattern getPattern(int i) { ruby_when_pattern(this, i, result) } + final F::Pattern getPattern(int i) { ruby_when_pattern(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_when_body(this, result) or ruby_when_pattern(this, _, result) } } @@ -1932,13 +1942,13 @@ module Ruby { final override string getAPrimaryQlClass() { result = "While" } /** Gets the node corresponding to the field `body`. */ - final Do getBody() { ruby_while_def(this, result, _) } + final F::Do getBody() { ruby_while_def(this, result, _) } /** Gets the node corresponding to the field `condition`. */ - final UnderscoreStatement getCondition() { ruby_while_def(this, _, result) } + final F::UnderscoreStatement getCondition() { ruby_while_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_while_def(this, result, _) or ruby_while_def(this, _, result) } } @@ -1949,13 +1959,13 @@ module Ruby { final override string getAPrimaryQlClass() { result = "WhileModifier" } /** Gets the node corresponding to the field `body`. */ - final UnderscoreStatement getBody() { ruby_while_modifier_def(this, result, _) } + final F::UnderscoreStatement getBody() { ruby_while_modifier_def(this, result, _) } /** Gets the node corresponding to the field `condition`. */ - final UnderscoreExpression getCondition() { ruby_while_modifier_def(this, _, result) } + final F::UnderscoreExpression getCondition() { ruby_while_modifier_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_while_modifier_def(this, result, _) or ruby_while_modifier_def(this, _, result) } } @@ -1966,10 +1976,10 @@ module Ruby { final override string getAPrimaryQlClass() { result = "Yield" } /** Gets the child of this node. */ - final ArgumentList getChild() { ruby_yield_child(this, result) } + final F::ArgumentList getChild() { ruby_yield_child(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_yield_child(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_yield_child(this, result) } } /** Provides predicates for mapping AST nodes to their named children. */ @@ -2309,6 +2319,8 @@ module Ruby { overlay[local] module Erb { + private import Erb as F + /** The base class for all AST nodes */ private class AstNodeImpl extends @erb_ast_node { /** Gets a string representation of this element. */ @@ -2318,13 +2330,13 @@ module Erb { final L::Location getLocation() { erb_ast_node_location(this, result) } /** Gets the parent of this element. */ - final AstNode getParent() { erb_ast_node_parent(this, result, _) } + final F::AstNode getParent() { erb_ast_node_parent(this, result, _) } /** Gets the index of this node among the children of its parent. */ final int getParentIndex() { erb_ast_node_parent(this, _, result) } /** Gets a field or child node of this node. */ - AstNode getAFieldOrChild() { none() } + F::AstNode getAFieldOrChild() { none() } /** Gets the name of the primary QL class for this element. */ string getAPrimaryQlClass() { result = "???" } @@ -2393,10 +2405,10 @@ module Erb { final override string getAPrimaryQlClass() { result = "CommentDirective" } /** Gets the child of this node. */ - final Comment getChild() { erb_comment_directive_child(this, result) } + final F::Comment getChild() { erb_comment_directive_child(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { erb_comment_directive_child(this, result) } + final override F::AstNode getAFieldOrChild() { erb_comment_directive_child(this, result) } } /** A class representing `content` tokens. */ @@ -2411,10 +2423,10 @@ module Erb { final override string getAPrimaryQlClass() { result = "Directive" } /** Gets the child of this node. */ - final Code getChild() { erb_directive_child(this, result) } + final F::Code getChild() { erb_directive_child(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { erb_directive_child(this, result) } + final override F::AstNode getAFieldOrChild() { erb_directive_child(this, result) } } /** A class representing `graphql_directive` nodes. */ @@ -2423,10 +2435,10 @@ module Erb { final override string getAPrimaryQlClass() { result = "GraphqlDirective" } /** Gets the child of this node. */ - final Code getChild() { erb_graphql_directive_child(this, result) } + final F::Code getChild() { erb_graphql_directive_child(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { erb_graphql_directive_child(this, result) } + final override F::AstNode getAFieldOrChild() { erb_graphql_directive_child(this, result) } } /** A class representing `output_directive` nodes. */ @@ -2435,10 +2447,10 @@ module Erb { final override string getAPrimaryQlClass() { result = "OutputDirective" } /** Gets the child of this node. */ - final Code getChild() { erb_output_directive_child(this, result) } + final F::Code getChild() { erb_output_directive_child(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { erb_output_directive_child(this, result) } + final override F::AstNode getAFieldOrChild() { erb_output_directive_child(this, result) } } /** A class representing `template` nodes. */ @@ -2447,10 +2459,10 @@ module Erb { final override string getAPrimaryQlClass() { result = "Template" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { erb_template_child(this, i, result) } + final F::AstNode getChild(int i) { erb_template_child(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { erb_template_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { erb_template_child(this, _, result) } } /** Provides predicates for mapping AST nodes to their named children. */ diff --git a/unified/ql/lib/codeql/unified/Ast.qll b/unified/ql/lib/codeql/unified/Ast.qll index 4ad61ff353bf..e4f17df788c3 100644 --- a/unified/ql/lib/codeql/unified/Ast.qll +++ b/unified/ql/lib/codeql/unified/Ast.qll @@ -25,6 +25,8 @@ private predicate discardLocation(@location_default loc) { overlay[local] module Unified { + private import FacadeAst::Unified as F + /** The base class for all AST nodes */ private class AstNodeImpl extends @unified_ast_node { /** Gets a string representation of this element. */ @@ -34,13 +36,13 @@ module Unified { final L::Location getLocation() { unified_ast_node_location(this, result) } /** Gets the parent of this element. */ - final AstNode getParent() { unified_ast_node_parent(this, result, _) } + final F::AstNode getParent() { unified_ast_node_parent(this, result, _) } /** Gets the index of this node among the children of its parent. */ final int getParentIndex() { unified_ast_node_parent(this, _, result) } /** Gets a field or child node of this node. */ - AstNode getAFieldOrChild() { none() } + F::AstNode getAFieldOrChild() { none() } /** Gets the name of the primary QL class for this element. */ string getAPrimaryQlClass() { result = "???" } @@ -103,25 +105,27 @@ module Unified { final override string getAPrimaryQlClass() { result = "AccessorDeclaration" } /** Gets the node corresponding to the field `accessor_kind`. */ - final AccessorKind getAccessorKind() { unified_accessor_declaration_def(this, result, _) } + final F::AccessorKind getAccessorKind() { unified_accessor_declaration_def(this, result, _) } /** Gets the node corresponding to the field `body`. */ - final Block getBody() { unified_accessor_declaration_body(this, result) } + final F::Block getBody() { unified_accessor_declaration_body(this, result) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_accessor_declaration_modifier(this, i, result) } + final F::Modifier getModifier(int i) { unified_accessor_declaration_modifier(this, i, result) } /** Gets the node corresponding to the field `name`. */ - final Identifier getName() { unified_accessor_declaration_def(this, _, result) } + final F::Identifier getName() { unified_accessor_declaration_def(this, _, result) } /** Gets the node corresponding to the field `parameter`. */ - final Parameter getParameter(int i) { unified_accessor_declaration_parameter(this, i, result) } + final F::Parameter getParameter(int i) { + unified_accessor_declaration_parameter(this, i, result) + } /** Gets the node corresponding to the field `type`. */ - final TypeExpr getType() { unified_accessor_declaration_type(this, result) } + final F::TypeExpr getType() { unified_accessor_declaration_type(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_accessor_declaration_def(this, result, _) or unified_accessor_declaration_body(this, result) or unified_accessor_declaration_modifier(this, _, result) or @@ -143,16 +147,16 @@ module Unified { final override string getAPrimaryQlClass() { result = "Argument" } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_argument_modifier(this, i, result) } + final F::Modifier getModifier(int i) { unified_argument_modifier(this, i, result) } /** Gets the node corresponding to the field `name`. */ - final Identifier getName() { unified_argument_name(this, result) } + final F::Identifier getName() { unified_argument_name(this, result) } /** Gets the node corresponding to the field `value`. */ - final Expr getValue() { unified_argument_def(this, result) } + final F::Expr getValue() { unified_argument_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_argument_modifier(this, _, result) or unified_argument_name(this, result) or unified_argument_def(this, result) @@ -165,10 +169,10 @@ module Unified { final override string getAPrimaryQlClass() { result = "ArrayLiteral" } /** Gets the node corresponding to the field `element`. */ - final Expr getElement(int i) { unified_array_literal_element(this, i, result) } + final F::Expr getElement(int i) { unified_array_literal_element(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { unified_array_literal_element(this, _, result) } + final override F::AstNode getAFieldOrChild() { unified_array_literal_element(this, _, result) } } /** A class representing `assign_expr` nodes. */ @@ -177,13 +181,13 @@ module Unified { final override string getAPrimaryQlClass() { result = "AssignExpr" } /** Gets the node corresponding to the field `target`. */ - final ExprOrPattern getTarget() { unified_assign_expr_def(this, result, _) } + final F::ExprOrPattern getTarget() { unified_assign_expr_def(this, result, _) } /** Gets the node corresponding to the field `value`. */ - final Expr getValue() { unified_assign_expr_def(this, _, result) } + final F::Expr getValue() { unified_assign_expr_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_assign_expr_def(this, result, _) or unified_assign_expr_def(this, _, result) } } @@ -194,18 +198,18 @@ module Unified { final override string getAPrimaryQlClass() { result = "AssociatedTypeDeclaration" } /** Gets the node corresponding to the field `bound`. */ - final TypeExpr getBound() { unified_associated_type_declaration_bound(this, result) } + final F::TypeExpr getBound() { unified_associated_type_declaration_bound(this, result) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { + final F::Modifier getModifier(int i) { unified_associated_type_declaration_modifier(this, i, result) } /** Gets the node corresponding to the field `name`. */ - final Identifier getName() { unified_associated_type_declaration_def(this, result) } + final F::Identifier getName() { unified_associated_type_declaration_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_associated_type_declaration_bound(this, result) or unified_associated_type_declaration_modifier(this, _, result) or unified_associated_type_declaration_def(this, result) @@ -218,13 +222,13 @@ module Unified { final override string getAPrimaryQlClass() { result = "BaseType" } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_base_type_modifier(this, i, result) } + final F::Modifier getModifier(int i) { unified_base_type_modifier(this, i, result) } /** Gets the node corresponding to the field `type`. */ - final TypeExpr getType() { unified_base_type_def(this, result) } + final F::TypeExpr getType() { unified_base_type_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_base_type_modifier(this, _, result) or unified_base_type_def(this, result) } } @@ -235,16 +239,16 @@ module Unified { final override string getAPrimaryQlClass() { result = "BinaryExpr" } /** Gets the node corresponding to the field `left`. */ - final Expr getLeft() { unified_binary_expr_def(this, result, _, _) } + final F::Expr getLeft() { unified_binary_expr_def(this, result, _, _) } /** Gets the node corresponding to the field `operator`. */ - final InfixOperator getOperator() { unified_binary_expr_def(this, _, result, _) } + final F::InfixOperator getOperator() { unified_binary_expr_def(this, _, result, _) } /** Gets the node corresponding to the field `right`. */ - final Expr getRight() { unified_binary_expr_def(this, _, _, result) } + final F::Expr getRight() { unified_binary_expr_def(this, _, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_binary_expr_def(this, result, _, _) or unified_binary_expr_def(this, _, result, _) or unified_binary_expr_def(this, _, _, result) @@ -257,10 +261,10 @@ module Unified { final override string getAPrimaryQlClass() { result = "Block" } /** Gets the node corresponding to the field `stmt`. */ - final Stmt getStmt(int i) { unified_block_stmt(this, i, result) } + final F::Stmt getStmt(int i) { unified_block_stmt(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { unified_block_stmt(this, _, result) } + final override F::AstNode getAFieldOrChild() { unified_block_stmt(this, _, result) } } /** A class representing `boolean_literal` tokens. */ @@ -275,13 +279,13 @@ module Unified { final override string getAPrimaryQlClass() { result = "BoundTypeConstraint" } /** Gets the node corresponding to the field `bound`. */ - final TypeExpr getBound() { unified_bound_type_constraint_def(this, result, _) } + final F::TypeExpr getBound() { unified_bound_type_constraint_def(this, result, _) } /** Gets the node corresponding to the field `type`. */ - final TypeExpr getType() { unified_bound_type_constraint_def(this, _, result) } + final F::TypeExpr getType() { unified_bound_type_constraint_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_bound_type_constraint_def(this, result, _) or unified_bound_type_constraint_def(this, _, result) } @@ -293,10 +297,10 @@ module Unified { final override string getAPrimaryQlClass() { result = "BreakExpr" } /** Gets the node corresponding to the field `label`. */ - final Identifier getLabel() { unified_break_expr_label(this, result) } + final F::Identifier getLabel() { unified_break_expr_label(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { unified_break_expr_label(this, result) } + final override F::AstNode getAFieldOrChild() { unified_break_expr_label(this, result) } } /** A class representing `builtin_expr` tokens. */ @@ -311,10 +315,12 @@ module Unified { final override string getAPrimaryQlClass() { result = "BulkImportingPattern" } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_bulk_importing_pattern_modifier(this, i, result) } + final F::Modifier getModifier(int i) { + unified_bulk_importing_pattern_modifier(this, i, result) + } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_bulk_importing_pattern_modifier(this, _, result) } } @@ -325,16 +331,16 @@ module Unified { final override string getAPrimaryQlClass() { result = "CallExpr" } /** Gets the node corresponding to the field `argument`. */ - final Argument getArgument(int i) { unified_call_expr_argument(this, i, result) } + final F::Argument getArgument(int i) { unified_call_expr_argument(this, i, result) } /** Gets the node corresponding to the field `callee`. */ - final ExprOrType getCallee() { unified_call_expr_def(this, result) } + final F::ExprOrType getCallee() { unified_call_expr_def(this, result) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_call_expr_modifier(this, i, result) } + final F::Modifier getModifier(int i) { unified_call_expr_modifier(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_call_expr_argument(this, _, result) or unified_call_expr_def(this, result) or unified_call_expr_modifier(this, _, result) @@ -347,16 +353,16 @@ module Unified { final override string getAPrimaryQlClass() { result = "CatchClause" } /** Gets the node corresponding to the field `body`. */ - final Block getBody() { unified_catch_clause_def(this, result) } + final F::Block getBody() { unified_catch_clause_def(this, result) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_catch_clause_modifier(this, i, result) } + final F::Modifier getModifier(int i) { unified_catch_clause_modifier(this, i, result) } /** Gets the node corresponding to the field `pattern`. */ - final Pattern getPattern() { unified_catch_clause_pattern(this, result) } + final F::Pattern getPattern() { unified_catch_clause_pattern(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_catch_clause_def(this, result) or unified_catch_clause_modifier(this, _, result) or unified_catch_clause_pattern(this, result) @@ -369,29 +375,33 @@ module Unified { final override string getAPrimaryQlClass() { result = "ClassLikeDeclaration" } /** Gets the node corresponding to the field `base_type`. */ - final BaseType getBaseType(int i) { unified_class_like_declaration_base_type(this, i, result) } + final F::BaseType getBaseType(int i) { + unified_class_like_declaration_base_type(this, i, result) + } /** Gets the node corresponding to the field `member`. */ - final Member getMember(int i) { unified_class_like_declaration_member(this, i, result) } + final F::Member getMember(int i) { unified_class_like_declaration_member(this, i, result) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_class_like_declaration_modifier(this, i, result) } + final F::Modifier getModifier(int i) { + unified_class_like_declaration_modifier(this, i, result) + } /** Gets the node corresponding to the field `name`. */ - final Identifier getName() { unified_class_like_declaration_name(this, result) } + final F::Identifier getName() { unified_class_like_declaration_name(this, result) } /** Gets the node corresponding to the field `type_constraint`. */ - final TypeConstraint getTypeConstraint(int i) { + final F::TypeConstraint getTypeConstraint(int i) { unified_class_like_declaration_type_constraint(this, i, result) } /** Gets the node corresponding to the field `type_parameter`. */ - final TypeParameter getTypeParameter(int i) { + final F::TypeParameter getTypeParameter(int i) { unified_class_like_declaration_type_parameter(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_class_like_declaration_base_type(this, _, result) or unified_class_like_declaration_member(this, _, result) or unified_class_like_declaration_modifier(this, _, result) or @@ -407,16 +417,16 @@ module Unified { final override string getAPrimaryQlClass() { result = "CompoundAssignExpr" } /** Gets the node corresponding to the field `operator`. */ - final InfixOperator getOperator() { unified_compound_assign_expr_def(this, result, _, _) } + final F::InfixOperator getOperator() { unified_compound_assign_expr_def(this, result, _, _) } /** Gets the node corresponding to the field `target`. */ - final Expr getTarget() { unified_compound_assign_expr_def(this, _, result, _) } + final F::Expr getTarget() { unified_compound_assign_expr_def(this, _, result, _) } /** Gets the node corresponding to the field `value`. */ - final Expr getValue() { unified_compound_assign_expr_def(this, _, _, result) } + final F::Expr getValue() { unified_compound_assign_expr_def(this, _, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_compound_assign_expr_def(this, result, _, _) or unified_compound_assign_expr_def(this, _, result, _) or unified_compound_assign_expr_def(this, _, _, result) @@ -429,16 +439,16 @@ module Unified { final override string getAPrimaryQlClass() { result = "ConditionalPattern" } /** Gets the node corresponding to the field `condition`. */ - final Expr getCondition() { unified_conditional_pattern_def(this, result, _) } + final F::Expr getCondition() { unified_conditional_pattern_def(this, result, _) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_conditional_pattern_modifier(this, i, result) } + final F::Modifier getModifier(int i) { unified_conditional_pattern_modifier(this, i, result) } /** Gets the node corresponding to the field `pattern`. */ - final Pattern getPattern() { unified_conditional_pattern_def(this, _, result) } + final F::Pattern getPattern() { unified_conditional_pattern_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_conditional_pattern_def(this, result, _) or unified_conditional_pattern_modifier(this, _, result) or unified_conditional_pattern_def(this, _, result) @@ -451,21 +461,23 @@ module Unified { final override string getAPrimaryQlClass() { result = "ConstructorDeclaration" } /** Gets the node corresponding to the field `body`. */ - final Block getBody() { unified_constructor_declaration_def(this, result) } + final F::Block getBody() { unified_constructor_declaration_def(this, result) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_constructor_declaration_modifier(this, i, result) } + final F::Modifier getModifier(int i) { + unified_constructor_declaration_modifier(this, i, result) + } /** Gets the node corresponding to the field `name`. */ - final Identifier getName() { unified_constructor_declaration_name(this, result) } + final F::Identifier getName() { unified_constructor_declaration_name(this, result) } /** Gets the node corresponding to the field `parameter`. */ - final Parameter getParameter(int i) { + final F::Parameter getParameter(int i) { unified_constructor_declaration_parameter(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_constructor_declaration_def(this, result) or unified_constructor_declaration_modifier(this, _, result) or unified_constructor_declaration_name(this, result) or @@ -479,16 +491,18 @@ module Unified { final override string getAPrimaryQlClass() { result = "ConstructorPattern" } /** Gets the node corresponding to the field `constructor`. */ - final ExprOrType getConstructor() { unified_constructor_pattern_def(this, result) } + final F::ExprOrType getConstructor() { unified_constructor_pattern_def(this, result) } /** Gets the node corresponding to the field `element`. */ - final PatternElement getElement(int i) { unified_constructor_pattern_element(this, i, result) } + final F::PatternElement getElement(int i) { + unified_constructor_pattern_element(this, i, result) + } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_constructor_pattern_modifier(this, i, result) } + final F::Modifier getModifier(int i) { unified_constructor_pattern_modifier(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_constructor_pattern_def(this, result) or unified_constructor_pattern_element(this, _, result) or unified_constructor_pattern_modifier(this, _, result) @@ -501,10 +515,10 @@ module Unified { final override string getAPrimaryQlClass() { result = "ContinueExpr" } /** Gets the node corresponding to the field `label`. */ - final Identifier getLabel() { unified_continue_expr_label(this, result) } + final F::Identifier getLabel() { unified_continue_expr_label(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { unified_continue_expr_label(this, result) } + final override F::AstNode getAFieldOrChild() { unified_continue_expr_label(this, result) } } /** A class representing `destructor_declaration` nodes. */ @@ -513,13 +527,15 @@ module Unified { final override string getAPrimaryQlClass() { result = "DestructorDeclaration" } /** Gets the node corresponding to the field `body`. */ - final Block getBody() { unified_destructor_declaration_def(this, result) } + final F::Block getBody() { unified_destructor_declaration_def(this, result) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_destructor_declaration_modifier(this, i, result) } + final F::Modifier getModifier(int i) { + unified_destructor_declaration_modifier(this, i, result) + } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_destructor_declaration_def(this, result) or unified_destructor_declaration_modifier(this, _, result) } @@ -531,16 +547,16 @@ module Unified { final override string getAPrimaryQlClass() { result = "DoWhileStmt" } /** Gets the node corresponding to the field `body`. */ - final Block getBody() { unified_do_while_stmt_body(this, result) } + final F::Block getBody() { unified_do_while_stmt_body(this, result) } /** Gets the node corresponding to the field `condition`. */ - final Expr getCondition() { unified_do_while_stmt_def(this, result) } + final F::Expr getCondition() { unified_do_while_stmt_def(this, result) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_do_while_stmt_modifier(this, i, result) } + final F::Modifier getModifier(int i) { unified_do_while_stmt_modifier(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_do_while_stmt_body(this, result) or unified_do_while_stmt_def(this, result) or unified_do_while_stmt_modifier(this, _, result) @@ -559,13 +575,13 @@ module Unified { final override string getAPrimaryQlClass() { result = "EqualityTypeConstraint" } /** Gets the node corresponding to the field `left`. */ - final TypeExpr getLeft() { unified_equality_type_constraint_def(this, result, _) } + final F::TypeExpr getLeft() { unified_equality_type_constraint_def(this, result, _) } /** Gets the node corresponding to the field `right`. */ - final TypeExpr getRight() { unified_equality_type_constraint_def(this, _, result) } + final F::TypeExpr getRight() { unified_equality_type_constraint_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_equality_type_constraint_def(this, result, _) or unified_equality_type_constraint_def(this, _, result) } @@ -579,10 +595,10 @@ module Unified { final override string getAPrimaryQlClass() { result = "ExprEqualityPattern" } /** Gets the node corresponding to the field `expr`. */ - final Expr getExpr() { unified_expr_equality_pattern_def(this, result) } + final F::Expr getExpr() { unified_expr_equality_pattern_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { unified_expr_equality_pattern_def(this, result) } + final override F::AstNode getAFieldOrChild() { unified_expr_equality_pattern_def(this, result) } } final class ExprOrOperator extends @unified_expr_or_operator, AstNodeImpl { } @@ -609,22 +625,22 @@ module Unified { final override string getAPrimaryQlClass() { result = "ForEachStmt" } /** Gets the node corresponding to the field `body`. */ - final Block getBody() { unified_for_each_stmt_body(this, result) } + final F::Block getBody() { unified_for_each_stmt_body(this, result) } /** Gets the node corresponding to the field `guard`. */ - final Expr getGuard() { unified_for_each_stmt_guard(this, result) } + final F::Expr getGuard() { unified_for_each_stmt_guard(this, result) } /** Gets the node corresponding to the field `iterable`. */ - final Expr getIterable() { unified_for_each_stmt_def(this, result, _) } + final F::Expr getIterable() { unified_for_each_stmt_def(this, result, _) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_for_each_stmt_modifier(this, i, result) } + final F::Modifier getModifier(int i) { unified_for_each_stmt_modifier(this, i, result) } /** Gets the node corresponding to the field `pattern`. */ - final Pattern getPattern() { unified_for_each_stmt_def(this, _, result) } + final F::Pattern getPattern() { unified_for_each_stmt_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_for_each_stmt_body(this, result) or unified_for_each_stmt_guard(this, result) or unified_for_each_stmt_def(this, result, _) or @@ -639,32 +655,34 @@ module Unified { final override string getAPrimaryQlClass() { result = "FunctionDeclaration" } /** Gets the node corresponding to the field `body`. */ - final Block getBody() { unified_function_declaration_body(this, result) } + final F::Block getBody() { unified_function_declaration_body(this, result) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_function_declaration_modifier(this, i, result) } + final F::Modifier getModifier(int i) { unified_function_declaration_modifier(this, i, result) } /** Gets the node corresponding to the field `name`. */ - final Identifier getName() { unified_function_declaration_def(this, result) } + final F::Identifier getName() { unified_function_declaration_def(this, result) } /** Gets the node corresponding to the field `parameter`. */ - final Parameter getParameter(int i) { unified_function_declaration_parameter(this, i, result) } + final F::Parameter getParameter(int i) { + unified_function_declaration_parameter(this, i, result) + } /** Gets the node corresponding to the field `return_type`. */ - final TypeExpr getReturnType() { unified_function_declaration_return_type(this, result) } + final F::TypeExpr getReturnType() { unified_function_declaration_return_type(this, result) } /** Gets the node corresponding to the field `type_constraint`. */ - final TypeConstraint getTypeConstraint(int i) { + final F::TypeConstraint getTypeConstraint(int i) { unified_function_declaration_type_constraint(this, i, result) } /** Gets the node corresponding to the field `type_parameter`. */ - final TypeParameter getTypeParameter(int i) { + final F::TypeParameter getTypeParameter(int i) { unified_function_declaration_type_parameter(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_function_declaration_body(this, result) or unified_function_declaration_modifier(this, _, result) or unified_function_declaration_def(this, result) or @@ -681,24 +699,24 @@ module Unified { final override string getAPrimaryQlClass() { result = "FunctionExpr" } /** Gets the node corresponding to the field `body`. */ - final Block getBody() { unified_function_expr_def(this, result) } + final F::Block getBody() { unified_function_expr_def(this, result) } /** Gets the node corresponding to the field `capture_declaration`. */ - final VariableDeclaration getCaptureDeclaration(int i) { + final F::VariableDeclaration getCaptureDeclaration(int i) { unified_function_expr_capture_declaration(this, i, result) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_function_expr_modifier(this, i, result) } + final F::Modifier getModifier(int i) { unified_function_expr_modifier(this, i, result) } /** Gets the node corresponding to the field `parameter`. */ - final Parameter getParameter(int i) { unified_function_expr_parameter(this, i, result) } + final F::Parameter getParameter(int i) { unified_function_expr_parameter(this, i, result) } /** Gets the node corresponding to the field `return_type`. */ - final TypeExpr getReturnType() { unified_function_expr_return_type(this, result) } + final F::TypeExpr getReturnType() { unified_function_expr_return_type(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_function_expr_def(this, result) or unified_function_expr_capture_declaration(this, _, result) or unified_function_expr_modifier(this, _, result) or @@ -713,13 +731,13 @@ module Unified { final override string getAPrimaryQlClass() { result = "FunctionTypeExpr" } /** Gets the node corresponding to the field `parameter`. */ - final Parameter getParameter(int i) { unified_function_type_expr_parameter(this, i, result) } + final F::Parameter getParameter(int i) { unified_function_type_expr_parameter(this, i, result) } /** Gets the node corresponding to the field `return_type`. */ - final TypeExpr getReturnType() { unified_function_type_expr_def(this, result) } + final F::TypeExpr getReturnType() { unified_function_type_expr_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_function_type_expr_parameter(this, _, result) or unified_function_type_expr_def(this, result) } @@ -731,15 +749,15 @@ module Unified { final override string getAPrimaryQlClass() { result = "GenericTypeExpr" } /** Gets the node corresponding to the field `base`. */ - final TypeExpr getBase() { unified_generic_type_expr_def(this, result) } + final F::TypeExpr getBase() { unified_generic_type_expr_def(this, result) } /** Gets the node corresponding to the field `type_argument`. */ - final TypeExpr getTypeArgument(int i) { + final F::TypeExpr getTypeArgument(int i) { unified_generic_type_expr_type_argument(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_generic_type_expr_def(this, result) or unified_generic_type_expr_type_argument(this, _, result) } @@ -751,13 +769,13 @@ module Unified { final override string getAPrimaryQlClass() { result = "GuardIfStmt" } /** Gets the node corresponding to the field `condition`. */ - final Expr getCondition() { unified_guard_if_stmt_def(this, result, _) } + final F::Expr getCondition() { unified_guard_if_stmt_def(this, result, _) } /** Gets the node corresponding to the field `else`. */ - final Block getElse() { unified_guard_if_stmt_def(this, _, result) } + final F::Block getElse() { unified_guard_if_stmt_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_guard_if_stmt_def(this, result, _) or unified_guard_if_stmt_def(this, _, result) } } @@ -774,16 +792,16 @@ module Unified { final override string getAPrimaryQlClass() { result = "IfExpr" } /** Gets the node corresponding to the field `condition`. */ - final Expr getCondition() { unified_if_expr_def(this, result) } + final F::Expr getCondition() { unified_if_expr_def(this, result) } /** Gets the node corresponding to the field `else`. */ - final Expr getElse() { unified_if_expr_else(this, result) } + final F::Expr getElse() { unified_if_expr_else(this, result) } /** Gets the node corresponding to the field `then`. */ - final Expr getThen() { unified_if_expr_then(this, result) } + final F::Expr getThen() { unified_if_expr_then(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_if_expr_def(this, result) or unified_if_expr_else(this, result) or unified_if_expr_then(this, result) @@ -802,16 +820,16 @@ module Unified { final override string getAPrimaryQlClass() { result = "ImportDeclaration" } /** Gets the node corresponding to the field `imported_expr`. */ - final Expr getImportedExpr() { unified_import_declaration_def(this, result) } + final F::Expr getImportedExpr() { unified_import_declaration_def(this, result) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_import_declaration_modifier(this, i, result) } + final F::Modifier getModifier(int i) { unified_import_declaration_modifier(this, i, result) } /** Gets the node corresponding to the field `pattern`. */ - final Pattern getPattern() { unified_import_declaration_pattern(this, result) } + final F::Pattern getPattern() { unified_import_declaration_pattern(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_import_declaration_def(this, result) or unified_import_declaration_modifier(this, _, result) or unified_import_declaration_pattern(this, result) @@ -836,13 +854,15 @@ module Unified { final override string getAPrimaryQlClass() { result = "InitializerDeclaration" } /** Gets the node corresponding to the field `body`. */ - final Block getBody() { unified_initializer_declaration_def(this, result) } + final F::Block getBody() { unified_initializer_declaration_def(this, result) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_initializer_declaration_modifier(this, i, result) } + final F::Modifier getModifier(int i) { + unified_initializer_declaration_modifier(this, i, result) + } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_initializer_declaration_def(this, result) or unified_initializer_declaration_modifier(this, _, result) } @@ -860,13 +880,13 @@ module Unified { final override string getAPrimaryQlClass() { result = "KeyValuePair" } /** Gets the node corresponding to the field `key`. */ - final Expr getKey() { unified_key_value_pair_def(this, result, _) } + final F::Expr getKey() { unified_key_value_pair_def(this, result, _) } /** Gets the node corresponding to the field `value`. */ - final Expr getValue() { unified_key_value_pair_def(this, _, result) } + final F::Expr getValue() { unified_key_value_pair_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_key_value_pair_def(this, result, _) or unified_key_value_pair_def(this, _, result) } } @@ -877,13 +897,13 @@ module Unified { final override string getAPrimaryQlClass() { result = "LabeledStmt" } /** Gets the node corresponding to the field `label`. */ - final Identifier getLabel() { unified_labeled_stmt_def(this, result, _) } + final F::Identifier getLabel() { unified_labeled_stmt_def(this, result, _) } /** Gets the node corresponding to the field `stmt`. */ - final Stmt getStmt() { unified_labeled_stmt_def(this, _, result) } + final F::Stmt getStmt() { unified_labeled_stmt_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_labeled_stmt_def(this, result, _) or unified_labeled_stmt_def(this, _, result) } } @@ -894,10 +914,10 @@ module Unified { final override string getAPrimaryQlClass() { result = "MapLiteral" } /** Gets the node corresponding to the field `element`. */ - final Expr getElement(int i) { unified_map_literal_element(this, i, result) } + final F::Expr getElement(int i) { unified_map_literal_element(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { unified_map_literal_element(this, _, result) } + final override F::AstNode getAFieldOrChild() { unified_map_literal_element(this, _, result) } } final class Member extends @unified_member, AstNodeImpl { } @@ -908,13 +928,13 @@ module Unified { final override string getAPrimaryQlClass() { result = "MemberAccessExpr" } /** Gets the node corresponding to the field `base`. */ - final ExprOrType getBase() { unified_member_access_expr_def(this, result, _) } + final F::ExprOrType getBase() { unified_member_access_expr_def(this, result, _) } /** Gets the node corresponding to the field `member`. */ - final Identifier getMember() { unified_member_access_expr_def(this, _, result) } + final F::Identifier getMember() { unified_member_access_expr_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_member_access_expr_def(this, result, _) or unified_member_access_expr_def(this, _, result) } @@ -932,10 +952,10 @@ module Unified { final override string getAPrimaryQlClass() { result = "NameExpr" } /** Gets the node corresponding to the field `identifier`. */ - final Identifier getIdentifier() { unified_name_expr_def(this, result) } + final F::Identifier getIdentifier() { unified_name_expr_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { unified_name_expr_def(this, result) } + final override F::AstNode getAFieldOrChild() { unified_name_expr_def(this, result) } } /** A class representing `name_pattern` nodes. */ @@ -944,13 +964,13 @@ module Unified { final override string getAPrimaryQlClass() { result = "NamePattern" } /** Gets the node corresponding to the field `identifier`. */ - final Identifier getIdentifier() { unified_name_pattern_def(this, result) } + final F::Identifier getIdentifier() { unified_name_pattern_def(this, result) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_name_pattern_modifier(this, i, result) } + final F::Modifier getModifier(int i) { unified_name_pattern_modifier(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_name_pattern_def(this, result) or unified_name_pattern_modifier(this, _, result) } } @@ -961,13 +981,13 @@ module Unified { final override string getAPrimaryQlClass() { result = "NamedTypeExpr" } /** Gets the node corresponding to the field `name`. */ - final Identifier getName() { unified_named_type_expr_def(this, result) } + final F::Identifier getName() { unified_named_type_expr_def(this, result) } /** Gets the node corresponding to the field `qualifier`. */ - final TypeExpr getQualifier() { unified_named_type_expr_qualifier(this, result) } + final F::TypeExpr getQualifier() { unified_named_type_expr_qualifier(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_named_type_expr_def(this, result) or unified_named_type_expr_qualifier(this, result) } } @@ -980,21 +1000,21 @@ module Unified { final override string getAPrimaryQlClass() { result = "OperatorSyntaxDeclaration" } /** Gets the node corresponding to the field `fixity`. */ - final Fixity getFixity() { unified_operator_syntax_declaration_fixity(this, result) } + final F::Fixity getFixity() { unified_operator_syntax_declaration_fixity(this, result) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { + final F::Modifier getModifier(int i) { unified_operator_syntax_declaration_modifier(this, i, result) } /** Gets the node corresponding to the field `name`. */ - final Identifier getName() { unified_operator_syntax_declaration_def(this, result) } + final F::Identifier getName() { unified_operator_syntax_declaration_def(this, result) } /** Gets the node corresponding to the field `precedence`. */ - final Expr getPrecedence() { unified_operator_syntax_declaration_precedence(this, result) } + final F::Expr getPrecedence() { unified_operator_syntax_declaration_precedence(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_operator_syntax_declaration_fixity(this, result) or unified_operator_syntax_declaration_modifier(this, _, result) or unified_operator_syntax_declaration_def(this, result) or @@ -1008,13 +1028,13 @@ module Unified { final override string getAPrimaryQlClass() { result = "OrPattern" } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_or_pattern_modifier(this, i, result) } + final F::Modifier getModifier(int i) { unified_or_pattern_modifier(this, i, result) } /** Gets the node corresponding to the field `pattern`. */ - final Pattern getPattern(int i) { unified_or_pattern_pattern(this, i, result) } + final F::Pattern getPattern(int i) { unified_or_pattern_pattern(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_or_pattern_modifier(this, _, result) or unified_or_pattern_pattern(this, _, result) } } @@ -1025,22 +1045,22 @@ module Unified { final override string getAPrimaryQlClass() { result = "Parameter" } /** Gets the node corresponding to the field `default`. */ - final Expr getDefault() { unified_parameter_default(this, result) } + final F::Expr getDefault() { unified_parameter_default(this, result) } /** Gets the node corresponding to the field `external_name`. */ - final Identifier getExternalName() { unified_parameter_external_name(this, result) } + final F::Identifier getExternalName() { unified_parameter_external_name(this, result) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_parameter_modifier(this, i, result) } + final F::Modifier getModifier(int i) { unified_parameter_modifier(this, i, result) } /** Gets the node corresponding to the field `pattern`. */ - final Pattern getPattern() { unified_parameter_pattern(this, result) } + final F::Pattern getPattern() { unified_parameter_pattern(this, result) } /** Gets the node corresponding to the field `type`. */ - final TypeExpr getType() { unified_parameter_type(this, result) } + final F::TypeExpr getType() { unified_parameter_type(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_parameter_default(this, result) or unified_parameter_external_name(this, result) or unified_parameter_modifier(this, _, result) or @@ -1057,16 +1077,16 @@ module Unified { final override string getAPrimaryQlClass() { result = "PatternElement" } /** Gets the node corresponding to the field `key`. */ - final Identifier getKey() { unified_pattern_element_key(this, result) } + final F::Identifier getKey() { unified_pattern_element_key(this, result) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_pattern_element_modifier(this, i, result) } + final F::Modifier getModifier(int i) { unified_pattern_element_modifier(this, i, result) } /** Gets the node corresponding to the field `pattern`. */ - final Pattern getPattern() { unified_pattern_element_def(this, result) } + final F::Pattern getPattern() { unified_pattern_element_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_pattern_element_key(this, result) or unified_pattern_element_modifier(this, _, result) or unified_pattern_element_def(this, result) @@ -1079,13 +1099,13 @@ module Unified { final override string getAPrimaryQlClass() { result = "PatternGuardExpr" } /** Gets the node corresponding to the field `pattern`. */ - final Pattern getPattern() { unified_pattern_guard_expr_def(this, result, _) } + final F::Pattern getPattern() { unified_pattern_guard_expr_def(this, result, _) } /** Gets the node corresponding to the field `value`. */ - final Expr getValue() { unified_pattern_guard_expr_def(this, _, result) } + final F::Expr getValue() { unified_pattern_guard_expr_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_pattern_guard_expr_def(this, result, _) or unified_pattern_guard_expr_def(this, _, result) } @@ -1115,10 +1135,10 @@ module Unified { final override string getAPrimaryQlClass() { result = "ReturnExpr" } /** Gets the node corresponding to the field `value`. */ - final Expr getValue() { unified_return_expr_value(this, result) } + final F::Expr getValue() { unified_return_expr_value(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { unified_return_expr_value(this, result) } + final override F::AstNode getAFieldOrChild() { unified_return_expr_value(this, result) } } final class Stmt extends @unified_stmt, AstNodeImpl { } @@ -1141,16 +1161,16 @@ module Unified { final override string getAPrimaryQlClass() { result = "SwitchCase" } /** Gets the node corresponding to the field `body`. */ - final Block getBody() { unified_switch_case_def(this, result) } + final F::Block getBody() { unified_switch_case_def(this, result) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_switch_case_modifier(this, i, result) } + final F::Modifier getModifier(int i) { unified_switch_case_modifier(this, i, result) } /** Gets the node corresponding to the field `pattern`. */ - final Pattern getPattern() { unified_switch_case_pattern(this, result) } + final F::Pattern getPattern() { unified_switch_case_pattern(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_switch_case_def(this, result) or unified_switch_case_modifier(this, _, result) or unified_switch_case_pattern(this, result) @@ -1163,16 +1183,16 @@ module Unified { final override string getAPrimaryQlClass() { result = "SwitchExpr" } /** Gets the node corresponding to the field `case`. */ - final SwitchCase getCase(int i) { unified_switch_expr_case(this, i, result) } + final F::SwitchCase getCase(int i) { unified_switch_expr_case(this, i, result) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_switch_expr_modifier(this, i, result) } + final F::Modifier getModifier(int i) { unified_switch_expr_modifier(this, i, result) } /** Gets the node corresponding to the field `value`. */ - final Expr getValue() { unified_switch_expr_def(this, result) } + final F::Expr getValue() { unified_switch_expr_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_switch_expr_case(this, _, result) or unified_switch_expr_modifier(this, _, result) or unified_switch_expr_def(this, result) @@ -1185,10 +1205,10 @@ module Unified { final override string getAPrimaryQlClass() { result = "ThrowExpr" } /** Gets the node corresponding to the field `value`. */ - final Expr getValue() { unified_throw_expr_value(this, result) } + final F::Expr getValue() { unified_throw_expr_value(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { unified_throw_expr_value(this, result) } + final override F::AstNode getAFieldOrChild() { unified_throw_expr_value(this, result) } } /** A class representing `top_level` nodes. */ @@ -1197,10 +1217,10 @@ module Unified { final override string getAPrimaryQlClass() { result = "TopLevel" } /** Gets the node corresponding to the field `body`. */ - final Block getBody() { unified_top_level_def(this, result) } + final F::Block getBody() { unified_top_level_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { unified_top_level_def(this, result) } + final override F::AstNode getAFieldOrChild() { unified_top_level_def(this, result) } } /** A class representing `try_expr` nodes. */ @@ -1209,16 +1229,16 @@ module Unified { final override string getAPrimaryQlClass() { result = "TryExpr" } /** Gets the node corresponding to the field `body`. */ - final Block getBody() { unified_try_expr_def(this, result) } + final F::Block getBody() { unified_try_expr_def(this, result) } /** Gets the node corresponding to the field `catch_clause`. */ - final CatchClause getCatchClause(int i) { unified_try_expr_catch_clause(this, i, result) } + final F::CatchClause getCatchClause(int i) { unified_try_expr_catch_clause(this, i, result) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_try_expr_modifier(this, i, result) } + final F::Modifier getModifier(int i) { unified_try_expr_modifier(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_try_expr_def(this, result) or unified_try_expr_catch_clause(this, _, result) or unified_try_expr_modifier(this, _, result) @@ -1231,10 +1251,10 @@ module Unified { final override string getAPrimaryQlClass() { result = "TupleExpr" } /** Gets the node corresponding to the field `element`. */ - final Expr getElement(int i) { unified_tuple_expr_element(this, i, result) } + final F::Expr getElement(int i) { unified_tuple_expr_element(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { unified_tuple_expr_element(this, _, result) } + final override F::AstNode getAFieldOrChild() { unified_tuple_expr_element(this, _, result) } } /** A class representing `tuple_pattern` nodes. */ @@ -1243,13 +1263,13 @@ module Unified { final override string getAPrimaryQlClass() { result = "TuplePattern" } /** Gets the node corresponding to the field `element`. */ - final PatternElement getElement(int i) { unified_tuple_pattern_element(this, i, result) } + final F::PatternElement getElement(int i) { unified_tuple_pattern_element(this, i, result) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_tuple_pattern_modifier(this, i, result) } + final F::Modifier getModifier(int i) { unified_tuple_pattern_modifier(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_tuple_pattern_element(this, _, result) or unified_tuple_pattern_modifier(this, _, result) } @@ -1261,13 +1281,13 @@ module Unified { final override string getAPrimaryQlClass() { result = "TupleTypeElement" } /** Gets the node corresponding to the field `name`. */ - final Identifier getName() { unified_tuple_type_element_name(this, result) } + final F::Identifier getName() { unified_tuple_type_element_name(this, result) } /** Gets the node corresponding to the field `type`. */ - final TypeExpr getType() { unified_tuple_type_element_def(this, result) } + final F::TypeExpr getType() { unified_tuple_type_element_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_tuple_type_element_name(this, result) or unified_tuple_type_element_def(this, result) } } @@ -1278,10 +1298,12 @@ module Unified { final override string getAPrimaryQlClass() { result = "TupleTypeExpr" } /** Gets the node corresponding to the field `element`. */ - final TupleTypeElement getElement(int i) { unified_tuple_type_expr_element(this, i, result) } + final F::TupleTypeElement getElement(int i) { unified_tuple_type_expr_element(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { unified_tuple_type_expr_element(this, _, result) } + final override F::AstNode getAFieldOrChild() { + unified_tuple_type_expr_element(this, _, result) + } } /** A class representing `type_alias_declaration` nodes. */ @@ -1290,26 +1312,28 @@ module Unified { final override string getAPrimaryQlClass() { result = "TypeAliasDeclaration" } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_type_alias_declaration_modifier(this, i, result) } + final F::Modifier getModifier(int i) { + unified_type_alias_declaration_modifier(this, i, result) + } /** Gets the node corresponding to the field `name`. */ - final Identifier getName() { unified_type_alias_declaration_def(this, result, _) } + final F::Identifier getName() { unified_type_alias_declaration_def(this, result, _) } /** Gets the node corresponding to the field `type`. */ - final TypeExpr getType() { unified_type_alias_declaration_def(this, _, result) } + final F::TypeExpr getType() { unified_type_alias_declaration_def(this, _, result) } /** Gets the node corresponding to the field `type_constraint`. */ - final TypeConstraint getTypeConstraint(int i) { + final F::TypeConstraint getTypeConstraint(int i) { unified_type_alias_declaration_type_constraint(this, i, result) } /** Gets the node corresponding to the field `type_parameter`. */ - final TypeParameter getTypeParameter(int i) { + final F::TypeParameter getTypeParameter(int i) { unified_type_alias_declaration_type_parameter(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_type_alias_declaration_modifier(this, _, result) or unified_type_alias_declaration_def(this, result, _) or unified_type_alias_declaration_def(this, _, result) or @@ -1324,16 +1348,16 @@ module Unified { final override string getAPrimaryQlClass() { result = "TypeCastExpr" } /** Gets the node corresponding to the field `expr`. */ - final Expr getExpr() { unified_type_cast_expr_def(this, result, _, _) } + final F::Expr getExpr() { unified_type_cast_expr_def(this, result, _, _) } /** Gets the node corresponding to the field `operator`. */ - final InfixOperator getOperator() { unified_type_cast_expr_def(this, _, result, _) } + final F::InfixOperator getOperator() { unified_type_cast_expr_def(this, _, result, _) } /** Gets the node corresponding to the field `type`. */ - final TypeExpr getType() { unified_type_cast_expr_def(this, _, _, result) } + final F::TypeExpr getType() { unified_type_cast_expr_def(this, _, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_type_cast_expr_def(this, result, _, _) or unified_type_cast_expr_def(this, _, result, _) or unified_type_cast_expr_def(this, _, _, result) @@ -1350,16 +1374,16 @@ module Unified { final override string getAPrimaryQlClass() { result = "TypeParameter" } /** Gets the node corresponding to the field `bound`. */ - final TypeExpr getBound() { unified_type_parameter_bound(this, result) } + final F::TypeExpr getBound() { unified_type_parameter_bound(this, result) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_type_parameter_modifier(this, i, result) } + final F::Modifier getModifier(int i) { unified_type_parameter_modifier(this, i, result) } /** Gets the node corresponding to the field `name`. */ - final Identifier getName() { unified_type_parameter_def(this, result) } + final F::Identifier getName() { unified_type_parameter_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_type_parameter_bound(this, result) or unified_type_parameter_modifier(this, _, result) or unified_type_parameter_def(this, result) @@ -1372,16 +1396,16 @@ module Unified { final override string getAPrimaryQlClass() { result = "TypeTestExpr" } /** Gets the node corresponding to the field `expr`. */ - final Expr getExpr() { unified_type_test_expr_def(this, result, _, _) } + final F::Expr getExpr() { unified_type_test_expr_def(this, result, _, _) } /** Gets the node corresponding to the field `operator`. */ - final InfixOperator getOperator() { unified_type_test_expr_def(this, _, result, _) } + final F::InfixOperator getOperator() { unified_type_test_expr_def(this, _, result, _) } /** Gets the node corresponding to the field `type`. */ - final TypeExpr getType() { unified_type_test_expr_def(this, _, _, result) } + final F::TypeExpr getType() { unified_type_test_expr_def(this, _, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_type_test_expr_def(this, result, _, _) or unified_type_test_expr_def(this, _, result, _) or unified_type_test_expr_def(this, _, _, result) @@ -1394,13 +1418,13 @@ module Unified { final override string getAPrimaryQlClass() { result = "TypeTestPattern" } /** Gets the node corresponding to the field `pattern`. */ - final Pattern getPattern() { unified_type_test_pattern_def(this, result, _) } + final F::Pattern getPattern() { unified_type_test_pattern_def(this, result, _) } /** Gets the node corresponding to the field `type`. */ - final TypeExpr getType() { unified_type_test_pattern_def(this, _, result) } + final F::TypeExpr getType() { unified_type_test_pattern_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_type_test_pattern_def(this, result, _) or unified_type_test_pattern_def(this, _, result) } @@ -1412,13 +1436,13 @@ module Unified { final override string getAPrimaryQlClass() { result = "UnaryExpr" } /** Gets the node corresponding to the field `operand`. */ - final Expr getOperand() { unified_unary_expr_def(this, result, _) } + final F::Expr getOperand() { unified_unary_expr_def(this, result, _) } /** Gets the node corresponding to the field `operator`. */ - final Operator getOperator() { unified_unary_expr_def(this, _, result) } + final F::Operator getOperator() { unified_unary_expr_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_unary_expr_def(this, result, _) or unified_unary_expr_def(this, _, result) } } @@ -1429,12 +1453,12 @@ module Unified { final override string getAPrimaryQlClass() { result = "UnresolvedOperatorSequence" } /** Gets the node corresponding to the field `element`. */ - final ExprOrOperator getElement(int i) { + final F::ExprOrOperator getElement(int i) { unified_unresolved_operator_sequence_element(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_unresolved_operator_sequence_element(this, _, result) } } @@ -1451,19 +1475,19 @@ module Unified { final override string getAPrimaryQlClass() { result = "VariableDeclaration" } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_variable_declaration_modifier(this, i, result) } + final F::Modifier getModifier(int i) { unified_variable_declaration_modifier(this, i, result) } /** Gets the node corresponding to the field `pattern`. */ - final Pattern getPattern() { unified_variable_declaration_def(this, result) } + final F::Pattern getPattern() { unified_variable_declaration_def(this, result) } /** Gets the node corresponding to the field `type`. */ - final TypeExpr getType() { unified_variable_declaration_type(this, result) } + final F::TypeExpr getType() { unified_variable_declaration_type(this, result) } /** Gets the node corresponding to the field `value`. */ - final Expr getValue() { unified_variable_declaration_value(this, result) } + final F::Expr getValue() { unified_variable_declaration_value(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_variable_declaration_modifier(this, _, result) or unified_variable_declaration_def(this, result) or unified_variable_declaration_type(this, result) or @@ -1477,16 +1501,16 @@ module Unified { final override string getAPrimaryQlClass() { result = "WhileStmt" } /** Gets the node corresponding to the field `body`. */ - final Block getBody() { unified_while_stmt_body(this, result) } + final F::Block getBody() { unified_while_stmt_body(this, result) } /** Gets the node corresponding to the field `condition`. */ - final Expr getCondition() { unified_while_stmt_def(this, result) } + final F::Expr getCondition() { unified_while_stmt_def(this, result) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_while_stmt_modifier(this, i, result) } + final F::Modifier getModifier(int i) { unified_while_stmt_modifier(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_while_stmt_body(this, result) or unified_while_stmt_def(this, result) or unified_while_stmt_modifier(this, _, result) From 0c196ded444185c526f666486905b336221a284f Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 30 Jul 2026 13:08:51 +0200 Subject: [PATCH 128/188] unified: Move AST files into internal Users are not supposed to 'import' these files directly, so putting them into 'internal'. --- unified/ql/lib/codeql/unified/{ => internal}/Ast.qll | 0 unified/scripts/create-extractor-pack.sh | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) rename unified/ql/lib/codeql/unified/{ => internal}/Ast.qll (100%) diff --git a/unified/ql/lib/codeql/unified/Ast.qll b/unified/ql/lib/codeql/unified/internal/Ast.qll similarity index 100% rename from unified/ql/lib/codeql/unified/Ast.qll rename to unified/ql/lib/codeql/unified/internal/Ast.qll diff --git a/unified/scripts/create-extractor-pack.sh b/unified/scripts/create-extractor-pack.sh index 7a41092e4a74..3c22b0e6cbfd 100755 --- a/unified/scripts/create-extractor-pack.sh +++ b/unified/scripts/create-extractor-pack.sh @@ -14,9 +14,9 @@ cd "$(dirname "$0")/.." # we are in a cargo workspace rooted at the git checkout BIN_DIR=../target/release -"$BIN_DIR/codeql-extractor-unified" generate --dbscheme ql/lib/unified.dbscheme --library ql/lib/codeql/unified/Ast.qll +"$BIN_DIR/codeql-extractor-unified" generate --dbscheme ql/lib/unified.dbscheme --library ql/lib/codeql/unified/internal/Ast.qll -codeql query format -i ql/lib/codeql/unified/Ast.qll +codeql query format -i ql/lib/codeql/unified/internal/Ast.qll rm -rf extractor-pack mkdir -p extractor-pack From 33cd8d2d39b34a6611a3c601a4968116dd92d9cf Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 30 Jul 2026 13:08:51 +0200 Subject: [PATCH 129/188] unified: Add a basic facade AST --- .../lib/codeql/unified/internal/FacadeAst.qll | 20 +++++++++++++++++++ unified/ql/lib/unified.qll | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 unified/ql/lib/codeql/unified/internal/FacadeAst.qll diff --git a/unified/ql/lib/codeql/unified/internal/FacadeAst.qll b/unified/ql/lib/codeql/unified/internal/FacadeAst.qll new file mode 100644 index 000000000000..12cf0cea6420 --- /dev/null +++ b/unified/ql/lib/codeql/unified/internal/FacadeAst.qll @@ -0,0 +1,20 @@ +/** + * Provides facade AST classes, with additional hand-written members on top of the generated ones. + */ +overlay[local?] +module; + +module Unified { + private import Ast::Unified as G + import G + + class AstNode extends G::AstNode { + /** Holds if this AST node has a modifier with the given text. */ + predicate hasModifier(string text) { + exists(Modifier mod | + mod.getParent() = this and + mod.getValue() = text + ) + } + } +} diff --git a/unified/ql/lib/unified.qll b/unified/ql/lib/unified.qll index 477ac22f3661..ae22a2d76410 100644 --- a/unified/ql/lib/unified.qll +++ b/unified/ql/lib/unified.qll @@ -4,6 +4,6 @@ import codeql.Locations import codeql.files.FileSystem -import codeql.unified.Ast::Unified +import codeql.unified.internal.FacadeAst::Unified import codeql.unified.internal.AstExtra::Public import codeql.unified.internal.Variables::Public From 7ee0ac2b3b16bed4b11cafcac0bb4092439a6646 Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 30 Jul 2026 14:22:24 +0200 Subject: [PATCH 130/188] tree-sitter-extractor: Move final aliases into sibling module The split between private, non-final Impl classes and public final classes ultimately prevented the facade AST from instrumenting base classes like 'Expr' and have its subclasses actually inherit those members. This commit takes a step towards fixing that by moving the final aliases into a separate module and making the other classes public and stripping their Impl suffix. It is up to each language to avoid leaking the non-final classes (which Ruby and QL4QL don't do anyway). --- .../src/generator/mod.rs | 64 +++++++-- .../src/generator/ql_gen.rs | 122 +++++++----------- 2 files changed, 99 insertions(+), 87 deletions(-) diff --git a/shared/tree-sitter-extractor/src/generator/mod.rs b/shared/tree-sitter-extractor/src/generator/mod.rs index bc1d6fc34aab..718c25cd2d84 100644 --- a/shared/tree-sitter-extractor/src/generator/mod.rs +++ b/shared/tree-sitter-extractor/src/generator/mod.rs @@ -135,17 +135,16 @@ pub fn generate( alias: Some("F"), })); - for c in ql_gen::create_ast_node_class( + body.push(ql::TopLevel::Class(ql_gen::create_ast_node_class( &ast_node_name, &node_location_table_name, &node_parent_table_name, - ) { - body.push(ql::TopLevel::Class(c)); - } + ))); - for c in ql_gen::create_token_class(&token_name, &tokeninfo_name) { - body.push(ql::TopLevel::Class(c)); - } + body.push(ql::TopLevel::Class(ql_gen::create_token_class( + &token_name, + &tokeninfo_name, + ))); if has_trivia_tokens { body.push(ql::TopLevel::Class(ql_gen::create_trivia_token_class( @@ -179,14 +178,53 @@ pub fn generate( body.append(&mut ql_gen::convert_nodes(&nodes)); body.push(ql_gen::create_print_ast_module(&nodes)); + let mut final_body = vec![ + ql::TopLevel::Import(ql::Import { + is_private: true, + module: &facade_import_name, + alias: Some("F"), + }), + ql::TopLevel::Import(ql::Import { + is_private: false, + module: "F", + alias: None, + }), + ]; + let final_aliases = body + .iter() + .filter_map(|decl| match decl { + ql::TopLevel::Class(c) => Some(ql::TopLevel::Class(ql::Class { + qldoc: None, + name: c.name, + is_abstract: false, + is_final: true, + is_private: false, + supertypes: Set::new(), + characteristic_predicate: None, + predicates: vec![], + alias: Some(format!("F::{}", c.name)), + })), + _ => None, + }) + .collect::>(); + final_body.extend(final_aliases); + let final_module_name = format!("{}Final", language.name); ql::write( &mut ql_writer, - &[ql::TopLevel::Module(ql::Module { - qldoc: None, - name: &language.name, - body, - overlay: Some(ql::OverlayAnnotation::Local), - })], + &[ + ql::TopLevel::Module(ql::Module { + qldoc: None, + name: &language.name, + body, + overlay: Some(ql::OverlayAnnotation::Local), + }), + ql::TopLevel::Module(ql::Module { + qldoc: None, + name: &final_module_name, + body: final_body, + overlay: None, + }), + ], )?; } Ok(()) diff --git a/shared/tree-sitter-extractor/src/generator/ql_gen.rs b/shared/tree-sitter-extractor/src/generator/ql_gen.rs index 73fc5bc0e975..e68d2b336c38 100644 --- a/shared/tree-sitter-extractor/src/generator/ql_gen.rs +++ b/shared/tree-sitter-extractor/src/generator/ql_gen.rs @@ -8,7 +8,7 @@ pub fn create_ast_node_class<'a>( ast_node: &'a str, node_location_table: &'a str, node_parent_table: &'a str, -) -> [ql::Class<'a>; 2] { +) -> ql::Class<'a> { // Default implementation of `toString` calls `this.getAPrimaryQlClass()` let to_string = ql::Predicate { qldoc: Some(String::from( @@ -132,41 +132,28 @@ pub fn create_ast_node_class<'a>( ), overlay: None, }; - [ - ql::Class { - qldoc: Some(String::from("The base class for all AST nodes")), - name: "AstNodeImpl", - is_abstract: false, - is_final: false, - is_private: true, - alias: None, - supertypes: vec![ql::Type::At(ast_node)].into_iter().collect(), - characteristic_predicate: None, - predicates: vec![ - to_string, - get_location, - get_parent, - get_parent_index, - get_a_field_or_child, - get_a_primary_ql_class, - get_primary_ql_classes, - ], - }, - ql::Class { - qldoc: None, - name: "AstNode", - is_abstract: false, - is_final: true, - is_private: false, - alias: Some("AstNodeImpl".to_string()), - supertypes: vec![].into_iter().collect(), - characteristic_predicate: None, - predicates: vec![], - }, - ] + ql::Class { + qldoc: Some(String::from("The base class for all AST nodes")), + name: "AstNode", + is_abstract: false, + is_final: false, + is_private: false, + alias: None, + supertypes: vec![ql::Type::At(ast_node)].into_iter().collect(), + characteristic_predicate: None, + predicates: vec![ + to_string, + get_location, + get_parent, + get_parent_index, + get_a_field_or_child, + get_a_primary_ql_class, + get_primary_ql_classes, + ], + } } -pub fn create_token_class<'a>(token_type: &'a str, tokeninfo: &'a str) -> [ql::Class<'a>; 2] { +pub fn create_token_class<'a>(token_type: &'a str, tokeninfo: &'a str) -> ql::Class<'a> { let tokeninfo_arity = 3; // id, kind, value let get_value = ql::Predicate { qldoc: Some(String::from("Gets the value of this token.")), @@ -199,36 +186,23 @@ pub fn create_token_class<'a>(token_type: &'a str, tokeninfo: &'a str) -> [ql::C ), overlay: None, }; - [ - ql::Class { - qldoc: Some(String::from("A token.")), - name: "TokenImpl", - is_abstract: false, - is_final: false, - is_private: true, - alias: None, - supertypes: vec![ql::Type::At(token_type), ql::Type::Normal("AstNodeImpl")] - .into_iter() - .collect(), - characteristic_predicate: None, - predicates: vec![ - get_value, - to_string, - create_get_a_primary_ql_class("Token", false), - ], - }, - ql::Class { - qldoc: None, - name: "Token", - is_abstract: false, - is_final: true, - is_private: false, - alias: Some("TokenImpl".to_string()), - supertypes: vec![].into_iter().collect(), - characteristic_predicate: None, - predicates: vec![], - }, - ] + ql::Class { + qldoc: Some(String::from("A token.")), + name: "Token", + is_abstract: false, + is_final: false, + is_private: false, + alias: None, + supertypes: vec![ql::Type::At(token_type), ql::Type::Normal("AstNode")] + .into_iter() + .collect(), + characteristic_predicate: None, + predicates: vec![ + get_value, + to_string, + create_get_a_primary_ql_class("Token", false), + ], + } } /// Creates the `TriviaToken` class. Trivia tokens (e.g. comments) are @@ -283,12 +257,12 @@ pub fn create_trivia_token_class<'a>( )), name: "TriviaToken", is_abstract: false, - is_final: true, + is_final: false, is_private: false, alias: None, supertypes: vec![ ql::Type::At(trivia_token_type), - ql::Type::Normal("AstNodeImpl"), + ql::Type::Normal("AstNode"), ] .into_iter() .collect(), @@ -309,10 +283,10 @@ pub fn create_reserved_word_class(db_name: &str) -> ql::Class<'_> { qldoc: Some(String::from("A reserved word.")), name: class_name, is_abstract: false, - is_final: true, + is_final: false, is_private: false, alias: None, - supertypes: vec![ql::Type::At(db_name), ql::Type::Normal("TokenImpl")] + supertypes: vec![ql::Type::At(db_name), ql::Type::Normal("Token")] .into_iter() .collect(), characteristic_predicate: None, @@ -816,12 +790,12 @@ pub fn convert_nodes(nodes: &node_types::NodeTypeMap) -> Vec> { create_get_a_primary_ql_class(&node.ql_class_name, true); let mut supertypes: BTreeSet = BTreeSet::new(); supertypes.insert(ql::Type::At(&node.dbscheme_name)); - supertypes.insert(ql::Type::Normal("TokenImpl")); + supertypes.insert(ql::Type::Normal("Token")); classes.push(ql::TopLevel::Class(ql::Class { qldoc: Some(format!("A class representing `{}` tokens.", type_name.kind)), name: &node.ql_class_name, is_abstract: false, - is_final: true, + is_final: false, is_private: false, alias: None, supertypes, @@ -837,12 +811,12 @@ pub fn convert_nodes(nodes: &node_types::NodeTypeMap) -> Vec> { qldoc: None, name: &node.ql_class_name, is_abstract: false, - is_final: true, + is_final: false, is_private: false, alias: None, supertypes: vec![ ql::Type::At(&node.dbscheme_name), - ql::Type::Normal("AstNodeImpl"), + ql::Type::Normal("AstNode"), ] .into_iter() .collect(), @@ -871,12 +845,12 @@ pub fn convert_nodes(nodes: &node_types::NodeTypeMap) -> Vec> { qldoc: Some(format!("A class representing `{}` nodes.", type_name.kind)), name: main_class_name, is_abstract: false, - is_final: true, + is_final: false, is_private: false, alias: None, supertypes: vec![ ql::Type::At(&node.dbscheme_name), - ql::Type::Normal("AstNodeImpl"), + ql::Type::Normal("AstNode"), ] .into_iter() .collect(), From c62722ff3943656c295b8482f1bcbf25424b1dff Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 30 Jul 2026 14:22:44 +0200 Subject: [PATCH 131/188] unified: Regenerate AST and update import --- .../ql/lib/codeql/unified/internal/Ast.qll | 381 +++++++++++++----- unified/ql/lib/unified.qll | 2 +- 2 files changed, 285 insertions(+), 98 deletions(-) diff --git a/unified/ql/lib/codeql/unified/internal/Ast.qll b/unified/ql/lib/codeql/unified/internal/Ast.qll index e4f17df788c3..a165be1af82e 100644 --- a/unified/ql/lib/codeql/unified/internal/Ast.qll +++ b/unified/ql/lib/codeql/unified/internal/Ast.qll @@ -28,7 +28,7 @@ module Unified { private import FacadeAst::Unified as F /** The base class for all AST nodes */ - private class AstNodeImpl extends @unified_ast_node { + class AstNode extends @unified_ast_node { /** Gets a string representation of this element. */ string toString() { result = this.getAPrimaryQlClass() } @@ -51,10 +51,8 @@ module Unified { string getPrimaryQlClasses() { result = concat(this.getAPrimaryQlClass(), ",") } } - final class AstNode = AstNodeImpl; - /** A token. */ - private class TokenImpl extends @unified_token, AstNodeImpl { + class Token extends @unified_token, AstNode { /** Gets the value of this token. */ final string getValue() { unified_tokeninfo(this, _, result) } @@ -65,10 +63,8 @@ module Unified { override string getAPrimaryQlClass() { result = "Token" } } - final class Token = TokenImpl; - /** A trivia token, such as a comment, preserved from the original parse tree. */ - final class TriviaToken extends @unified_trivia_token, AstNodeImpl { + class TriviaToken extends @unified_trivia_token, AstNode { /** Gets the source text of this trivia token. */ final string getValue() { unified_trivia_tokeninfo(this, _, result) } @@ -100,7 +96,7 @@ module Unified { } /** A class representing `accessor_declaration` nodes. */ - final class AccessorDeclaration extends @unified_accessor_declaration, AstNodeImpl { + class AccessorDeclaration extends @unified_accessor_declaration, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "AccessorDeclaration" } @@ -136,13 +132,13 @@ module Unified { } /** A class representing `accessor_kind` tokens. */ - final class AccessorKind extends @unified_token_accessor_kind, TokenImpl { + class AccessorKind extends @unified_token_accessor_kind, Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "AccessorKind" } } /** A class representing `argument` nodes. */ - final class Argument extends @unified_argument, AstNodeImpl { + class Argument extends @unified_argument, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Argument" } @@ -164,7 +160,7 @@ module Unified { } /** A class representing `array_literal` nodes. */ - final class ArrayLiteral extends @unified_array_literal, AstNodeImpl { + class ArrayLiteral extends @unified_array_literal, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ArrayLiteral" } @@ -176,7 +172,7 @@ module Unified { } /** A class representing `assign_expr` nodes. */ - final class AssignExpr extends @unified_assign_expr, AstNodeImpl { + class AssignExpr extends @unified_assign_expr, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "AssignExpr" } @@ -193,7 +189,7 @@ module Unified { } /** A class representing `associated_type_declaration` nodes. */ - final class AssociatedTypeDeclaration extends @unified_associated_type_declaration, AstNodeImpl { + class AssociatedTypeDeclaration extends @unified_associated_type_declaration, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "AssociatedTypeDeclaration" } @@ -217,7 +213,7 @@ module Unified { } /** A class representing `base_type` nodes. */ - final class BaseType extends @unified_base_type, AstNodeImpl { + class BaseType extends @unified_base_type, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BaseType" } @@ -234,7 +230,7 @@ module Unified { } /** A class representing `binary_expr` nodes. */ - final class BinaryExpr extends @unified_binary_expr, AstNodeImpl { + class BinaryExpr extends @unified_binary_expr, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BinaryExpr" } @@ -256,7 +252,7 @@ module Unified { } /** A class representing `block` nodes. */ - final class Block extends @unified_block, AstNodeImpl { + class Block extends @unified_block, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Block" } @@ -268,13 +264,13 @@ module Unified { } /** A class representing `boolean_literal` tokens. */ - final class BooleanLiteral extends @unified_token_boolean_literal, TokenImpl { + class BooleanLiteral extends @unified_token_boolean_literal, Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BooleanLiteral" } } /** A class representing `bound_type_constraint` nodes. */ - final class BoundTypeConstraint extends @unified_bound_type_constraint, AstNodeImpl { + class BoundTypeConstraint extends @unified_bound_type_constraint, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BoundTypeConstraint" } @@ -292,7 +288,7 @@ module Unified { } /** A class representing `break_expr` nodes. */ - final class BreakExpr extends @unified_break_expr, AstNodeImpl { + class BreakExpr extends @unified_break_expr, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BreakExpr" } @@ -304,13 +300,13 @@ module Unified { } /** A class representing `builtin_expr` tokens. */ - final class BuiltinExpr extends @unified_token_builtin_expr, TokenImpl { + class BuiltinExpr extends @unified_token_builtin_expr, Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BuiltinExpr" } } /** A class representing `bulk_importing_pattern` nodes. */ - final class BulkImportingPattern extends @unified_bulk_importing_pattern, AstNodeImpl { + class BulkImportingPattern extends @unified_bulk_importing_pattern, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BulkImportingPattern" } @@ -326,7 +322,7 @@ module Unified { } /** A class representing `call_expr` nodes. */ - final class CallExpr extends @unified_call_expr, AstNodeImpl { + class CallExpr extends @unified_call_expr, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "CallExpr" } @@ -348,7 +344,7 @@ module Unified { } /** A class representing `catch_clause` nodes. */ - final class CatchClause extends @unified_catch_clause, AstNodeImpl { + class CatchClause extends @unified_catch_clause, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "CatchClause" } @@ -370,7 +366,7 @@ module Unified { } /** A class representing `class_like_declaration` nodes. */ - final class ClassLikeDeclaration extends @unified_class_like_declaration, AstNodeImpl { + class ClassLikeDeclaration extends @unified_class_like_declaration, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ClassLikeDeclaration" } @@ -412,7 +408,7 @@ module Unified { } /** A class representing `compound_assign_expr` nodes. */ - final class CompoundAssignExpr extends @unified_compound_assign_expr, AstNodeImpl { + class CompoundAssignExpr extends @unified_compound_assign_expr, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "CompoundAssignExpr" } @@ -456,7 +452,7 @@ module Unified { } /** A class representing `constructor_declaration` nodes. */ - final class ConstructorDeclaration extends @unified_constructor_declaration, AstNodeImpl { + class ConstructorDeclaration extends @unified_constructor_declaration, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ConstructorDeclaration" } @@ -486,7 +482,7 @@ module Unified { } /** A class representing `constructor_pattern` nodes. */ - final class ConstructorPattern extends @unified_constructor_pattern, AstNodeImpl { + class ConstructorPattern extends @unified_constructor_pattern, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ConstructorPattern" } @@ -510,7 +506,7 @@ module Unified { } /** A class representing `continue_expr` nodes. */ - final class ContinueExpr extends @unified_continue_expr, AstNodeImpl { + class ContinueExpr extends @unified_continue_expr, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ContinueExpr" } @@ -522,7 +518,7 @@ module Unified { } /** A class representing `destructor_declaration` nodes. */ - final class DestructorDeclaration extends @unified_destructor_declaration, AstNodeImpl { + class DestructorDeclaration extends @unified_destructor_declaration, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "DestructorDeclaration" } @@ -542,7 +538,7 @@ module Unified { } /** A class representing `do_while_stmt` nodes. */ - final class DoWhileStmt extends @unified_do_while_stmt, AstNodeImpl { + class DoWhileStmt extends @unified_do_while_stmt, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "DoWhileStmt" } @@ -564,13 +560,13 @@ module Unified { } /** A class representing `empty_expr` tokens. */ - final class EmptyExpr extends @unified_token_empty_expr, TokenImpl { + class EmptyExpr extends @unified_token_empty_expr, Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "EmptyExpr" } } /** A class representing `equality_type_constraint` nodes. */ - final class EqualityTypeConstraint extends @unified_equality_type_constraint, AstNodeImpl { + class EqualityTypeConstraint extends @unified_equality_type_constraint, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "EqualityTypeConstraint" } @@ -587,10 +583,10 @@ module Unified { } } - final class Expr extends @unified_expr, AstNodeImpl { } + class Expr extends @unified_expr, AstNode { } /** A class representing `expr_equality_pattern` nodes. */ - final class ExprEqualityPattern extends @unified_expr_equality_pattern, AstNodeImpl { + class ExprEqualityPattern extends @unified_expr_equality_pattern, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ExprEqualityPattern" } @@ -601,26 +597,26 @@ module Unified { final override F::AstNode getAFieldOrChild() { unified_expr_equality_pattern_def(this, result) } } - final class ExprOrOperator extends @unified_expr_or_operator, AstNodeImpl { } + class ExprOrOperator extends @unified_expr_or_operator, AstNode { } - final class ExprOrPattern extends @unified_expr_or_pattern, AstNodeImpl { } + class ExprOrPattern extends @unified_expr_or_pattern, AstNode { } - final class ExprOrType extends @unified_expr_or_type, AstNodeImpl { } + class ExprOrType extends @unified_expr_or_type, AstNode { } /** A class representing `fixity` tokens. */ - final class Fixity extends @unified_token_fixity, TokenImpl { + class Fixity extends @unified_token_fixity, Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Fixity" } } /** A class representing `float_literal` tokens. */ - final class FloatLiteral extends @unified_token_float_literal, TokenImpl { + class FloatLiteral extends @unified_token_float_literal, Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "FloatLiteral" } } /** A class representing `for_each_stmt` nodes. */ - final class ForEachStmt extends @unified_for_each_stmt, AstNodeImpl { + class ForEachStmt extends @unified_for_each_stmt, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ForEachStmt" } @@ -650,7 +646,7 @@ module Unified { } /** A class representing `function_declaration` nodes. */ - final class FunctionDeclaration extends @unified_function_declaration, AstNodeImpl { + class FunctionDeclaration extends @unified_function_declaration, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "FunctionDeclaration" } @@ -694,7 +690,7 @@ module Unified { } /** A class representing `function_expr` nodes. */ - final class FunctionExpr extends @unified_function_expr, AstNodeImpl { + class FunctionExpr extends @unified_function_expr, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "FunctionExpr" } @@ -726,7 +722,7 @@ module Unified { } /** A class representing `function_type_expr` nodes. */ - final class FunctionTypeExpr extends @unified_function_type_expr, AstNodeImpl { + class FunctionTypeExpr extends @unified_function_type_expr, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "FunctionTypeExpr" } @@ -744,7 +740,7 @@ module Unified { } /** A class representing `generic_type_expr` nodes. */ - final class GenericTypeExpr extends @unified_generic_type_expr, AstNodeImpl { + class GenericTypeExpr extends @unified_generic_type_expr, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "GenericTypeExpr" } @@ -764,7 +760,7 @@ module Unified { } /** A class representing `guard_if_stmt` nodes. */ - final class GuardIfStmt extends @unified_guard_if_stmt, AstNodeImpl { + class GuardIfStmt extends @unified_guard_if_stmt, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "GuardIfStmt" } @@ -781,13 +777,13 @@ module Unified { } /** A class representing `identifier` tokens. */ - final class Identifier extends @unified_token_identifier, TokenImpl { + class Identifier extends @unified_token_identifier, Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Identifier" } } /** A class representing `if_expr` nodes. */ - final class IfExpr extends @unified_if_expr, AstNodeImpl { + class IfExpr extends @unified_if_expr, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "IfExpr" } @@ -809,13 +805,13 @@ module Unified { } /** A class representing `ignore_pattern` tokens. */ - final class IgnorePattern extends @unified_token_ignore_pattern, TokenImpl { + class IgnorePattern extends @unified_token_ignore_pattern, Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "IgnorePattern" } } /** A class representing `import_declaration` nodes. */ - final class ImportDeclaration extends @unified_import_declaration, AstNodeImpl { + class ImportDeclaration extends @unified_import_declaration, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ImportDeclaration" } @@ -837,19 +833,19 @@ module Unified { } /** A class representing `inferred_type_expr` tokens. */ - final class InferredTypeExpr extends @unified_token_inferred_type_expr, TokenImpl { + class InferredTypeExpr extends @unified_token_inferred_type_expr, Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "InferredTypeExpr" } } /** A class representing `infix_operator` tokens. */ - final class InfixOperator extends @unified_token_infix_operator, TokenImpl { + class InfixOperator extends @unified_token_infix_operator, Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "InfixOperator" } } /** A class representing `initializer_declaration` nodes. */ - final class InitializerDeclaration extends @unified_initializer_declaration, AstNodeImpl { + class InitializerDeclaration extends @unified_initializer_declaration, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "InitializerDeclaration" } @@ -869,13 +865,13 @@ module Unified { } /** A class representing `int_literal` tokens. */ - final class IntLiteral extends @unified_token_int_literal, TokenImpl { + class IntLiteral extends @unified_token_int_literal, Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "IntLiteral" } } /** A class representing `key_value_pair` nodes. */ - final class KeyValuePair extends @unified_key_value_pair, AstNodeImpl { + class KeyValuePair extends @unified_key_value_pair, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "KeyValuePair" } @@ -892,7 +888,7 @@ module Unified { } /** A class representing `labeled_stmt` nodes. */ - final class LabeledStmt extends @unified_labeled_stmt, AstNodeImpl { + class LabeledStmt extends @unified_labeled_stmt, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "LabeledStmt" } @@ -909,7 +905,7 @@ module Unified { } /** A class representing `map_literal` nodes. */ - final class MapLiteral extends @unified_map_literal, AstNodeImpl { + class MapLiteral extends @unified_map_literal, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "MapLiteral" } @@ -920,10 +916,10 @@ module Unified { final override F::AstNode getAFieldOrChild() { unified_map_literal_element(this, _, result) } } - final class Member extends @unified_member, AstNodeImpl { } + class Member extends @unified_member, AstNode { } /** A class representing `member_access_expr` nodes. */ - final class MemberAccessExpr extends @unified_member_access_expr, AstNodeImpl { + class MemberAccessExpr extends @unified_member_access_expr, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "MemberAccessExpr" } @@ -941,13 +937,13 @@ module Unified { } /** A class representing `modifier` tokens. */ - final class Modifier extends @unified_token_modifier, TokenImpl { + class Modifier extends @unified_token_modifier, Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Modifier" } } /** A class representing `name_expr` nodes. */ - final class NameExpr extends @unified_name_expr, AstNodeImpl { + class NameExpr extends @unified_name_expr, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "NameExpr" } @@ -959,7 +955,7 @@ module Unified { } /** A class representing `name_pattern` nodes. */ - final class NamePattern extends @unified_name_pattern, AstNodeImpl { + class NamePattern extends @unified_name_pattern, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "NamePattern" } @@ -976,7 +972,7 @@ module Unified { } /** A class representing `named_type_expr` nodes. */ - final class NamedTypeExpr extends @unified_named_type_expr, AstNodeImpl { + class NamedTypeExpr extends @unified_named_type_expr, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "NamedTypeExpr" } @@ -992,10 +988,10 @@ module Unified { } } - final class Operator extends @unified_operator, AstNodeImpl { } + class Operator extends @unified_operator, AstNode { } /** A class representing `operator_syntax_declaration` nodes. */ - final class OperatorSyntaxDeclaration extends @unified_operator_syntax_declaration, AstNodeImpl { + class OperatorSyntaxDeclaration extends @unified_operator_syntax_declaration, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "OperatorSyntaxDeclaration" } @@ -1023,7 +1019,7 @@ module Unified { } /** A class representing `or_pattern` nodes. */ - final class OrPattern extends @unified_or_pattern, AstNodeImpl { + class OrPattern extends @unified_or_pattern, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "OrPattern" } @@ -1040,7 +1036,7 @@ module Unified { } /** A class representing `parameter` nodes. */ - final class Parameter extends @unified_parameter, AstNodeImpl { + class Parameter extends @unified_parameter, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Parameter" } @@ -1069,10 +1065,10 @@ module Unified { } } - final class Pattern extends @unified_pattern, AstNodeImpl { } + class Pattern extends @unified_pattern, AstNode { } /** A class representing `pattern_element` nodes. */ - final class PatternElement extends @unified_pattern_element, AstNodeImpl { + class PatternElement extends @unified_pattern_element, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "PatternElement" } @@ -1094,7 +1090,7 @@ module Unified { } /** A class representing `pattern_guard_expr` nodes. */ - final class PatternGuardExpr extends @unified_pattern_guard_expr, AstNodeImpl { + class PatternGuardExpr extends @unified_pattern_guard_expr, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "PatternGuardExpr" } @@ -1112,25 +1108,25 @@ module Unified { } /** A class representing `postfix_operator` tokens. */ - final class PostfixOperator extends @unified_token_postfix_operator, TokenImpl { + class PostfixOperator extends @unified_token_postfix_operator, Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "PostfixOperator" } } /** A class representing `prefix_operator` tokens. */ - final class PrefixOperator extends @unified_token_prefix_operator, TokenImpl { + class PrefixOperator extends @unified_token_prefix_operator, Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "PrefixOperator" } } /** A class representing `regex_literal` tokens. */ - final class RegexLiteral extends @unified_token_regex_literal, TokenImpl { + class RegexLiteral extends @unified_token_regex_literal, Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "RegexLiteral" } } /** A class representing `return_expr` nodes. */ - final class ReturnExpr extends @unified_return_expr, AstNodeImpl { + class ReturnExpr extends @unified_return_expr, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ReturnExpr" } @@ -1141,22 +1137,22 @@ module Unified { final override F::AstNode getAFieldOrChild() { unified_return_expr_value(this, result) } } - final class Stmt extends @unified_stmt, AstNodeImpl { } + class Stmt extends @unified_stmt, AstNode { } /** A class representing `string_literal` tokens. */ - final class StringLiteral extends @unified_token_string_literal, TokenImpl { + class StringLiteral extends @unified_token_string_literal, Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "StringLiteral" } } /** A class representing `super_expr` tokens. */ - final class SuperExpr extends @unified_token_super_expr, TokenImpl { + class SuperExpr extends @unified_token_super_expr, Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "SuperExpr" } } /** A class representing `switch_case` nodes. */ - final class SwitchCase extends @unified_switch_case, AstNodeImpl { + class SwitchCase extends @unified_switch_case, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "SwitchCase" } @@ -1178,7 +1174,7 @@ module Unified { } /** A class representing `switch_expr` nodes. */ - final class SwitchExpr extends @unified_switch_expr, AstNodeImpl { + class SwitchExpr extends @unified_switch_expr, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "SwitchExpr" } @@ -1200,7 +1196,7 @@ module Unified { } /** A class representing `throw_expr` nodes. */ - final class ThrowExpr extends @unified_throw_expr, AstNodeImpl { + class ThrowExpr extends @unified_throw_expr, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ThrowExpr" } @@ -1212,7 +1208,7 @@ module Unified { } /** A class representing `top_level` nodes. */ - final class TopLevel extends @unified_top_level, AstNodeImpl { + class TopLevel extends @unified_top_level, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TopLevel" } @@ -1224,7 +1220,7 @@ module Unified { } /** A class representing `try_expr` nodes. */ - final class TryExpr extends @unified_try_expr, AstNodeImpl { + class TryExpr extends @unified_try_expr, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TryExpr" } @@ -1246,7 +1242,7 @@ module Unified { } /** A class representing `tuple_expr` nodes. */ - final class TupleExpr extends @unified_tuple_expr, AstNodeImpl { + class TupleExpr extends @unified_tuple_expr, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TupleExpr" } @@ -1258,7 +1254,7 @@ module Unified { } /** A class representing `tuple_pattern` nodes. */ - final class TuplePattern extends @unified_tuple_pattern, AstNodeImpl { + class TuplePattern extends @unified_tuple_pattern, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TuplePattern" } @@ -1276,7 +1272,7 @@ module Unified { } /** A class representing `tuple_type_element` nodes. */ - final class TupleTypeElement extends @unified_tuple_type_element, AstNodeImpl { + class TupleTypeElement extends @unified_tuple_type_element, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TupleTypeElement" } @@ -1293,7 +1289,7 @@ module Unified { } /** A class representing `tuple_type_expr` nodes. */ - final class TupleTypeExpr extends @unified_tuple_type_expr, AstNodeImpl { + class TupleTypeExpr extends @unified_tuple_type_expr, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TupleTypeExpr" } @@ -1307,7 +1303,7 @@ module Unified { } /** A class representing `type_alias_declaration` nodes. */ - final class TypeAliasDeclaration extends @unified_type_alias_declaration, AstNodeImpl { + class TypeAliasDeclaration extends @unified_type_alias_declaration, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TypeAliasDeclaration" } @@ -1343,7 +1339,7 @@ module Unified { } /** A class representing `type_cast_expr` nodes. */ - final class TypeCastExpr extends @unified_type_cast_expr, AstNodeImpl { + class TypeCastExpr extends @unified_type_cast_expr, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TypeCastExpr" } @@ -1364,12 +1360,12 @@ module Unified { } } - final class TypeConstraint extends @unified_type_constraint, AstNodeImpl { } + class TypeConstraint extends @unified_type_constraint, AstNode { } - final class TypeExpr extends @unified_type_expr, AstNodeImpl { } + class TypeExpr extends @unified_type_expr, AstNode { } /** A class representing `type_parameter` nodes. */ - final class TypeParameter extends @unified_type_parameter, AstNodeImpl { + class TypeParameter extends @unified_type_parameter, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TypeParameter" } @@ -1391,7 +1387,7 @@ module Unified { } /** A class representing `type_test_expr` nodes. */ - final class TypeTestExpr extends @unified_type_test_expr, AstNodeImpl { + class TypeTestExpr extends @unified_type_test_expr, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TypeTestExpr" } @@ -1413,7 +1409,7 @@ module Unified { } /** A class representing `type_test_pattern` nodes. */ - final class TypeTestPattern extends @unified_type_test_pattern, AstNodeImpl { + class TypeTestPattern extends @unified_type_test_pattern, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TypeTestPattern" } @@ -1431,7 +1427,7 @@ module Unified { } /** A class representing `unary_expr` nodes. */ - final class UnaryExpr extends @unified_unary_expr, AstNodeImpl { + class UnaryExpr extends @unified_unary_expr, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "UnaryExpr" } @@ -1448,7 +1444,7 @@ module Unified { } /** A class representing `unresolved_operator_sequence` nodes. */ - final class UnresolvedOperatorSequence extends @unified_unresolved_operator_sequence, AstNodeImpl { + class UnresolvedOperatorSequence extends @unified_unresolved_operator_sequence, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "UnresolvedOperatorSequence" } @@ -1464,13 +1460,13 @@ module Unified { } /** A class representing `unsupported_node` tokens. */ - final class UnsupportedNode extends @unified_token_unsupported_node, TokenImpl { + class UnsupportedNode extends @unified_token_unsupported_node, Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "UnsupportedNode" } } /** A class representing `variable_declaration` nodes. */ - final class VariableDeclaration extends @unified_variable_declaration, AstNodeImpl { + class VariableDeclaration extends @unified_variable_declaration, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "VariableDeclaration" } @@ -1496,7 +1492,7 @@ module Unified { } /** A class representing `while_stmt` nodes. */ - final class WhileStmt extends @unified_while_stmt, AstNodeImpl { + class WhileStmt extends @unified_while_stmt, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "WhileStmt" } @@ -1849,3 +1845,194 @@ module Unified { } } } + +module UnifiedFinal { + private import FacadeAst::Unified as F + import F + + final class AstNode = F::AstNode; + + final class Token = F::Token; + + final class TriviaToken = F::TriviaToken; + + final class AccessorDeclaration = F::AccessorDeclaration; + + final class AccessorKind = F::AccessorKind; + + final class Argument = F::Argument; + + final class ArrayLiteral = F::ArrayLiteral; + + final class AssignExpr = F::AssignExpr; + + final class AssociatedTypeDeclaration = F::AssociatedTypeDeclaration; + + final class BaseType = F::BaseType; + + final class BinaryExpr = F::BinaryExpr; + + final class Block = F::Block; + + final class BooleanLiteral = F::BooleanLiteral; + + final class BoundTypeConstraint = F::BoundTypeConstraint; + + final class BreakExpr = F::BreakExpr; + + final class BuiltinExpr = F::BuiltinExpr; + + final class BulkImportingPattern = F::BulkImportingPattern; + + final class CallExpr = F::CallExpr; + + final class CatchClause = F::CatchClause; + + final class ClassLikeDeclaration = F::ClassLikeDeclaration; + + final class CompoundAssignExpr = F::CompoundAssignExpr; + + final class ConstructorDeclaration = F::ConstructorDeclaration; + + final class ConstructorPattern = F::ConstructorPattern; + + final class ContinueExpr = F::ContinueExpr; + + final class DestructorDeclaration = F::DestructorDeclaration; + + final class DoWhileStmt = F::DoWhileStmt; + + final class EmptyExpr = F::EmptyExpr; + + final class EqualityTypeConstraint = F::EqualityTypeConstraint; + + final class Expr = F::Expr; + + final class ExprEqualityPattern = F::ExprEqualityPattern; + + final class ExprOrOperator = F::ExprOrOperator; + + final class ExprOrPattern = F::ExprOrPattern; + + final class ExprOrType = F::ExprOrType; + + final class Fixity = F::Fixity; + + final class FloatLiteral = F::FloatLiteral; + + final class ForEachStmt = F::ForEachStmt; + + final class FunctionDeclaration = F::FunctionDeclaration; + + final class FunctionExpr = F::FunctionExpr; + + final class FunctionTypeExpr = F::FunctionTypeExpr; + + final class GenericTypeExpr = F::GenericTypeExpr; + + final class GuardIfStmt = F::GuardIfStmt; + + final class Identifier = F::Identifier; + + final class IfExpr = F::IfExpr; + + final class IgnorePattern = F::IgnorePattern; + + final class ImportDeclaration = F::ImportDeclaration; + + final class InferredTypeExpr = F::InferredTypeExpr; + + final class InfixOperator = F::InfixOperator; + + final class InitializerDeclaration = F::InitializerDeclaration; + + final class IntLiteral = F::IntLiteral; + + final class KeyValuePair = F::KeyValuePair; + + final class LabeledStmt = F::LabeledStmt; + + final class MapLiteral = F::MapLiteral; + + final class Member = F::Member; + + final class MemberAccessExpr = F::MemberAccessExpr; + + final class Modifier = F::Modifier; + + final class NameExpr = F::NameExpr; + + final class NamePattern = F::NamePattern; + + final class NamedTypeExpr = F::NamedTypeExpr; + + final class Operator = F::Operator; + + final class OperatorSyntaxDeclaration = F::OperatorSyntaxDeclaration; + + final class OrPattern = F::OrPattern; + + final class Parameter = F::Parameter; + + final class Pattern = F::Pattern; + + final class PatternElement = F::PatternElement; + + final class PatternGuardExpr = F::PatternGuardExpr; + + final class PostfixOperator = F::PostfixOperator; + + final class PrefixOperator = F::PrefixOperator; + + final class RegexLiteral = F::RegexLiteral; + + final class ReturnExpr = F::ReturnExpr; + + final class Stmt = F::Stmt; + + final class StringLiteral = F::StringLiteral; + + final class SuperExpr = F::SuperExpr; + + final class SwitchCase = F::SwitchCase; + + final class SwitchExpr = F::SwitchExpr; + + final class ThrowExpr = F::ThrowExpr; + + final class TopLevel = F::TopLevel; + + final class TryExpr = F::TryExpr; + + final class TupleExpr = F::TupleExpr; + + final class TuplePattern = F::TuplePattern; + + final class TupleTypeElement = F::TupleTypeElement; + + final class TupleTypeExpr = F::TupleTypeExpr; + + final class TypeAliasDeclaration = F::TypeAliasDeclaration; + + final class TypeCastExpr = F::TypeCastExpr; + + final class TypeConstraint = F::TypeConstraint; + + final class TypeExpr = F::TypeExpr; + + final class TypeParameter = F::TypeParameter; + + final class TypeTestExpr = F::TypeTestExpr; + + final class TypeTestPattern = F::TypeTestPattern; + + final class UnaryExpr = F::UnaryExpr; + + final class UnresolvedOperatorSequence = F::UnresolvedOperatorSequence; + + final class UnsupportedNode = F::UnsupportedNode; + + final class VariableDeclaration = F::VariableDeclaration; + + final class WhileStmt = F::WhileStmt; +} diff --git a/unified/ql/lib/unified.qll b/unified/ql/lib/unified.qll index ae22a2d76410..fad4b3ef9e67 100644 --- a/unified/ql/lib/unified.qll +++ b/unified/ql/lib/unified.qll @@ -4,6 +4,6 @@ import codeql.Locations import codeql.files.FileSystem -import codeql.unified.internal.FacadeAst::Unified +import codeql.unified.internal.Ast::UnifiedFinal import codeql.unified.internal.AstExtra::Public import codeql.unified.internal.Variables::Public From e3ef8e8d5fb3b854acc97c607eddfd4c21a18c76 Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 30 Jul 2026 14:35:46 +0200 Subject: [PATCH 132/188] tree-sitter-extractor: List more precise base classes Previously each class just used 'AstNode' as its base class. Now it mentions each of the supertypes it is part of. --- .../src/generator/ql_gen.rs | 67 ++++++-- .../tree-sitter-extractor/src/node_types.rs | 2 +- .../ql/lib/codeql/unified/internal/Ast.qll | 148 +++++++++--------- 3 files changed, 129 insertions(+), 88 deletions(-) diff --git a/shared/tree-sitter-extractor/src/generator/ql_gen.rs b/shared/tree-sitter-extractor/src/generator/ql_gen.rs index e68d2b336c38..e389a960f35a 100644 --- a/shared/tree-sitter-extractor/src/generator/ql_gen.rs +++ b/shared/tree-sitter-extractor/src/generator/ql_gen.rs @@ -770,10 +770,51 @@ fn create_field_getters<'a>( ) } +fn compute_direct_supertypes<'a>( + nodes: &'a node_types::NodeTypeMap, +) -> std::collections::BTreeMap> { + let mut supertypes = std::collections::BTreeMap::new(); + for node in nodes.values() { + if let node_types::EntryKind::Union { members } = &node.kind { + for member in members { + supertypes + .entry(member.clone()) + .or_insert_with(BTreeSet::new) + .insert(node.ql_class_name.as_str()); + } + } + } + supertypes +} + +fn ast_base_types<'a>( + type_name: &node_types::TypeName, + direct_supertypes: &std::collections::BTreeMap>, +) -> BTreeSet> { + match direct_supertypes.get(type_name) { + Some(supertypes) if !supertypes.is_empty() => supertypes + .iter() + .map(|name| ql::Type::Normal(name)) + .collect(), + _ => vec![ql::Type::Normal("AstNode")].into_iter().collect(), + } +} + +fn class_supertypes<'a>( + type_name: &node_types::TypeName, + dbscheme_name: &'a str, + direct_supertypes: &std::collections::BTreeMap>, +) -> BTreeSet> { + let mut supertypes = ast_base_types(type_name, direct_supertypes); + supertypes.insert(ql::Type::At(dbscheme_name)); + supertypes +} + /// Converts the given node types into CodeQL classes wrapping the dbscheme. pub fn convert_nodes(nodes: &node_types::NodeTypeMap) -> Vec> { let mut classes = Vec::new(); let mut token_kinds = BTreeSet::new(); + let direct_supertypes = compute_direct_supertypes(nodes); for (type_name, node) in nodes { if let node_types::EntryKind::Token { .. } = &node.kind { if type_name.named { @@ -788,8 +829,8 @@ pub fn convert_nodes(nodes: &node_types::NodeTypeMap) -> Vec> { if type_name.named { let get_a_primary_ql_class = create_get_a_primary_ql_class(&node.ql_class_name, true); - let mut supertypes: BTreeSet = BTreeSet::new(); - supertypes.insert(ql::Type::At(&node.dbscheme_name)); + let mut supertypes = + class_supertypes(type_name, &node.dbscheme_name, &direct_supertypes); supertypes.insert(ql::Type::Normal("Token")); classes.push(ql::TopLevel::Class(ql::Class { qldoc: Some(format!("A class representing `{}` tokens.", type_name.kind)), @@ -814,12 +855,11 @@ pub fn convert_nodes(nodes: &node_types::NodeTypeMap) -> Vec> { is_final: false, is_private: false, alias: None, - supertypes: vec![ - ql::Type::At(&node.dbscheme_name), - ql::Type::Normal("AstNode"), - ] - .into_iter() - .collect(), + supertypes: class_supertypes( + type_name, + &node.dbscheme_name, + &direct_supertypes, + ), characteristic_predicate: None, predicates: vec![], })); @@ -848,12 +888,11 @@ pub fn convert_nodes(nodes: &node_types::NodeTypeMap) -> Vec> { is_final: false, is_private: false, alias: None, - supertypes: vec![ - ql::Type::At(&node.dbscheme_name), - ql::Type::Normal("AstNode"), - ] - .into_iter() - .collect(), + supertypes: class_supertypes( + type_name, + &node.dbscheme_name, + &direct_supertypes, + ), characteristic_predicate: None, predicates: vec![create_get_a_primary_ql_class(main_class_name, true)], }; diff --git a/shared/tree-sitter-extractor/src/node_types.rs b/shared/tree-sitter-extractor/src/node_types.rs index 7a457fa73f0d..b56515b06456 100644 --- a/shared/tree-sitter-extractor/src/node_types.rs +++ b/shared/tree-sitter-extractor/src/node_types.rs @@ -22,7 +22,7 @@ pub enum EntryKind { Token { kind_id: usize }, } -#[derive(Debug, Ord, PartialOrd, Eq, PartialEq)] +#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq)] pub struct TypeName { pub kind: String, pub named: bool, diff --git a/unified/ql/lib/codeql/unified/internal/Ast.qll b/unified/ql/lib/codeql/unified/internal/Ast.qll index a165be1af82e..3187c46f9e2a 100644 --- a/unified/ql/lib/codeql/unified/internal/Ast.qll +++ b/unified/ql/lib/codeql/unified/internal/Ast.qll @@ -96,7 +96,7 @@ module Unified { } /** A class representing `accessor_declaration` nodes. */ - class AccessorDeclaration extends @unified_accessor_declaration, AstNode { + class AccessorDeclaration extends @unified_accessor_declaration, Member, Stmt { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "AccessorDeclaration" } @@ -132,7 +132,7 @@ module Unified { } /** A class representing `accessor_kind` tokens. */ - class AccessorKind extends @unified_token_accessor_kind, Token { + class AccessorKind extends @unified_token_accessor_kind, AstNode, Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "AccessorKind" } } @@ -160,7 +160,7 @@ module Unified { } /** A class representing `array_literal` nodes. */ - class ArrayLiteral extends @unified_array_literal, AstNode { + class ArrayLiteral extends @unified_array_literal, Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ArrayLiteral" } @@ -172,7 +172,7 @@ module Unified { } /** A class representing `assign_expr` nodes. */ - class AssignExpr extends @unified_assign_expr, AstNode { + class AssignExpr extends @unified_assign_expr, Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "AssignExpr" } @@ -189,7 +189,7 @@ module Unified { } /** A class representing `associated_type_declaration` nodes. */ - class AssociatedTypeDeclaration extends @unified_associated_type_declaration, AstNode { + class AssociatedTypeDeclaration extends @unified_associated_type_declaration, Member { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "AssociatedTypeDeclaration" } @@ -230,7 +230,7 @@ module Unified { } /** A class representing `binary_expr` nodes. */ - class BinaryExpr extends @unified_binary_expr, AstNode { + class BinaryExpr extends @unified_binary_expr, Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BinaryExpr" } @@ -252,7 +252,7 @@ module Unified { } /** A class representing `block` nodes. */ - class Block extends @unified_block, AstNode { + class Block extends @unified_block, Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Block" } @@ -264,13 +264,13 @@ module Unified { } /** A class representing `boolean_literal` tokens. */ - class BooleanLiteral extends @unified_token_boolean_literal, Token { + class BooleanLiteral extends @unified_token_boolean_literal, Expr, Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BooleanLiteral" } } /** A class representing `bound_type_constraint` nodes. */ - class BoundTypeConstraint extends @unified_bound_type_constraint, AstNode { + class BoundTypeConstraint extends @unified_bound_type_constraint, TypeConstraint { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BoundTypeConstraint" } @@ -288,7 +288,7 @@ module Unified { } /** A class representing `break_expr` nodes. */ - class BreakExpr extends @unified_break_expr, AstNode { + class BreakExpr extends @unified_break_expr, Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BreakExpr" } @@ -300,13 +300,13 @@ module Unified { } /** A class representing `builtin_expr` tokens. */ - class BuiltinExpr extends @unified_token_builtin_expr, Token { + class BuiltinExpr extends @unified_token_builtin_expr, Expr, Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BuiltinExpr" } } /** A class representing `bulk_importing_pattern` nodes. */ - class BulkImportingPattern extends @unified_bulk_importing_pattern, AstNode { + class BulkImportingPattern extends @unified_bulk_importing_pattern, Pattern { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BulkImportingPattern" } @@ -322,7 +322,7 @@ module Unified { } /** A class representing `call_expr` nodes. */ - class CallExpr extends @unified_call_expr, AstNode { + class CallExpr extends @unified_call_expr, Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "CallExpr" } @@ -366,7 +366,7 @@ module Unified { } /** A class representing `class_like_declaration` nodes. */ - class ClassLikeDeclaration extends @unified_class_like_declaration, AstNode { + class ClassLikeDeclaration extends @unified_class_like_declaration, Member, Stmt { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ClassLikeDeclaration" } @@ -408,7 +408,7 @@ module Unified { } /** A class representing `compound_assign_expr` nodes. */ - class CompoundAssignExpr extends @unified_compound_assign_expr, AstNode { + class CompoundAssignExpr extends @unified_compound_assign_expr, Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "CompoundAssignExpr" } @@ -452,7 +452,7 @@ module Unified { } /** A class representing `constructor_declaration` nodes. */ - class ConstructorDeclaration extends @unified_constructor_declaration, AstNode { + class ConstructorDeclaration extends @unified_constructor_declaration, Member, Stmt { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ConstructorDeclaration" } @@ -482,7 +482,7 @@ module Unified { } /** A class representing `constructor_pattern` nodes. */ - class ConstructorPattern extends @unified_constructor_pattern, AstNode { + class ConstructorPattern extends @unified_constructor_pattern, Pattern { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ConstructorPattern" } @@ -506,7 +506,7 @@ module Unified { } /** A class representing `continue_expr` nodes. */ - class ContinueExpr extends @unified_continue_expr, AstNode { + class ContinueExpr extends @unified_continue_expr, Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ContinueExpr" } @@ -518,7 +518,7 @@ module Unified { } /** A class representing `destructor_declaration` nodes. */ - class DestructorDeclaration extends @unified_destructor_declaration, AstNode { + class DestructorDeclaration extends @unified_destructor_declaration, Member, Stmt { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "DestructorDeclaration" } @@ -538,7 +538,7 @@ module Unified { } /** A class representing `do_while_stmt` nodes. */ - class DoWhileStmt extends @unified_do_while_stmt, AstNode { + class DoWhileStmt extends @unified_do_while_stmt, Stmt { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "DoWhileStmt" } @@ -560,13 +560,13 @@ module Unified { } /** A class representing `empty_expr` tokens. */ - class EmptyExpr extends @unified_token_empty_expr, Token { + class EmptyExpr extends @unified_token_empty_expr, Expr, Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "EmptyExpr" } } /** A class representing `equality_type_constraint` nodes. */ - class EqualityTypeConstraint extends @unified_equality_type_constraint, AstNode { + class EqualityTypeConstraint extends @unified_equality_type_constraint, TypeConstraint { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "EqualityTypeConstraint" } @@ -583,10 +583,10 @@ module Unified { } } - class Expr extends @unified_expr, AstNode { } + class Expr extends @unified_expr, ExprOrOperator, ExprOrPattern, ExprOrType, Stmt { } /** A class representing `expr_equality_pattern` nodes. */ - class ExprEqualityPattern extends @unified_expr_equality_pattern, AstNode { + class ExprEqualityPattern extends @unified_expr_equality_pattern, Pattern { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ExprEqualityPattern" } @@ -604,19 +604,19 @@ module Unified { class ExprOrType extends @unified_expr_or_type, AstNode { } /** A class representing `fixity` tokens. */ - class Fixity extends @unified_token_fixity, Token { + class Fixity extends @unified_token_fixity, AstNode, Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Fixity" } } /** A class representing `float_literal` tokens. */ - class FloatLiteral extends @unified_token_float_literal, Token { + class FloatLiteral extends @unified_token_float_literal, Expr, Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "FloatLiteral" } } /** A class representing `for_each_stmt` nodes. */ - class ForEachStmt extends @unified_for_each_stmt, AstNode { + class ForEachStmt extends @unified_for_each_stmt, Stmt { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ForEachStmt" } @@ -646,7 +646,7 @@ module Unified { } /** A class representing `function_declaration` nodes. */ - class FunctionDeclaration extends @unified_function_declaration, AstNode { + class FunctionDeclaration extends @unified_function_declaration, Member, Stmt { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "FunctionDeclaration" } @@ -690,7 +690,7 @@ module Unified { } /** A class representing `function_expr` nodes. */ - class FunctionExpr extends @unified_function_expr, AstNode { + class FunctionExpr extends @unified_function_expr, Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "FunctionExpr" } @@ -722,7 +722,7 @@ module Unified { } /** A class representing `function_type_expr` nodes. */ - class FunctionTypeExpr extends @unified_function_type_expr, AstNode { + class FunctionTypeExpr extends @unified_function_type_expr, TypeExpr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "FunctionTypeExpr" } @@ -740,7 +740,7 @@ module Unified { } /** A class representing `generic_type_expr` nodes. */ - class GenericTypeExpr extends @unified_generic_type_expr, AstNode { + class GenericTypeExpr extends @unified_generic_type_expr, TypeExpr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "GenericTypeExpr" } @@ -760,7 +760,7 @@ module Unified { } /** A class representing `guard_if_stmt` nodes. */ - class GuardIfStmt extends @unified_guard_if_stmt, AstNode { + class GuardIfStmt extends @unified_guard_if_stmt, Stmt { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "GuardIfStmt" } @@ -777,13 +777,13 @@ module Unified { } /** A class representing `identifier` tokens. */ - class Identifier extends @unified_token_identifier, Token { + class Identifier extends @unified_token_identifier, AstNode, Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Identifier" } } /** A class representing `if_expr` nodes. */ - class IfExpr extends @unified_if_expr, AstNode { + class IfExpr extends @unified_if_expr, Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "IfExpr" } @@ -805,13 +805,13 @@ module Unified { } /** A class representing `ignore_pattern` tokens. */ - class IgnorePattern extends @unified_token_ignore_pattern, Token { + class IgnorePattern extends @unified_token_ignore_pattern, Pattern, Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "IgnorePattern" } } /** A class representing `import_declaration` nodes. */ - class ImportDeclaration extends @unified_import_declaration, AstNode { + class ImportDeclaration extends @unified_import_declaration, Stmt { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ImportDeclaration" } @@ -833,19 +833,19 @@ module Unified { } /** A class representing `inferred_type_expr` tokens. */ - class InferredTypeExpr extends @unified_token_inferred_type_expr, Token { + class InferredTypeExpr extends @unified_token_inferred_type_expr, Token, TypeExpr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "InferredTypeExpr" } } /** A class representing `infix_operator` tokens. */ - class InfixOperator extends @unified_token_infix_operator, Token { + class InfixOperator extends @unified_token_infix_operator, ExprOrOperator, Operator, Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "InfixOperator" } } /** A class representing `initializer_declaration` nodes. */ - class InitializerDeclaration extends @unified_initializer_declaration, AstNode { + class InitializerDeclaration extends @unified_initializer_declaration, Member { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "InitializerDeclaration" } @@ -865,13 +865,13 @@ module Unified { } /** A class representing `int_literal` tokens. */ - class IntLiteral extends @unified_token_int_literal, Token { + class IntLiteral extends @unified_token_int_literal, Expr, Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "IntLiteral" } } /** A class representing `key_value_pair` nodes. */ - class KeyValuePair extends @unified_key_value_pair, AstNode { + class KeyValuePair extends @unified_key_value_pair, Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "KeyValuePair" } @@ -888,7 +888,7 @@ module Unified { } /** A class representing `labeled_stmt` nodes. */ - class LabeledStmt extends @unified_labeled_stmt, AstNode { + class LabeledStmt extends @unified_labeled_stmt, Stmt { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "LabeledStmt" } @@ -905,7 +905,7 @@ module Unified { } /** A class representing `map_literal` nodes. */ - class MapLiteral extends @unified_map_literal, AstNode { + class MapLiteral extends @unified_map_literal, Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "MapLiteral" } @@ -919,7 +919,7 @@ module Unified { class Member extends @unified_member, AstNode { } /** A class representing `member_access_expr` nodes. */ - class MemberAccessExpr extends @unified_member_access_expr, AstNode { + class MemberAccessExpr extends @unified_member_access_expr, Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "MemberAccessExpr" } @@ -937,13 +937,13 @@ module Unified { } /** A class representing `modifier` tokens. */ - class Modifier extends @unified_token_modifier, Token { + class Modifier extends @unified_token_modifier, AstNode, Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Modifier" } } /** A class representing `name_expr` nodes. */ - class NameExpr extends @unified_name_expr, AstNode { + class NameExpr extends @unified_name_expr, Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "NameExpr" } @@ -955,7 +955,7 @@ module Unified { } /** A class representing `name_pattern` nodes. */ - class NamePattern extends @unified_name_pattern, AstNode { + class NamePattern extends @unified_name_pattern, Pattern { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "NamePattern" } @@ -972,7 +972,7 @@ module Unified { } /** A class representing `named_type_expr` nodes. */ - class NamedTypeExpr extends @unified_named_type_expr, AstNode { + class NamedTypeExpr extends @unified_named_type_expr, TypeExpr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "NamedTypeExpr" } @@ -991,7 +991,7 @@ module Unified { class Operator extends @unified_operator, AstNode { } /** A class representing `operator_syntax_declaration` nodes. */ - class OperatorSyntaxDeclaration extends @unified_operator_syntax_declaration, AstNode { + class OperatorSyntaxDeclaration extends @unified_operator_syntax_declaration, Stmt { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "OperatorSyntaxDeclaration" } @@ -1019,7 +1019,7 @@ module Unified { } /** A class representing `or_pattern` nodes. */ - class OrPattern extends @unified_or_pattern, AstNode { + class OrPattern extends @unified_or_pattern, Pattern { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "OrPattern" } @@ -1065,7 +1065,7 @@ module Unified { } } - class Pattern extends @unified_pattern, AstNode { } + class Pattern extends @unified_pattern, ExprOrPattern { } /** A class representing `pattern_element` nodes. */ class PatternElement extends @unified_pattern_element, AstNode { @@ -1090,7 +1090,7 @@ module Unified { } /** A class representing `pattern_guard_expr` nodes. */ - class PatternGuardExpr extends @unified_pattern_guard_expr, AstNode { + class PatternGuardExpr extends @unified_pattern_guard_expr, Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "PatternGuardExpr" } @@ -1108,25 +1108,25 @@ module Unified { } /** A class representing `postfix_operator` tokens. */ - class PostfixOperator extends @unified_token_postfix_operator, Token { + class PostfixOperator extends @unified_token_postfix_operator, Operator, Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "PostfixOperator" } } /** A class representing `prefix_operator` tokens. */ - class PrefixOperator extends @unified_token_prefix_operator, Token { + class PrefixOperator extends @unified_token_prefix_operator, Operator, Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "PrefixOperator" } } /** A class representing `regex_literal` tokens. */ - class RegexLiteral extends @unified_token_regex_literal, Token { + class RegexLiteral extends @unified_token_regex_literal, Expr, Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "RegexLiteral" } } /** A class representing `return_expr` nodes. */ - class ReturnExpr extends @unified_return_expr, AstNode { + class ReturnExpr extends @unified_return_expr, Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ReturnExpr" } @@ -1140,13 +1140,13 @@ module Unified { class Stmt extends @unified_stmt, AstNode { } /** A class representing `string_literal` tokens. */ - class StringLiteral extends @unified_token_string_literal, Token { + class StringLiteral extends @unified_token_string_literal, Expr, Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "StringLiteral" } } /** A class representing `super_expr` tokens. */ - class SuperExpr extends @unified_token_super_expr, Token { + class SuperExpr extends @unified_token_super_expr, Expr, Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "SuperExpr" } } @@ -1174,7 +1174,7 @@ module Unified { } /** A class representing `switch_expr` nodes. */ - class SwitchExpr extends @unified_switch_expr, AstNode { + class SwitchExpr extends @unified_switch_expr, Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "SwitchExpr" } @@ -1196,7 +1196,7 @@ module Unified { } /** A class representing `throw_expr` nodes. */ - class ThrowExpr extends @unified_throw_expr, AstNode { + class ThrowExpr extends @unified_throw_expr, Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ThrowExpr" } @@ -1220,7 +1220,7 @@ module Unified { } /** A class representing `try_expr` nodes. */ - class TryExpr extends @unified_try_expr, AstNode { + class TryExpr extends @unified_try_expr, Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TryExpr" } @@ -1242,7 +1242,7 @@ module Unified { } /** A class representing `tuple_expr` nodes. */ - class TupleExpr extends @unified_tuple_expr, AstNode { + class TupleExpr extends @unified_tuple_expr, Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TupleExpr" } @@ -1254,7 +1254,7 @@ module Unified { } /** A class representing `tuple_pattern` nodes. */ - class TuplePattern extends @unified_tuple_pattern, AstNode { + class TuplePattern extends @unified_tuple_pattern, Pattern { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TuplePattern" } @@ -1289,7 +1289,7 @@ module Unified { } /** A class representing `tuple_type_expr` nodes. */ - class TupleTypeExpr extends @unified_tuple_type_expr, AstNode { + class TupleTypeExpr extends @unified_tuple_type_expr, TypeExpr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TupleTypeExpr" } @@ -1303,7 +1303,7 @@ module Unified { } /** A class representing `type_alias_declaration` nodes. */ - class TypeAliasDeclaration extends @unified_type_alias_declaration, AstNode { + class TypeAliasDeclaration extends @unified_type_alias_declaration, Member, Stmt { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TypeAliasDeclaration" } @@ -1339,7 +1339,7 @@ module Unified { } /** A class representing `type_cast_expr` nodes. */ - class TypeCastExpr extends @unified_type_cast_expr, AstNode { + class TypeCastExpr extends @unified_type_cast_expr, Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TypeCastExpr" } @@ -1362,7 +1362,7 @@ module Unified { class TypeConstraint extends @unified_type_constraint, AstNode { } - class TypeExpr extends @unified_type_expr, AstNode { } + class TypeExpr extends @unified_type_expr, ExprOrType { } /** A class representing `type_parameter` nodes. */ class TypeParameter extends @unified_type_parameter, AstNode { @@ -1387,7 +1387,7 @@ module Unified { } /** A class representing `type_test_expr` nodes. */ - class TypeTestExpr extends @unified_type_test_expr, AstNode { + class TypeTestExpr extends @unified_type_test_expr, Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TypeTestExpr" } @@ -1427,7 +1427,7 @@ module Unified { } /** A class representing `unary_expr` nodes. */ - class UnaryExpr extends @unified_unary_expr, AstNode { + class UnaryExpr extends @unified_unary_expr, Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "UnaryExpr" } @@ -1444,7 +1444,7 @@ module Unified { } /** A class representing `unresolved_operator_sequence` nodes. */ - class UnresolvedOperatorSequence extends @unified_unresolved_operator_sequence, AstNode { + class UnresolvedOperatorSequence extends @unified_unresolved_operator_sequence, Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "UnresolvedOperatorSequence" } @@ -1460,13 +1460,15 @@ module Unified { } /** A class representing `unsupported_node` tokens. */ - class UnsupportedNode extends @unified_token_unsupported_node, Token { + class UnsupportedNode extends @unified_token_unsupported_node, Expr, Member, Pattern, Token, + TypeExpr + { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "UnsupportedNode" } } /** A class representing `variable_declaration` nodes. */ - class VariableDeclaration extends @unified_variable_declaration, AstNode { + class VariableDeclaration extends @unified_variable_declaration, Member, Stmt { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "VariableDeclaration" } @@ -1492,7 +1494,7 @@ module Unified { } /** A class representing `while_stmt` nodes. */ - class WhileStmt extends @unified_while_stmt, AstNode { + class WhileStmt extends @unified_while_stmt, Stmt { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "WhileStmt" } From 628d1b4a2479a8f4945ad0da13dc85561b296446 Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 30 Jul 2026 14:39:37 +0200 Subject: [PATCH 133/188] unified: Refer to facade in more cases Now that final classes are factored out, base classes can refer to the facade now. Also covers a few other missed cases. --- .../src/generator/ql_gen.rs | 16 +- .../ql/lib/codeql/unified/internal/Ast.qll | 190 +++++++++--------- 2 files changed, 104 insertions(+), 102 deletions(-) diff --git a/shared/tree-sitter-extractor/src/generator/ql_gen.rs b/shared/tree-sitter-extractor/src/generator/ql_gen.rs index e389a960f35a..e08debb2b079 100644 --- a/shared/tree-sitter-extractor/src/generator/ql_gen.rs +++ b/shared/tree-sitter-extractor/src/generator/ql_gen.rs @@ -193,7 +193,7 @@ pub fn create_token_class<'a>(token_type: &'a str, tokeninfo: &'a str) -> ql::Cl is_final: false, is_private: false, alias: None, - supertypes: vec![ql::Type::At(token_type), ql::Type::Normal("AstNode")] + supertypes: vec![ql::Type::At(token_type), ql::Type::Facade("AstNode")] .into_iter() .collect(), characteristic_predicate: None, @@ -262,7 +262,7 @@ pub fn create_trivia_token_class<'a>( alias: None, supertypes: vec![ ql::Type::At(trivia_token_type), - ql::Type::Normal("AstNode"), + ql::Type::Facade("AstNode"), ] .into_iter() .collect(), @@ -286,7 +286,7 @@ pub fn create_reserved_word_class(db_name: &str) -> ql::Class<'_> { is_final: false, is_private: false, alias: None, - supertypes: vec![ql::Type::At(db_name), ql::Type::Normal("Token")] + supertypes: vec![ql::Type::At(db_name), ql::Type::Facade("Token")] .into_iter() .collect(), characteristic_predicate: None, @@ -794,9 +794,9 @@ fn ast_base_types<'a>( match direct_supertypes.get(type_name) { Some(supertypes) if !supertypes.is_empty() => supertypes .iter() - .map(|name| ql::Type::Normal(name)) + .map(|name| ql::Type::Facade(name)) .collect(), - _ => vec![ql::Type::Normal("AstNode")].into_iter().collect(), + _ => vec![ql::Type::Facade("AstNode")].into_iter().collect(), } } @@ -831,7 +831,7 @@ pub fn convert_nodes(nodes: &node_types::NodeTypeMap) -> Vec> { create_get_a_primary_ql_class(&node.ql_class_name, true); let mut supertypes = class_supertypes(type_name, &node.dbscheme_name, &direct_supertypes); - supertypes.insert(ql::Type::Normal("Token")); + supertypes.insert(ql::Type::Facade("Token")); classes.push(ql::TopLevel::Class(ql::Class { qldoc: Some(format!("A class representing `{}` tokens.", type_name.kind)), name: &node.ql_class_name, @@ -1005,11 +1005,11 @@ pub fn create_print_ast_module(nodes: &node_types::NodeTypeMap) -> ql::TopLevel< overridden: false, is_private: false, is_final: false, - return_type: Some(ql::Type::Normal("AstNode")), + return_type: Some(ql::Type::Facade("AstNode")), formal_parameters: vec![ ql::FormalParameter { name: "node", - param_type: ql::Type::Normal("AstNode"), + param_type: ql::Type::Facade("AstNode"), }, ql::FormalParameter { name: "name", diff --git a/unified/ql/lib/codeql/unified/internal/Ast.qll b/unified/ql/lib/codeql/unified/internal/Ast.qll index 3187c46f9e2a..8e231bee79f4 100644 --- a/unified/ql/lib/codeql/unified/internal/Ast.qll +++ b/unified/ql/lib/codeql/unified/internal/Ast.qll @@ -52,7 +52,7 @@ module Unified { } /** A token. */ - class Token extends @unified_token, AstNode { + class Token extends @unified_token, F::AstNode { /** Gets the value of this token. */ final string getValue() { unified_tokeninfo(this, _, result) } @@ -64,7 +64,7 @@ module Unified { } /** A trivia token, such as a comment, preserved from the original parse tree. */ - class TriviaToken extends @unified_trivia_token, AstNode { + class TriviaToken extends @unified_trivia_token, F::AstNode { /** Gets the source text of this trivia token. */ final string getValue() { unified_trivia_tokeninfo(this, _, result) } @@ -96,7 +96,7 @@ module Unified { } /** A class representing `accessor_declaration` nodes. */ - class AccessorDeclaration extends @unified_accessor_declaration, Member, Stmt { + class AccessorDeclaration extends @unified_accessor_declaration, F::Member, F::Stmt { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "AccessorDeclaration" } @@ -132,13 +132,13 @@ module Unified { } /** A class representing `accessor_kind` tokens. */ - class AccessorKind extends @unified_token_accessor_kind, AstNode, Token { + class AccessorKind extends @unified_token_accessor_kind, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "AccessorKind" } } /** A class representing `argument` nodes. */ - class Argument extends @unified_argument, AstNode { + class Argument extends @unified_argument, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Argument" } @@ -160,7 +160,7 @@ module Unified { } /** A class representing `array_literal` nodes. */ - class ArrayLiteral extends @unified_array_literal, Expr { + class ArrayLiteral extends @unified_array_literal, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ArrayLiteral" } @@ -172,7 +172,7 @@ module Unified { } /** A class representing `assign_expr` nodes. */ - class AssignExpr extends @unified_assign_expr, Expr { + class AssignExpr extends @unified_assign_expr, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "AssignExpr" } @@ -189,7 +189,7 @@ module Unified { } /** A class representing `associated_type_declaration` nodes. */ - class AssociatedTypeDeclaration extends @unified_associated_type_declaration, Member { + class AssociatedTypeDeclaration extends @unified_associated_type_declaration, F::Member { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "AssociatedTypeDeclaration" } @@ -213,7 +213,7 @@ module Unified { } /** A class representing `base_type` nodes. */ - class BaseType extends @unified_base_type, AstNode { + class BaseType extends @unified_base_type, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BaseType" } @@ -230,7 +230,7 @@ module Unified { } /** A class representing `binary_expr` nodes. */ - class BinaryExpr extends @unified_binary_expr, Expr { + class BinaryExpr extends @unified_binary_expr, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BinaryExpr" } @@ -252,7 +252,7 @@ module Unified { } /** A class representing `block` nodes. */ - class Block extends @unified_block, Expr { + class Block extends @unified_block, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Block" } @@ -264,13 +264,13 @@ module Unified { } /** A class representing `boolean_literal` tokens. */ - class BooleanLiteral extends @unified_token_boolean_literal, Expr, Token { + class BooleanLiteral extends @unified_token_boolean_literal, F::Expr, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BooleanLiteral" } } /** A class representing `bound_type_constraint` nodes. */ - class BoundTypeConstraint extends @unified_bound_type_constraint, TypeConstraint { + class BoundTypeConstraint extends @unified_bound_type_constraint, F::TypeConstraint { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BoundTypeConstraint" } @@ -288,7 +288,7 @@ module Unified { } /** A class representing `break_expr` nodes. */ - class BreakExpr extends @unified_break_expr, Expr { + class BreakExpr extends @unified_break_expr, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BreakExpr" } @@ -300,13 +300,13 @@ module Unified { } /** A class representing `builtin_expr` tokens. */ - class BuiltinExpr extends @unified_token_builtin_expr, Expr, Token { + class BuiltinExpr extends @unified_token_builtin_expr, F::Expr, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BuiltinExpr" } } /** A class representing `bulk_importing_pattern` nodes. */ - class BulkImportingPattern extends @unified_bulk_importing_pattern, Pattern { + class BulkImportingPattern extends @unified_bulk_importing_pattern, F::Pattern { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BulkImportingPattern" } @@ -322,7 +322,7 @@ module Unified { } /** A class representing `call_expr` nodes. */ - class CallExpr extends @unified_call_expr, Expr { + class CallExpr extends @unified_call_expr, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "CallExpr" } @@ -344,7 +344,7 @@ module Unified { } /** A class representing `catch_clause` nodes. */ - class CatchClause extends @unified_catch_clause, AstNode { + class CatchClause extends @unified_catch_clause, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "CatchClause" } @@ -366,7 +366,7 @@ module Unified { } /** A class representing `class_like_declaration` nodes. */ - class ClassLikeDeclaration extends @unified_class_like_declaration, Member, Stmt { + class ClassLikeDeclaration extends @unified_class_like_declaration, F::Member, F::Stmt { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ClassLikeDeclaration" } @@ -408,7 +408,7 @@ module Unified { } /** A class representing `compound_assign_expr` nodes. */ - class CompoundAssignExpr extends @unified_compound_assign_expr, Expr { + class CompoundAssignExpr extends @unified_compound_assign_expr, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "CompoundAssignExpr" } @@ -452,7 +452,7 @@ module Unified { } /** A class representing `constructor_declaration` nodes. */ - class ConstructorDeclaration extends @unified_constructor_declaration, Member, Stmt { + class ConstructorDeclaration extends @unified_constructor_declaration, F::Member, F::Stmt { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ConstructorDeclaration" } @@ -482,7 +482,7 @@ module Unified { } /** A class representing `constructor_pattern` nodes. */ - class ConstructorPattern extends @unified_constructor_pattern, Pattern { + class ConstructorPattern extends @unified_constructor_pattern, F::Pattern { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ConstructorPattern" } @@ -506,7 +506,7 @@ module Unified { } /** A class representing `continue_expr` nodes. */ - class ContinueExpr extends @unified_continue_expr, Expr { + class ContinueExpr extends @unified_continue_expr, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ContinueExpr" } @@ -518,7 +518,7 @@ module Unified { } /** A class representing `destructor_declaration` nodes. */ - class DestructorDeclaration extends @unified_destructor_declaration, Member, Stmt { + class DestructorDeclaration extends @unified_destructor_declaration, F::Member, F::Stmt { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "DestructorDeclaration" } @@ -538,7 +538,7 @@ module Unified { } /** A class representing `do_while_stmt` nodes. */ - class DoWhileStmt extends @unified_do_while_stmt, Stmt { + class DoWhileStmt extends @unified_do_while_stmt, F::Stmt { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "DoWhileStmt" } @@ -560,13 +560,13 @@ module Unified { } /** A class representing `empty_expr` tokens. */ - class EmptyExpr extends @unified_token_empty_expr, Expr, Token { + class EmptyExpr extends @unified_token_empty_expr, F::Expr, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "EmptyExpr" } } /** A class representing `equality_type_constraint` nodes. */ - class EqualityTypeConstraint extends @unified_equality_type_constraint, TypeConstraint { + class EqualityTypeConstraint extends @unified_equality_type_constraint, F::TypeConstraint { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "EqualityTypeConstraint" } @@ -583,10 +583,10 @@ module Unified { } } - class Expr extends @unified_expr, ExprOrOperator, ExprOrPattern, ExprOrType, Stmt { } + class Expr extends @unified_expr, F::ExprOrOperator, F::ExprOrPattern, F::ExprOrType, F::Stmt { } /** A class representing `expr_equality_pattern` nodes. */ - class ExprEqualityPattern extends @unified_expr_equality_pattern, Pattern { + class ExprEqualityPattern extends @unified_expr_equality_pattern, F::Pattern { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ExprEqualityPattern" } @@ -597,26 +597,26 @@ module Unified { final override F::AstNode getAFieldOrChild() { unified_expr_equality_pattern_def(this, result) } } - class ExprOrOperator extends @unified_expr_or_operator, AstNode { } + class ExprOrOperator extends @unified_expr_or_operator, F::AstNode { } - class ExprOrPattern extends @unified_expr_or_pattern, AstNode { } + class ExprOrPattern extends @unified_expr_or_pattern, F::AstNode { } - class ExprOrType extends @unified_expr_or_type, AstNode { } + class ExprOrType extends @unified_expr_or_type, F::AstNode { } /** A class representing `fixity` tokens. */ - class Fixity extends @unified_token_fixity, AstNode, Token { + class Fixity extends @unified_token_fixity, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Fixity" } } /** A class representing `float_literal` tokens. */ - class FloatLiteral extends @unified_token_float_literal, Expr, Token { + class FloatLiteral extends @unified_token_float_literal, F::Expr, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "FloatLiteral" } } /** A class representing `for_each_stmt` nodes. */ - class ForEachStmt extends @unified_for_each_stmt, Stmt { + class ForEachStmt extends @unified_for_each_stmt, F::Stmt { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ForEachStmt" } @@ -646,7 +646,7 @@ module Unified { } /** A class representing `function_declaration` nodes. */ - class FunctionDeclaration extends @unified_function_declaration, Member, Stmt { + class FunctionDeclaration extends @unified_function_declaration, F::Member, F::Stmt { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "FunctionDeclaration" } @@ -690,7 +690,7 @@ module Unified { } /** A class representing `function_expr` nodes. */ - class FunctionExpr extends @unified_function_expr, Expr { + class FunctionExpr extends @unified_function_expr, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "FunctionExpr" } @@ -722,7 +722,7 @@ module Unified { } /** A class representing `function_type_expr` nodes. */ - class FunctionTypeExpr extends @unified_function_type_expr, TypeExpr { + class FunctionTypeExpr extends @unified_function_type_expr, F::TypeExpr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "FunctionTypeExpr" } @@ -740,7 +740,7 @@ module Unified { } /** A class representing `generic_type_expr` nodes. */ - class GenericTypeExpr extends @unified_generic_type_expr, TypeExpr { + class GenericTypeExpr extends @unified_generic_type_expr, F::TypeExpr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "GenericTypeExpr" } @@ -760,7 +760,7 @@ module Unified { } /** A class representing `guard_if_stmt` nodes. */ - class GuardIfStmt extends @unified_guard_if_stmt, Stmt { + class GuardIfStmt extends @unified_guard_if_stmt, F::Stmt { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "GuardIfStmt" } @@ -777,13 +777,13 @@ module Unified { } /** A class representing `identifier` tokens. */ - class Identifier extends @unified_token_identifier, AstNode, Token { + class Identifier extends @unified_token_identifier, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Identifier" } } /** A class representing `if_expr` nodes. */ - class IfExpr extends @unified_if_expr, Expr { + class IfExpr extends @unified_if_expr, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "IfExpr" } @@ -805,13 +805,13 @@ module Unified { } /** A class representing `ignore_pattern` tokens. */ - class IgnorePattern extends @unified_token_ignore_pattern, Pattern, Token { + class IgnorePattern extends @unified_token_ignore_pattern, F::Pattern, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "IgnorePattern" } } /** A class representing `import_declaration` nodes. */ - class ImportDeclaration extends @unified_import_declaration, Stmt { + class ImportDeclaration extends @unified_import_declaration, F::Stmt { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ImportDeclaration" } @@ -833,19 +833,21 @@ module Unified { } /** A class representing `inferred_type_expr` tokens. */ - class InferredTypeExpr extends @unified_token_inferred_type_expr, Token, TypeExpr { + class InferredTypeExpr extends @unified_token_inferred_type_expr, F::Token, F::TypeExpr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "InferredTypeExpr" } } /** A class representing `infix_operator` tokens. */ - class InfixOperator extends @unified_token_infix_operator, ExprOrOperator, Operator, Token { + class InfixOperator extends @unified_token_infix_operator, F::ExprOrOperator, F::Operator, + F::Token + { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "InfixOperator" } } /** A class representing `initializer_declaration` nodes. */ - class InitializerDeclaration extends @unified_initializer_declaration, Member { + class InitializerDeclaration extends @unified_initializer_declaration, F::Member { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "InitializerDeclaration" } @@ -865,13 +867,13 @@ module Unified { } /** A class representing `int_literal` tokens. */ - class IntLiteral extends @unified_token_int_literal, Expr, Token { + class IntLiteral extends @unified_token_int_literal, F::Expr, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "IntLiteral" } } /** A class representing `key_value_pair` nodes. */ - class KeyValuePair extends @unified_key_value_pair, Expr { + class KeyValuePair extends @unified_key_value_pair, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "KeyValuePair" } @@ -888,7 +890,7 @@ module Unified { } /** A class representing `labeled_stmt` nodes. */ - class LabeledStmt extends @unified_labeled_stmt, Stmt { + class LabeledStmt extends @unified_labeled_stmt, F::Stmt { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "LabeledStmt" } @@ -905,7 +907,7 @@ module Unified { } /** A class representing `map_literal` nodes. */ - class MapLiteral extends @unified_map_literal, Expr { + class MapLiteral extends @unified_map_literal, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "MapLiteral" } @@ -916,10 +918,10 @@ module Unified { final override F::AstNode getAFieldOrChild() { unified_map_literal_element(this, _, result) } } - class Member extends @unified_member, AstNode { } + class Member extends @unified_member, F::AstNode { } /** A class representing `member_access_expr` nodes. */ - class MemberAccessExpr extends @unified_member_access_expr, Expr { + class MemberAccessExpr extends @unified_member_access_expr, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "MemberAccessExpr" } @@ -937,13 +939,13 @@ module Unified { } /** A class representing `modifier` tokens. */ - class Modifier extends @unified_token_modifier, AstNode, Token { + class Modifier extends @unified_token_modifier, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Modifier" } } /** A class representing `name_expr` nodes. */ - class NameExpr extends @unified_name_expr, Expr { + class NameExpr extends @unified_name_expr, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "NameExpr" } @@ -955,7 +957,7 @@ module Unified { } /** A class representing `name_pattern` nodes. */ - class NamePattern extends @unified_name_pattern, Pattern { + class NamePattern extends @unified_name_pattern, F::Pattern { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "NamePattern" } @@ -972,7 +974,7 @@ module Unified { } /** A class representing `named_type_expr` nodes. */ - class NamedTypeExpr extends @unified_named_type_expr, TypeExpr { + class NamedTypeExpr extends @unified_named_type_expr, F::TypeExpr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "NamedTypeExpr" } @@ -988,10 +990,10 @@ module Unified { } } - class Operator extends @unified_operator, AstNode { } + class Operator extends @unified_operator, F::AstNode { } /** A class representing `operator_syntax_declaration` nodes. */ - class OperatorSyntaxDeclaration extends @unified_operator_syntax_declaration, Stmt { + class OperatorSyntaxDeclaration extends @unified_operator_syntax_declaration, F::Stmt { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "OperatorSyntaxDeclaration" } @@ -1019,7 +1021,7 @@ module Unified { } /** A class representing `or_pattern` nodes. */ - class OrPattern extends @unified_or_pattern, Pattern { + class OrPattern extends @unified_or_pattern, F::Pattern { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "OrPattern" } @@ -1036,7 +1038,7 @@ module Unified { } /** A class representing `parameter` nodes. */ - class Parameter extends @unified_parameter, AstNode { + class Parameter extends @unified_parameter, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Parameter" } @@ -1065,10 +1067,10 @@ module Unified { } } - class Pattern extends @unified_pattern, ExprOrPattern { } + class Pattern extends @unified_pattern, F::ExprOrPattern { } /** A class representing `pattern_element` nodes. */ - class PatternElement extends @unified_pattern_element, AstNode { + class PatternElement extends @unified_pattern_element, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "PatternElement" } @@ -1090,7 +1092,7 @@ module Unified { } /** A class representing `pattern_guard_expr` nodes. */ - class PatternGuardExpr extends @unified_pattern_guard_expr, Expr { + class PatternGuardExpr extends @unified_pattern_guard_expr, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "PatternGuardExpr" } @@ -1108,25 +1110,25 @@ module Unified { } /** A class representing `postfix_operator` tokens. */ - class PostfixOperator extends @unified_token_postfix_operator, Operator, Token { + class PostfixOperator extends @unified_token_postfix_operator, F::Operator, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "PostfixOperator" } } /** A class representing `prefix_operator` tokens. */ - class PrefixOperator extends @unified_token_prefix_operator, Operator, Token { + class PrefixOperator extends @unified_token_prefix_operator, F::Operator, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "PrefixOperator" } } /** A class representing `regex_literal` tokens. */ - class RegexLiteral extends @unified_token_regex_literal, Expr, Token { + class RegexLiteral extends @unified_token_regex_literal, F::Expr, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "RegexLiteral" } } /** A class representing `return_expr` nodes. */ - class ReturnExpr extends @unified_return_expr, Expr { + class ReturnExpr extends @unified_return_expr, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ReturnExpr" } @@ -1137,22 +1139,22 @@ module Unified { final override F::AstNode getAFieldOrChild() { unified_return_expr_value(this, result) } } - class Stmt extends @unified_stmt, AstNode { } + class Stmt extends @unified_stmt, F::AstNode { } /** A class representing `string_literal` tokens. */ - class StringLiteral extends @unified_token_string_literal, Expr, Token { + class StringLiteral extends @unified_token_string_literal, F::Expr, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "StringLiteral" } } /** A class representing `super_expr` tokens. */ - class SuperExpr extends @unified_token_super_expr, Expr, Token { + class SuperExpr extends @unified_token_super_expr, F::Expr, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "SuperExpr" } } /** A class representing `switch_case` nodes. */ - class SwitchCase extends @unified_switch_case, AstNode { + class SwitchCase extends @unified_switch_case, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "SwitchCase" } @@ -1174,7 +1176,7 @@ module Unified { } /** A class representing `switch_expr` nodes. */ - class SwitchExpr extends @unified_switch_expr, Expr { + class SwitchExpr extends @unified_switch_expr, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "SwitchExpr" } @@ -1196,7 +1198,7 @@ module Unified { } /** A class representing `throw_expr` nodes. */ - class ThrowExpr extends @unified_throw_expr, Expr { + class ThrowExpr extends @unified_throw_expr, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ThrowExpr" } @@ -1208,7 +1210,7 @@ module Unified { } /** A class representing `top_level` nodes. */ - class TopLevel extends @unified_top_level, AstNode { + class TopLevel extends @unified_top_level, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TopLevel" } @@ -1220,7 +1222,7 @@ module Unified { } /** A class representing `try_expr` nodes. */ - class TryExpr extends @unified_try_expr, Expr { + class TryExpr extends @unified_try_expr, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TryExpr" } @@ -1242,7 +1244,7 @@ module Unified { } /** A class representing `tuple_expr` nodes. */ - class TupleExpr extends @unified_tuple_expr, Expr { + class TupleExpr extends @unified_tuple_expr, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TupleExpr" } @@ -1254,7 +1256,7 @@ module Unified { } /** A class representing `tuple_pattern` nodes. */ - class TuplePattern extends @unified_tuple_pattern, Pattern { + class TuplePattern extends @unified_tuple_pattern, F::Pattern { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TuplePattern" } @@ -1272,7 +1274,7 @@ module Unified { } /** A class representing `tuple_type_element` nodes. */ - class TupleTypeElement extends @unified_tuple_type_element, AstNode { + class TupleTypeElement extends @unified_tuple_type_element, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TupleTypeElement" } @@ -1289,7 +1291,7 @@ module Unified { } /** A class representing `tuple_type_expr` nodes. */ - class TupleTypeExpr extends @unified_tuple_type_expr, TypeExpr { + class TupleTypeExpr extends @unified_tuple_type_expr, F::TypeExpr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TupleTypeExpr" } @@ -1303,7 +1305,7 @@ module Unified { } /** A class representing `type_alias_declaration` nodes. */ - class TypeAliasDeclaration extends @unified_type_alias_declaration, Member, Stmt { + class TypeAliasDeclaration extends @unified_type_alias_declaration, F::Member, F::Stmt { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TypeAliasDeclaration" } @@ -1339,7 +1341,7 @@ module Unified { } /** A class representing `type_cast_expr` nodes. */ - class TypeCastExpr extends @unified_type_cast_expr, Expr { + class TypeCastExpr extends @unified_type_cast_expr, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TypeCastExpr" } @@ -1360,12 +1362,12 @@ module Unified { } } - class TypeConstraint extends @unified_type_constraint, AstNode { } + class TypeConstraint extends @unified_type_constraint, F::AstNode { } - class TypeExpr extends @unified_type_expr, ExprOrType { } + class TypeExpr extends @unified_type_expr, F::ExprOrType { } /** A class representing `type_parameter` nodes. */ - class TypeParameter extends @unified_type_parameter, AstNode { + class TypeParameter extends @unified_type_parameter, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TypeParameter" } @@ -1387,7 +1389,7 @@ module Unified { } /** A class representing `type_test_expr` nodes. */ - class TypeTestExpr extends @unified_type_test_expr, Expr { + class TypeTestExpr extends @unified_type_test_expr, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TypeTestExpr" } @@ -1409,7 +1411,7 @@ module Unified { } /** A class representing `type_test_pattern` nodes. */ - class TypeTestPattern extends @unified_type_test_pattern, AstNode { + class TypeTestPattern extends @unified_type_test_pattern, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TypeTestPattern" } @@ -1427,7 +1429,7 @@ module Unified { } /** A class representing `unary_expr` nodes. */ - class UnaryExpr extends @unified_unary_expr, Expr { + class UnaryExpr extends @unified_unary_expr, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "UnaryExpr" } @@ -1444,7 +1446,7 @@ module Unified { } /** A class representing `unresolved_operator_sequence` nodes. */ - class UnresolvedOperatorSequence extends @unified_unresolved_operator_sequence, Expr { + class UnresolvedOperatorSequence extends @unified_unresolved_operator_sequence, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "UnresolvedOperatorSequence" } @@ -1460,15 +1462,15 @@ module Unified { } /** A class representing `unsupported_node` tokens. */ - class UnsupportedNode extends @unified_token_unsupported_node, Expr, Member, Pattern, Token, - TypeExpr + class UnsupportedNode extends @unified_token_unsupported_node, F::Expr, F::Member, F::Pattern, + F::Token, F::TypeExpr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "UnsupportedNode" } } /** A class representing `variable_declaration` nodes. */ - class VariableDeclaration extends @unified_variable_declaration, Member, Stmt { + class VariableDeclaration extends @unified_variable_declaration, F::Member, F::Stmt { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "VariableDeclaration" } @@ -1494,7 +1496,7 @@ module Unified { } /** A class representing `while_stmt` nodes. */ - class WhileStmt extends @unified_while_stmt, Stmt { + class WhileStmt extends @unified_while_stmt, F::Stmt { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "WhileStmt" } @@ -1518,7 +1520,7 @@ module Unified { /** Provides predicates for mapping AST nodes to their named children. */ module PrintAst { /** Gets a child of `node` returned by the member predicate with the given `name`. If the predicate takes an index argument, `i` is bound to that index, otherwise `i` is `-1` (which is never a valid index). */ - AstNode getChild(AstNode node, string name, int i) { + F::AstNode getChild(F::AstNode node, string name, int i) { result = node.(AccessorDeclaration).getAccessorKind() and i = -1 and name = "getAccessorKind" or result = node.(AccessorDeclaration).getBody() and i = -1 and name = "getBody" From 0ab8c20c77f2e6ad486c27f221dc009449618e82 Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 30 Jul 2026 14:35:21 +0200 Subject: [PATCH 134/188] unified: Fix a broken import in a test --- unified/ql/test/library-tests/BasicTest/test.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unified/ql/test/library-tests/BasicTest/test.ql b/unified/ql/test/library-tests/BasicTest/test.ql index ca422d039781..5e70f9303687 100644 --- a/unified/ql/test/library-tests/BasicTest/test.ql +++ b/unified/ql/test/library-tests/BasicTest/test.ql @@ -1,4 +1,4 @@ -import codeql.unified.Ast::Unified +import unified query predicate nameExpr(NameExpr node, string value) { value = node.getIdentifier().getValue() } From ea1ba4349d0f74cfa9eb6bd23ec9b087b0fc5119 Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 30 Jul 2026 14:49:19 +0200 Subject: [PATCH 135/188] Regenerate QL and Ruby AST classes --- .../src/codeql_ql/ast/internal/TreeSitter.qll | 664 +++++++++++----- .../codeql/ruby/ast/internal/TreeSitter.qll | 718 +++++++++++++----- 2 files changed, 1031 insertions(+), 351 deletions(-) diff --git a/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll b/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll index 7452f7b290b2..fd1494d06b5c 100644 --- a/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll +++ b/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll @@ -28,7 +28,7 @@ module QL { private import QL as F /** The base class for all AST nodes */ - private class AstNodeImpl extends @ql_ast_node { + class AstNode extends @ql_ast_node { /** Gets a string representation of this element. */ string toString() { result = this.getAPrimaryQlClass() } @@ -51,10 +51,8 @@ module QL { string getPrimaryQlClasses() { result = concat(this.getAPrimaryQlClass(), ",") } } - final class AstNode = AstNodeImpl; - /** A token. */ - private class TokenImpl extends @ql_token, AstNodeImpl { + class Token extends @ql_token, F::AstNode { /** Gets the value of this token. */ final string getValue() { ql_tokeninfo(this, _, result) } @@ -65,10 +63,8 @@ module QL { override string getAPrimaryQlClass() { result = "Token" } } - final class Token = TokenImpl; - /** A reserved word. */ - final class ReservedWord extends @ql_reserved_word, TokenImpl { + class ReservedWord extends @ql_reserved_word, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ReservedWord" } } @@ -94,7 +90,7 @@ module QL { } /** A class representing `add_expr` nodes. */ - final class AddExpr extends @ql_add_expr, AstNodeImpl { + class AddExpr extends @ql_add_expr, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "AddExpr" } @@ -116,19 +112,19 @@ module QL { } /** A class representing `addop` tokens. */ - final class Addop extends @ql_token_addop, TokenImpl { + class Addop extends @ql_token_addop, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Addop" } } /** A class representing `aggId` tokens. */ - final class AggId extends @ql_token_agg_id, TokenImpl { + class AggId extends @ql_token_agg_id, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "AggId" } } /** A class representing `aggregate` nodes. */ - final class Aggregate extends @ql_aggregate, AstNodeImpl { + class Aggregate extends @ql_aggregate, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Aggregate" } @@ -140,7 +136,7 @@ module QL { } /** A class representing `annotArg` nodes. */ - final class AnnotArg extends @ql_annot_arg, AstNodeImpl { + class AnnotArg extends @ql_annot_arg, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "AnnotArg" } @@ -152,13 +148,13 @@ module QL { } /** A class representing `annotName` tokens. */ - final class AnnotName extends @ql_token_annot_name, TokenImpl { + class AnnotName extends @ql_token_annot_name, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "AnnotName" } } /** A class representing `annotation` nodes. */ - final class Annotation extends @ql_annotation, AstNodeImpl { + class Annotation extends @ql_annotation, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Annotation" } @@ -175,7 +171,7 @@ module QL { } /** A class representing `aritylessPredicateExpr` nodes. */ - final class AritylessPredicateExpr extends @ql_arityless_predicate_expr, AstNodeImpl { + class AritylessPredicateExpr extends @ql_arityless_predicate_expr, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "AritylessPredicateExpr" } @@ -193,7 +189,7 @@ module QL { } /** A class representing `asExpr` nodes. */ - final class AsExpr extends @ql_as_expr, AstNodeImpl { + class AsExpr extends @ql_as_expr, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "AsExpr" } @@ -205,7 +201,7 @@ module QL { } /** A class representing `asExprs` nodes. */ - final class AsExprs extends @ql_as_exprs, AstNodeImpl { + class AsExprs extends @ql_as_exprs, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "AsExprs" } @@ -217,13 +213,13 @@ module QL { } /** A class representing `block_comment` tokens. */ - final class BlockComment extends @ql_token_block_comment, TokenImpl { + class BlockComment extends @ql_token_block_comment, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BlockComment" } } /** A class representing `body` nodes. */ - final class Body extends @ql_body, AstNodeImpl { + class Body extends @ql_body, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Body" } @@ -235,7 +231,7 @@ module QL { } /** A class representing `bool` nodes. */ - final class Bool extends @ql_bool, AstNodeImpl { + class Bool extends @ql_bool, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Bool" } @@ -247,7 +243,7 @@ module QL { } /** A class representing `call_body` nodes. */ - final class CallBody extends @ql_call_body, AstNodeImpl { + class CallBody extends @ql_call_body, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "CallBody" } @@ -259,7 +255,7 @@ module QL { } /** A class representing `call_or_unqual_agg_expr` nodes. */ - final class CallOrUnqualAggExpr extends @ql_call_or_unqual_agg_expr, AstNodeImpl { + class CallOrUnqualAggExpr extends @ql_call_or_unqual_agg_expr, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "CallOrUnqualAggExpr" } @@ -273,7 +269,7 @@ module QL { } /** A class representing `charpred` nodes. */ - final class Charpred extends @ql_charpred, AstNodeImpl { + class Charpred extends @ql_charpred, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Charpred" } @@ -290,7 +286,7 @@ module QL { } /** A class representing `classMember` nodes. */ - final class ClassMember extends @ql_class_member, AstNodeImpl { + class ClassMember extends @ql_class_member, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ClassMember" } @@ -302,13 +298,13 @@ module QL { } /** A class representing `className` tokens. */ - final class ClassName extends @ql_token_class_name, TokenImpl { + class ClassName extends @ql_token_class_name, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ClassName" } } /** A class representing `classlessPredicate` nodes. */ - final class ClasslessPredicate extends @ql_classless_predicate, AstNodeImpl { + class ClasslessPredicate extends @ql_classless_predicate, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ClasslessPredicate" } @@ -330,13 +326,13 @@ module QL { } /** A class representing `closure` tokens. */ - final class Closure extends @ql_token_closure, TokenImpl { + class Closure extends @ql_token_closure, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Closure" } } /** A class representing `comp_term` nodes. */ - final class CompTerm extends @ql_comp_term, AstNodeImpl { + class CompTerm extends @ql_comp_term, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "CompTerm" } @@ -358,13 +354,13 @@ module QL { } /** A class representing `compop` tokens. */ - final class Compop extends @ql_token_compop, TokenImpl { + class Compop extends @ql_token_compop, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Compop" } } /** A class representing `conjunction` nodes. */ - final class Conjunction extends @ql_conjunction, AstNodeImpl { + class Conjunction extends @ql_conjunction, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Conjunction" } @@ -381,7 +377,7 @@ module QL { } /** A class representing `dataclass` nodes. */ - final class Dataclass extends @ql_dataclass, AstNodeImpl { + class Dataclass extends @ql_dataclass, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Dataclass" } @@ -407,7 +403,7 @@ module QL { } /** A class representing `datatype` nodes. */ - final class Datatype extends @ql_datatype, AstNodeImpl { + class Datatype extends @ql_datatype, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Datatype" } @@ -424,7 +420,7 @@ module QL { } /** A class representing `datatypeBranch` nodes. */ - final class DatatypeBranch extends @ql_datatype_branch, AstNodeImpl { + class DatatypeBranch extends @ql_datatype_branch, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "DatatypeBranch" } @@ -441,7 +437,7 @@ module QL { } /** A class representing `datatypeBranches` nodes. */ - final class DatatypeBranches extends @ql_datatype_branches, AstNodeImpl { + class DatatypeBranches extends @ql_datatype_branches, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "DatatypeBranches" } @@ -453,19 +449,19 @@ module QL { } /** A class representing `dbtype` tokens. */ - final class Dbtype extends @ql_token_dbtype, TokenImpl { + class Dbtype extends @ql_token_dbtype, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Dbtype" } } /** A class representing `direction` tokens. */ - final class Direction extends @ql_token_direction, TokenImpl { + class Direction extends @ql_token_direction, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Direction" } } /** A class representing `disjunction` nodes. */ - final class Disjunction extends @ql_disjunction, AstNodeImpl { + class Disjunction extends @ql_disjunction, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Disjunction" } @@ -482,13 +478,13 @@ module QL { } /** A class representing `empty` tokens. */ - final class Empty extends @ql_token_empty, TokenImpl { + class Empty extends @ql_token_empty, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Empty" } } /** A class representing `expr_aggregate_body` nodes. */ - final class ExprAggregateBody extends @ql_expr_aggregate_body, AstNodeImpl { + class ExprAggregateBody extends @ql_expr_aggregate_body, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ExprAggregateBody" } @@ -505,7 +501,7 @@ module QL { } /** A class representing `expr_annotation` nodes. */ - final class ExprAnnotation extends @ql_expr_annotation, AstNodeImpl { + class ExprAnnotation extends @ql_expr_annotation, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ExprAnnotation" } @@ -527,13 +523,13 @@ module QL { } /** A class representing `false` tokens. */ - final class False extends @ql_token_false, TokenImpl { + class False extends @ql_token_false, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "False" } } /** A class representing `field` nodes. */ - final class Field extends @ql_field, AstNodeImpl { + class Field extends @ql_field, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Field" } @@ -545,13 +541,13 @@ module QL { } /** A class representing `float` tokens. */ - final class Float extends @ql_token_float, TokenImpl { + class Float extends @ql_token_float, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Float" } } /** A class representing `full_aggregate_body` nodes. */ - final class FullAggregateBody extends @ql_full_aggregate_body, AstNodeImpl { + class FullAggregateBody extends @ql_full_aggregate_body, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "FullAggregateBody" } @@ -577,7 +573,7 @@ module QL { } /** A class representing `higherOrderTerm` nodes. */ - final class HigherOrderTerm extends @ql_higher_order_term, AstNodeImpl { + class HigherOrderTerm extends @ql_higher_order_term, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "HigherOrderTerm" } @@ -594,7 +590,7 @@ module QL { } /** A class representing `if_term` nodes. */ - final class IfTerm extends @ql_if_term, AstNodeImpl { + class IfTerm extends @ql_if_term, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "IfTerm" } @@ -616,7 +612,7 @@ module QL { } /** A class representing `implication` nodes. */ - final class Implication extends @ql_implication, AstNodeImpl { + class Implication extends @ql_implication, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Implication" } @@ -633,7 +629,7 @@ module QL { } /** A class representing `importDirective` nodes. */ - final class ImportDirective extends @ql_import_directive, AstNodeImpl { + class ImportDirective extends @ql_import_directive, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ImportDirective" } @@ -645,7 +641,7 @@ module QL { } /** A class representing `importModuleExpr` nodes. */ - final class ImportModuleExpr extends @ql_import_module_expr, AstNodeImpl { + class ImportModuleExpr extends @ql_import_module_expr, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ImportModuleExpr" } @@ -662,7 +658,7 @@ module QL { } /** A class representing `in_expr` nodes. */ - final class InExpr extends @ql_in_expr, AstNodeImpl { + class InExpr extends @ql_in_expr, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "InExpr" } @@ -679,7 +675,7 @@ module QL { } /** A class representing `instance_of` nodes. */ - final class InstanceOf extends @ql_instance_of, AstNodeImpl { + class InstanceOf extends @ql_instance_of, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "InstanceOf" } @@ -691,19 +687,19 @@ module QL { } /** A class representing `integer` tokens. */ - final class Integer extends @ql_token_integer, TokenImpl { + class Integer extends @ql_token_integer, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Integer" } } /** A class representing `line_comment` tokens. */ - final class LineComment extends @ql_token_line_comment, TokenImpl { + class LineComment extends @ql_token_line_comment, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "LineComment" } } /** A class representing `literal` nodes. */ - final class Literal extends @ql_literal, AstNodeImpl { + class Literal extends @ql_literal, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Literal" } @@ -715,13 +711,13 @@ module QL { } /** A class representing `literalId` tokens. */ - final class LiteralId extends @ql_token_literal_id, TokenImpl { + class LiteralId extends @ql_token_literal_id, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "LiteralId" } } /** A class representing `memberPredicate` nodes. */ - final class MemberPredicate extends @ql_member_predicate, AstNodeImpl { + class MemberPredicate extends @ql_member_predicate, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "MemberPredicate" } @@ -743,7 +739,7 @@ module QL { } /** A class representing `module` nodes. */ - final class Module extends @ql_module, AstNodeImpl { + class Module extends @ql_module, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Module" } @@ -769,7 +765,7 @@ module QL { } /** A class representing `moduleAliasBody` nodes. */ - final class ModuleAliasBody extends @ql_module_alias_body, AstNodeImpl { + class ModuleAliasBody extends @ql_module_alias_body, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ModuleAliasBody" } @@ -781,7 +777,7 @@ module QL { } /** A class representing `moduleExpr` nodes. */ - final class ModuleExpr extends @ql_module_expr, AstNodeImpl { + class ModuleExpr extends @ql_module_expr, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ModuleExpr" } @@ -798,7 +794,7 @@ module QL { } /** A class representing `moduleInstantiation` nodes. */ - final class ModuleInstantiation extends @ql_module_instantiation, AstNodeImpl { + class ModuleInstantiation extends @ql_module_instantiation, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ModuleInstantiation" } @@ -815,7 +811,7 @@ module QL { } /** A class representing `moduleMember` nodes. */ - final class ModuleMember extends @ql_module_member, AstNodeImpl { + class ModuleMember extends @ql_module_member, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ModuleMember" } @@ -827,7 +823,7 @@ module QL { } /** A class representing `moduleName` nodes. */ - final class ModuleName extends @ql_module_name, AstNodeImpl { + class ModuleName extends @ql_module_name, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ModuleName" } @@ -839,7 +835,7 @@ module QL { } /** A class representing `moduleParam` nodes. */ - final class ModuleParam extends @ql_module_param, AstNodeImpl { + class ModuleParam extends @ql_module_param, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ModuleParam" } @@ -856,7 +852,7 @@ module QL { } /** A class representing `mul_expr` nodes. */ - final class MulExpr extends @ql_mul_expr, AstNodeImpl { + class MulExpr extends @ql_mul_expr, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "MulExpr" } @@ -878,13 +874,13 @@ module QL { } /** A class representing `mulop` tokens. */ - final class Mulop extends @ql_token_mulop, TokenImpl { + class Mulop extends @ql_token_mulop, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Mulop" } } /** A class representing `negation` nodes. */ - final class Negation extends @ql_negation, AstNodeImpl { + class Negation extends @ql_negation, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Negation" } @@ -896,7 +892,7 @@ module QL { } /** A class representing `orderBy` nodes. */ - final class OrderBy extends @ql_order_by, AstNodeImpl { + class OrderBy extends @ql_order_by, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "OrderBy" } @@ -908,7 +904,7 @@ module QL { } /** A class representing `orderBys` nodes. */ - final class OrderBys extends @ql_order_bys, AstNodeImpl { + class OrderBys extends @ql_order_bys, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "OrderBys" } @@ -920,7 +916,7 @@ module QL { } /** A class representing `par_expr` nodes. */ - final class ParExpr extends @ql_par_expr, AstNodeImpl { + class ParExpr extends @ql_par_expr, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ParExpr" } @@ -932,13 +928,13 @@ module QL { } /** A class representing `predicate` tokens. */ - final class Predicate extends @ql_token_predicate, TokenImpl { + class Predicate extends @ql_token_predicate, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Predicate" } } /** A class representing `predicateAliasBody` nodes. */ - final class PredicateAliasBody extends @ql_predicate_alias_body, AstNodeImpl { + class PredicateAliasBody extends @ql_predicate_alias_body, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "PredicateAliasBody" } @@ -950,7 +946,7 @@ module QL { } /** A class representing `predicateExpr` nodes. */ - final class PredicateExpr extends @ql_predicate_expr, AstNodeImpl { + class PredicateExpr extends @ql_predicate_expr, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "PredicateExpr" } @@ -962,13 +958,13 @@ module QL { } /** A class representing `predicateName` tokens. */ - final class PredicateName extends @ql_token_predicate_name, TokenImpl { + class PredicateName extends @ql_token_predicate_name, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "PredicateName" } } /** A class representing `prefix_cast` nodes. */ - final class PrefixCast extends @ql_prefix_cast, AstNodeImpl { + class PrefixCast extends @ql_prefix_cast, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "PrefixCast" } @@ -980,13 +976,13 @@ module QL { } /** A class representing `primitiveType` tokens. */ - final class PrimitiveType extends @ql_token_primitive_type, TokenImpl { + class PrimitiveType extends @ql_token_primitive_type, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "PrimitiveType" } } /** A class representing `ql` nodes. */ - final class Ql extends @ql_ql, AstNodeImpl { + class Ql extends @ql_ql, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Ql" } @@ -998,13 +994,13 @@ module QL { } /** A class representing `qldoc` tokens. */ - final class Qldoc extends @ql_token_qldoc, TokenImpl { + class Qldoc extends @ql_token_qldoc, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Qldoc" } } /** A class representing `qualifiedRhs` nodes. */ - final class QualifiedRhs extends @ql_qualified_rhs, AstNodeImpl { + class QualifiedRhs extends @ql_qualified_rhs, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "QualifiedRhs" } @@ -1021,7 +1017,7 @@ module QL { } /** A class representing `qualified_expr` nodes. */ - final class QualifiedExpr extends @ql_qualified_expr, AstNodeImpl { + class QualifiedExpr extends @ql_qualified_expr, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "QualifiedExpr" } @@ -1033,7 +1029,7 @@ module QL { } /** A class representing `quantified` nodes. */ - final class Quantified extends @ql_quantified, AstNodeImpl { + class Quantified extends @ql_quantified, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Quantified" } @@ -1059,13 +1055,13 @@ module QL { } /** A class representing `quantifier` tokens. */ - final class Quantifier extends @ql_token_quantifier, TokenImpl { + class Quantifier extends @ql_token_quantifier, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Quantifier" } } /** A class representing `range` nodes. */ - final class Range extends @ql_range, AstNodeImpl { + class Range extends @ql_range, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Range" } @@ -1082,13 +1078,13 @@ module QL { } /** A class representing `result` tokens. */ - final class Result extends @ql_token_result, TokenImpl { + class Result extends @ql_token_result, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Result" } } /** A class representing `select` nodes. */ - final class Select extends @ql_select, AstNodeImpl { + class Select extends @ql_select, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Select" } @@ -1100,7 +1096,7 @@ module QL { } /** A class representing `set_literal` nodes. */ - final class SetLiteral extends @ql_set_literal, AstNodeImpl { + class SetLiteral extends @ql_set_literal, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "SetLiteral" } @@ -1112,7 +1108,7 @@ module QL { } /** A class representing `signatureExpr` nodes. */ - final class SignatureExpr extends @ql_signature_expr, AstNodeImpl { + class SignatureExpr extends @ql_signature_expr, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "SignatureExpr" } @@ -1134,19 +1130,19 @@ module QL { } /** A class representing `simpleId` tokens. */ - final class SimpleId extends @ql_token_simple_id, TokenImpl { + class SimpleId extends @ql_token_simple_id, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "SimpleId" } } /** A class representing `specialId` tokens. */ - final class SpecialId extends @ql_token_special_id, TokenImpl { + class SpecialId extends @ql_token_special_id, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "SpecialId" } } /** A class representing `special_call` nodes. */ - final class SpecialCall extends @ql_special_call, AstNodeImpl { + class SpecialCall extends @ql_special_call, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "SpecialCall" } @@ -1158,19 +1154,19 @@ module QL { } /** A class representing `string` tokens. */ - final class String extends @ql_token_string, TokenImpl { + class String extends @ql_token_string, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "String" } } /** A class representing `super` tokens. */ - final class Super extends @ql_token_super, TokenImpl { + class Super extends @ql_token_super, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Super" } } /** A class representing `super_ref` nodes. */ - final class SuperRef extends @ql_super_ref, AstNodeImpl { + class SuperRef extends @ql_super_ref, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "SuperRef" } @@ -1182,19 +1178,19 @@ module QL { } /** A class representing `this` tokens. */ - final class This extends @ql_token_this, TokenImpl { + class This extends @ql_token_this, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "This" } } /** A class representing `true` tokens. */ - final class True extends @ql_token_true, TokenImpl { + class True extends @ql_token_true, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "True" } } /** A class representing `typeAliasBody` nodes. */ - final class TypeAliasBody extends @ql_type_alias_body, AstNodeImpl { + class TypeAliasBody extends @ql_type_alias_body, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TypeAliasBody" } @@ -1206,7 +1202,7 @@ module QL { } /** A class representing `typeExpr` nodes. */ - final class TypeExpr extends @ql_type_expr, AstNodeImpl { + class TypeExpr extends @ql_type_expr, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TypeExpr" } @@ -1228,7 +1224,7 @@ module QL { } /** A class representing `typeUnionBody` nodes. */ - final class TypeUnionBody extends @ql_type_union_body, AstNodeImpl { + class TypeUnionBody extends @ql_type_union_body, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TypeUnionBody" } @@ -1240,7 +1236,7 @@ module QL { } /** A class representing `unary_expr` nodes. */ - final class UnaryExpr extends @ql_unary_expr, AstNodeImpl { + class UnaryExpr extends @ql_unary_expr, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "UnaryExpr" } @@ -1252,19 +1248,19 @@ module QL { } /** A class representing `underscore` tokens. */ - final class Underscore extends @ql_token_underscore, TokenImpl { + class Underscore extends @ql_token_underscore, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Underscore" } } /** A class representing `unop` tokens. */ - final class Unop extends @ql_token_unop, TokenImpl { + class Unop extends @ql_token_unop, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Unop" } } /** A class representing `unqual_agg_body` nodes. */ - final class UnqualAggBody extends @ql_unqual_agg_body, AstNodeImpl { + class UnqualAggBody extends @ql_unqual_agg_body, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "UnqualAggBody" } @@ -1286,7 +1282,7 @@ module QL { } /** A class representing `varDecl` nodes. */ - final class VarDecl extends @ql_var_decl, AstNodeImpl { + class VarDecl extends @ql_var_decl, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "VarDecl" } @@ -1298,7 +1294,7 @@ module QL { } /** A class representing `varName` nodes. */ - final class VarName extends @ql_var_name, AstNodeImpl { + class VarName extends @ql_var_name, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "VarName" } @@ -1310,7 +1306,7 @@ module QL { } /** A class representing `variable` nodes. */ - final class Variable extends @ql_variable, AstNodeImpl { + class Variable extends @ql_variable, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Variable" } @@ -1324,7 +1320,7 @@ module QL { /** Provides predicates for mapping AST nodes to their named children. */ module PrintAst { /** Gets a child of `node` returned by the member predicate with the given `name`. If the predicate takes an index argument, `i` is bound to that index, otherwise `i` is `-1` (which is never a valid index). */ - AstNode getChild(AstNode node, string name, int i) { + F::AstNode getChild(F::AstNode node, string name, int i) { result = node.(AddExpr).getLeft() and i = -1 and name = "getLeft" or result = node.(AddExpr).getRight() and i = -1 and name = "getRight" @@ -1560,12 +1556,217 @@ module QL { } } +module QLFinal { + private import QL as F + import F + + final class AstNode = F::AstNode; + + final class Token = F::Token; + + final class ReservedWord = F::ReservedWord; + + final class AddExpr = F::AddExpr; + + final class Addop = F::Addop; + + final class AggId = F::AggId; + + final class Aggregate = F::Aggregate; + + final class AnnotArg = F::AnnotArg; + + final class AnnotName = F::AnnotName; + + final class Annotation = F::Annotation; + + final class AritylessPredicateExpr = F::AritylessPredicateExpr; + + final class AsExpr = F::AsExpr; + + final class AsExprs = F::AsExprs; + + final class BlockComment = F::BlockComment; + + final class Body = F::Body; + + final class Bool = F::Bool; + + final class CallBody = F::CallBody; + + final class CallOrUnqualAggExpr = F::CallOrUnqualAggExpr; + + final class Charpred = F::Charpred; + + final class ClassMember = F::ClassMember; + + final class ClassName = F::ClassName; + + final class ClasslessPredicate = F::ClasslessPredicate; + + final class Closure = F::Closure; + + final class CompTerm = F::CompTerm; + + final class Compop = F::Compop; + + final class Conjunction = F::Conjunction; + + final class Dataclass = F::Dataclass; + + final class Datatype = F::Datatype; + + final class DatatypeBranch = F::DatatypeBranch; + + final class DatatypeBranches = F::DatatypeBranches; + + final class Dbtype = F::Dbtype; + + final class Direction = F::Direction; + + final class Disjunction = F::Disjunction; + + final class Empty = F::Empty; + + final class ExprAggregateBody = F::ExprAggregateBody; + + final class ExprAnnotation = F::ExprAnnotation; + + final class False = F::False; + + final class Field = F::Field; + + final class Float = F::Float; + + final class FullAggregateBody = F::FullAggregateBody; + + final class HigherOrderTerm = F::HigherOrderTerm; + + final class IfTerm = F::IfTerm; + + final class Implication = F::Implication; + + final class ImportDirective = F::ImportDirective; + + final class ImportModuleExpr = F::ImportModuleExpr; + + final class InExpr = F::InExpr; + + final class InstanceOf = F::InstanceOf; + + final class Integer = F::Integer; + + final class LineComment = F::LineComment; + + final class Literal = F::Literal; + + final class LiteralId = F::LiteralId; + + final class MemberPredicate = F::MemberPredicate; + + final class Module = F::Module; + + final class ModuleAliasBody = F::ModuleAliasBody; + + final class ModuleExpr = F::ModuleExpr; + + final class ModuleInstantiation = F::ModuleInstantiation; + + final class ModuleMember = F::ModuleMember; + + final class ModuleName = F::ModuleName; + + final class ModuleParam = F::ModuleParam; + + final class MulExpr = F::MulExpr; + + final class Mulop = F::Mulop; + + final class Negation = F::Negation; + + final class OrderBy = F::OrderBy; + + final class OrderBys = F::OrderBys; + + final class ParExpr = F::ParExpr; + + final class Predicate = F::Predicate; + + final class PredicateAliasBody = F::PredicateAliasBody; + + final class PredicateExpr = F::PredicateExpr; + + final class PredicateName = F::PredicateName; + + final class PrefixCast = F::PrefixCast; + + final class PrimitiveType = F::PrimitiveType; + + final class Ql = F::Ql; + + final class Qldoc = F::Qldoc; + + final class QualifiedRhs = F::QualifiedRhs; + + final class QualifiedExpr = F::QualifiedExpr; + + final class Quantified = F::Quantified; + + final class Quantifier = F::Quantifier; + + final class Range = F::Range; + + final class Result = F::Result; + + final class Select = F::Select; + + final class SetLiteral = F::SetLiteral; + + final class SignatureExpr = F::SignatureExpr; + + final class SimpleId = F::SimpleId; + + final class SpecialId = F::SpecialId; + + final class SpecialCall = F::SpecialCall; + + final class String = F::String; + + final class Super = F::Super; + + final class SuperRef = F::SuperRef; + + final class This = F::This; + + final class True = F::True; + + final class TypeAliasBody = F::TypeAliasBody; + + final class TypeExpr = F::TypeExpr; + + final class TypeUnionBody = F::TypeUnionBody; + + final class UnaryExpr = F::UnaryExpr; + + final class Underscore = F::Underscore; + + final class Unop = F::Unop; + + final class UnqualAggBody = F::UnqualAggBody; + + final class VarDecl = F::VarDecl; + + final class VarName = F::VarName; + + final class Variable = F::Variable; +} + overlay[local] module Dbscheme { private import Dbscheme as F /** The base class for all AST nodes */ - private class AstNodeImpl extends @dbscheme_ast_node { + class AstNode extends @dbscheme_ast_node { /** Gets a string representation of this element. */ string toString() { result = this.getAPrimaryQlClass() } @@ -1588,10 +1789,8 @@ module Dbscheme { string getPrimaryQlClasses() { result = concat(this.getAPrimaryQlClass(), ",") } } - final class AstNode = AstNodeImpl; - /** A token. */ - private class TokenImpl extends @dbscheme_token, AstNodeImpl { + class Token extends @dbscheme_token, F::AstNode { /** Gets the value of this token. */ final string getValue() { dbscheme_tokeninfo(this, _, result) } @@ -1602,10 +1801,8 @@ module Dbscheme { override string getAPrimaryQlClass() { result = "Token" } } - final class Token = TokenImpl; - /** A reserved word. */ - final class ReservedWord extends @dbscheme_reserved_word, TokenImpl { + class ReservedWord extends @dbscheme_reserved_word, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ReservedWord" } } @@ -1631,13 +1828,13 @@ module Dbscheme { } /** A class representing `annotName` tokens. */ - final class AnnotName extends @dbscheme_token_annot_name, TokenImpl { + class AnnotName extends @dbscheme_token_annot_name, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "AnnotName" } } /** A class representing `annotation` nodes. */ - final class Annotation extends @dbscheme_annotation, AstNodeImpl { + class Annotation extends @dbscheme_annotation, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Annotation" } @@ -1657,7 +1854,7 @@ module Dbscheme { } /** A class representing `argsAnnotation` nodes. */ - final class ArgsAnnotation extends @dbscheme_args_annotation, AstNodeImpl { + class ArgsAnnotation extends @dbscheme_args_annotation, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ArgsAnnotation" } @@ -1674,19 +1871,19 @@ module Dbscheme { } /** A class representing `block_comment` tokens. */ - final class BlockComment extends @dbscheme_token_block_comment, TokenImpl { + class BlockComment extends @dbscheme_token_block_comment, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BlockComment" } } /** A class representing `boolean` tokens. */ - final class Boolean extends @dbscheme_token_boolean, TokenImpl { + class Boolean extends @dbscheme_token_boolean, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Boolean" } } /** A class representing `branch` nodes. */ - final class Branch extends @dbscheme_branch, AstNodeImpl { + class Branch extends @dbscheme_branch, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Branch" } @@ -1703,7 +1900,7 @@ module Dbscheme { } /** A class representing `caseDecl` nodes. */ - final class CaseDecl extends @dbscheme_case_decl, AstNodeImpl { + class CaseDecl extends @dbscheme_case_decl, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "CaseDecl" } @@ -1725,7 +1922,7 @@ module Dbscheme { } /** A class representing `colType` nodes. */ - final class ColType extends @dbscheme_col_type, AstNodeImpl { + class ColType extends @dbscheme_col_type, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ColType" } @@ -1737,7 +1934,7 @@ module Dbscheme { } /** A class representing `column` nodes. */ - final class Column extends @dbscheme_column, AstNodeImpl { + class Column extends @dbscheme_column, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Column" } @@ -1771,13 +1968,13 @@ module Dbscheme { } /** A class representing `date` tokens. */ - final class Date extends @dbscheme_token_date, TokenImpl { + class Date extends @dbscheme_token_date, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Date" } } /** A class representing `dbscheme` nodes. */ - final class Dbscheme extends @dbscheme_dbscheme, AstNodeImpl { + class Dbscheme extends @dbscheme_dbscheme, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Dbscheme" } @@ -1789,13 +1986,13 @@ module Dbscheme { } /** A class representing `dbtype` tokens. */ - final class Dbtype extends @dbscheme_token_dbtype, TokenImpl { + class Dbtype extends @dbscheme_token_dbtype, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Dbtype" } } /** A class representing `entry` nodes. */ - final class Entry extends @dbscheme_entry, AstNodeImpl { + class Entry extends @dbscheme_entry, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Entry" } @@ -1807,43 +2004,43 @@ module Dbscheme { } /** A class representing `float` tokens. */ - final class Float extends @dbscheme_token_float, TokenImpl { + class Float extends @dbscheme_token_float, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Float" } } /** A class representing `int` tokens. */ - final class Int extends @dbscheme_token_int, TokenImpl { + class Int extends @dbscheme_token_int, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Int" } } /** A class representing `integer` tokens. */ - final class Integer extends @dbscheme_token_integer, TokenImpl { + class Integer extends @dbscheme_token_integer, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Integer" } } /** A class representing `line_comment` tokens. */ - final class LineComment extends @dbscheme_token_line_comment, TokenImpl { + class LineComment extends @dbscheme_token_line_comment, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "LineComment" } } /** A class representing `qldoc` tokens. */ - final class Qldoc extends @dbscheme_token_qldoc, TokenImpl { + class Qldoc extends @dbscheme_token_qldoc, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Qldoc" } } /** A class representing `ref` tokens. */ - final class Ref extends @dbscheme_token_ref, TokenImpl { + class Ref extends @dbscheme_token_ref, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Ref" } } /** A class representing `reprType` nodes. */ - final class ReprType extends @dbscheme_repr_type, AstNodeImpl { + class ReprType extends @dbscheme_repr_type, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ReprType" } @@ -1855,19 +2052,19 @@ module Dbscheme { } /** A class representing `simpleId` tokens. */ - final class SimpleId extends @dbscheme_token_simple_id, TokenImpl { + class SimpleId extends @dbscheme_token_simple_id, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "SimpleId" } } /** A class representing `string` tokens. */ - final class String extends @dbscheme_token_string, TokenImpl { + class String extends @dbscheme_token_string, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "String" } } /** A class representing `table` nodes. */ - final class Table extends @dbscheme_table, AstNodeImpl { + class Table extends @dbscheme_table, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Table" } @@ -1884,7 +2081,7 @@ module Dbscheme { } /** A class representing `tableName` nodes. */ - final class TableName extends @dbscheme_table_name, AstNodeImpl { + class TableName extends @dbscheme_table_name, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TableName" } @@ -1896,7 +2093,7 @@ module Dbscheme { } /** A class representing `unionDecl` nodes. */ - final class UnionDecl extends @dbscheme_union_decl, AstNodeImpl { + class UnionDecl extends @dbscheme_union_decl, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "UnionDecl" } @@ -1913,13 +2110,13 @@ module Dbscheme { } /** A class representing `unique` tokens. */ - final class Unique extends @dbscheme_token_unique, TokenImpl { + class Unique extends @dbscheme_token_unique, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Unique" } } /** A class representing `varchar` tokens. */ - final class Varchar extends @dbscheme_token_varchar, TokenImpl { + class Varchar extends @dbscheme_token_varchar, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Varchar" } } @@ -1927,7 +2124,7 @@ module Dbscheme { /** Provides predicates for mapping AST nodes to their named children. */ module PrintAst { /** Gets a child of `node` returned by the member predicate with the given `name`. If the predicate takes an index argument, `i` is bound to that index, otherwise `i` is `-1` (which is never a valid index). */ - AstNode getChild(AstNode node, string name, int i) { + F::AstNode getChild(F::AstNode node, string name, int i) { result = node.(Annotation).getArgsAnnotation() and i = -1 and name = "getArgsAnnotation" or result = node.(Annotation).getSimpleAnnotation() and i = -1 and name = "getSimpleAnnotation" @@ -1979,12 +2176,77 @@ module Dbscheme { } } +module DbschemeFinal { + private import Dbscheme as F + import F + + final class AstNode = F::AstNode; + + final class Token = F::Token; + + final class ReservedWord = F::ReservedWord; + + final class AnnotName = F::AnnotName; + + final class Annotation = F::Annotation; + + final class ArgsAnnotation = F::ArgsAnnotation; + + final class BlockComment = F::BlockComment; + + final class Boolean = F::Boolean; + + final class Branch = F::Branch; + + final class CaseDecl = F::CaseDecl; + + final class ColType = F::ColType; + + final class Column = F::Column; + + final class Date = F::Date; + + final class Dbscheme = F::Dbscheme; + + final class Dbtype = F::Dbtype; + + final class Entry = F::Entry; + + final class Float = F::Float; + + final class Int = F::Int; + + final class Integer = F::Integer; + + final class LineComment = F::LineComment; + + final class Qldoc = F::Qldoc; + + final class Ref = F::Ref; + + final class ReprType = F::ReprType; + + final class SimpleId = F::SimpleId; + + final class String = F::String; + + final class Table = F::Table; + + final class TableName = F::TableName; + + final class UnionDecl = F::UnionDecl; + + final class Unique = F::Unique; + + final class Varchar = F::Varchar; +} + overlay[local] module Blame { private import Blame as F /** The base class for all AST nodes */ - private class AstNodeImpl extends @blame_ast_node { + class AstNode extends @blame_ast_node { /** Gets a string representation of this element. */ string toString() { result = this.getAPrimaryQlClass() } @@ -2007,10 +2269,8 @@ module Blame { string getPrimaryQlClasses() { result = concat(this.getAPrimaryQlClass(), ",") } } - final class AstNode = AstNodeImpl; - /** A token. */ - private class TokenImpl extends @blame_token, AstNodeImpl { + class Token extends @blame_token, F::AstNode { /** Gets the value of this token. */ final string getValue() { blame_tokeninfo(this, _, result) } @@ -2021,10 +2281,8 @@ module Blame { override string getAPrimaryQlClass() { result = "Token" } } - final class Token = TokenImpl; - /** A reserved word. */ - final class ReservedWord extends @blame_reserved_word, TokenImpl { + class ReservedWord extends @blame_reserved_word, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ReservedWord" } } @@ -2050,7 +2308,7 @@ module Blame { } /** A class representing `blame_entry` nodes. */ - final class BlameEntry extends @blame_blame_entry, AstNodeImpl { + class BlameEntry extends @blame_blame_entry, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BlameEntry" } @@ -2067,7 +2325,7 @@ module Blame { } /** A class representing `blame_info` nodes. */ - final class BlameInfo extends @blame_blame_info, AstNodeImpl { + class BlameInfo extends @blame_blame_info, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BlameInfo" } @@ -2084,13 +2342,13 @@ module Blame { } /** A class representing `date` tokens. */ - final class Date extends @blame_token_date, TokenImpl { + class Date extends @blame_token_date, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Date" } } /** A class representing `file_entry` nodes. */ - final class FileEntry extends @blame_file_entry, AstNodeImpl { + class FileEntry extends @blame_file_entry, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "FileEntry" } @@ -2107,13 +2365,13 @@ module Blame { } /** A class representing `filename` tokens. */ - final class Filename extends @blame_token_filename, TokenImpl { + class Filename extends @blame_token_filename, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Filename" } } /** A class representing `number` tokens. */ - final class Number extends @blame_token_number, TokenImpl { + class Number extends @blame_token_number, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Number" } } @@ -2121,7 +2379,7 @@ module Blame { /** Provides predicates for mapping AST nodes to their named children. */ module PrintAst { /** Gets a child of `node` returned by the member predicate with the given `name`. If the predicate takes an index argument, `i` is bound to that index, otherwise `i` is `-1` (which is never a valid index). */ - AstNode getChild(AstNode node, string name, int i) { + F::AstNode getChild(F::AstNode node, string name, int i) { result = node.(BlameEntry).getDate() and i = -1 and name = "getDate" or result = node.(BlameEntry).getLine(i) and name = "getLine" @@ -2137,12 +2395,35 @@ module Blame { } } +module BlameFinal { + private import Blame as F + import F + + final class AstNode = F::AstNode; + + final class Token = F::Token; + + final class ReservedWord = F::ReservedWord; + + final class BlameEntry = F::BlameEntry; + + final class BlameInfo = F::BlameInfo; + + final class Date = F::Date; + + final class FileEntry = F::FileEntry; + + final class Filename = F::Filename; + + final class Number = F::Number; +} + overlay[local] module JSON { private import JSON as F /** The base class for all AST nodes */ - private class AstNodeImpl extends @json_ast_node { + class AstNode extends @json_ast_node { /** Gets a string representation of this element. */ string toString() { result = this.getAPrimaryQlClass() } @@ -2165,10 +2446,8 @@ module JSON { string getPrimaryQlClasses() { result = concat(this.getAPrimaryQlClass(), ",") } } - final class AstNode = AstNodeImpl; - /** A token. */ - private class TokenImpl extends @json_token, AstNodeImpl { + class Token extends @json_token, F::AstNode { /** Gets the value of this token. */ final string getValue() { json_tokeninfo(this, _, result) } @@ -2179,10 +2458,8 @@ module JSON { override string getAPrimaryQlClass() { result = "Token" } } - final class Token = TokenImpl; - /** A reserved word. */ - final class ReservedWord extends @json_reserved_word, TokenImpl { + class ReservedWord extends @json_reserved_word, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ReservedWord" } } @@ -2207,10 +2484,10 @@ module JSON { ) } - final class UnderscoreValue extends @json_underscore_value, AstNodeImpl { } + class UnderscoreValue extends @json_underscore_value, F::AstNode { } /** A class representing `array` nodes. */ - final class Array extends @json_array, AstNodeImpl { + class Array extends @json_array, F::UnderscoreValue { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Array" } @@ -2222,13 +2499,13 @@ module JSON { } /** A class representing `comment` tokens. */ - final class Comment extends @json_token_comment, TokenImpl { + class Comment extends @json_token_comment, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Comment" } } /** A class representing `document` nodes. */ - final class Document extends @json_document, AstNodeImpl { + class Document extends @json_document, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Document" } @@ -2240,31 +2517,31 @@ module JSON { } /** A class representing `escape_sequence` tokens. */ - final class EscapeSequence extends @json_token_escape_sequence, TokenImpl { + class EscapeSequence extends @json_token_escape_sequence, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "EscapeSequence" } } /** A class representing `false` tokens. */ - final class False extends @json_token_false, TokenImpl { + class False extends @json_token_false, F::Token, F::UnderscoreValue { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "False" } } /** A class representing `null` tokens. */ - final class Null extends @json_token_null, TokenImpl { + class Null extends @json_token_null, F::Token, F::UnderscoreValue { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Null" } } /** A class representing `number` tokens. */ - final class Number extends @json_token_number, TokenImpl { + class Number extends @json_token_number, F::Token, F::UnderscoreValue { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Number" } } /** A class representing `object` nodes. */ - final class Object extends @json_object, AstNodeImpl { + class Object extends @json_object, F::UnderscoreValue { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Object" } @@ -2276,7 +2553,7 @@ module JSON { } /** A class representing `pair` nodes. */ - final class Pair extends @json_pair, AstNodeImpl { + class Pair extends @json_pair, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Pair" } @@ -2293,7 +2570,7 @@ module JSON { } /** A class representing `string` nodes. */ - final class String extends @json_string__, AstNodeImpl { + class String extends @json_string__, F::UnderscoreValue { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "String" } @@ -2305,13 +2582,13 @@ module JSON { } /** A class representing `string_content` tokens. */ - final class StringContent extends @json_token_string_content, TokenImpl { + class StringContent extends @json_token_string_content, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "StringContent" } } /** A class representing `true` tokens. */ - final class True extends @json_token_true, TokenImpl { + class True extends @json_token_true, F::Token, F::UnderscoreValue { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "True" } } @@ -2319,7 +2596,7 @@ module JSON { /** Provides predicates for mapping AST nodes to their named children. */ module PrintAst { /** Gets a child of `node` returned by the member predicate with the given `name`. If the predicate takes an index argument, `i` is bound to that index, otherwise `i` is `-1` (which is never a valid index). */ - AstNode getChild(AstNode node, string name, int i) { + F::AstNode getChild(F::AstNode node, string name, int i) { result = node.(Array).getChild(i) and name = "getChild" or result = node.(Document).getChild(i) and name = "getChild" @@ -2334,3 +2611,40 @@ module JSON { } } } + +module JSONFinal { + private import JSON as F + import F + + final class AstNode = F::AstNode; + + final class Token = F::Token; + + final class ReservedWord = F::ReservedWord; + + final class UnderscoreValue = F::UnderscoreValue; + + final class Array = F::Array; + + final class Comment = F::Comment; + + final class Document = F::Document; + + final class EscapeSequence = F::EscapeSequence; + + final class False = F::False; + + final class Null = F::Null; + + final class Number = F::Number; + + final class Object = F::Object; + + final class Pair = F::Pair; + + final class String = F::String; + + final class StringContent = F::StringContent; + + final class True = F::True; +} diff --git a/ruby/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll b/ruby/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll index db5360ef5d58..c4ca03fc96a1 100644 --- a/ruby/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll +++ b/ruby/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll @@ -28,7 +28,7 @@ module Ruby { private import Ruby as F /** The base class for all AST nodes */ - private class AstNodeImpl extends @ruby_ast_node { + class AstNode extends @ruby_ast_node { /** Gets a string representation of this element. */ string toString() { result = this.getAPrimaryQlClass() } @@ -51,10 +51,8 @@ module Ruby { string getPrimaryQlClasses() { result = concat(this.getAPrimaryQlClass(), ",") } } - final class AstNode = AstNodeImpl; - /** A token. */ - private class TokenImpl extends @ruby_token, AstNodeImpl { + class Token extends @ruby_token, F::AstNode { /** Gets the value of this token. */ final string getValue() { ruby_tokeninfo(this, _, result) } @@ -65,10 +63,8 @@ module Ruby { override string getAPrimaryQlClass() { result = "Token" } } - final class Token = TokenImpl; - /** A reserved word. */ - final class ReservedWord extends @ruby_reserved_word, TokenImpl { + class ReservedWord extends @ruby_reserved_word, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ReservedWord" } } @@ -93,41 +89,49 @@ module Ruby { ) } - final class UnderscoreArg extends @ruby_underscore_arg, AstNodeImpl { } - - final class UnderscoreCallOperator extends @ruby_underscore_call_operator, AstNodeImpl { } + class UnderscoreArg extends @ruby_underscore_arg, F::UnderscoreExpression { } - final class UnderscoreExpression extends @ruby_underscore_expression, AstNodeImpl { } + class UnderscoreCallOperator extends @ruby_underscore_call_operator, F::AstNode { } - final class UnderscoreLhs extends @ruby_underscore_lhs, AstNodeImpl { } + class UnderscoreExpression extends @ruby_underscore_expression, F::UnderscoreStatement { } - final class UnderscoreMethodName extends @ruby_underscore_method_name, AstNodeImpl { } + class UnderscoreLhs extends @ruby_underscore_lhs, F::UnderscorePrimary { } - final class UnderscoreNonlocalVariable extends @ruby_underscore_nonlocal_variable, AstNodeImpl { } + class UnderscoreMethodName extends @ruby_underscore_method_name, F::AstNode { } - final class UnderscorePatternConstant extends @ruby_underscore_pattern_constant, AstNodeImpl { } + class UnderscoreNonlocalVariable extends @ruby_underscore_nonlocal_variable, + F::UnderscoreMethodName, F::UnderscoreVariable + { } - final class UnderscorePatternExpr extends @ruby_underscore_pattern_expr, AstNodeImpl { } + class UnderscorePatternConstant extends @ruby_underscore_pattern_constant, + F::UnderscorePatternExprBasic + { } - final class UnderscorePatternExprBasic extends @ruby_underscore_pattern_expr_basic, AstNodeImpl { - } + class UnderscorePatternExpr extends @ruby_underscore_pattern_expr, F::UnderscorePatternTopExprBody + { } - final class UnderscorePatternPrimitive extends @ruby_underscore_pattern_primitive, AstNodeImpl { } + class UnderscorePatternExprBasic extends @ruby_underscore_pattern_expr_basic, + F::UnderscorePatternExpr + { } - final class UnderscorePatternTopExprBody extends @ruby_underscore_pattern_top_expr_body, - AstNodeImpl + class UnderscorePatternPrimitive extends @ruby_underscore_pattern_primitive, + F::UnderscorePatternExprBasic { } - final class UnderscorePrimary extends @ruby_underscore_primary, AstNodeImpl { } + class UnderscorePatternTopExprBody extends @ruby_underscore_pattern_top_expr_body, F::AstNode { } + + class UnderscorePrimary extends @ruby_underscore_primary, F::UnderscoreArg { } - final class UnderscoreSimpleNumeric extends @ruby_underscore_simple_numeric, AstNodeImpl { } + class UnderscoreSimpleNumeric extends @ruby_underscore_simple_numeric, + F::UnderscorePatternPrimitive, F::UnderscorePrimary + { } - final class UnderscoreStatement extends @ruby_underscore_statement, AstNodeImpl { } + class UnderscoreStatement extends @ruby_underscore_statement, F::AstNode { } - final class UnderscoreVariable extends @ruby_underscore_variable, AstNodeImpl { } + class UnderscoreVariable extends @ruby_underscore_variable, F::UnderscoreLhs { } /** A class representing `alias` nodes. */ - final class Alias extends @ruby_alias, AstNodeImpl { + class Alias extends @ruby_alias, F::UnderscoreStatement { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Alias" } @@ -144,7 +148,7 @@ module Ruby { } /** A class representing `alternative_pattern` nodes. */ - final class AlternativePattern extends @ruby_alternative_pattern, AstNodeImpl { + class AlternativePattern extends @ruby_alternative_pattern, F::UnderscorePatternExpr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "AlternativePattern" } @@ -160,7 +164,7 @@ module Ruby { } /** A class representing `argument_list` nodes. */ - final class ArgumentList extends @ruby_argument_list, AstNodeImpl { + class ArgumentList extends @ruby_argument_list, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ArgumentList" } @@ -172,7 +176,7 @@ module Ruby { } /** A class representing `array` nodes. */ - final class Array extends @ruby_array, AstNodeImpl { + class Array extends @ruby_array, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Array" } @@ -184,7 +188,9 @@ module Ruby { } /** A class representing `array_pattern` nodes. */ - final class ArrayPattern extends @ruby_array_pattern, AstNodeImpl { + class ArrayPattern extends @ruby_array_pattern, F::UnderscorePatternExprBasic, + F::UnderscorePatternTopExprBody + { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ArrayPattern" } @@ -201,7 +207,7 @@ module Ruby { } /** A class representing `as_pattern` nodes. */ - final class AsPattern extends @ruby_as_pattern, AstNodeImpl { + class AsPattern extends @ruby_as_pattern, F::UnderscorePatternExpr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "AsPattern" } @@ -218,7 +224,7 @@ module Ruby { } /** A class representing `assignment` nodes. */ - final class Assignment extends @ruby_assignment, AstNodeImpl { + class Assignment extends @ruby_assignment, F::UnderscoreArg, F::UnderscoreExpression { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Assignment" } @@ -235,7 +241,7 @@ module Ruby { } /** A class representing `bare_string` nodes. */ - final class BareString extends @ruby_bare_string, AstNodeImpl { + class BareString extends @ruby_bare_string, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BareString" } @@ -247,7 +253,7 @@ module Ruby { } /** A class representing `bare_symbol` nodes. */ - final class BareSymbol extends @ruby_bare_symbol, AstNodeImpl { + class BareSymbol extends @ruby_bare_symbol, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BareSymbol" } @@ -259,7 +265,7 @@ module Ruby { } /** A class representing `begin` nodes. */ - final class Begin extends @ruby_begin, AstNodeImpl { + class Begin extends @ruby_begin, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Begin" } @@ -271,7 +277,7 @@ module Ruby { } /** A class representing `begin_block` nodes. */ - final class BeginBlock extends @ruby_begin_block, AstNodeImpl { + class BeginBlock extends @ruby_begin_block, F::UnderscoreStatement { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BeginBlock" } @@ -283,7 +289,7 @@ module Ruby { } /** A class representing `binary` nodes. */ - final class Binary extends @ruby_binary, AstNodeImpl { + class Binary extends @ruby_binary, F::UnderscoreArg, F::UnderscoreExpression { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Binary" } @@ -355,7 +361,7 @@ module Ruby { } /** A class representing `block` nodes. */ - final class Block extends @ruby_block, AstNodeImpl { + class Block extends @ruby_block, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Block" } @@ -372,7 +378,7 @@ module Ruby { } /** A class representing `block_argument` nodes. */ - final class BlockArgument extends @ruby_block_argument, AstNodeImpl { + class BlockArgument extends @ruby_block_argument, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BlockArgument" } @@ -384,7 +390,7 @@ module Ruby { } /** A class representing `block_body` nodes. */ - final class BlockBody extends @ruby_block_body, AstNodeImpl { + class BlockBody extends @ruby_block_body, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BlockBody" } @@ -396,7 +402,7 @@ module Ruby { } /** A class representing `block_parameter` nodes. */ - final class BlockParameter extends @ruby_block_parameter, AstNodeImpl { + class BlockParameter extends @ruby_block_parameter, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BlockParameter" } @@ -408,7 +414,7 @@ module Ruby { } /** A class representing `block_parameters` nodes. */ - final class BlockParameters extends @ruby_block_parameters, AstNodeImpl { + class BlockParameters extends @ruby_block_parameters, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BlockParameters" } @@ -425,7 +431,7 @@ module Ruby { } /** A class representing `body_statement` nodes. */ - final class BodyStatement extends @ruby_body_statement, AstNodeImpl { + class BodyStatement extends @ruby_body_statement, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BodyStatement" } @@ -437,7 +443,7 @@ module Ruby { } /** A class representing `break` nodes. */ - final class Break extends @ruby_break, AstNodeImpl { + class Break extends @ruby_break, F::UnderscoreExpression, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Break" } @@ -449,7 +455,7 @@ module Ruby { } /** A class representing `call` nodes. */ - final class Call extends @ruby_call, AstNodeImpl { + class Call extends @ruby_call, F::UnderscoreExpression, F::UnderscoreLhs, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Call" } @@ -479,7 +485,7 @@ module Ruby { } /** A class representing `case` nodes. */ - final class Case extends @ruby_case__, AstNodeImpl { + class Case extends @ruby_case__, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Case" } @@ -496,7 +502,7 @@ module Ruby { } /** A class representing `case_match` nodes. */ - final class CaseMatch extends @ruby_case_match, AstNodeImpl { + class CaseMatch extends @ruby_case_match, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "CaseMatch" } @@ -518,7 +524,7 @@ module Ruby { } /** A class representing `chained_string` nodes. */ - final class ChainedString extends @ruby_chained_string, AstNodeImpl { + class ChainedString extends @ruby_chained_string, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ChainedString" } @@ -530,13 +536,13 @@ module Ruby { } /** A class representing `character` tokens. */ - final class Character extends @ruby_token_character, TokenImpl { + class Character extends @ruby_token_character, F::Token, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Character" } } /** A class representing `class` nodes. */ - final class Class extends @ruby_class, AstNodeImpl { + class Class extends @ruby_class, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Class" } @@ -558,19 +564,19 @@ module Ruby { } /** A class representing `class_variable` tokens. */ - final class ClassVariable extends @ruby_token_class_variable, TokenImpl { + class ClassVariable extends @ruby_token_class_variable, F::Token, F::UnderscoreNonlocalVariable { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ClassVariable" } } /** A class representing `comment` tokens. */ - final class Comment extends @ruby_token_comment, TokenImpl { + class Comment extends @ruby_token_comment, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Comment" } } /** A class representing `complex` nodes. */ - final class Complex extends @ruby_complex, AstNodeImpl { + class Complex extends @ruby_complex, F::UnderscoreSimpleNumeric { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Complex" } @@ -582,7 +588,7 @@ module Ruby { } /** A class representing `conditional` nodes. */ - final class Conditional extends @ruby_conditional, AstNodeImpl { + class Conditional extends @ruby_conditional, F::UnderscoreArg { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Conditional" } @@ -604,13 +610,17 @@ module Ruby { } /** A class representing `constant` tokens. */ - final class Constant extends @ruby_token_constant, TokenImpl { + class Constant extends @ruby_token_constant, F::Token, F::UnderscoreMethodName, + F::UnderscorePatternConstant, F::UnderscoreVariable + { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Constant" } } /** A class representing `delimited_symbol` nodes. */ - final class DelimitedSymbol extends @ruby_delimited_symbol, AstNodeImpl { + class DelimitedSymbol extends @ruby_delimited_symbol, F::UnderscoreMethodName, + F::UnderscorePatternPrimitive, F::UnderscorePrimary + { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "DelimitedSymbol" } @@ -622,7 +632,7 @@ module Ruby { } /** A class representing `destructured_left_assignment` nodes. */ - final class DestructuredLeftAssignment extends @ruby_destructured_left_assignment, AstNodeImpl { + class DestructuredLeftAssignment extends @ruby_destructured_left_assignment, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "DestructuredLeftAssignment" } @@ -636,7 +646,7 @@ module Ruby { } /** A class representing `destructured_parameter` nodes. */ - final class DestructuredParameter extends @ruby_destructured_parameter, AstNodeImpl { + class DestructuredParameter extends @ruby_destructured_parameter, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "DestructuredParameter" } @@ -650,7 +660,7 @@ module Ruby { } /** A class representing `do` nodes. */ - final class Do extends @ruby_do, AstNodeImpl { + class Do extends @ruby_do, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Do" } @@ -662,7 +672,7 @@ module Ruby { } /** A class representing `do_block` nodes. */ - final class DoBlock extends @ruby_do_block, AstNodeImpl { + class DoBlock extends @ruby_do_block, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "DoBlock" } @@ -679,7 +689,7 @@ module Ruby { } /** A class representing `element_reference` nodes. */ - final class ElementReference extends @ruby_element_reference, AstNodeImpl { + class ElementReference extends @ruby_element_reference, F::UnderscoreLhs { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ElementReference" } @@ -701,7 +711,7 @@ module Ruby { } /** A class representing `else` nodes. */ - final class Else extends @ruby_else, AstNodeImpl { + class Else extends @ruby_else, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Else" } @@ -713,7 +723,7 @@ module Ruby { } /** A class representing `elsif` nodes. */ - final class Elsif extends @ruby_elsif, AstNodeImpl { + class Elsif extends @ruby_elsif, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Elsif" } @@ -735,19 +745,19 @@ module Ruby { } /** A class representing `empty_statement` tokens. */ - final class EmptyStatement extends @ruby_token_empty_statement, TokenImpl { + class EmptyStatement extends @ruby_token_empty_statement, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "EmptyStatement" } } /** A class representing `encoding` tokens. */ - final class Encoding extends @ruby_token_encoding, TokenImpl { + class Encoding extends @ruby_token_encoding, F::Token, F::UnderscorePatternPrimitive { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Encoding" } } /** A class representing `end_block` nodes. */ - final class EndBlock extends @ruby_end_block, AstNodeImpl { + class EndBlock extends @ruby_end_block, F::UnderscoreStatement { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "EndBlock" } @@ -759,7 +769,7 @@ module Ruby { } /** A class representing `ensure` nodes. */ - final class Ensure extends @ruby_ensure, AstNodeImpl { + class Ensure extends @ruby_ensure, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Ensure" } @@ -771,13 +781,13 @@ module Ruby { } /** A class representing `escape_sequence` tokens. */ - final class EscapeSequence extends @ruby_token_escape_sequence, TokenImpl { + class EscapeSequence extends @ruby_token_escape_sequence, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "EscapeSequence" } } /** A class representing `exception_variable` nodes. */ - final class ExceptionVariable extends @ruby_exception_variable, AstNodeImpl { + class ExceptionVariable extends @ruby_exception_variable, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ExceptionVariable" } @@ -789,7 +799,7 @@ module Ruby { } /** A class representing `exceptions` nodes. */ - final class Exceptions extends @ruby_exceptions, AstNodeImpl { + class Exceptions extends @ruby_exceptions, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Exceptions" } @@ -801,7 +811,9 @@ module Ruby { } /** A class representing `expression_reference_pattern` nodes. */ - final class ExpressionReferencePattern extends @ruby_expression_reference_pattern, AstNodeImpl { + class ExpressionReferencePattern extends @ruby_expression_reference_pattern, + F::UnderscorePatternExprBasic + { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ExpressionReferencePattern" } @@ -815,19 +827,21 @@ module Ruby { } /** A class representing `false` tokens. */ - final class False extends @ruby_token_false, TokenImpl { + class False extends @ruby_token_false, F::Token, F::UnderscoreLhs, F::UnderscorePatternPrimitive { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "False" } } /** A class representing `file` tokens. */ - final class File extends @ruby_token_file, TokenImpl { + class File extends @ruby_token_file, F::Token, F::UnderscorePatternPrimitive { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "File" } } /** A class representing `find_pattern` nodes. */ - final class FindPattern extends @ruby_find_pattern, AstNodeImpl { + class FindPattern extends @ruby_find_pattern, F::UnderscorePatternExprBasic, + F::UnderscorePatternTopExprBody + { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "FindPattern" } @@ -844,13 +858,13 @@ module Ruby { } /** A class representing `float` tokens. */ - final class Float extends @ruby_token_float, TokenImpl { + class Float extends @ruby_token_float, F::Token, F::UnderscoreSimpleNumeric { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Float" } } /** A class representing `for` nodes. */ - final class For extends @ruby_for, AstNodeImpl { + class For extends @ruby_for, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "For" } @@ -872,25 +886,25 @@ module Ruby { } /** A class representing `forward_argument` tokens. */ - final class ForwardArgument extends @ruby_token_forward_argument, TokenImpl { + class ForwardArgument extends @ruby_token_forward_argument, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ForwardArgument" } } /** A class representing `forward_parameter` tokens. */ - final class ForwardParameter extends @ruby_token_forward_parameter, TokenImpl { + class ForwardParameter extends @ruby_token_forward_parameter, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ForwardParameter" } } /** A class representing `global_variable` tokens. */ - final class GlobalVariable extends @ruby_token_global_variable, TokenImpl { + class GlobalVariable extends @ruby_token_global_variable, F::Token, F::UnderscoreNonlocalVariable { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "GlobalVariable" } } /** A class representing `hash` nodes. */ - final class Hash extends @ruby_hash, AstNodeImpl { + class Hash extends @ruby_hash, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Hash" } @@ -902,13 +916,15 @@ module Ruby { } /** A class representing `hash_key_symbol` tokens. */ - final class HashKeySymbol extends @ruby_token_hash_key_symbol, TokenImpl { + class HashKeySymbol extends @ruby_token_hash_key_symbol, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "HashKeySymbol" } } /** A class representing `hash_pattern` nodes. */ - final class HashPattern extends @ruby_hash_pattern, AstNodeImpl { + class HashPattern extends @ruby_hash_pattern, F::UnderscorePatternExprBasic, + F::UnderscorePatternTopExprBody + { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "HashPattern" } @@ -925,7 +941,7 @@ module Ruby { } /** A class representing `hash_splat_argument` nodes. */ - final class HashSplatArgument extends @ruby_hash_splat_argument, AstNodeImpl { + class HashSplatArgument extends @ruby_hash_splat_argument, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "HashSplatArgument" } @@ -937,13 +953,13 @@ module Ruby { } /** A class representing `hash_splat_nil` tokens. */ - final class HashSplatNil extends @ruby_token_hash_splat_nil, TokenImpl { + class HashSplatNil extends @ruby_token_hash_splat_nil, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "HashSplatNil" } } /** A class representing `hash_splat_parameter` nodes. */ - final class HashSplatParameter extends @ruby_hash_splat_parameter, AstNodeImpl { + class HashSplatParameter extends @ruby_hash_splat_parameter, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "HashSplatParameter" } @@ -955,13 +971,15 @@ module Ruby { } /** A class representing `heredoc_beginning` tokens. */ - final class HeredocBeginning extends @ruby_token_heredoc_beginning, TokenImpl { + class HeredocBeginning extends @ruby_token_heredoc_beginning, F::Token, + F::UnderscorePatternPrimitive, F::UnderscorePrimary + { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "HeredocBeginning" } } /** A class representing `heredoc_body` nodes. */ - final class HeredocBody extends @ruby_heredoc_body, AstNodeImpl { + class HeredocBody extends @ruby_heredoc_body, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "HeredocBody" } @@ -973,25 +991,27 @@ module Ruby { } /** A class representing `heredoc_content` tokens. */ - final class HeredocContent extends @ruby_token_heredoc_content, TokenImpl { + class HeredocContent extends @ruby_token_heredoc_content, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "HeredocContent" } } /** A class representing `heredoc_end` tokens. */ - final class HeredocEnd extends @ruby_token_heredoc_end, TokenImpl { + class HeredocEnd extends @ruby_token_heredoc_end, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "HeredocEnd" } } /** A class representing `identifier` tokens. */ - final class Identifier extends @ruby_token_identifier, TokenImpl { + class Identifier extends @ruby_token_identifier, F::Token, F::UnderscoreMethodName, + F::UnderscorePatternExprBasic, F::UnderscoreVariable + { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Identifier" } } /** A class representing `if` nodes. */ - final class If extends @ruby_if, AstNodeImpl { + class If extends @ruby_if, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "If" } @@ -1013,7 +1033,7 @@ module Ruby { } /** A class representing `if_guard` nodes. */ - final class IfGuard extends @ruby_if_guard, AstNodeImpl { + class IfGuard extends @ruby_if_guard, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "IfGuard" } @@ -1025,7 +1045,7 @@ module Ruby { } /** A class representing `if_modifier` nodes. */ - final class IfModifier extends @ruby_if_modifier, AstNodeImpl { + class IfModifier extends @ruby_if_modifier, F::UnderscoreStatement { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "IfModifier" } @@ -1042,7 +1062,7 @@ module Ruby { } /** A class representing `in` nodes. */ - final class In extends @ruby_in, AstNodeImpl { + class In extends @ruby_in, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "In" } @@ -1054,7 +1074,7 @@ module Ruby { } /** A class representing `in_clause` nodes. */ - final class InClause extends @ruby_in_clause, AstNodeImpl { + class InClause extends @ruby_in_clause, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "InClause" } @@ -1076,19 +1096,21 @@ module Ruby { } /** A class representing `instance_variable` tokens. */ - final class InstanceVariable extends @ruby_token_instance_variable, TokenImpl { + class InstanceVariable extends @ruby_token_instance_variable, F::Token, + F::UnderscoreNonlocalVariable + { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "InstanceVariable" } } /** A class representing `integer` tokens. */ - final class Integer extends @ruby_token_integer, TokenImpl { + class Integer extends @ruby_token_integer, F::Token, F::UnderscoreSimpleNumeric { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Integer" } } /** A class representing `interpolation` nodes. */ - final class Interpolation extends @ruby_interpolation, AstNodeImpl { + class Interpolation extends @ruby_interpolation, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Interpolation" } @@ -1100,7 +1122,7 @@ module Ruby { } /** A class representing `keyword_parameter` nodes. */ - final class KeywordParameter extends @ruby_keyword_parameter, AstNodeImpl { + class KeywordParameter extends @ruby_keyword_parameter, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "KeywordParameter" } @@ -1117,7 +1139,7 @@ module Ruby { } /** A class representing `keyword_pattern` nodes. */ - final class KeywordPattern extends @ruby_keyword_pattern, AstNodeImpl { + class KeywordPattern extends @ruby_keyword_pattern, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "KeywordPattern" } @@ -1134,7 +1156,7 @@ module Ruby { } /** A class representing `lambda` nodes. */ - final class Lambda extends @ruby_lambda, AstNodeImpl { + class Lambda extends @ruby_lambda, F::UnderscorePatternPrimitive, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Lambda" } @@ -1151,7 +1173,7 @@ module Ruby { } /** A class representing `lambda_parameters` nodes. */ - final class LambdaParameters extends @ruby_lambda_parameters, AstNodeImpl { + class LambdaParameters extends @ruby_lambda_parameters, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "LambdaParameters" } @@ -1163,7 +1185,7 @@ module Ruby { } /** A class representing `left_assignment_list` nodes. */ - final class LeftAssignmentList extends @ruby_left_assignment_list, AstNodeImpl { + class LeftAssignmentList extends @ruby_left_assignment_list, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "LeftAssignmentList" } @@ -1177,13 +1199,13 @@ module Ruby { } /** A class representing `line` tokens. */ - final class Line extends @ruby_token_line, TokenImpl { + class Line extends @ruby_token_line, F::Token, F::UnderscorePatternPrimitive { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Line" } } /** A class representing `match_pattern` nodes. */ - final class MatchPattern extends @ruby_match_pattern, AstNodeImpl { + class MatchPattern extends @ruby_match_pattern, F::UnderscoreExpression { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "MatchPattern" } @@ -1200,7 +1222,7 @@ module Ruby { } /** A class representing `method` nodes. */ - final class Method extends @ruby_method, AstNodeImpl { + class Method extends @ruby_method, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Method" } @@ -1222,7 +1244,7 @@ module Ruby { } /** A class representing `method_parameters` nodes. */ - final class MethodParameters extends @ruby_method_parameters, AstNodeImpl { + class MethodParameters extends @ruby_method_parameters, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "MethodParameters" } @@ -1234,7 +1256,7 @@ module Ruby { } /** A class representing `module` nodes. */ - final class Module extends @ruby_module, AstNodeImpl { + class Module extends @ruby_module, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Module" } @@ -1251,7 +1273,7 @@ module Ruby { } /** A class representing `next` nodes. */ - final class Next extends @ruby_next, AstNodeImpl { + class Next extends @ruby_next, F::UnderscoreExpression, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Next" } @@ -1263,19 +1285,21 @@ module Ruby { } /** A class representing `nil` tokens. */ - final class Nil extends @ruby_token_nil, TokenImpl { + class Nil extends @ruby_token_nil, F::Token, F::UnderscoreLhs, F::UnderscorePatternPrimitive { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Nil" } } /** A class representing `operator` tokens. */ - final class Operator extends @ruby_token_operator, TokenImpl { + class Operator extends @ruby_token_operator, F::Token, F::UnderscoreMethodName { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Operator" } } /** A class representing `operator_assignment` nodes. */ - final class OperatorAssignment extends @ruby_operator_assignment, AstNodeImpl { + class OperatorAssignment extends @ruby_operator_assignment, F::UnderscoreArg, + F::UnderscoreExpression + { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "OperatorAssignment" } @@ -1324,7 +1348,7 @@ module Ruby { } /** A class representing `optional_parameter` nodes. */ - final class OptionalParameter extends @ruby_optional_parameter, AstNodeImpl { + class OptionalParameter extends @ruby_optional_parameter, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "OptionalParameter" } @@ -1341,7 +1365,7 @@ module Ruby { } /** A class representing `pair` nodes. */ - final class Pair extends @ruby_pair, AstNodeImpl { + class Pair extends @ruby_pair, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Pair" } @@ -1358,7 +1382,7 @@ module Ruby { } /** A class representing `parenthesized_pattern` nodes. */ - final class ParenthesizedPattern extends @ruby_parenthesized_pattern, AstNodeImpl { + class ParenthesizedPattern extends @ruby_parenthesized_pattern, F::UnderscorePatternExprBasic { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ParenthesizedPattern" } @@ -1370,7 +1394,7 @@ module Ruby { } /** A class representing `parenthesized_statements` nodes. */ - final class ParenthesizedStatements extends @ruby_parenthesized_statements, AstNodeImpl { + class ParenthesizedStatements extends @ruby_parenthesized_statements, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ParenthesizedStatements" } @@ -1384,7 +1408,7 @@ module Ruby { } /** A class representing `pattern` nodes. */ - final class Pattern extends @ruby_pattern, AstNodeImpl { + class Pattern extends @ruby_pattern, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Pattern" } @@ -1396,7 +1420,7 @@ module Ruby { } /** A class representing `program` nodes. */ - final class Program extends @ruby_program, AstNodeImpl { + class Program extends @ruby_program, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Program" } @@ -1408,7 +1432,7 @@ module Ruby { } /** A class representing `range` nodes. */ - final class Range extends @ruby_range, AstNodeImpl { + class Range extends @ruby_range, F::UnderscoreArg, F::UnderscorePatternExprBasic { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Range" } @@ -1434,7 +1458,7 @@ module Ruby { } /** A class representing `rational` nodes. */ - final class Rational extends @ruby_rational, AstNodeImpl { + class Rational extends @ruby_rational, F::UnderscoreSimpleNumeric { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Rational" } @@ -1446,7 +1470,7 @@ module Ruby { } /** A class representing `redo` nodes. */ - final class Redo extends @ruby_redo, AstNodeImpl { + class Redo extends @ruby_redo, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Redo" } @@ -1458,7 +1482,7 @@ module Ruby { } /** A class representing `regex` nodes. */ - final class Regex extends @ruby_regex, AstNodeImpl { + class Regex extends @ruby_regex, F::UnderscorePatternPrimitive, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Regex" } @@ -1470,7 +1494,7 @@ module Ruby { } /** A class representing `rescue` nodes. */ - final class Rescue extends @ruby_rescue, AstNodeImpl { + class Rescue extends @ruby_rescue, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Rescue" } @@ -1492,7 +1516,7 @@ module Ruby { } /** A class representing `rescue_modifier` nodes. */ - final class RescueModifier extends @ruby_rescue_modifier, AstNodeImpl { + class RescueModifier extends @ruby_rescue_modifier, F::UnderscoreStatement { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "RescueModifier" } @@ -1509,7 +1533,7 @@ module Ruby { } /** A class representing `rest_assignment` nodes. */ - final class RestAssignment extends @ruby_rest_assignment, AstNodeImpl { + class RestAssignment extends @ruby_rest_assignment, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "RestAssignment" } @@ -1521,7 +1545,7 @@ module Ruby { } /** A class representing `retry` nodes. */ - final class Retry extends @ruby_retry, AstNodeImpl { + class Retry extends @ruby_retry, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Retry" } @@ -1533,7 +1557,7 @@ module Ruby { } /** A class representing `return` nodes. */ - final class Return extends @ruby_return, AstNodeImpl { + class Return extends @ruby_return, F::UnderscoreExpression, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Return" } @@ -1545,7 +1569,7 @@ module Ruby { } /** A class representing `right_assignment_list` nodes. */ - final class RightAssignmentList extends @ruby_right_assignment_list, AstNodeImpl { + class RightAssignmentList extends @ruby_right_assignment_list, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "RightAssignmentList" } @@ -1559,7 +1583,9 @@ module Ruby { } /** A class representing `scope_resolution` nodes. */ - final class ScopeResolution extends @ruby_scope_resolution, AstNodeImpl { + class ScopeResolution extends @ruby_scope_resolution, F::UnderscoreLhs, + F::UnderscorePatternConstant + { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ScopeResolution" } @@ -1576,13 +1602,15 @@ module Ruby { } /** A class representing `self` tokens. */ - final class Self extends @ruby_token_self, TokenImpl { + class Self extends @ruby_token_self, F::Token, F::UnderscorePatternPrimitive, + F::UnderscoreVariable + { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Self" } } /** A class representing `setter` nodes. */ - final class Setter extends @ruby_setter, AstNodeImpl { + class Setter extends @ruby_setter, F::UnderscoreMethodName { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Setter" } @@ -1594,13 +1622,15 @@ module Ruby { } /** A class representing `simple_symbol` tokens. */ - final class SimpleSymbol extends @ruby_token_simple_symbol, TokenImpl { + class SimpleSymbol extends @ruby_token_simple_symbol, F::Token, F::UnderscoreMethodName, + F::UnderscorePatternPrimitive, F::UnderscorePrimary + { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "SimpleSymbol" } } /** A class representing `singleton_class` nodes. */ - final class SingletonClass extends @ruby_singleton_class, AstNodeImpl { + class SingletonClass extends @ruby_singleton_class, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "SingletonClass" } @@ -1617,7 +1647,7 @@ module Ruby { } /** A class representing `singleton_method` nodes. */ - final class SingletonMethod extends @ruby_singleton_method, AstNodeImpl { + class SingletonMethod extends @ruby_singleton_method, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "SingletonMethod" } @@ -1643,7 +1673,7 @@ module Ruby { } /** A class representing `splat_argument` nodes. */ - final class SplatArgument extends @ruby_splat_argument, AstNodeImpl { + class SplatArgument extends @ruby_splat_argument, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "SplatArgument" } @@ -1655,7 +1685,7 @@ module Ruby { } /** A class representing `splat_parameter` nodes. */ - final class SplatParameter extends @ruby_splat_parameter, AstNodeImpl { + class SplatParameter extends @ruby_splat_parameter, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "SplatParameter" } @@ -1667,7 +1697,7 @@ module Ruby { } /** A class representing `string` nodes. */ - final class String extends @ruby_string__, AstNodeImpl { + class String extends @ruby_string__, F::UnderscorePatternPrimitive, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "String" } @@ -1679,7 +1709,7 @@ module Ruby { } /** A class representing `string_array` nodes. */ - final class StringArray extends @ruby_string_array, AstNodeImpl { + class StringArray extends @ruby_string_array, F::UnderscorePatternPrimitive, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "StringArray" } @@ -1691,13 +1721,13 @@ module Ruby { } /** A class representing `string_content` tokens. */ - final class StringContent extends @ruby_token_string_content, TokenImpl { + class StringContent extends @ruby_token_string_content, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "StringContent" } } /** A class representing `subshell` nodes. */ - final class Subshell extends @ruby_subshell, AstNodeImpl { + class Subshell extends @ruby_subshell, F::UnderscorePatternPrimitive, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Subshell" } @@ -1709,13 +1739,13 @@ module Ruby { } /** A class representing `super` tokens. */ - final class Super extends @ruby_token_super, TokenImpl { + class Super extends @ruby_token_super, F::Token, F::UnderscoreVariable { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Super" } } /** A class representing `superclass` nodes. */ - final class Superclass extends @ruby_superclass, AstNodeImpl { + class Superclass extends @ruby_superclass, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Superclass" } @@ -1727,7 +1757,7 @@ module Ruby { } /** A class representing `symbol_array` nodes. */ - final class SymbolArray extends @ruby_symbol_array, AstNodeImpl { + class SymbolArray extends @ruby_symbol_array, F::UnderscorePatternPrimitive, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "SymbolArray" } @@ -1739,7 +1769,7 @@ module Ruby { } /** A class representing `test_pattern` nodes. */ - final class TestPattern extends @ruby_test_pattern, AstNodeImpl { + class TestPattern extends @ruby_test_pattern, F::UnderscoreExpression { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TestPattern" } @@ -1756,7 +1786,7 @@ module Ruby { } /** A class representing `then` nodes. */ - final class Then extends @ruby_then, AstNodeImpl { + class Then extends @ruby_then, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Then" } @@ -1768,13 +1798,15 @@ module Ruby { } /** A class representing `true` tokens. */ - final class True extends @ruby_token_true, TokenImpl { + class True extends @ruby_token_true, F::Token, F::UnderscoreLhs, F::UnderscorePatternPrimitive { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "True" } } /** A class representing `unary` nodes. */ - final class Unary extends @ruby_unary, AstNodeImpl { + class Unary extends @ruby_unary, F::UnderscoreArg, F::UnderscoreExpression, + F::UnderscorePatternPrimitive, F::UnderscorePrimary + { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Unary" } @@ -1803,7 +1835,7 @@ module Ruby { } /** A class representing `undef` nodes. */ - final class Undef extends @ruby_undef, AstNodeImpl { + class Undef extends @ruby_undef, F::UnderscoreStatement { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Undef" } @@ -1815,13 +1847,13 @@ module Ruby { } /** A class representing `uninterpreted` tokens. */ - final class Uninterpreted extends @ruby_token_uninterpreted, TokenImpl { + class Uninterpreted extends @ruby_token_uninterpreted, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Uninterpreted" } } /** A class representing `unless` nodes. */ - final class Unless extends @ruby_unless, AstNodeImpl { + class Unless extends @ruby_unless, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Unless" } @@ -1843,7 +1875,7 @@ module Ruby { } /** A class representing `unless_guard` nodes. */ - final class UnlessGuard extends @ruby_unless_guard, AstNodeImpl { + class UnlessGuard extends @ruby_unless_guard, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "UnlessGuard" } @@ -1855,7 +1887,7 @@ module Ruby { } /** A class representing `unless_modifier` nodes. */ - final class UnlessModifier extends @ruby_unless_modifier, AstNodeImpl { + class UnlessModifier extends @ruby_unless_modifier, F::UnderscoreStatement { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "UnlessModifier" } @@ -1872,7 +1904,7 @@ module Ruby { } /** A class representing `until` nodes. */ - final class Until extends @ruby_until, AstNodeImpl { + class Until extends @ruby_until, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Until" } @@ -1889,7 +1921,7 @@ module Ruby { } /** A class representing `until_modifier` nodes. */ - final class UntilModifier extends @ruby_until_modifier, AstNodeImpl { + class UntilModifier extends @ruby_until_modifier, F::UnderscoreStatement { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "UntilModifier" } @@ -1906,7 +1938,9 @@ module Ruby { } /** A class representing `variable_reference_pattern` nodes. */ - final class VariableReferencePattern extends @ruby_variable_reference_pattern, AstNodeImpl { + class VariableReferencePattern extends @ruby_variable_reference_pattern, + F::UnderscorePatternExprBasic + { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "VariableReferencePattern" } @@ -1920,7 +1954,7 @@ module Ruby { } /** A class representing `when` nodes. */ - final class When extends @ruby_when, AstNodeImpl { + class When extends @ruby_when, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "When" } @@ -1937,7 +1971,7 @@ module Ruby { } /** A class representing `while` nodes. */ - final class While extends @ruby_while, AstNodeImpl { + class While extends @ruby_while, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "While" } @@ -1954,7 +1988,7 @@ module Ruby { } /** A class representing `while_modifier` nodes. */ - final class WhileModifier extends @ruby_while_modifier, AstNodeImpl { + class WhileModifier extends @ruby_while_modifier, F::UnderscoreStatement { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "WhileModifier" } @@ -1971,7 +2005,7 @@ module Ruby { } /** A class representing `yield` nodes. */ - final class Yield extends @ruby_yield, AstNodeImpl { + class Yield extends @ruby_yield, F::UnderscoreExpression, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Yield" } @@ -1985,7 +2019,7 @@ module Ruby { /** Provides predicates for mapping AST nodes to their named children. */ module PrintAst { /** Gets a child of `node` returned by the member predicate with the given `name`. If the predicate takes an index argument, `i` is bound to that index, otherwise `i` is `-1` (which is never a valid index). */ - AstNode getChild(AstNode node, string name, int i) { + F::AstNode getChild(F::AstNode node, string name, int i) { result = node.(Alias).getAlias() and i = -1 and name = "getAlias" or result = node.(Alias).getName() and i = -1 and name = "getName" @@ -2317,12 +2351,321 @@ module Ruby { } } +module RubyFinal { + private import Ruby as F + import F + + final class AstNode = F::AstNode; + + final class Token = F::Token; + + final class ReservedWord = F::ReservedWord; + + final class UnderscoreArg = F::UnderscoreArg; + + final class UnderscoreCallOperator = F::UnderscoreCallOperator; + + final class UnderscoreExpression = F::UnderscoreExpression; + + final class UnderscoreLhs = F::UnderscoreLhs; + + final class UnderscoreMethodName = F::UnderscoreMethodName; + + final class UnderscoreNonlocalVariable = F::UnderscoreNonlocalVariable; + + final class UnderscorePatternConstant = F::UnderscorePatternConstant; + + final class UnderscorePatternExpr = F::UnderscorePatternExpr; + + final class UnderscorePatternExprBasic = F::UnderscorePatternExprBasic; + + final class UnderscorePatternPrimitive = F::UnderscorePatternPrimitive; + + final class UnderscorePatternTopExprBody = F::UnderscorePatternTopExprBody; + + final class UnderscorePrimary = F::UnderscorePrimary; + + final class UnderscoreSimpleNumeric = F::UnderscoreSimpleNumeric; + + final class UnderscoreStatement = F::UnderscoreStatement; + + final class UnderscoreVariable = F::UnderscoreVariable; + + final class Alias = F::Alias; + + final class AlternativePattern = F::AlternativePattern; + + final class ArgumentList = F::ArgumentList; + + final class Array = F::Array; + + final class ArrayPattern = F::ArrayPattern; + + final class AsPattern = F::AsPattern; + + final class Assignment = F::Assignment; + + final class BareString = F::BareString; + + final class BareSymbol = F::BareSymbol; + + final class Begin = F::Begin; + + final class BeginBlock = F::BeginBlock; + + final class Binary = F::Binary; + + final class Block = F::Block; + + final class BlockArgument = F::BlockArgument; + + final class BlockBody = F::BlockBody; + + final class BlockParameter = F::BlockParameter; + + final class BlockParameters = F::BlockParameters; + + final class BodyStatement = F::BodyStatement; + + final class Break = F::Break; + + final class Call = F::Call; + + final class Case = F::Case; + + final class CaseMatch = F::CaseMatch; + + final class ChainedString = F::ChainedString; + + final class Character = F::Character; + + final class Class = F::Class; + + final class ClassVariable = F::ClassVariable; + + final class Comment = F::Comment; + + final class Complex = F::Complex; + + final class Conditional = F::Conditional; + + final class Constant = F::Constant; + + final class DelimitedSymbol = F::DelimitedSymbol; + + final class DestructuredLeftAssignment = F::DestructuredLeftAssignment; + + final class DestructuredParameter = F::DestructuredParameter; + + final class Do = F::Do; + + final class DoBlock = F::DoBlock; + + final class ElementReference = F::ElementReference; + + final class Else = F::Else; + + final class Elsif = F::Elsif; + + final class EmptyStatement = F::EmptyStatement; + + final class Encoding = F::Encoding; + + final class EndBlock = F::EndBlock; + + final class Ensure = F::Ensure; + + final class EscapeSequence = F::EscapeSequence; + + final class ExceptionVariable = F::ExceptionVariable; + + final class Exceptions = F::Exceptions; + + final class ExpressionReferencePattern = F::ExpressionReferencePattern; + + final class False = F::False; + + final class File = F::File; + + final class FindPattern = F::FindPattern; + + final class Float = F::Float; + + final class For = F::For; + + final class ForwardArgument = F::ForwardArgument; + + final class ForwardParameter = F::ForwardParameter; + + final class GlobalVariable = F::GlobalVariable; + + final class Hash = F::Hash; + + final class HashKeySymbol = F::HashKeySymbol; + + final class HashPattern = F::HashPattern; + + final class HashSplatArgument = F::HashSplatArgument; + + final class HashSplatNil = F::HashSplatNil; + + final class HashSplatParameter = F::HashSplatParameter; + + final class HeredocBeginning = F::HeredocBeginning; + + final class HeredocBody = F::HeredocBody; + + final class HeredocContent = F::HeredocContent; + + final class HeredocEnd = F::HeredocEnd; + + final class Identifier = F::Identifier; + + final class If = F::If; + + final class IfGuard = F::IfGuard; + + final class IfModifier = F::IfModifier; + + final class In = F::In; + + final class InClause = F::InClause; + + final class InstanceVariable = F::InstanceVariable; + + final class Integer = F::Integer; + + final class Interpolation = F::Interpolation; + + final class KeywordParameter = F::KeywordParameter; + + final class KeywordPattern = F::KeywordPattern; + + final class Lambda = F::Lambda; + + final class LambdaParameters = F::LambdaParameters; + + final class LeftAssignmentList = F::LeftAssignmentList; + + final class Line = F::Line; + + final class MatchPattern = F::MatchPattern; + + final class Method = F::Method; + + final class MethodParameters = F::MethodParameters; + + final class Module = F::Module; + + final class Next = F::Next; + + final class Nil = F::Nil; + + final class Operator = F::Operator; + + final class OperatorAssignment = F::OperatorAssignment; + + final class OptionalParameter = F::OptionalParameter; + + final class Pair = F::Pair; + + final class ParenthesizedPattern = F::ParenthesizedPattern; + + final class ParenthesizedStatements = F::ParenthesizedStatements; + + final class Pattern = F::Pattern; + + final class Program = F::Program; + + final class Range = F::Range; + + final class Rational = F::Rational; + + final class Redo = F::Redo; + + final class Regex = F::Regex; + + final class Rescue = F::Rescue; + + final class RescueModifier = F::RescueModifier; + + final class RestAssignment = F::RestAssignment; + + final class Retry = F::Retry; + + final class Return = F::Return; + + final class RightAssignmentList = F::RightAssignmentList; + + final class ScopeResolution = F::ScopeResolution; + + final class Self = F::Self; + + final class Setter = F::Setter; + + final class SimpleSymbol = F::SimpleSymbol; + + final class SingletonClass = F::SingletonClass; + + final class SingletonMethod = F::SingletonMethod; + + final class SplatArgument = F::SplatArgument; + + final class SplatParameter = F::SplatParameter; + + final class String = F::String; + + final class StringArray = F::StringArray; + + final class StringContent = F::StringContent; + + final class Subshell = F::Subshell; + + final class Super = F::Super; + + final class Superclass = F::Superclass; + + final class SymbolArray = F::SymbolArray; + + final class TestPattern = F::TestPattern; + + final class Then = F::Then; + + final class True = F::True; + + final class Unary = F::Unary; + + final class Undef = F::Undef; + + final class Uninterpreted = F::Uninterpreted; + + final class Unless = F::Unless; + + final class UnlessGuard = F::UnlessGuard; + + final class UnlessModifier = F::UnlessModifier; + + final class Until = F::Until; + + final class UntilModifier = F::UntilModifier; + + final class VariableReferencePattern = F::VariableReferencePattern; + + final class When = F::When; + + final class While = F::While; + + final class WhileModifier = F::WhileModifier; + + final class Yield = F::Yield; +} + overlay[local] module Erb { private import Erb as F /** The base class for all AST nodes */ - private class AstNodeImpl extends @erb_ast_node { + class AstNode extends @erb_ast_node { /** Gets a string representation of this element. */ string toString() { result = this.getAPrimaryQlClass() } @@ -2345,10 +2688,8 @@ module Erb { string getPrimaryQlClasses() { result = concat(this.getAPrimaryQlClass(), ",") } } - final class AstNode = AstNodeImpl; - /** A token. */ - private class TokenImpl extends @erb_token, AstNodeImpl { + class Token extends @erb_token, F::AstNode { /** Gets the value of this token. */ final string getValue() { erb_tokeninfo(this, _, result) } @@ -2359,10 +2700,8 @@ module Erb { override string getAPrimaryQlClass() { result = "Token" } } - final class Token = TokenImpl; - /** A reserved word. */ - final class ReservedWord extends @erb_reserved_word, TokenImpl { + class ReservedWord extends @erb_reserved_word, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ReservedWord" } } @@ -2388,19 +2727,19 @@ module Erb { } /** A class representing `code` tokens. */ - final class Code extends @erb_token_code, TokenImpl { + class Code extends @erb_token_code, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Code" } } /** A class representing `comment` tokens. */ - final class Comment extends @erb_token_comment, TokenImpl { + class Comment extends @erb_token_comment, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Comment" } } /** A class representing `comment_directive` nodes. */ - final class CommentDirective extends @erb_comment_directive, AstNodeImpl { + class CommentDirective extends @erb_comment_directive, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "CommentDirective" } @@ -2412,13 +2751,13 @@ module Erb { } /** A class representing `content` tokens. */ - final class Content extends @erb_token_content, TokenImpl { + class Content extends @erb_token_content, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Content" } } /** A class representing `directive` nodes. */ - final class Directive extends @erb_directive, AstNodeImpl { + class Directive extends @erb_directive, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Directive" } @@ -2430,7 +2769,7 @@ module Erb { } /** A class representing `graphql_directive` nodes. */ - final class GraphqlDirective extends @erb_graphql_directive, AstNodeImpl { + class GraphqlDirective extends @erb_graphql_directive, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "GraphqlDirective" } @@ -2442,7 +2781,7 @@ module Erb { } /** A class representing `output_directive` nodes. */ - final class OutputDirective extends @erb_output_directive, AstNodeImpl { + class OutputDirective extends @erb_output_directive, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "OutputDirective" } @@ -2454,7 +2793,7 @@ module Erb { } /** A class representing `template` nodes. */ - final class Template extends @erb_template, AstNodeImpl { + class Template extends @erb_template, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Template" } @@ -2468,7 +2807,7 @@ module Erb { /** Provides predicates for mapping AST nodes to their named children. */ module PrintAst { /** Gets a child of `node` returned by the member predicate with the given `name`. If the predicate takes an index argument, `i` is bound to that index, otherwise `i` is `-1` (which is never a valid index). */ - AstNode getChild(AstNode node, string name, int i) { + F::AstNode getChild(F::AstNode node, string name, int i) { result = node.(CommentDirective).getChild() and i = -1 and name = "getChild" or result = node.(Directive).getChild() and i = -1 and name = "getChild" @@ -2481,3 +2820,30 @@ module Erb { } } } + +module ErbFinal { + private import Erb as F + import F + + final class AstNode = F::AstNode; + + final class Token = F::Token; + + final class ReservedWord = F::ReservedWord; + + final class Code = F::Code; + + final class Comment = F::Comment; + + final class CommentDirective = F::CommentDirective; + + final class Content = F::Content; + + final class Directive = F::Directive; + + final class GraphqlDirective = F::GraphqlDirective; + + final class OutputDirective = F::OutputDirective; + + final class Template = F::Template; +} From d28b149833c8978fb41dc6c81f65875cecc88fea Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 30 Jul 2026 14:56:02 +0200 Subject: [PATCH 136/188] unified: Regenerate QL after rebasing --- unified/ql/lib/codeql/unified/internal/Ast.qll | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/unified/ql/lib/codeql/unified/internal/Ast.qll b/unified/ql/lib/codeql/unified/internal/Ast.qll index 8e231bee79f4..532b5d3cf716 100644 --- a/unified/ql/lib/codeql/unified/internal/Ast.qll +++ b/unified/ql/lib/codeql/unified/internal/Ast.qll @@ -430,7 +430,7 @@ module Unified { } /** A class representing `conditional_pattern` nodes. */ - final class ConditionalPattern extends @unified_conditional_pattern, AstNodeImpl { + class ConditionalPattern extends @unified_conditional_pattern, F::Pattern { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ConditionalPattern" } @@ -1896,6 +1896,8 @@ module UnifiedFinal { final class CompoundAssignExpr = F::CompoundAssignExpr; + final class ConditionalPattern = F::ConditionalPattern; + final class ConstructorDeclaration = F::ConstructorDeclaration; final class ConstructorPattern = F::ConstructorPattern; From 41bd51608200050eae5f880f6d15bdc47de32066 Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 30 Jul 2026 15:08:48 +0200 Subject: [PATCH 137/188] unified: Use start-line for detecting variable aliases --- unified/ql/test/library-tests/variables/test.swift | 7 +++---- unified/ql/test/library-tests/variables/variables.ql | 1 + 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/unified/ql/test/library-tests/variables/test.swift b/unified/ql/test/library-tests/variables/test.swift index 35aac75d393f..20ae492b78bd 100644 --- a/unified/ql/test/library-tests/variables/test.swift +++ b/unified/ql/test/library-tests/variables/test.swift @@ -343,11 +343,10 @@ enum E38 { } // Switch with a multi-pattern case that binds 'x' in each pattern -// Note: the testing framework does not make it possible to name the 'x' variable in this case. func t38(value: E38) { switch value { // $ access=value - case .a(let x), // $ access=x - .b(let x): // $ access=x - print(x) // $ access=x + case .a(let x), // $ access=x1 // name=x1 + .b(let x): // $ access=x1 + print(x) // $ access=x1 } } diff --git a/unified/ql/test/library-tests/variables/variables.ql b/unified/ql/test/library-tests/variables/variables.ql index 146da296ae74..f26c082a40c2 100644 --- a/unified/ql/test/library-tests/variables/variables.ql +++ b/unified/ql/test/library-tests/variables/variables.ql @@ -25,6 +25,7 @@ module VariableAccessTest implements TestSig { private predicate declAt(Variable v, string filepath, int line) { v.getLocation().hasLocationInfo(filepath, _, _, line, _) + v.getLocation().hasLocationInfo(filepath, line, _, _, _) } private predicate decl(Variable v, string alias) { From 99889b2e4d5dcc41490bd3a382cc3d015b971990 Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 30 Jul 2026 15:10:09 +0200 Subject: [PATCH 138/188] unified: Detect missing handling of ConditionalPattern ConditionalPattern was not added to getEnclosingOrPattern() Update the test to detect the bug --- unified/ql/test/library-tests/variables/test.swift | 4 ++++ .../test/library-tests/variables/variables.expected | 4 ++++ .../ql/test/library-tests/variables/variables.ql | 13 +++++++++++-- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/unified/ql/test/library-tests/variables/test.swift b/unified/ql/test/library-tests/variables/test.swift index 20ae492b78bd..e4280dc5b408 100644 --- a/unified/ql/test/library-tests/variables/test.swift +++ b/unified/ql/test/library-tests/variables/test.swift @@ -348,5 +348,9 @@ func t38(value: E38) { case .a(let x), // $ access=x1 // name=x1 .b(let x): // $ access=x1 print(x) // $ access=x1 + + case .a(let y) where y < 1, // $ access=y1 // name=y1 + .b(let y): // $ access=y1 + print(y) // $ access=y1 } } diff --git a/unified/ql/test/library-tests/variables/variables.expected b/unified/ql/test/library-tests/variables/variables.expected index e69de29bb2d1..a9c2d35f1237 100644 --- a/unified/ql/test/library-tests/variables/variables.expected +++ b/unified/ql/test/library-tests/variables/variables.expected @@ -0,0 +1,4 @@ +testFailures +ambiguousVariable +| test.swift:352:10:353:17 | y | y | test.swift | 352 | +| test.swift:352:17:352:17 | y | y | test.swift | 352 | diff --git a/unified/ql/test/library-tests/variables/variables.ql b/unified/ql/test/library-tests/variables/variables.ql index f26c082a40c2..cf653afebd9d 100644 --- a/unified/ql/test/library-tests/variables/variables.ql +++ b/unified/ql/test/library-tests/variables/variables.ql @@ -23,8 +23,7 @@ predicate keyValueCommentAt(string filepath, int line, string key, string value) module VariableAccessTest implements TestSig { string getARelevantTag() { result = "access" } - private predicate declAt(Variable v, string filepath, int line) { - v.getLocation().hasLocationInfo(filepath, _, _, line, _) + additional predicate declAt(Variable v, string filepath, int line) { v.getLocation().hasLocationInfo(filepath, line, _, _, _) } @@ -50,3 +49,13 @@ module VariableAccessTest implements TestSig { } import MakeTest + +private Variable getVariableAt(string name, string filepath, int line) { + VariableAccessTest::declAt(result, filepath, line) and + result.getName() = name +} + +query predicate ambiguousVariable(Variable v, string name, string filepath, int line) { + v = getVariableAt(name, filepath, line) and + strictcount(getVariableAt(name, filepath, line)) >= 2 +} From 90ca93cf90e83d2fe1e7e526ce5ad2135e28cfa3 Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 30 Jul 2026 15:14:05 +0200 Subject: [PATCH 139/188] unified: Add Pattern.getEnclosingPattern() --- .../lib/codeql/unified/internal/FacadeAst.qll | 9 +++++++ .../lib/codeql/unified/internal/Variables.qll | 27 +++---------------- .../variables/variables.expected | 2 -- 3 files changed, 12 insertions(+), 26 deletions(-) diff --git a/unified/ql/lib/codeql/unified/internal/FacadeAst.qll b/unified/ql/lib/codeql/unified/internal/FacadeAst.qll index 12cf0cea6420..d64bdeddc026 100644 --- a/unified/ql/lib/codeql/unified/internal/FacadeAst.qll +++ b/unified/ql/lib/codeql/unified/internal/FacadeAst.qll @@ -17,4 +17,13 @@ module Unified { ) } } + + class Pattern extends G::Pattern { + /** Gets the immediately-enclosing pattern in which this is a nested pattern. */ + Pattern getEnclosingPattern() { + result = this.getParent() + or + result = this.getParent().(PatternElement).getParent() + } + } } diff --git a/unified/ql/lib/codeql/unified/internal/Variables.qll b/unified/ql/lib/codeql/unified/internal/Variables.qll index 539f19930dc6..49cad56d05db 100644 --- a/unified/ql/lib/codeql/unified/internal/Variables.qll +++ b/unified/ql/lib/codeql/unified/internal/Variables.qll @@ -192,25 +192,7 @@ private module LocalNameBindingInput implements LocalNameBindingInputSig Date: Thu, 30 Jul 2026 15:24:26 +0200 Subject: [PATCH 140/188] shared: Fix clippy and rustfmt errors --- .../src/generator/ql_gen.rs | 15 +++++-------- shared/yeast-macros/src/parse.rs | 13 ++++++----- shared/yeast/src/dump.rs | 22 +++++++++---------- 3 files changed, 24 insertions(+), 26 deletions(-) diff --git a/shared/tree-sitter-extractor/src/generator/ql_gen.rs b/shared/tree-sitter-extractor/src/generator/ql_gen.rs index e08debb2b079..fff899317373 100644 --- a/shared/tree-sitter-extractor/src/generator/ql_gen.rs +++ b/shared/tree-sitter-extractor/src/generator/ql_gen.rs @@ -260,12 +260,9 @@ pub fn create_trivia_token_class<'a>( is_final: false, is_private: false, alias: None, - supertypes: vec![ - ql::Type::At(trivia_token_type), - ql::Type::Facade("AstNode"), - ] - .into_iter() - .collect(), + supertypes: vec![ql::Type::At(trivia_token_type), ql::Type::Facade("AstNode")] + .into_iter() + .collect(), characteristic_predicate: None, predicates: vec![ get_value, @@ -770,9 +767,9 @@ fn create_field_getters<'a>( ) } -fn compute_direct_supertypes<'a>( - nodes: &'a node_types::NodeTypeMap, -) -> std::collections::BTreeMap> { +fn compute_direct_supertypes( + nodes: &node_types::NodeTypeMap, +) -> std::collections::BTreeMap> { let mut supertypes = std::collections::BTreeMap::new(); for node in nodes.values() { if let node_types::EntryKind::Union { members } = &node.kind { diff --git a/shared/yeast-macros/src/parse.rs b/shared/yeast-macros/src/parse.rs index 40f9dbce61c8..34e859c912e9 100644 --- a/shared/yeast-macros/src/parse.rs +++ b/shared/yeast-macros/src/parse.rs @@ -157,11 +157,14 @@ fn parse_query_fields(tokens: &mut Tokens) -> Result> { map: &mut std::collections::HashMap>, name: String, elem: TokenStream| { - if !map.contains_key(&name) { - order.push(name.clone()); - map.insert(name, vec![elem]); - } else { - map.get_mut(&name).unwrap().push(elem); + match map.entry(name) { + std::collections::hash_map::Entry::Occupied(mut entry) => { + entry.get_mut().push(elem); + } + std::collections::hash_map::Entry::Vacant(entry) => { + order.push(entry.key().clone()); + entry.insert(vec![elem]); + } } }; while tokens.peek().is_some() { diff --git a/shared/yeast/src/dump.rs b/shared/yeast/src/dump.rs index dc348f8789b6..06ede1fa3438 100644 --- a/shared/yeast/src/dump.rs +++ b/shared/yeast/src/dump.rs @@ -2,6 +2,12 @@ use std::fmt::Write; use crate::{schema::Schema, Ast, Id, Node, NodeContent, CHILD_FIELD}; +type TypeCheckContext<'a> = ( + &'a Schema, + Option<&'a [crate::schema::NodeType]>, + Option<(&'a str, &'a str)>, +); + /// Options for controlling AST dump output. pub struct DumpOptions { /// Whether to include source locations in the output. @@ -179,11 +185,7 @@ fn dump_node( source: &str, options: &DumpOptions, indent: usize, - type_check: Option<( - &Schema, - Option<&[crate::schema::NodeType]>, - Option<(&str, &str)>, - )>, + type_check: Option>, out: &mut String, ) { let node = match ast.get_node(id) { @@ -268,8 +270,8 @@ fn dump_node( let children = &node.fields[&field_id]; let field_name = ast.field_name_for_id(field_id).unwrap_or("?"); let child_type_check = type_check.map(|(schema, _, _)| { - let expected = expected_for_field(schema, node.kind_name(), field_name) - .or(Some(EMPTY_NODE_TYPES)); + let expected = + expected_for_field(schema, node.kind_name(), field_name).or(Some(EMPTY_NODE_TYPES)); let parent_field = Some((node.kind_name(), field_name)); (schema, expected, parent_field) }); @@ -359,11 +361,7 @@ fn dump_node_inline( id: Id, source: &str, options: &DumpOptions, - type_check: Option<( - &Schema, - Option<&[crate::schema::NodeType]>, - Option<(&str, &str)>, - )>, + type_check: Option>, out: &mut String, ) { let node = match ast.get_node(id) { From 051b4bde6cb4947300d0438b803deb32543531ca Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 30 Jul 2026 15:29:13 +0200 Subject: [PATCH 141/188] tree-sitter-extractor: Use a module alias for 'F' when not using facades When not using a facade, the self-import could accidentally resolve to a file instead of the enclosing module. --- .../src/generator/mod.rs | 57 +++++++++++++------ .../tree-sitter-extractor/src/generator/ql.rs | 18 ++++++ 2 files changed, 58 insertions(+), 17 deletions(-) diff --git a/shared/tree-sitter-extractor/src/generator/mod.rs b/shared/tree-sitter-extractor/src/generator/mod.rs index 718c25cd2d84..cf445aaaac7f 100644 --- a/shared/tree-sitter-extractor/src/generator/mod.rs +++ b/shared/tree-sitter-extractor/src/generator/mod.rs @@ -129,11 +129,19 @@ pub fn generate( } else { language.name.clone() // If not using a facade AST, treat the module itself as the facade module. }; - body.push(ql::TopLevel::Import(ql::Import { - is_private: true, - module: &facade_import_name, - alias: Some("F"), - })); + if use_facade_ast { + body.push(ql::TopLevel::Import(ql::Import { + is_private: true, + module: &facade_import_name, + alias: Some("F"), + })); + } else { + body.push(ql::TopLevel::ModuleAlias(ql::ModuleAlias { + is_private: true, + name: "F", + target: &language.name, + })); + } body.push(ql::TopLevel::Class(ql_gen::create_ast_node_class( &ast_node_name, @@ -178,18 +186,33 @@ pub fn generate( body.append(&mut ql_gen::convert_nodes(&nodes)); body.push(ql_gen::create_print_ast_module(&nodes)); - let mut final_body = vec![ - ql::TopLevel::Import(ql::Import { - is_private: true, - module: &facade_import_name, - alias: Some("F"), - }), - ql::TopLevel::Import(ql::Import { - is_private: false, - module: "F", - alias: None, - }), - ]; + let mut final_body = if use_facade_ast { + vec![ + ql::TopLevel::Import(ql::Import { + is_private: true, + module: &facade_import_name, + alias: Some("F"), + }), + ql::TopLevel::Import(ql::Import { + is_private: false, + module: "F", + alias: None, + }), + ] + } else { + vec![ + ql::TopLevel::ModuleAlias(ql::ModuleAlias { + is_private: true, + name: "F", + target: &language.name, + }), + ql::TopLevel::Import(ql::Import { + is_private: false, + module: "F", + alias: None, + }), + ] + }; let final_aliases = body .iter() .filter_map(|decl| match decl { diff --git a/shared/tree-sitter-extractor/src/generator/ql.rs b/shared/tree-sitter-extractor/src/generator/ql.rs index 5991cab4a6c1..f114e251af21 100644 --- a/shared/tree-sitter-extractor/src/generator/ql.rs +++ b/shared/tree-sitter-extractor/src/generator/ql.rs @@ -5,6 +5,7 @@ use std::fmt; pub enum TopLevel<'a> { Class(Class<'a>), Import(Import<'a>), + ModuleAlias(ModuleAlias<'a>), Module(Module<'a>), Predicate(Predicate<'a>), } @@ -14,12 +15,29 @@ impl fmt::Display for TopLevel<'_> { match self { TopLevel::Import(imp) => write!(f, "{imp}"), TopLevel::Class(cls) => write!(f, "{cls}"), + TopLevel::ModuleAlias(alias) => write!(f, "{alias}"), TopLevel::Module(m) => write!(f, "{m}"), TopLevel::Predicate(pred) => write!(f, "{pred}"), } } } +#[derive(Clone, Eq, PartialEq, Hash)] +pub struct ModuleAlias<'a> { + pub is_private: bool, + pub name: &'a str, + pub target: &'a str, +} + +impl fmt::Display for ModuleAlias<'_> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.is_private { + write!(f, "private ")?; + } + write!(f, "module {} = {};", self.name, self.target) + } +} + #[derive(Clone, Eq, PartialEq, Hash)] pub struct Import<'a> { pub is_private: bool, From c1c41c80f3bebdcc6bc6ea4ba374f0e7bee2634c Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 30 Jul 2026 16:22:31 +0200 Subject: [PATCH 142/188] Regenerate QL again --- .../src/codeql_ql/ast/internal/TreeSitter.qll | 20 +++++++++++-------- .../codeql/ruby/ast/internal/TreeSitter.qll | 10 ++++++---- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll b/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll index fd1494d06b5c..d741bac2b221 100644 --- a/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll +++ b/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll @@ -25,7 +25,7 @@ private predicate discardLocation(@location_default loc) { overlay[local] module QL { - private import QL as F + private module F = QL; /** The base class for all AST nodes */ class AstNode extends @ql_ast_node { @@ -1557,7 +1557,8 @@ module QL { } module QLFinal { - private import QL as F + private module F = QL; + import F final class AstNode = F::AstNode; @@ -1763,7 +1764,7 @@ module QLFinal { overlay[local] module Dbscheme { - private import Dbscheme as F + private module F = Dbscheme; /** The base class for all AST nodes */ class AstNode extends @dbscheme_ast_node { @@ -2177,7 +2178,8 @@ module Dbscheme { } module DbschemeFinal { - private import Dbscheme as F + private module F = Dbscheme; + import F final class AstNode = F::AstNode; @@ -2243,7 +2245,7 @@ module DbschemeFinal { overlay[local] module Blame { - private import Blame as F + private module F = Blame; /** The base class for all AST nodes */ class AstNode extends @blame_ast_node { @@ -2396,7 +2398,8 @@ module Blame { } module BlameFinal { - private import Blame as F + private module F = Blame; + import F final class AstNode = F::AstNode; @@ -2420,7 +2423,7 @@ module BlameFinal { overlay[local] module JSON { - private import JSON as F + private module F = JSON; /** The base class for all AST nodes */ class AstNode extends @json_ast_node { @@ -2613,7 +2616,8 @@ module JSON { } module JSONFinal { - private import JSON as F + private module F = JSON; + import F final class AstNode = F::AstNode; diff --git a/ruby/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll b/ruby/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll index c4ca03fc96a1..d4b21080b245 100644 --- a/ruby/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll +++ b/ruby/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll @@ -25,7 +25,7 @@ private predicate discardLocation(@location_default loc) { overlay[local] module Ruby { - private import Ruby as F + private module F = Ruby; /** The base class for all AST nodes */ class AstNode extends @ruby_ast_node { @@ -2352,7 +2352,8 @@ module Ruby { } module RubyFinal { - private import Ruby as F + private module F = Ruby; + import F final class AstNode = F::AstNode; @@ -2662,7 +2663,7 @@ module RubyFinal { overlay[local] module Erb { - private import Erb as F + private module F = Erb; /** The base class for all AST nodes */ class AstNode extends @erb_ast_node { @@ -2822,7 +2823,8 @@ module Erb { } module ErbFinal { - private import Erb as F + private module F = Erb; + import F final class AstNode = F::AstNode; From cfff4dbcea5f4b31b94a391c9eebc90b322d5f4e Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 30 Jul 2026 16:33:37 +0200 Subject: [PATCH 143/188] tree-sitter-extractor: Generate plural getters --- .../src/generator/ql_gen.rs | 53 +++++++++++++------ .../tree-sitter-extractor/src/node_types.rs | 14 +++++ 2 files changed, 51 insertions(+), 16 deletions(-) diff --git a/shared/tree-sitter-extractor/src/generator/ql_gen.rs b/shared/tree-sitter-extractor/src/generator/ql_gen.rs index fff899317373..fe6f9a2a828b 100644 --- a/shared/tree-sitter-extractor/src/generator/ql_gen.rs +++ b/shared/tree-sitter-extractor/src/generator/ql_gen.rs @@ -606,10 +606,11 @@ fn create_get_field_expr_for_table_storage<'a>( ) } -/// Creates a pair consisting of a predicate to get the given field, and an -/// optional expression that will get the same field. When the field can occur -/// multiple times, the predicate will take an index argument, while the -/// expression will use the "don't care" expression to hold for all occurrences. +/// Creates a list of predicates to get the given field, and an optional +/// expression that will get the same field. When the field can occur multiple +/// times, this includes an indexed getter and a convenience getter that returns +/// any member; the expression uses the "don't care" expression to hold for all +/// occurrences. /// /// # Arguments /// @@ -627,7 +628,7 @@ fn create_field_getters<'a>( main_table_column_index: &mut usize, field: &'a node_types::Field, nodes: &'a node_types::NodeTypeMap, -) -> (ql::Predicate<'a>, Option>) { +) -> (Vec>, Option>) { let return_type = match &field.type_info { node_types::FieldTypeInfo::Single(t) => { Some(ql::Type::Facade(&nodes.get(t).unwrap().ql_class_name)) @@ -751,20 +752,40 @@ fn create_field_getters<'a>( } } }; - ( - ql::Predicate { - qldoc: Some(qldoc), - name: &field.getter_name, + let mut predicates = vec![ql::Predicate { + qldoc: Some(qldoc.clone()), + name: &field.getter_name, + overridden: false, + is_private: false, + is_final: true, + return_type: return_type.clone(), + formal_parameters, + body, + overlay: None, + }]; + + if let Some(any_getter_name) = &field.any_getter_name { + predicates.push(ql::Predicate { + qldoc: Some(qldoc.clone()), + name: any_getter_name, overridden: false, is_private: false, is_final: true, return_type, - formal_parameters, - body, + formal_parameters: vec![], + body: ql::Expression::Equals( + Box::new(ql::Expression::Var("result")), + Box::new(ql::Expression::Dot( + Box::new(ql::Expression::Var("this")), + &field.getter_name, + vec![ql::Expression::Var("_")], + )), + ), overlay: None, - }, - optional_expr, - ) + }); + } + + (predicates, optional_expr) } fn compute_direct_supertypes( @@ -902,14 +923,14 @@ pub fn convert_nodes(nodes: &node_types::NodeTypeMap) -> Vec> { // - predicates to access the fields, // - the QL expressions to access the fields that will be part of getAFieldOrChild. for field in fields { - let (get_pred, get_child_expr) = create_field_getters( + let (get_preds, get_child_expr) = create_field_getters( main_table_name, main_table_arity, &mut main_table_column_index, field, nodes, ); - main_class.predicates.push(get_pred); + main_class.predicates.extend(get_preds); if let Some(get_child_expr) = get_child_expr { get_child_exprs.push(get_child_expr) } diff --git a/shared/tree-sitter-extractor/src/node_types.rs b/shared/tree-sitter-extractor/src/node_types.rs index b56515b06456..4c67c2e4f20e 100644 --- a/shared/tree-sitter-extractor/src/node_types.rs +++ b/shared/tree-sitter-extractor/src/node_types.rs @@ -56,6 +56,9 @@ pub struct Field { pub name: Option, /// The name of the predicate to get this field. pub getter_name: String, + /// For plural fields, the name of a convenience getter that returns + /// any member (for example `getAnArgument` for `getArgument(i)`). + pub any_getter_name: Option, pub storage: Storage, } @@ -281,6 +284,16 @@ fn add_field( "get{}", dbscheme_name_to_class_name(&escape_name(&name_for_field_or_child(&field_name))) ); + let getter_suffix = getter_name.strip_prefix("get").unwrap_or(&getter_name); + let article = match getter_suffix.chars().next().map(|c| c.to_ascii_lowercase()) { + Some('a' | 'e' | 'i' | 'o' | 'u') => "An", + _ => "A", + }; + let any_getter_name = if field_info.multiple { + Some(format!("get{article}{getter_suffix}")) + } else { + None + }; fields.push(Field { parent: TypeName { kind: parent_type_name.kind.to_string(), @@ -289,6 +302,7 @@ fn add_field( type_info, name: field_name, getter_name, + any_getter_name, storage, }); } From b0055636dedef7cf23c5d12e5602f1879eae39ac Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 30 Jul 2026 16:33:46 +0200 Subject: [PATCH 144/188] Regenerate ASTs --- .../src/codeql_ql/ast/internal/TreeSitter.qll | 162 ++++++++++++++++ .../codeql/ruby/ast/internal/TreeSitter.qll | 132 +++++++++++++ .../ql/lib/codeql/unified/internal/Ast.qll | 174 ++++++++++++++++++ 3 files changed, 468 insertions(+) diff --git a/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll b/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll index d741bac2b221..51424106719d 100644 --- a/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll +++ b/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll @@ -131,6 +131,9 @@ module QL { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ql_aggregate_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ql_aggregate_child(this, _, result) } } @@ -161,6 +164,9 @@ module QL { /** Gets the node corresponding to the field `args`. */ final F::AstNode getArgs(int i) { ql_annotation_args(this, i, result) } + /** Gets the node corresponding to the field `args`. */ + final F::AstNode getAnArgs() { result = this.getArgs(_) } + /** Gets the node corresponding to the field `name`. */ final F::AnnotName getName() { ql_annotation_def(this, result) } @@ -196,6 +202,9 @@ module QL { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ql_as_expr_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ql_as_expr_child(this, _, result) } } @@ -208,6 +217,9 @@ module QL { /** Gets the `i`th child of this node. */ final F::AsExpr getChild(int i) { ql_as_exprs_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AsExpr getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ql_as_exprs_child(this, _, result) } } @@ -250,6 +262,9 @@ module QL { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ql_call_body_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ql_call_body_child(this, _, result) } } @@ -262,6 +277,9 @@ module QL { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ql_call_or_unqual_agg_expr_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ql_call_or_unqual_agg_expr_child(this, _, result) @@ -293,6 +311,9 @@ module QL { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ql_class_member_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ql_class_member_child(this, _, result) } } @@ -317,6 +338,9 @@ module QL { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ql_classless_predicate_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ql_classless_predicate_def(this, result, _) or @@ -384,15 +408,24 @@ module QL { /** Gets the node corresponding to the field `extends`. */ final F::AstNode getExtends(int i) { ql_dataclass_extends(this, i, result) } + /** Gets the node corresponding to the field `extends`. */ + final F::AstNode getAnExtends() { result = this.getExtends(_) } + /** Gets the node corresponding to the field `instanceof`. */ final F::AstNode getInstanceof(int i) { ql_dataclass_instanceof(this, i, result) } + /** Gets the node corresponding to the field `instanceof`. */ + final F::AstNode getAnInstanceof() { result = this.getInstanceof(_) } + /** Gets the node corresponding to the field `name`. */ final F::ClassName getName() { ql_dataclass_def(this, result) } /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ql_dataclass_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ql_dataclass_extends(this, _, result) or @@ -430,6 +463,9 @@ module QL { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ql_datatype_branch_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ql_datatype_branch_def(this, result) or ql_datatype_branch_child(this, _, result) @@ -444,6 +480,9 @@ module QL { /** Gets the `i`th child of this node. */ final F::DatatypeBranch getChild(int i) { ql_datatype_branches_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::DatatypeBranch getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ql_datatype_branches_child(this, _, result) } } @@ -563,6 +602,9 @@ module QL { /** Gets the `i`th child of this node. */ final F::VarDecl getChild(int i) { ql_full_aggregate_body_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::VarDecl getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ql_full_aggregate_body_as_exprs(this, result) or @@ -583,6 +625,9 @@ module QL { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ql_higher_order_term_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ql_higher_order_term_def(this, result) or ql_higher_order_term_child(this, _, result) @@ -636,6 +681,9 @@ module QL { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ql_import_directive_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ql_import_directive_child(this, _, result) } } @@ -648,6 +696,9 @@ module QL { /** Gets the node corresponding to the field `qualName`. */ final F::SimpleId getQualName(int i) { ql_import_module_expr_qual_name(this, i, result) } + /** Gets the node corresponding to the field `qualName`. */ + final F::SimpleId getAQualName() { result = this.getQualName(_) } + /** Gets the child of this node. */ final F::ModuleExpr getChild() { ql_import_module_expr_def(this, result) } @@ -682,6 +733,9 @@ module QL { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ql_instance_of_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ql_instance_of_child(this, _, result) } } @@ -730,6 +784,9 @@ module QL { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ql_member_predicate_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ql_member_predicate_def(this, result, _) or @@ -746,15 +803,24 @@ module QL { /** Gets the node corresponding to the field `implements`. */ final F::SignatureExpr getImplements(int i) { ql_module_implements(this, i, result) } + /** Gets the node corresponding to the field `implements`. */ + final F::SignatureExpr getAnImplements() { result = this.getImplements(_) } + /** Gets the node corresponding to the field `name`. */ final F::ModuleName getName() { ql_module_def(this, result) } /** Gets the node corresponding to the field `parameter`. */ final F::ModuleParam getParameter(int i) { ql_module_parameter(this, i, result) } + /** Gets the node corresponding to the field `parameter`. */ + final F::ModuleParam getAParameter() { result = this.getParameter(_) } + /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ql_module_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ql_module_implements(this, _, result) or @@ -804,6 +870,9 @@ module QL { /** Gets the `i`th child of this node. */ final F::SignatureExpr getChild(int i) { ql_module_instantiation_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::SignatureExpr getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ql_module_instantiation_def(this, result) or ql_module_instantiation_child(this, _, result) @@ -818,6 +887,9 @@ module QL { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ql_module_member_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ql_module_member_child(this, _, result) } } @@ -899,6 +971,9 @@ module QL { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ql_order_by_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ql_order_by_child(this, _, result) } } @@ -911,6 +986,9 @@ module QL { /** Gets the `i`th child of this node. */ final F::OrderBy getChild(int i) { ql_order_bys_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::OrderBy getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ql_order_bys_child(this, _, result) } } @@ -953,6 +1031,9 @@ module QL { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ql_predicate_expr_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ql_predicate_expr_child(this, _, result) } } @@ -971,6 +1052,9 @@ module QL { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ql_prefix_cast_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ql_prefix_cast_child(this, _, result) } } @@ -989,6 +1073,9 @@ module QL { /** Gets the `i`th child of this node. */ final F::ModuleMember getChild(int i) { ql_ql_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::ModuleMember getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ql_ql_child(this, _, result) } } @@ -1010,6 +1097,9 @@ module QL { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ql_qualified_rhs_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ql_qualified_rhs_name(this, result) or ql_qualified_rhs_child(this, _, result) @@ -1024,6 +1114,9 @@ module QL { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ql_qualified_expr_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ql_qualified_expr_child(this, _, result) } } @@ -1045,6 +1138,9 @@ module QL { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ql_quantified_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ql_quantified_expr(this, result) or @@ -1091,6 +1187,9 @@ module QL { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ql_select_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ql_select_child(this, _, result) } } @@ -1103,6 +1202,9 @@ module QL { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ql_set_literal_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ql_set_literal_child(this, _, result) } } @@ -1173,6 +1275,9 @@ module QL { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ql_super_ref_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ql_super_ref_child(this, _, result) } } @@ -1231,6 +1336,9 @@ module QL { /** Gets the `i`th child of this node. */ final F::TypeExpr getChild(int i) { ql_type_union_body_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::TypeExpr getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ql_type_union_body_child(this, _, result) } } @@ -1243,6 +1351,9 @@ module QL { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ql_unary_expr_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ql_unary_expr_child(this, _, result) } } @@ -1267,12 +1378,18 @@ module QL { /** Gets the node corresponding to the field `asExprs`. */ final F::AstNode getAsExprs(int i) { ql_unqual_agg_body_as_exprs(this, i, result) } + /** Gets the node corresponding to the field `asExprs`. */ + final F::AstNode getAnAsExprs() { result = this.getAsExprs(_) } + /** Gets the node corresponding to the field `guard`. */ final F::AstNode getGuard() { ql_unqual_agg_body_guard(this, result) } /** Gets the `i`th child of this node. */ final F::VarDecl getChild(int i) { ql_unqual_agg_body_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::VarDecl getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ql_unqual_agg_body_as_exprs(this, _, result) or @@ -1289,6 +1406,9 @@ module QL { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ql_var_decl_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ql_var_decl_child(this, _, result) } } @@ -1865,6 +1985,9 @@ module Dbscheme { /** Gets the `i`th child of this node. */ final F::SimpleId getChild(int i) { dbscheme_args_annotation_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::SimpleId getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { dbscheme_args_annotation_def(this, result) or dbscheme_args_annotation_child(this, _, result) @@ -1894,6 +2017,9 @@ module Dbscheme { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { dbscheme_branch_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { dbscheme_branch_qldoc(this, result) or dbscheme_branch_child(this, _, result) @@ -1914,6 +2040,9 @@ module Dbscheme { /** Gets the `i`th child of this node. */ final F::Branch getChild(int i) { dbscheme_case_decl_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::Branch getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { dbscheme_case_decl_def(this, result, _) or @@ -1982,6 +2111,9 @@ module Dbscheme { /** Gets the `i`th child of this node. */ final F::Entry getChild(int i) { dbscheme_dbscheme_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::Entry getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { dbscheme_dbscheme_child(this, _, result) } } @@ -2048,6 +2180,9 @@ module Dbscheme { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { dbscheme_repr_type_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { dbscheme_repr_type_child(this, _, result) } } @@ -2075,6 +2210,9 @@ module Dbscheme { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { dbscheme_table_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { dbscheme_table_def(this, result) or dbscheme_table_child(this, _, result) @@ -2104,6 +2242,9 @@ module Dbscheme { /** Gets the `i`th child of this node. */ final F::Dbtype getChild(int i) { dbscheme_union_decl_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::Dbtype getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { dbscheme_union_decl_def(this, result) or dbscheme_union_decl_child(this, _, result) @@ -2320,6 +2461,9 @@ module Blame { /** Gets the node corresponding to the field `line`. */ final F::Number getLine(int i) { blame_blame_entry_line(this, i, result) } + /** Gets the node corresponding to the field `line`. */ + final F::Number getALine() { result = this.getLine(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { blame_blame_entry_def(this, result) or blame_blame_entry_line(this, _, result) @@ -2334,6 +2478,9 @@ module Blame { /** Gets the node corresponding to the field `file_entry`. */ final F::FileEntry getFileEntry(int i) { blame_blame_info_file_entry(this, i, result) } + /** Gets the node corresponding to the field `file_entry`. */ + final F::FileEntry getAFileEntry() { result = this.getFileEntry(_) } + /** Gets the node corresponding to the field `today`. */ final F::Date getToday() { blame_blame_info_def(this, result) } @@ -2357,6 +2504,9 @@ module Blame { /** Gets the node corresponding to the field `blame_entry`. */ final F::BlameEntry getBlameEntry(int i) { blame_file_entry_blame_entry(this, i, result) } + /** Gets the node corresponding to the field `blame_entry`. */ + final F::BlameEntry getABlameEntry() { result = this.getBlameEntry(_) } + /** Gets the node corresponding to the field `file_name`. */ final F::Filename getFileName() { blame_file_entry_def(this, result) } @@ -2497,6 +2647,9 @@ module JSON { /** Gets the `i`th child of this node. */ final F::UnderscoreValue getChild(int i) { json_array_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::UnderscoreValue getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { json_array_child(this, _, result) } } @@ -2515,6 +2668,9 @@ module JSON { /** Gets the `i`th child of this node. */ final F::UnderscoreValue getChild(int i) { json_document_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::UnderscoreValue getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { json_document_child(this, _, result) } } @@ -2551,6 +2707,9 @@ module JSON { /** Gets the `i`th child of this node. */ final F::Pair getChild(int i) { json_object_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::Pair getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { json_object_child(this, _, result) } } @@ -2580,6 +2739,9 @@ module JSON { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { json_string_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { json_string_child(this, _, result) } } diff --git a/ruby/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll b/ruby/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll index d4b21080b245..0d442a5dda88 100644 --- a/ruby/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll +++ b/ruby/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll @@ -157,6 +157,9 @@ module Ruby { ruby_alternative_pattern_alternatives(this, i, result) } + /** Gets the node corresponding to the field `alternatives`. */ + final F::UnderscorePatternExprBasic getAnAlternatives() { result = this.getAlternatives(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ruby_alternative_pattern_alternatives(this, _, result) @@ -171,6 +174,9 @@ module Ruby { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ruby_argument_list_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ruby_argument_list_child(this, _, result) } } @@ -183,6 +189,9 @@ module Ruby { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ruby_array_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ruby_array_child(this, _, result) } } @@ -200,6 +209,9 @@ module Ruby { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ruby_array_pattern_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ruby_array_pattern_class(this, result) or ruby_array_pattern_child(this, _, result) @@ -248,6 +260,9 @@ module Ruby { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ruby_bare_string_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ruby_bare_string_child(this, _, result) } } @@ -260,6 +275,9 @@ module Ruby { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ruby_bare_symbol_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ruby_bare_symbol_child(this, _, result) } } @@ -272,6 +290,9 @@ module Ruby { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ruby_begin_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ruby_begin_child(this, _, result) } } @@ -284,6 +305,9 @@ module Ruby { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ruby_begin_block_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ruby_begin_block_child(this, _, result) } } @@ -397,6 +421,9 @@ module Ruby { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ruby_block_body_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ruby_block_body_child(this, _, result) } } @@ -421,9 +448,15 @@ module Ruby { /** Gets the node corresponding to the field `locals`. */ final F::Identifier getLocals(int i) { ruby_block_parameters_locals(this, i, result) } + /** Gets the node corresponding to the field `locals`. */ + final F::Identifier getALocals() { result = this.getLocals(_) } + /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ruby_block_parameters_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ruby_block_parameters_locals(this, _, result) or ruby_block_parameters_child(this, _, result) @@ -438,6 +471,9 @@ module Ruby { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ruby_body_statement_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ruby_body_statement_child(this, _, result) } } @@ -495,6 +531,9 @@ module Ruby { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ruby_case_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ruby_case_value(this, result) or ruby_case_child(this, _, result) @@ -509,6 +548,9 @@ module Ruby { /** Gets the node corresponding to the field `clauses`. */ final F::InClause getClauses(int i) { ruby_case_match_clauses(this, i, result) } + /** Gets the node corresponding to the field `clauses`. */ + final F::InClause getAClauses() { result = this.getClauses(_) } + /** Gets the node corresponding to the field `else`. */ final F::Else getElse() { ruby_case_match_else(this, result) } @@ -531,6 +573,9 @@ module Ruby { /** Gets the `i`th child of this node. */ final F::String getChild(int i) { ruby_chained_string_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::String getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ruby_chained_string_child(this, _, result) } } @@ -627,6 +672,9 @@ module Ruby { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ruby_delimited_symbol_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ruby_delimited_symbol_child(this, _, result) } } @@ -639,6 +687,9 @@ module Ruby { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ruby_destructured_left_assignment_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ruby_destructured_left_assignment_child(this, _, result) @@ -653,6 +704,9 @@ module Ruby { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ruby_destructured_parameter_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ruby_destructured_parameter_child(this, _, result) @@ -667,6 +721,9 @@ module Ruby { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ruby_do_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ruby_do_child(this, _, result) } } @@ -702,6 +759,9 @@ module Ruby { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ruby_element_reference_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ruby_element_reference_block(this, result) or @@ -718,6 +778,9 @@ module Ruby { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ruby_else_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ruby_else_child(this, _, result) } } @@ -764,6 +827,9 @@ module Ruby { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ruby_end_block_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ruby_end_block_child(this, _, result) } } @@ -776,6 +842,9 @@ module Ruby { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ruby_ensure_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ruby_ensure_child(this, _, result) } } @@ -806,6 +875,9 @@ module Ruby { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ruby_exceptions_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ruby_exceptions_child(this, _, result) } } @@ -851,6 +923,9 @@ module Ruby { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ruby_find_pattern_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ruby_find_pattern_class(this, result) or ruby_find_pattern_child(this, _, result) @@ -911,6 +986,9 @@ module Ruby { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ruby_hash_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ruby_hash_child(this, _, result) } } @@ -934,6 +1012,9 @@ module Ruby { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ruby_hash_pattern_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ruby_hash_pattern_class(this, result) or ruby_hash_pattern_child(this, _, result) @@ -986,6 +1067,9 @@ module Ruby { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ruby_heredoc_body_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ruby_heredoc_body_child(this, _, result) } } @@ -1117,6 +1201,9 @@ module Ruby { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ruby_interpolation_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ruby_interpolation_child(this, _, result) } } @@ -1180,6 +1267,9 @@ module Ruby { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ruby_lambda_parameters_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ruby_lambda_parameters_child(this, _, result) } } @@ -1192,6 +1282,9 @@ module Ruby { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ruby_left_assignment_list_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ruby_left_assignment_list_child(this, _, result) @@ -1251,6 +1344,9 @@ module Ruby { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ruby_method_parameters_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ruby_method_parameters_child(this, _, result) } } @@ -1401,6 +1497,9 @@ module Ruby { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ruby_parenthesized_statements_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ruby_parenthesized_statements_child(this, _, result) @@ -1427,6 +1526,9 @@ module Ruby { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ruby_program_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ruby_program_child(this, _, result) } } @@ -1489,6 +1591,9 @@ module Ruby { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ruby_regex_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ruby_regex_child(this, _, result) } } @@ -1576,6 +1681,9 @@ module Ruby { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ruby_right_assignment_list_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ruby_right_assignment_list_child(this, _, result) @@ -1704,6 +1812,9 @@ module Ruby { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ruby_string_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ruby_string_child(this, _, result) } } @@ -1716,6 +1827,9 @@ module Ruby { /** Gets the `i`th child of this node. */ final F::BareString getChild(int i) { ruby_string_array_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::BareString getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ruby_string_array_child(this, _, result) } } @@ -1734,6 +1848,9 @@ module Ruby { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ruby_subshell_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ruby_subshell_child(this, _, result) } } @@ -1764,6 +1881,9 @@ module Ruby { /** Gets the `i`th child of this node. */ final F::BareSymbol getChild(int i) { ruby_symbol_array_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::BareSymbol getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ruby_symbol_array_child(this, _, result) } } @@ -1793,6 +1913,9 @@ module Ruby { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { ruby_then_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ruby_then_child(this, _, result) } } @@ -1842,6 +1965,9 @@ module Ruby { /** Gets the `i`th child of this node. */ final F::UnderscoreMethodName getChild(int i) { ruby_undef_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::UnderscoreMethodName getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ruby_undef_child(this, _, result) } } @@ -1964,6 +2090,9 @@ module Ruby { /** Gets the node corresponding to the field `pattern`. */ final F::Pattern getPattern(int i) { ruby_when_pattern(this, i, result) } + /** Gets the node corresponding to the field `pattern`. */ + final F::Pattern getAPattern() { result = this.getPattern(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { ruby_when_body(this, result) or ruby_when_pattern(this, _, result) @@ -2801,6 +2930,9 @@ module Erb { /** Gets the `i`th child of this node. */ final F::AstNode getChild(int i) { erb_template_child(this, i, result) } + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { erb_template_child(this, _, result) } } diff --git a/unified/ql/lib/codeql/unified/internal/Ast.qll b/unified/ql/lib/codeql/unified/internal/Ast.qll index 532b5d3cf716..20ff74e6eaf7 100644 --- a/unified/ql/lib/codeql/unified/internal/Ast.qll +++ b/unified/ql/lib/codeql/unified/internal/Ast.qll @@ -109,6 +109,9 @@ module Unified { /** Gets the node corresponding to the field `modifier`. */ final F::Modifier getModifier(int i) { unified_accessor_declaration_modifier(this, i, result) } + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } + /** Gets the node corresponding to the field `name`. */ final F::Identifier getName() { unified_accessor_declaration_def(this, _, result) } @@ -117,6 +120,9 @@ module Unified { unified_accessor_declaration_parameter(this, i, result) } + /** Gets the node corresponding to the field `parameter`. */ + final F::Parameter getAParameter() { result = this.getParameter(_) } + /** Gets the node corresponding to the field `type`. */ final F::TypeExpr getType() { unified_accessor_declaration_type(this, result) } @@ -145,6 +151,9 @@ module Unified { /** Gets the node corresponding to the field `modifier`. */ final F::Modifier getModifier(int i) { unified_argument_modifier(this, i, result) } + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } + /** Gets the node corresponding to the field `name`. */ final F::Identifier getName() { unified_argument_name(this, result) } @@ -167,6 +176,9 @@ module Unified { /** Gets the node corresponding to the field `element`. */ final F::Expr getElement(int i) { unified_array_literal_element(this, i, result) } + /** Gets the node corresponding to the field `element`. */ + final F::Expr getAnElement() { result = this.getElement(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { unified_array_literal_element(this, _, result) } } @@ -201,6 +213,9 @@ module Unified { unified_associated_type_declaration_modifier(this, i, result) } + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } + /** Gets the node corresponding to the field `name`. */ final F::Identifier getName() { unified_associated_type_declaration_def(this, result) } @@ -220,6 +235,9 @@ module Unified { /** Gets the node corresponding to the field `modifier`. */ final F::Modifier getModifier(int i) { unified_base_type_modifier(this, i, result) } + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } + /** Gets the node corresponding to the field `type`. */ final F::TypeExpr getType() { unified_base_type_def(this, result) } @@ -259,6 +277,9 @@ module Unified { /** Gets the node corresponding to the field `stmt`. */ final F::Stmt getStmt(int i) { unified_block_stmt(this, i, result) } + /** Gets the node corresponding to the field `stmt`. */ + final F::Stmt getAStmt() { result = this.getStmt(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { unified_block_stmt(this, _, result) } } @@ -315,6 +336,9 @@ module Unified { unified_bulk_importing_pattern_modifier(this, i, result) } + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { unified_bulk_importing_pattern_modifier(this, _, result) @@ -329,12 +353,18 @@ module Unified { /** Gets the node corresponding to the field `argument`. */ final F::Argument getArgument(int i) { unified_call_expr_argument(this, i, result) } + /** Gets the node corresponding to the field `argument`. */ + final F::Argument getAnArgument() { result = this.getArgument(_) } + /** Gets the node corresponding to the field `callee`. */ final F::ExprOrType getCallee() { unified_call_expr_def(this, result) } /** Gets the node corresponding to the field `modifier`. */ final F::Modifier getModifier(int i) { unified_call_expr_modifier(this, i, result) } + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { unified_call_expr_argument(this, _, result) or @@ -354,6 +384,9 @@ module Unified { /** Gets the node corresponding to the field `modifier`. */ final F::Modifier getModifier(int i) { unified_catch_clause_modifier(this, i, result) } + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } + /** Gets the node corresponding to the field `pattern`. */ final F::Pattern getPattern() { unified_catch_clause_pattern(this, result) } @@ -375,14 +408,23 @@ module Unified { unified_class_like_declaration_base_type(this, i, result) } + /** Gets the node corresponding to the field `base_type`. */ + final F::BaseType getABaseType() { result = this.getBaseType(_) } + /** Gets the node corresponding to the field `member`. */ final F::Member getMember(int i) { unified_class_like_declaration_member(this, i, result) } + /** Gets the node corresponding to the field `member`. */ + final F::Member getAMember() { result = this.getMember(_) } + /** Gets the node corresponding to the field `modifier`. */ final F::Modifier getModifier(int i) { unified_class_like_declaration_modifier(this, i, result) } + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } + /** Gets the node corresponding to the field `name`. */ final F::Identifier getName() { unified_class_like_declaration_name(this, result) } @@ -391,11 +433,17 @@ module Unified { unified_class_like_declaration_type_constraint(this, i, result) } + /** Gets the node corresponding to the field `type_constraint`. */ + final F::TypeConstraint getATypeConstraint() { result = this.getTypeConstraint(_) } + /** Gets the node corresponding to the field `type_parameter`. */ final F::TypeParameter getTypeParameter(int i) { unified_class_like_declaration_type_parameter(this, i, result) } + /** Gets the node corresponding to the field `type_parameter`. */ + final F::TypeParameter getATypeParameter() { result = this.getTypeParameter(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { unified_class_like_declaration_base_type(this, _, result) or @@ -440,6 +488,9 @@ module Unified { /** Gets the node corresponding to the field `modifier`. */ final F::Modifier getModifier(int i) { unified_conditional_pattern_modifier(this, i, result) } + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } + /** Gets the node corresponding to the field `pattern`. */ final F::Pattern getPattern() { unified_conditional_pattern_def(this, _, result) } @@ -464,6 +515,9 @@ module Unified { unified_constructor_declaration_modifier(this, i, result) } + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } + /** Gets the node corresponding to the field `name`. */ final F::Identifier getName() { unified_constructor_declaration_name(this, result) } @@ -472,6 +526,9 @@ module Unified { unified_constructor_declaration_parameter(this, i, result) } + /** Gets the node corresponding to the field `parameter`. */ + final F::Parameter getAParameter() { result = this.getParameter(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { unified_constructor_declaration_def(this, result) or @@ -494,9 +551,15 @@ module Unified { unified_constructor_pattern_element(this, i, result) } + /** Gets the node corresponding to the field `element`. */ + final F::PatternElement getAnElement() { result = this.getElement(_) } + /** Gets the node corresponding to the field `modifier`. */ final F::Modifier getModifier(int i) { unified_constructor_pattern_modifier(this, i, result) } + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { unified_constructor_pattern_def(this, result) or @@ -530,6 +593,9 @@ module Unified { unified_destructor_declaration_modifier(this, i, result) } + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { unified_destructor_declaration_def(this, result) or @@ -551,6 +617,9 @@ module Unified { /** Gets the node corresponding to the field `modifier`. */ final F::Modifier getModifier(int i) { unified_do_while_stmt_modifier(this, i, result) } + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { unified_do_while_stmt_body(this, result) or @@ -632,6 +701,9 @@ module Unified { /** Gets the node corresponding to the field `modifier`. */ final F::Modifier getModifier(int i) { unified_for_each_stmt_modifier(this, i, result) } + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } + /** Gets the node corresponding to the field `pattern`. */ final F::Pattern getPattern() { unified_for_each_stmt_def(this, _, result) } @@ -656,6 +728,9 @@ module Unified { /** Gets the node corresponding to the field `modifier`. */ final F::Modifier getModifier(int i) { unified_function_declaration_modifier(this, i, result) } + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } + /** Gets the node corresponding to the field `name`. */ final F::Identifier getName() { unified_function_declaration_def(this, result) } @@ -664,6 +739,9 @@ module Unified { unified_function_declaration_parameter(this, i, result) } + /** Gets the node corresponding to the field `parameter`. */ + final F::Parameter getAParameter() { result = this.getParameter(_) } + /** Gets the node corresponding to the field `return_type`. */ final F::TypeExpr getReturnType() { unified_function_declaration_return_type(this, result) } @@ -672,11 +750,17 @@ module Unified { unified_function_declaration_type_constraint(this, i, result) } + /** Gets the node corresponding to the field `type_constraint`. */ + final F::TypeConstraint getATypeConstraint() { result = this.getTypeConstraint(_) } + /** Gets the node corresponding to the field `type_parameter`. */ final F::TypeParameter getTypeParameter(int i) { unified_function_declaration_type_parameter(this, i, result) } + /** Gets the node corresponding to the field `type_parameter`. */ + final F::TypeParameter getATypeParameter() { result = this.getTypeParameter(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { unified_function_declaration_body(this, result) or @@ -702,12 +786,21 @@ module Unified { unified_function_expr_capture_declaration(this, i, result) } + /** Gets the node corresponding to the field `capture_declaration`. */ + final F::VariableDeclaration getACaptureDeclaration() { result = this.getCaptureDeclaration(_) } + /** Gets the node corresponding to the field `modifier`. */ final F::Modifier getModifier(int i) { unified_function_expr_modifier(this, i, result) } + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } + /** Gets the node corresponding to the field `parameter`. */ final F::Parameter getParameter(int i) { unified_function_expr_parameter(this, i, result) } + /** Gets the node corresponding to the field `parameter`. */ + final F::Parameter getAParameter() { result = this.getParameter(_) } + /** Gets the node corresponding to the field `return_type`. */ final F::TypeExpr getReturnType() { unified_function_expr_return_type(this, result) } @@ -729,6 +822,9 @@ module Unified { /** Gets the node corresponding to the field `parameter`. */ final F::Parameter getParameter(int i) { unified_function_type_expr_parameter(this, i, result) } + /** Gets the node corresponding to the field `parameter`. */ + final F::Parameter getAParameter() { result = this.getParameter(_) } + /** Gets the node corresponding to the field `return_type`. */ final F::TypeExpr getReturnType() { unified_function_type_expr_def(this, result) } @@ -752,6 +848,9 @@ module Unified { unified_generic_type_expr_type_argument(this, i, result) } + /** Gets the node corresponding to the field `type_argument`. */ + final F::TypeExpr getATypeArgument() { result = this.getTypeArgument(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { unified_generic_type_expr_def(this, result) or @@ -821,6 +920,9 @@ module Unified { /** Gets the node corresponding to the field `modifier`. */ final F::Modifier getModifier(int i) { unified_import_declaration_modifier(this, i, result) } + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } + /** Gets the node corresponding to the field `pattern`. */ final F::Pattern getPattern() { unified_import_declaration_pattern(this, result) } @@ -859,6 +961,9 @@ module Unified { unified_initializer_declaration_modifier(this, i, result) } + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { unified_initializer_declaration_def(this, result) or @@ -914,6 +1019,9 @@ module Unified { /** Gets the node corresponding to the field `element`. */ final F::Expr getElement(int i) { unified_map_literal_element(this, i, result) } + /** Gets the node corresponding to the field `element`. */ + final F::Expr getAnElement() { result = this.getElement(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { unified_map_literal_element(this, _, result) } } @@ -967,6 +1075,9 @@ module Unified { /** Gets the node corresponding to the field `modifier`. */ final F::Modifier getModifier(int i) { unified_name_pattern_modifier(this, i, result) } + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { unified_name_pattern_def(this, result) or unified_name_pattern_modifier(this, _, result) @@ -1005,6 +1116,9 @@ module Unified { unified_operator_syntax_declaration_modifier(this, i, result) } + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } + /** Gets the node corresponding to the field `name`. */ final F::Identifier getName() { unified_operator_syntax_declaration_def(this, result) } @@ -1028,9 +1142,15 @@ module Unified { /** Gets the node corresponding to the field `modifier`. */ final F::Modifier getModifier(int i) { unified_or_pattern_modifier(this, i, result) } + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } + /** Gets the node corresponding to the field `pattern`. */ final F::Pattern getPattern(int i) { unified_or_pattern_pattern(this, i, result) } + /** Gets the node corresponding to the field `pattern`. */ + final F::Pattern getAPattern() { result = this.getPattern(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { unified_or_pattern_modifier(this, _, result) or unified_or_pattern_pattern(this, _, result) @@ -1051,6 +1171,9 @@ module Unified { /** Gets the node corresponding to the field `modifier`. */ final F::Modifier getModifier(int i) { unified_parameter_modifier(this, i, result) } + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } + /** Gets the node corresponding to the field `pattern`. */ final F::Pattern getPattern() { unified_parameter_pattern(this, result) } @@ -1080,6 +1203,9 @@ module Unified { /** Gets the node corresponding to the field `modifier`. */ final F::Modifier getModifier(int i) { unified_pattern_element_modifier(this, i, result) } + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } + /** Gets the node corresponding to the field `pattern`. */ final F::Pattern getPattern() { unified_pattern_element_def(this, result) } @@ -1164,6 +1290,9 @@ module Unified { /** Gets the node corresponding to the field `modifier`. */ final F::Modifier getModifier(int i) { unified_switch_case_modifier(this, i, result) } + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } + /** Gets the node corresponding to the field `pattern`. */ final F::Pattern getPattern() { unified_switch_case_pattern(this, result) } @@ -1183,9 +1312,15 @@ module Unified { /** Gets the node corresponding to the field `case`. */ final F::SwitchCase getCase(int i) { unified_switch_expr_case(this, i, result) } + /** Gets the node corresponding to the field `case`. */ + final F::SwitchCase getACase() { result = this.getCase(_) } + /** Gets the node corresponding to the field `modifier`. */ final F::Modifier getModifier(int i) { unified_switch_expr_modifier(this, i, result) } + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } + /** Gets the node corresponding to the field `value`. */ final F::Expr getValue() { unified_switch_expr_def(this, result) } @@ -1232,9 +1367,15 @@ module Unified { /** Gets the node corresponding to the field `catch_clause`. */ final F::CatchClause getCatchClause(int i) { unified_try_expr_catch_clause(this, i, result) } + /** Gets the node corresponding to the field `catch_clause`. */ + final F::CatchClause getACatchClause() { result = this.getCatchClause(_) } + /** Gets the node corresponding to the field `modifier`. */ final F::Modifier getModifier(int i) { unified_try_expr_modifier(this, i, result) } + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { unified_try_expr_def(this, result) or @@ -1251,6 +1392,9 @@ module Unified { /** Gets the node corresponding to the field `element`. */ final F::Expr getElement(int i) { unified_tuple_expr_element(this, i, result) } + /** Gets the node corresponding to the field `element`. */ + final F::Expr getAnElement() { result = this.getElement(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { unified_tuple_expr_element(this, _, result) } } @@ -1263,9 +1407,15 @@ module Unified { /** Gets the node corresponding to the field `element`. */ final F::PatternElement getElement(int i) { unified_tuple_pattern_element(this, i, result) } + /** Gets the node corresponding to the field `element`. */ + final F::PatternElement getAnElement() { result = this.getElement(_) } + /** Gets the node corresponding to the field `modifier`. */ final F::Modifier getModifier(int i) { unified_tuple_pattern_modifier(this, i, result) } + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { unified_tuple_pattern_element(this, _, result) or @@ -1298,6 +1448,9 @@ module Unified { /** Gets the node corresponding to the field `element`. */ final F::TupleTypeElement getElement(int i) { unified_tuple_type_expr_element(this, i, result) } + /** Gets the node corresponding to the field `element`. */ + final F::TupleTypeElement getAnElement() { result = this.getElement(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { unified_tuple_type_expr_element(this, _, result) @@ -1314,6 +1467,9 @@ module Unified { unified_type_alias_declaration_modifier(this, i, result) } + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } + /** Gets the node corresponding to the field `name`. */ final F::Identifier getName() { unified_type_alias_declaration_def(this, result, _) } @@ -1325,11 +1481,17 @@ module Unified { unified_type_alias_declaration_type_constraint(this, i, result) } + /** Gets the node corresponding to the field `type_constraint`. */ + final F::TypeConstraint getATypeConstraint() { result = this.getTypeConstraint(_) } + /** Gets the node corresponding to the field `type_parameter`. */ final F::TypeParameter getTypeParameter(int i) { unified_type_alias_declaration_type_parameter(this, i, result) } + /** Gets the node corresponding to the field `type_parameter`. */ + final F::TypeParameter getATypeParameter() { result = this.getTypeParameter(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { unified_type_alias_declaration_modifier(this, _, result) or @@ -1377,6 +1539,9 @@ module Unified { /** Gets the node corresponding to the field `modifier`. */ final F::Modifier getModifier(int i) { unified_type_parameter_modifier(this, i, result) } + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } + /** Gets the node corresponding to the field `name`. */ final F::Identifier getName() { unified_type_parameter_def(this, result) } @@ -1455,6 +1620,9 @@ module Unified { unified_unresolved_operator_sequence_element(this, i, result) } + /** Gets the node corresponding to the field `element`. */ + final F::ExprOrOperator getAnElement() { result = this.getElement(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { unified_unresolved_operator_sequence_element(this, _, result) @@ -1477,6 +1645,9 @@ module Unified { /** Gets the node corresponding to the field `modifier`. */ final F::Modifier getModifier(int i) { unified_variable_declaration_modifier(this, i, result) } + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } + /** Gets the node corresponding to the field `pattern`. */ final F::Pattern getPattern() { unified_variable_declaration_def(this, result) } @@ -1509,6 +1680,9 @@ module Unified { /** Gets the node corresponding to the field `modifier`. */ final F::Modifier getModifier(int i) { unified_while_stmt_modifier(this, i, result) } + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } + /** Gets a field or child node of this node. */ final override F::AstNode getAFieldOrChild() { unified_while_stmt_body(this, result) or From b34549425a514b133d2e006fe78ff6e449a06d98 Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 30 Jul 2026 16:40:17 +0200 Subject: [PATCH 145/188] unified: Fix qldoc warnings --- unified/ql/lib/codeql/unified/internal/FacadeAst.qll | 2 ++ 1 file changed, 2 insertions(+) diff --git a/unified/ql/lib/codeql/unified/internal/FacadeAst.qll b/unified/ql/lib/codeql/unified/internal/FacadeAst.qll index d64bdeddc026..a25fb3447c1e 100644 --- a/unified/ql/lib/codeql/unified/internal/FacadeAst.qll +++ b/unified/ql/lib/codeql/unified/internal/FacadeAst.qll @@ -8,6 +8,7 @@ module Unified { private import Ast::Unified as G import G + /** The base class for all AST nodes. */ class AstNode extends G::AstNode { /** Holds if this AST node has a modifier with the given text. */ predicate hasModifier(string text) { @@ -18,6 +19,7 @@ module Unified { } } + /** The base class for all patterns. */ class Pattern extends G::Pattern { /** Gets the immediately-enclosing pattern in which this is a nested pattern. */ Pattern getEnclosingPattern() { From f9125b705da4e264579dbe921a89a6e4f03f5378 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 30 Jul 2026 13:17:48 +0100 Subject: [PATCH 146/188] C++: Make "windows-registry" a subkind of local flow sources so we can target those specifically in queries. --- cpp/ql/lib/ext/Windows.model.yml | 20 +++++++++---------- .../semmle/code/cpp/security/FlowSources.qll | 9 +++++++++ .../dataflow/external-models/flow.expected | 18 ++++++++--------- .../dataflow/external-models/sources.expected | 20 +++++++++---------- 4 files changed, 38 insertions(+), 29 deletions(-) diff --git a/cpp/ql/lib/ext/Windows.model.yml b/cpp/ql/lib/ext/Windows.model.yml index 8c25b874ccff..96b59d039392 100644 --- a/cpp/ql/lib/ext/Windows.model.yml +++ b/cpp/ql/lib/ext/Windows.model.yml @@ -35,18 +35,18 @@ extensions: - ["", "", False, "HttpReceiveRequestEntityBody", "", "", "Argument[*3]", "remote", "manual"] - ["", "", False, "HttpReceiveClientCertificate", "", "", "Argument[*3]", "remote", "manual"] # winreg.h - - ["", "", False, "RegQueryValueA", "", "", "Argument[*2]", "local", "manual"] - - ["", "", False, "RegQueryValueExA", "", "", "Argument[*4]", "local", "manual"] - - ["", "", False, "RegQueryValueW", "", "", "Argument[*2]", "local", "manual"] - - ["", "", False, "RegQueryValueExW", "", "", "Argument[*4]", "local", "manual"] - - ["", "", False, "RegGetValueA", "", "", "Argument[*5]", "local", "manual"] - - ["", "", False, "RegGetValueW", "", "", "Argument[*5]", "local", "manual"] + - ["", "", False, "RegQueryValueA", "", "", "Argument[*2]", "windows-registry", "manual"] + - ["", "", False, "RegQueryValueExA", "", "", "Argument[*4]", "windows-registry", "manual"] + - ["", "", False, "RegQueryValueW", "", "", "Argument[*2]", "windows-registry", "manual"] + - ["", "", False, "RegQueryValueExW", "", "", "Argument[*4]", "windows-registry", "manual"] + - ["", "", False, "RegGetValueA", "", "", "Argument[*5]", "windows-registry", "manual"] + - ["", "", False, "RegGetValueW", "", "", "Argument[*5]", "windows-registry", "manual"] # TODO: Once we support access paths at sources we should also mark Argument[*1].Field[*ve_valueptr] - - ["", "", False, "RegQueryMultipleValuesA", "", "", "Argument[*3]", "local", "manual"] + - ["", "", False, "RegQueryMultipleValuesA", "", "", "Argument[*3]", "windows-registry", "manual"] # TODO: Once we support access paths at sources we should also mark Argument[*1].Field[*ve_valueptr] - - ["", "", False, "RegQueryMultipleValuesW", "", "", "Argument[*3]", "local", "manual"] - - ["", "", False, "RegEnumValueA", "", "", "Argument[*6]", "local", "manual"] - - ["", "", False, "RegEnumValueW", "", "", "Argument[*6]", "local", "manual"] + - ["", "", False, "RegQueryMultipleValuesW", "", "", "Argument[*3]", "windows-registry", "manual"] + - ["", "", False, "RegEnumValueA", "", "", "Argument[*6]", "windows-registry", "manual"] + - ["", "", False, "RegEnumValueW", "", "", "Argument[*6]", "windows-registry", "manual"] - addsTo: pack: codeql/cpp-all extensible: summaryModel diff --git a/cpp/ql/lib/semmle/code/cpp/security/FlowSources.qll b/cpp/ql/lib/semmle/code/cpp/security/FlowSources.qll index 33695fdd51ab..e0890064aa75 100644 --- a/cpp/ql/lib/semmle/code/cpp/security/FlowSources.qll +++ b/cpp/ql/lib/semmle/code/cpp/security/FlowSources.qll @@ -20,6 +20,9 @@ abstract class RemoteFlowSource extends FlowSource { } /** A data flow source of local user input. */ abstract class LocalFlowSource extends FlowSource { } +/** A data flow source of local user input. */ +abstract class WindowsRegistrySource extends LocalFlowSource { } + /** * A remote data flow source that is defined through a `RemoteFlowSourceFunction` model. */ @@ -101,6 +104,12 @@ private class ExternalLocalFlowSource extends LocalFlowSource { override string getSourceType() { result = "external" } } +private class ExternalWindowsRegistrySource extends WindowsRegistrySource { + ExternalWindowsRegistrySource() { sourceNode(this, "windows-registry") } + + override string getSourceType() { result = "a value from the Windows registry" } +} + /** A remote data flow sink. */ abstract class RemoteFlowSink extends DataFlow::Node { /** Gets a string that describes the type of this flow sink. */ diff --git a/cpp/ql/test/library-tests/dataflow/external-models/flow.expected b/cpp/ql/test/library-tests/dataflow/external-models/flow.expected index a14376b044e7..a3670ee3e555 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/flow.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/flow.expected @@ -17,15 +17,15 @@ models | 16 | Source: ; ; false; NtReadFile; ; ; Argument[*5]; local; manual | | 17 | Source: ; ; false; ReadFile; ; ; Argument[*1]; local; manual | | 18 | Source: ; ; false; ReadFileEx; ; ; Argument[*1]; local; manual | -| 19 | Source: ; ; false; RegEnumValueA; ; ; Argument[*6]; local; manual | -| 20 | Source: ; ; false; RegEnumValueW; ; ; Argument[*6]; local; manual | -| 21 | Source: ; ; false; RegGetValueA; ; ; Argument[*5]; local; manual | -| 22 | Source: ; ; false; RegQueryMultipleValuesA; ; ; Argument[*3]; local; manual | -| 23 | Source: ; ; false; RegQueryMultipleValuesW; ; ; Argument[*3]; local; manual | -| 24 | Source: ; ; false; RegQueryValueA; ; ; Argument[*2]; local; manual | -| 25 | Source: ; ; false; RegQueryValueExA; ; ; Argument[*4]; local; manual | -| 26 | Source: ; ; false; RegQueryValueExW; ; ; Argument[*4]; local; manual | -| 27 | Source: ; ; false; RegQueryValueW; ; ; Argument[*2]; local; manual | +| 19 | Source: ; ; false; RegEnumValueA; ; ; Argument[*6]; windows-registry; manual | +| 20 | Source: ; ; false; RegEnumValueW; ; ; Argument[*6]; windows-registry; manual | +| 21 | Source: ; ; false; RegGetValueA; ; ; Argument[*5]; windows-registry; manual | +| 22 | Source: ; ; false; RegQueryMultipleValuesA; ; ; Argument[*3]; windows-registry; manual | +| 23 | Source: ; ; false; RegQueryMultipleValuesW; ; ; Argument[*3]; windows-registry; manual | +| 24 | Source: ; ; false; RegQueryValueA; ; ; Argument[*2]; windows-registry; manual | +| 25 | Source: ; ; false; RegQueryValueExA; ; ; Argument[*4]; windows-registry; manual | +| 26 | Source: ; ; false; RegQueryValueExW; ; ; Argument[*4]; windows-registry; manual | +| 27 | Source: ; ; false; RegQueryValueW; ; ; Argument[*2]; windows-registry; manual | | 28 | Source: ; ; false; WinHttpQueryHeaders; ; ; Argument[*3]; remote; manual | | 29 | Source: ; ; false; WinHttpQueryHeadersEx; ; ; Argument[**8]; remote; manual | | 30 | Source: ; ; false; WinHttpQueryHeadersEx; ; ; Argument[*5]; remote; manual | diff --git a/cpp/ql/test/library-tests/dataflow/external-models/sources.expected b/cpp/ql/test/library-tests/dataflow/external-models/sources.expected index 1e60cc73dcfa..e35d79d23271 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/sources.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/sources.expected @@ -43,13 +43,13 @@ | windows.cpp:900:64:900:77 | HttpReceiveHttpRequest output argument | remote | | windows.cpp:929:70:929:75 | HttpReceiveRequestEntityBody output argument | remote | | windows.cpp:936:70:936:78 | HttpReceiveClientCertificate output argument | remote | -| windows.cpp:1004:35:1004:38 | RegQueryValueA output argument | local | -| windows.cpp:1011:36:1011:39 | RegQueryValueW output argument | local | -| windows.cpp:1019:53:1019:56 | RegQueryValueExA output argument | local | -| windows.cpp:1027:54:1027:57 | RegQueryValueExW output argument | local | -| windows.cpp:1035:46:1035:49 | RegQueryMultipleValuesA output argument | local | -| windows.cpp:1043:46:1043:49 | RegQueryMultipleValuesW output argument | local | -| windows.cpp:1051:53:1051:56 | RegGetValueA output argument | local | -| windows.cpp:1060:53:1060:56 | RegGetValueA output argument | local | -| windows.cpp:1070:71:1070:74 | RegEnumValueA output argument | local | -| windows.cpp:1080:71:1080:74 | RegEnumValueW output argument | local | +| windows.cpp:1004:35:1004:38 | RegQueryValueA output argument | windows-registry | +| windows.cpp:1011:36:1011:39 | RegQueryValueW output argument | windows-registry | +| windows.cpp:1019:53:1019:56 | RegQueryValueExA output argument | windows-registry | +| windows.cpp:1027:54:1027:57 | RegQueryValueExW output argument | windows-registry | +| windows.cpp:1035:46:1035:49 | RegQueryMultipleValuesA output argument | windows-registry | +| windows.cpp:1043:46:1043:49 | RegQueryMultipleValuesW output argument | windows-registry | +| windows.cpp:1051:53:1051:56 | RegGetValueA output argument | windows-registry | +| windows.cpp:1060:53:1060:56 | RegGetValueA output argument | windows-registry | +| windows.cpp:1070:71:1070:74 | RegEnumValueA output argument | windows-registry | +| windows.cpp:1080:71:1080:74 | RegEnumValueW output argument | windows-registry | From d1b7498378094d80aa80c94e266b7f8ca24220fe Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 30 Jul 2026 13:54:16 +0100 Subject: [PATCH 147/188] C++: Add missing flow test cases. --- .../dataflow/external-models/windows.cpp | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp b/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp index aaa06105c915..e879beba4d33 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp +++ b/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp @@ -1081,4 +1081,95 @@ void test_registry_queries(HKEY hKey) { sink(data); // clean sink(*data); // $ ir } +} + +using LPCOLESTR = const char*; +using LPOLESTR = char*; +using GUID = int; +using CLSID = GUID; +using IID = GUID; +using REFIID = const IID&; +using REFCLSID = const CLSID&; +using REFGUID = const GUID&; +using LPIID = IID*; +using LPCLSID = CLSID*; +using HRESULT = long; + +HRESULT IIDFromString(LPCOLESTR lpsz, LPIID lpiid); +HRESULT StringFromIID(REFIID rclsid, LPOLESTR* lplpsz); +HRESULT ProgIDFromCLSID(REFCLSID clsid, LPOLESTR* lplpszProgID); +HRESULT CLSIDFromProgID(LPCOLESTR lpszProgID, LPCLSID lpclsid); +HRESULT CLSIDFromString(LPCOLESTR lpsz, LPCLSID pclsid); +HRESULT StringFromCLSID(REFCLSID rclsid, LPOLESTR* lplpsz); +int StringFromGUID(REFGUID rguid, LPOLESTR lpsz); +int GUIDFromString(LPCOLESTR psz, GUID* pguid); +int StringFromGUID2(REFGUID rguid, LPOLESTR lpsz, int cchMax); + +void sink(GUID); +void sink(GUID*); + +void test_com_string_conversions() { + { + char str[256]; + str[0] = (char)source(); + IID iid; + IIDFromString(str, &iid); + sink(iid); // $ MISSING: ir + } + { + IID iid = source(); + LPOLESTR str = nullptr; + StringFromIID(iid, &str); + sink(str); + sink(*str); // $ MISSING: ir + } + { + CLSID clsid = source(); + LPOLESTR str = nullptr; + ProgIDFromCLSID(clsid, &str); + sink(str); + sink(*str); // $ MISSING: ir + } + { + char progID[256]; + progID[0] = (char)source(); + CLSID clsid; + CLSIDFromProgID(progID, &clsid); + sink(clsid); // $ MISSING: ir + } + { + char str[256]; + str[0] = (char)source(); + CLSID clsid; + CLSIDFromString(str, &clsid); + sink(clsid); // $ MISSING: ir + } + { + CLSID clsid = source(); + LPOLESTR str = nullptr; + StringFromCLSID(clsid, &str); + sink(str); + sink(*str); // $ MISSING: ir + } + { + GUID guid = source(); + char str[256]; + StringFromGUID(guid, str); + sink(str); + sink(*str); // $ MISSING: ir + } + { + char str[256]; + str[0] = (char)source(); + GUID guid; + GUIDFromString(str, &guid); + sink(guid); // $ MISSING: ir + } + { + GUID guid = source(); + char str[256]; + StringFromGUID2(guid, str, 256); + sink(str); + sink(*str); // $ MISSING: ir + } } \ No newline at end of file From 05c6fe3f063334ca47ae27b7e876caf72d6a813e Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 30 Jul 2026 13:57:11 +0100 Subject: [PATCH 148/188] C++: Add flow models and accept test changes. --- cpp/ql/lib/ext/Windows.model.yml | 12 +- .../dataflow/external-models/flow.expected | 236 ++++++++++++------ .../dataflow/external-models/steps.expected | 9 + .../dataflow/external-models/windows.cpp | 18 +- 4 files changed, 192 insertions(+), 83 deletions(-) diff --git a/cpp/ql/lib/ext/Windows.model.yml b/cpp/ql/lib/ext/Windows.model.yml index 96b59d039392..d62e5e9e73b8 100644 --- a/cpp/ql/lib/ext/Windows.model.yml +++ b/cpp/ql/lib/ext/Windows.model.yml @@ -71,4 +71,14 @@ extensions: # winternl.h - ["", "", False, "RtlInitUnicodeString", "", "", "Argument[*1]", "Argument[*0].Field[*Buffer]", "value", "manual"] # winhttp.h - - ["", "", False, "WinHttpCrackUrl", "", "", "Argument[*0]", "Argument[*3]", "taint", "manual"] \ No newline at end of file + - ["", "", False, "WinHttpCrackUrl", "", "", "Argument[*0]", "Argument[*3]", "taint", "manual"] + # combaseapi.h + - ["", "", False, "IIDFromString", "", "", "Argument[*0]", "Argument[*1]", "taint", "manual"] + - ["", "", False, "StringFromIID", "", "", "Argument[*0]", "Argument[**1]", "taint", "manual"] + - ["", "", False, "ProgIDFromCLSID", "", "", "Argument[*0]", "Argument[**1]", "taint", "manual"] + - ["", "", False, "CLSIDFromProgID", "", "", "Argument[*0]", "Argument[*1]", "taint", "manual"] + - ["", "", False, "CLSIDFromString", "", "", "Argument[*0]", "Argument[*1]", "taint", "manual"] + - ["", "", False, "StringFromCLSID", "", "", "Argument[*0]", "Argument[**1]", "taint", "manual"] + - ["", "", False, "StringFromGUID", "", "", "Argument[*0]", "Argument[*1]", "taint", "manual"] + - ["", "", False, "GUIDFromString", "", "", "Argument[*0]", "Argument[*1]", "taint", "manual"] + - ["", "", False, "StringFromGUID2", "", "", "Argument[*0]", "Argument[*1]", "taint", "manual"] \ No newline at end of file diff --git a/cpp/ql/test/library-tests/dataflow/external-models/flow.expected b/cpp/ql/test/library-tests/dataflow/external-models/flow.expected index a3670ee3e555..9a5d1131a613 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/flow.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/flow.expected @@ -40,39 +40,48 @@ models | 39 | Source: Azure::Core::Http; Request; true; GetHeader; ; ; ReturnValue; remote; manual | | 40 | Source: Azure::Core::Http; Request; true; GetHeaders; ; ; ReturnValue; remote; manual | | 41 | Source: boost::asio; ; false; read_until; ; ; Argument[*1]; remote; manual | -| 42 | Summary: ; ; false; CommandLineToArgvA; ; ; Argument[*0]; ReturnValue[**]; taint; manual | -| 43 | Summary: ; ; false; CreateRemoteThread; ; ; Argument[@4]; Argument[3].Parameter[@0]; value; manual | -| 44 | Summary: ; ; false; CreateRemoteThreadEx; ; ; Argument[@4]; Argument[3].Parameter[@0]; value; manual | -| 45 | Summary: ; ; false; CreateThread; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual | -| 46 | Summary: ; ; false; ReadFileEx; ; ; Argument[*3].Field[@hEvent]; Argument[4].Parameter[*2].Field[@hEvent]; value; manual | -| 47 | Summary: ; ; false; RtlCopyDeviceMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | -| 48 | Summary: ; ; false; RtlCopyMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | -| 49 | Summary: ; ; false; RtlCopyMemoryNonTemporal; ; ; Argument[*@1]; Argument[*@0]; value; manual | -| 50 | Summary: ; ; false; RtlCopyUnicodeString; ; ; Argument[*1].Field[*Buffer]; Argument[*0].Field[*Buffer]; value; manual | -| 51 | Summary: ; ; false; RtlCopyVolatileMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | -| 52 | Summary: ; ; false; RtlInitUnicodeString; ; ; Argument[*1]; Argument[*0].Field[*Buffer]; value; manual | -| 53 | Summary: ; ; false; RtlMoveMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | -| 54 | Summary: ; ; false; RtlMoveVolatileMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | -| 55 | Summary: ; ; false; WinHttpCrackUrl; ; ; Argument[*0]; Argument[*3]; taint; manual | -| 56 | Summary: ; ; false; callWithArgument; ; ; Argument[1]; Argument[0].Parameter[0]; value; manual | -| 57 | Summary: ; ; false; callWithNonTypeTemplate; (const T &); ; Argument[*0]; ReturnValue; value; manual | -| 58 | Summary: ; ; false; pthread_create; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual | -| 59 | Summary: ; ; false; read_field_from_struct; ; ; Argument[*0].Field[MyNamespace::MyStructInNamespace::myField]; ReturnValue; value; manual | -| 60 | Summary: ; ; false; read_field_from_struct_2; ; ; Argument[*0].Field[MyGlobalStruct::myField]; ReturnValue; value; manual | -| 61 | Summary: ; ; false; ymlStepGenerated; ; ; Argument[0]; ReturnValue; taint; df-generated | -| 62 | Summary: ; ; false; ymlStepManual; ; ; Argument[0]; ReturnValue; taint; manual | -| 63 | Summary: ; ; false; ymlStepManual_with_body; ; ; Argument[0]; ReturnValue; taint; manual | -| 64 | Summary: ; MyString; true; operator[]; ; ; Argument[-1]; ReturnValue[*]; taint; manual | -| 65 | Summary: ; MyString; true; operator[]; ; ; ReturnValue[*]; Argument[-1]; taint; manual | -| 66 | Summary: ; ReverseFlow; true; get_ptr; ; ; ReturnValue[*]; Argument[-1].Field[ReverseFlow::value]; value; manual | -| 67 | Summary: ; TemplateClass1; true; templateFunction2; (U,V); ; Argument[1]; ReturnValue; value; manual | -| 68 | Summary: ; TemplateClass1; false; templateFunction; (T,U); ; Argument[0]; ReturnValue; value; manual | -| 69 | Summary: ; TemplateClass2; true; function; (U,T); ; Argument[1]; ReturnValue; value; manual | -| 70 | Summary: Azure::Core::IO; BodyStream; true; Read; ; ; Argument[-1]; Argument[*0]; taint; manual | -| 71 | Summary: Azure::Core::IO; BodyStream; true; ReadToCount; ; ; Argument[-1]; Argument[*0]; taint; manual | -| 72 | Summary: Azure::Core::IO; BodyStream; true; ReadToEnd; ; ; Argument[-1]; ReturnValue.Element; taint; manual | -| 73 | Summary: Azure; Nullable; true; Value; ; ; Argument[-1]; ReturnValue[*]; taint; manual | -| 74 | Summary: boost::asio; ; false; buffer; ; ; Argument[*0]; ReturnValue; taint; manual | +| 42 | Summary: ; ; false; CLSIDFromProgID; ; ; Argument[*0]; Argument[*1]; taint; manual | +| 43 | Summary: ; ; false; CLSIDFromString; ; ; Argument[*0]; Argument[*1]; taint; manual | +| 44 | Summary: ; ; false; CommandLineToArgvA; ; ; Argument[*0]; ReturnValue[**]; taint; manual | +| 45 | Summary: ; ; false; CreateRemoteThread; ; ; Argument[@4]; Argument[3].Parameter[@0]; value; manual | +| 46 | Summary: ; ; false; CreateRemoteThreadEx; ; ; Argument[@4]; Argument[3].Parameter[@0]; value; manual | +| 47 | Summary: ; ; false; CreateThread; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual | +| 48 | Summary: ; ; false; GUIDFromString; ; ; Argument[*0]; Argument[*1]; taint; manual | +| 49 | Summary: ; ; false; IIDFromString; ; ; Argument[*0]; Argument[*1]; taint; manual | +| 50 | Summary: ; ; false; ProgIDFromCLSID; ; ; Argument[*0]; Argument[**1]; taint; manual | +| 51 | Summary: ; ; false; ReadFileEx; ; ; Argument[*3].Field[@hEvent]; Argument[4].Parameter[*2].Field[@hEvent]; value; manual | +| 52 | Summary: ; ; false; RtlCopyDeviceMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | +| 53 | Summary: ; ; false; RtlCopyMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | +| 54 | Summary: ; ; false; RtlCopyMemoryNonTemporal; ; ; Argument[*@1]; Argument[*@0]; value; manual | +| 55 | Summary: ; ; false; RtlCopyUnicodeString; ; ; Argument[*1].Field[*Buffer]; Argument[*0].Field[*Buffer]; value; manual | +| 56 | Summary: ; ; false; RtlCopyVolatileMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | +| 57 | Summary: ; ; false; RtlInitUnicodeString; ; ; Argument[*1]; Argument[*0].Field[*Buffer]; value; manual | +| 58 | Summary: ; ; false; RtlMoveMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | +| 59 | Summary: ; ; false; RtlMoveVolatileMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | +| 60 | Summary: ; ; false; StringFromCLSID; ; ; Argument[*0]; Argument[**1]; taint; manual | +| 61 | Summary: ; ; false; StringFromGUID2; ; ; Argument[*0]; Argument[*1]; taint; manual | +| 62 | Summary: ; ; false; StringFromGUID; ; ; Argument[*0]; Argument[*1]; taint; manual | +| 63 | Summary: ; ; false; StringFromIID; ; ; Argument[*0]; Argument[**1]; taint; manual | +| 64 | Summary: ; ; false; WinHttpCrackUrl; ; ; Argument[*0]; Argument[*3]; taint; manual | +| 65 | Summary: ; ; false; callWithArgument; ; ; Argument[1]; Argument[0].Parameter[0]; value; manual | +| 66 | Summary: ; ; false; callWithNonTypeTemplate; (const T &); ; Argument[*0]; ReturnValue; value; manual | +| 67 | Summary: ; ; false; pthread_create; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual | +| 68 | Summary: ; ; false; read_field_from_struct; ; ; Argument[*0].Field[MyNamespace::MyStructInNamespace::myField]; ReturnValue; value; manual | +| 69 | Summary: ; ; false; read_field_from_struct_2; ; ; Argument[*0].Field[MyGlobalStruct::myField]; ReturnValue; value; manual | +| 70 | Summary: ; ; false; ymlStepGenerated; ; ; Argument[0]; ReturnValue; taint; df-generated | +| 71 | Summary: ; ; false; ymlStepManual; ; ; Argument[0]; ReturnValue; taint; manual | +| 72 | Summary: ; ; false; ymlStepManual_with_body; ; ; Argument[0]; ReturnValue; taint; manual | +| 73 | Summary: ; MyString; true; operator[]; ; ; Argument[-1]; ReturnValue[*]; taint; manual | +| 74 | Summary: ; MyString; true; operator[]; ; ; ReturnValue[*]; Argument[-1]; taint; manual | +| 75 | Summary: ; ReverseFlow; true; get_ptr; ; ; ReturnValue[*]; Argument[-1].Field[ReverseFlow::value]; value; manual | +| 76 | Summary: ; TemplateClass1; true; templateFunction2; (U,V); ; Argument[1]; ReturnValue; value; manual | +| 77 | Summary: ; TemplateClass1; false; templateFunction; (T,U); ; Argument[0]; ReturnValue; value; manual | +| 78 | Summary: ; TemplateClass2; true; function; (U,T); ; Argument[1]; ReturnValue; value; manual | +| 79 | Summary: Azure::Core::IO; BodyStream; true; Read; ; ; Argument[-1]; Argument[*0]; taint; manual | +| 80 | Summary: Azure::Core::IO; BodyStream; true; ReadToCount; ; ; Argument[-1]; Argument[*0]; taint; manual | +| 81 | Summary: Azure::Core::IO; BodyStream; true; ReadToEnd; ; ; Argument[-1]; ReturnValue.Element; taint; manual | +| 82 | Summary: Azure; Nullable; true; Value; ; ; Argument[-1]; ReturnValue[*]; taint; manual | +| 83 | Summary: boost::asio; ; false; buffer; ; ; Argument[*0]; ReturnValue; taint; manual | edges | asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:91:7:91:17 | recv_buffer | provenance | Src:MaD:41 | | asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:93:29:93:39 | *recv_buffer | provenance | Src:MaD:41 Sink:MaD:2 | @@ -81,16 +90,16 @@ edges | asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | | | asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:101:7:101:17 | send_buffer | provenance | | | asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:103:29:103:39 | *send_buffer | provenance | Sink:MaD:2 | -| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:74 | +| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:83 | | azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:253:48:253:60 | *call to GetBodyStream | provenance | Src:MaD:38 | | azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:257:5:257:8 | *resp | provenance | | | azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:262:5:262:8 | *resp | provenance | | | azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:266:38:266:41 | *resp | provenance | | -| azure.cpp:257:5:257:8 | *resp | azure.cpp:257:16:257:21 | Read output argument | provenance | MaD:70 | +| azure.cpp:257:5:257:8 | *resp | azure.cpp:257:16:257:21 | Read output argument | provenance | MaD:79 | | azure.cpp:257:16:257:21 | Read output argument | azure.cpp:258:10:258:16 | * ... | provenance | | -| azure.cpp:262:5:262:8 | *resp | azure.cpp:262:23:262:28 | ReadToCount output argument | provenance | MaD:71 | +| azure.cpp:262:5:262:8 | *resp | azure.cpp:262:23:262:28 | ReadToCount output argument | provenance | MaD:80 | | azure.cpp:262:23:262:28 | ReadToCount output argument | azure.cpp:263:10:263:16 | * ... | provenance | | -| azure.cpp:266:38:266:41 | *resp | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | provenance | MaD:72 | +| azure.cpp:266:38:266:41 | *resp | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | provenance | MaD:81 | | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | provenance | | | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | azure.cpp:267:10:267:12 | vec [element] | provenance | | | azure.cpp:267:10:267:12 | vec [element] | azure.cpp:267:10:267:12 | vec | provenance | | @@ -106,10 +115,10 @@ edges | azure.cpp:278:10:278:13 | body | azure.cpp:278:10:278:13 | body | provenance | | | azure.cpp:281:68:281:84 | *call to ExtractBodyStream | azure.cpp:281:68:281:84 | *call to ExtractBodyStream | provenance | Src:MaD:35 | | azure.cpp:281:68:281:84 | *call to ExtractBodyStream | azure.cpp:282:21:282:23 | *call to get | provenance | | -| azure.cpp:282:21:282:23 | *call to get | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | provenance | MaD:72 | +| azure.cpp:282:21:282:23 | *call to get | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | provenance | MaD:81 | | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | azure.cpp:282:10:282:38 | call to ReadToEnd | provenance | | | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | provenance | | -| azure.cpp:289:24:289:56 | call to GetHeader | azure.cpp:289:63:289:65 | call to Value | provenance | MaD:73 | +| azure.cpp:289:24:289:56 | call to GetHeader | azure.cpp:289:63:289:65 | call to Value | provenance | MaD:82 | | azure.cpp:289:32:289:40 | call to GetHeader | azure.cpp:289:24:289:56 | call to GetHeader | provenance | | | azure.cpp:289:32:289:40 | call to GetHeader | azure.cpp:289:32:289:40 | call to GetHeader | provenance | Src:MaD:39 | | azure.cpp:289:63:289:65 | call to Value | azure.cpp:289:63:289:65 | call to Value | provenance | | @@ -131,13 +140,13 @@ edges | test.cpp:10:10:10:18 | call to ymlSource | test.cpp:32:41:32:41 | x | provenance | | | test.cpp:17:10:17:22 | call to ymlStepManual | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | | | test.cpp:17:10:17:22 | call to ymlStepManual | test.cpp:18:10:18:10 | y | provenance | Sink:MaD:1 | -| test.cpp:17:24:17:24 | x | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | MaD:62 | +| test.cpp:17:24:17:24 | x | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | MaD:71 | | test.cpp:21:10:21:25 | call to ymlStepGenerated | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | | | test.cpp:21:10:21:25 | call to ymlStepGenerated | test.cpp:22:10:22:10 | z | provenance | Sink:MaD:1 | -| test.cpp:21:27:21:27 | x | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | MaD:61 | +| test.cpp:21:27:21:27 | x | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | MaD:70 | | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | | | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | test.cpp:26:10:26:11 | y2 | provenance | Sink:MaD:1 | -| test.cpp:25:35:25:35 | x | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | MaD:63 | +| test.cpp:25:35:25:35 | x | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | MaD:72 | | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | provenance | | | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | test.cpp:33:10:33:11 | z2 | provenance | Sink:MaD:1 | | test.cpp:32:41:32:41 | x | test.cpp:7:47:7:52 | value2 | provenance | | @@ -148,7 +157,7 @@ edges | test.cpp:56:2:56:2 | *s [post update] [x] | test.cpp:59:55:59:64 | *& ... [x] | provenance | | | test.cpp:56:2:56:18 | ... = ... | test.cpp:56:2:56:2 | *s [post update] [x] | provenance | | | test.cpp:56:8:56:16 | call to ymlSource | test.cpp:56:2:56:18 | ... = ... | provenance | Src:MaD:34 | -| test.cpp:59:55:59:64 | *& ... [x] | test.cpp:46:30:46:32 | *arg [x] | provenance | MaD:58 | +| test.cpp:59:55:59:64 | *& ... [x] | test.cpp:46:30:46:32 | *arg [x] | provenance | MaD:67 | | test.cpp:68:22:68:22 | y | test.cpp:69:11:69:11 | y | provenance | Sink:MaD:1 | | test.cpp:74:22:74:22 | y | test.cpp:75:11:75:11 | y | provenance | Sink:MaD:1 | | test.cpp:82:22:82:22 | y | test.cpp:83:11:83:11 | y | provenance | Sink:MaD:1 | @@ -158,62 +167,62 @@ edges | test.cpp:94:10:94:18 | call to ymlSource | test.cpp:101:26:101:26 | x | provenance | | | test.cpp:94:10:94:18 | call to ymlSource | test.cpp:103:63:103:63 | x | provenance | | | test.cpp:94:10:94:18 | call to ymlSource | test.cpp:104:62:104:62 | x | provenance | | -| test.cpp:97:26:97:26 | x | test.cpp:68:22:68:22 | y | provenance | MaD:56 | -| test.cpp:101:26:101:26 | x | test.cpp:74:22:74:22 | y | provenance | MaD:56 | -| test.cpp:103:63:103:63 | x | test.cpp:82:22:82:22 | y | provenance | MaD:56 | -| test.cpp:104:62:104:62 | x | test.cpp:88:22:88:22 | y | provenance | MaD:56 | +| test.cpp:97:26:97:26 | x | test.cpp:68:22:68:22 | y | provenance | MaD:65 | +| test.cpp:101:26:101:26 | x | test.cpp:74:22:74:22 | y | provenance | MaD:65 | +| test.cpp:103:63:103:63 | x | test.cpp:82:22:82:22 | y | provenance | MaD:65 | +| test.cpp:104:62:104:62 | x | test.cpp:88:22:88:22 | y | provenance | MaD:65 | | test.cpp:114:10:114:18 | call to ymlSource | test.cpp:114:10:114:18 | call to ymlSource | provenance | Src:MaD:34 | | test.cpp:114:10:114:18 | call to ymlSource | test.cpp:118:44:118:44 | *x | provenance | | | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | provenance | | | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | test.cpp:119:10:119:11 | y2 | provenance | Sink:MaD:1 | -| test.cpp:118:44:118:44 | *x | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | provenance | MaD:57 | +| test.cpp:118:44:118:44 | *x | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | provenance | MaD:66 | | test.cpp:133:10:133:18 | call to ymlSource | test.cpp:133:10:133:18 | call to ymlSource | provenance | Src:MaD:34 | | test.cpp:133:10:133:18 | call to ymlSource | test.cpp:134:45:134:45 | x | provenance | | | test.cpp:134:13:134:43 | call to templateFunction | test.cpp:134:13:134:43 | call to templateFunction | provenance | | | test.cpp:134:13:134:43 | call to templateFunction | test.cpp:135:10:135:10 | y | provenance | Sink:MaD:1 | -| test.cpp:134:45:134:45 | x | test.cpp:134:13:134:43 | call to templateFunction | provenance | MaD:68 | +| test.cpp:134:45:134:45 | x | test.cpp:134:13:134:43 | call to templateFunction | provenance | MaD:77 | | test.cpp:146:10:146:18 | call to ymlSource | test.cpp:146:10:146:18 | call to ymlSource | provenance | Src:MaD:34 | | test.cpp:146:10:146:18 | call to ymlSource | test.cpp:148:26:148:26 | x | provenance | | | test.cpp:148:10:148:27 | call to function | test.cpp:148:10:148:27 | call to function | provenance | | | test.cpp:148:10:148:27 | call to function | test.cpp:149:10:149:10 | z | provenance | Sink:MaD:1 | -| test.cpp:148:26:148:26 | x | test.cpp:148:10:148:27 | call to function | provenance | MaD:69 | +| test.cpp:148:26:148:26 | x | test.cpp:148:10:148:27 | call to function | provenance | MaD:78 | | test.cpp:155:10:155:18 | call to ymlSource | test.cpp:155:10:155:18 | call to ymlSource | provenance | Src:MaD:34 | | test.cpp:155:10:155:18 | call to ymlSource | test.cpp:157:26:157:26 | x | provenance | | | test.cpp:157:13:157:20 | call to function | test.cpp:157:13:157:20 | call to function | provenance | | | test.cpp:157:13:157:20 | call to function | test.cpp:158:10:158:10 | z | provenance | Sink:MaD:1 | -| test.cpp:157:26:157:26 | x | test.cpp:157:13:157:20 | call to function | provenance | MaD:69 | +| test.cpp:157:26:157:26 | x | test.cpp:157:13:157:20 | call to function | provenance | MaD:78 | | test.cpp:164:34:164:34 | x | test.cpp:165:69:165:69 | x | provenance | | | test.cpp:165:12:165:64 | call to templateFunction2 | test.cpp:164:7:164:7 | *templateFunction3 | provenance | | | test.cpp:165:12:165:64 | call to templateFunction2 | test.cpp:165:12:165:64 | call to templateFunction2 | provenance | | -| test.cpp:165:69:165:69 | x | test.cpp:165:12:165:64 | call to templateFunction2 | provenance | MaD:67 | +| test.cpp:165:69:165:69 | x | test.cpp:165:12:165:64 | call to templateFunction2 | provenance | MaD:76 | | test.cpp:170:10:170:18 | call to ymlSource | test.cpp:170:10:170:18 | call to ymlSource | provenance | Src:MaD:34 | | test.cpp:170:10:170:18 | call to ymlSource | test.cpp:172:51:172:51 | x | provenance | | | test.cpp:172:13:172:44 | call to templateFunction3 | test.cpp:172:13:172:44 | call to templateFunction3 | provenance | | | test.cpp:172:13:172:44 | call to templateFunction3 | test.cpp:173:10:173:10 | y | provenance | Sink:MaD:1 | | test.cpp:172:51:172:51 | x | test.cpp:164:34:164:34 | x | provenance | | -| test.cpp:172:51:172:51 | x | test.cpp:172:13:172:44 | call to templateFunction3 | provenance | MaD:67 | +| test.cpp:172:51:172:51 | x | test.cpp:172:13:172:44 | call to templateFunction3 | provenance | MaD:76 | | test.cpp:186:2:186:2 | *s [post update] [myField] | test.cpp:187:33:187:34 | *& ... [myField] | provenance | | | test.cpp:186:2:186:24 | ... = ... | test.cpp:186:2:186:2 | *s [post update] [myField] | provenance | | | test.cpp:186:14:186:22 | call to ymlSource | test.cpp:186:2:186:24 | ... = ... | provenance | Src:MaD:34 | | test.cpp:187:10:187:31 | call to read_field_from_struct | test.cpp:187:10:187:31 | call to read_field_from_struct | provenance | | | test.cpp:187:10:187:31 | call to read_field_from_struct | test.cpp:188:10:188:10 | x | provenance | Sink:MaD:1 | -| test.cpp:187:33:187:34 | *& ... [myField] | test.cpp:187:10:187:31 | call to read_field_from_struct | provenance | MaD:59 | +| test.cpp:187:33:187:34 | *& ... [myField] | test.cpp:187:10:187:31 | call to read_field_from_struct | provenance | MaD:68 | | test.cpp:199:2:199:2 | *s [post update] [myField] | test.cpp:200:35:200:36 | *& ... [myField] | provenance | | | test.cpp:199:2:199:24 | ... = ... | test.cpp:199:2:199:2 | *s [post update] [myField] | provenance | | | test.cpp:199:14:199:22 | call to ymlSource | test.cpp:199:2:199:24 | ... = ... | provenance | Src:MaD:34 | | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | provenance | | | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | test.cpp:201:10:201:10 | x | provenance | Sink:MaD:1 | -| test.cpp:200:35:200:36 | *& ... [myField] | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | provenance | MaD:60 | +| test.cpp:200:35:200:36 | *& ... [myField] | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | provenance | MaD:69 | | test.cpp:216:3:216:4 | get_ptr output argument [value] | test.cpp:217:11:217:12 | *rf [value] | provenance | | -| test.cpp:216:3:216:28 | ... = ... | test.cpp:216:3:216:4 | get_ptr output argument [value] | provenance | MaD:66 | +| test.cpp:216:3:216:28 | ... = ... | test.cpp:216:3:216:4 | get_ptr output argument [value] | provenance | MaD:75 | | test.cpp:216:18:216:26 | call to ymlSource | test.cpp:216:3:216:28 | ... = ... | provenance | Src:MaD:34 | | test.cpp:217:11:217:12 | *rf [value] | test.cpp:217:14:217:18 | value | provenance | | | test.cpp:217:14:217:18 | value | test.cpp:217:14:217:18 | value | provenance | | | test.cpp:217:14:217:18 | value | test.cpp:218:11:218:11 | x | provenance | Sink:MaD:1 | | test.cpp:222:3:222:3 | operator[] output argument | test.cpp:223:12:223:12 | *s | provenance | | -| test.cpp:222:3:222:20 | ... = ... | test.cpp:222:3:222:3 | operator[] output argument | provenance | MaD:65 | +| test.cpp:222:3:222:20 | ... = ... | test.cpp:222:3:222:3 | operator[] output argument | provenance | MaD:74 | | test.cpp:222:10:222:20 | call to ymlSource | test.cpp:222:3:222:20 | ... = ... | provenance | Src:MaD:34 | -| test.cpp:223:12:223:12 | *s | test.cpp:223:13:223:15 | call to operator[] | provenance | MaD:64 | +| test.cpp:223:12:223:12 | *s | test.cpp:223:13:223:15 | call to operator[] | provenance | MaD:73 | | test.cpp:223:13:223:15 | call to operator[] | test.cpp:223:13:223:15 | call to operator[] | provenance | | | test.cpp:223:13:223:15 | call to operator[] | test.cpp:224:11:224:11 | c | provenance | Sink:MaD:1 | | windows.cpp:22:15:22:29 | *call to GetCommandLineA | windows.cpp:22:15:22:29 | *call to GetCommandLineA | provenance | Src:MaD:3 | @@ -221,7 +230,7 @@ edges | windows.cpp:22:15:22:29 | *call to GetCommandLineA | windows.cpp:27:36:27:38 | *cmd | provenance | | | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | provenance | | | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | windows.cpp:30:8:30:15 | * ... | provenance | | -| windows.cpp:27:36:27:38 | *cmd | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | provenance | MaD:42 | +| windows.cpp:27:36:27:38 | *cmd | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | provenance | MaD:44 | | windows.cpp:34:17:34:38 | *call to GetEnvironmentStringsA | windows.cpp:34:17:34:38 | *call to GetEnvironmentStringsA | provenance | Src:MaD:4 | | windows.cpp:34:17:34:38 | *call to GetEnvironmentStringsA | windows.cpp:36:10:36:13 | * ... | provenance | | | windows.cpp:39:36:39:38 | GetEnvironmentVariableA output argument | windows.cpp:41:10:41:13 | * ... | provenance | Src:MaD:5 | @@ -241,11 +250,11 @@ edges | windows.cpp:189:21:189:26 | ReadFile output argument | windows.cpp:190:5:190:56 | *... = ... | provenance | Src:MaD:17 | | windows.cpp:190:5:190:14 | *overlapped [post update] [*hEvent] | windows.cpp:192:53:192:63 | *& ... [*hEvent] | provenance | | | windows.cpp:190:5:190:56 | *... = ... | windows.cpp:190:5:190:14 | *overlapped [post update] [*hEvent] | provenance | | -| windows.cpp:192:53:192:63 | *& ... [*hEvent] | windows.cpp:147:16:147:27 | *lpOverlapped [*hEvent] | provenance | MaD:46 | +| windows.cpp:192:53:192:63 | *& ... [*hEvent] | windows.cpp:147:16:147:27 | *lpOverlapped [*hEvent] | provenance | MaD:51 | | windows.cpp:198:21:198:26 | ReadFile output argument | windows.cpp:199:5:199:57 | ... = ... | provenance | Src:MaD:17 | | windows.cpp:199:5:199:14 | *overlapped [post update] [hEvent] | windows.cpp:201:53:201:63 | *& ... [hEvent] | provenance | | | windows.cpp:199:5:199:57 | ... = ... | windows.cpp:199:5:199:14 | *overlapped [post update] [hEvent] | provenance | | -| windows.cpp:201:53:201:63 | *& ... [hEvent] | windows.cpp:157:16:157:27 | *lpOverlapped [hEvent] | provenance | MaD:46 | +| windows.cpp:201:53:201:63 | *& ... [hEvent] | windows.cpp:157:16:157:27 | *lpOverlapped [hEvent] | provenance | MaD:51 | | windows.cpp:209:84:209:89 | NtReadFile output argument | windows.cpp:211:10:211:16 | * ... | provenance | Src:MaD:16 | | windows.cpp:286:23:286:35 | *call to MapViewOfFile | windows.cpp:286:23:286:35 | *call to MapViewOfFile | provenance | Src:MaD:12 | | windows.cpp:286:23:286:35 | *call to MapViewOfFile | windows.cpp:287:20:287:52 | *pMapView | provenance | | @@ -282,9 +291,9 @@ edges | windows.cpp:431:3:431:3 | *s [post update] [x] | windows.cpp:464:7:464:8 | *& ... [x] | provenance | | | windows.cpp:431:3:431:16 | ... = ... | windows.cpp:431:3:431:3 | *s [post update] [x] | provenance | | | windows.cpp:431:9:431:14 | call to source | windows.cpp:431:3:431:16 | ... = ... | provenance | | -| windows.cpp:439:7:439:8 | *& ... [x] | windows.cpp:403:26:403:36 | *lpParameter [x] | provenance | MaD:45 | -| windows.cpp:451:7:451:8 | *& ... [x] | windows.cpp:410:26:410:36 | *lpParameter [x] | provenance | MaD:43 | -| windows.cpp:464:7:464:8 | *& ... [x] | windows.cpp:417:26:417:36 | *lpParameter [x] | provenance | MaD:44 | +| windows.cpp:439:7:439:8 | *& ... [x] | windows.cpp:403:26:403:36 | *lpParameter [x] | provenance | MaD:47 | +| windows.cpp:451:7:451:8 | *& ... [x] | windows.cpp:410:26:410:36 | *lpParameter [x] | provenance | MaD:45 | +| windows.cpp:464:7:464:8 | *& ... [x] | windows.cpp:417:26:417:36 | *lpParameter [x] | provenance | MaD:46 | | windows.cpp:533:11:533:16 | call to source | windows.cpp:533:11:533:16 | call to source | provenance | | | windows.cpp:533:11:533:16 | call to source | windows.cpp:537:40:537:41 | *& ... | provenance | | | windows.cpp:533:11:533:16 | call to source | windows.cpp:542:38:542:39 | *& ... | provenance | | @@ -293,30 +302,30 @@ edges | windows.cpp:533:11:533:16 | call to source | windows.cpp:568:32:568:33 | *& ... | provenance | | | windows.cpp:533:11:533:16 | call to source | windows.cpp:573:40:573:41 | *& ... | provenance | | | windows.cpp:537:27:537:37 | RtlCopyVolatileMemory output argument | windows.cpp:538:10:538:23 | access to array | provenance | | -| windows.cpp:537:40:537:41 | *& ... | windows.cpp:537:27:537:37 | RtlCopyVolatileMemory output argument | provenance | MaD:51 | +| windows.cpp:537:40:537:41 | *& ... | windows.cpp:537:27:537:37 | RtlCopyVolatileMemory output argument | provenance | MaD:56 | | windows.cpp:542:25:542:35 | RtlCopyDeviceMemory output argument | windows.cpp:543:10:543:23 | access to array | provenance | | -| windows.cpp:542:38:542:39 | *& ... | windows.cpp:542:25:542:35 | RtlCopyDeviceMemory output argument | provenance | MaD:47 | +| windows.cpp:542:38:542:39 | *& ... | windows.cpp:542:25:542:35 | RtlCopyDeviceMemory output argument | provenance | MaD:52 | | windows.cpp:547:19:547:29 | RtlCopyMemory output argument | windows.cpp:548:10:548:23 | access to array | provenance | | -| windows.cpp:547:32:547:33 | *& ... | windows.cpp:547:19:547:29 | RtlCopyMemory output argument | provenance | MaD:48 | +| windows.cpp:547:32:547:33 | *& ... | windows.cpp:547:19:547:29 | RtlCopyMemory output argument | provenance | MaD:53 | | windows.cpp:552:30:552:40 | RtlCopyMemoryNonTemporal output argument | windows.cpp:553:10:553:23 | access to array | provenance | | -| windows.cpp:552:43:552:44 | *& ... | windows.cpp:552:30:552:40 | RtlCopyMemoryNonTemporal output argument | provenance | MaD:49 | +| windows.cpp:552:43:552:44 | *& ... | windows.cpp:552:30:552:40 | RtlCopyMemoryNonTemporal output argument | provenance | MaD:54 | | windows.cpp:559:5:559:24 | ... = ... | windows.cpp:561:39:561:44 | *buffer | provenance | | | windows.cpp:559:17:559:24 | call to source | windows.cpp:559:5:559:24 | ... = ... | provenance | | | windows.cpp:561:26:561:36 | RtlInitUnicodeString output argument [*Buffer] | windows.cpp:562:10:562:19 | *src_string [*Buffer] | provenance | | | windows.cpp:561:26:561:36 | RtlInitUnicodeString output argument [*Buffer] | windows.cpp:563:40:563:50 | *& ... [*Buffer] | provenance | | -| windows.cpp:561:39:561:44 | *buffer | windows.cpp:561:26:561:36 | RtlInitUnicodeString output argument [*Buffer] | provenance | MaD:52 | +| windows.cpp:561:39:561:44 | *buffer | windows.cpp:561:26:561:36 | RtlInitUnicodeString output argument [*Buffer] | provenance | MaD:57 | | windows.cpp:562:10:562:19 | *src_string [*Buffer] | windows.cpp:562:10:562:29 | access to array | provenance | | | windows.cpp:562:10:562:19 | *src_string [*Buffer] | windows.cpp:562:21:562:26 | *Buffer | provenance | | | windows.cpp:562:21:562:26 | *Buffer | windows.cpp:562:10:562:29 | access to array | provenance | | | windows.cpp:563:26:563:37 | RtlCopyUnicodeString output argument [*Buffer] | windows.cpp:564:10:564:20 | *dest_string [*Buffer] | provenance | | -| windows.cpp:563:40:563:50 | *& ... [*Buffer] | windows.cpp:563:26:563:37 | RtlCopyUnicodeString output argument [*Buffer] | provenance | MaD:50 | +| windows.cpp:563:40:563:50 | *& ... [*Buffer] | windows.cpp:563:26:563:37 | RtlCopyUnicodeString output argument [*Buffer] | provenance | MaD:55 | | windows.cpp:564:10:564:20 | *dest_string [*Buffer] | windows.cpp:564:10:564:30 | access to array | provenance | | | windows.cpp:564:10:564:20 | *dest_string [*Buffer] | windows.cpp:564:22:564:27 | *Buffer | provenance | | | windows.cpp:564:22:564:27 | *Buffer | windows.cpp:564:10:564:30 | access to array | provenance | | | windows.cpp:568:19:568:29 | RtlMoveMemory output argument | windows.cpp:569:10:569:23 | access to array | provenance | | -| windows.cpp:568:32:568:33 | *& ... | windows.cpp:568:19:568:29 | RtlMoveMemory output argument | provenance | MaD:53 | +| windows.cpp:568:32:568:33 | *& ... | windows.cpp:568:19:568:29 | RtlMoveMemory output argument | provenance | MaD:58 | | windows.cpp:573:27:573:37 | RtlMoveVolatileMemory output argument | windows.cpp:574:10:574:23 | access to array | provenance | | -| windows.cpp:573:40:573:41 | *& ... | windows.cpp:573:27:573:37 | RtlMoveVolatileMemory output argument | provenance | MaD:54 | +| windows.cpp:573:40:573:41 | *& ... | windows.cpp:573:27:573:37 | RtlMoveVolatileMemory output argument | provenance | MaD:59 | | windows.cpp:645:45:645:50 | WinHttpReadData output argument | windows.cpp:647:10:647:16 | * ... | provenance | Src:MaD:32 | | windows.cpp:652:48:652:53 | WinHttpReadDataEx output argument | windows.cpp:654:10:654:16 | * ... | provenance | Src:MaD:33 | | windows.cpp:659:47:659:52 | WinHttpQueryHeaders output argument | windows.cpp:661:10:661:16 | * ... | provenance | Src:MaD:28 | @@ -325,7 +334,7 @@ edges | windows.cpp:669:105:669:112 | WinHttpQueryHeadersEx output argument | windows.cpp:675:10:675:27 | * ... | provenance | Src:MaD:29 | | windows.cpp:728:5:728:28 | ... = ... | windows.cpp:729:35:729:35 | *x | provenance | | | windows.cpp:728:12:728:28 | call to source | windows.cpp:728:5:728:28 | ... = ... | provenance | | -| windows.cpp:729:35:729:35 | *x | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | provenance | MaD:55 | +| windows.cpp:729:35:729:35 | *x | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | provenance | MaD:64 | | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | windows.cpp:731:10:731:36 | * ... | provenance | | | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | windows.cpp:733:10:733:35 | * ... | provenance | | | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | windows.cpp:735:10:735:37 | * ... | provenance | | @@ -356,6 +365,42 @@ edges | windows.cpp:1060:53:1060:56 | RegGetValueA output argument | windows.cpp:1062:10:1062:14 | * ... | provenance | Src:MaD:21 | | windows.cpp:1070:71:1070:74 | RegEnumValueA output argument | windows.cpp:1072:10:1072:14 | * ... | provenance | Src:MaD:19 | | windows.cpp:1080:71:1080:74 | RegEnumValueW output argument | windows.cpp:1082:10:1082:14 | * ... | provenance | Src:MaD:20 | +| windows.cpp:1114:5:1114:27 | ... = ... | windows.cpp:1116:19:1116:21 | *str | provenance | | +| windows.cpp:1114:14:1114:27 | call to source | windows.cpp:1114:5:1114:27 | ... = ... | provenance | | +| windows.cpp:1116:19:1116:21 | *str | windows.cpp:1116:24:1116:27 | IIDFromString output argument | provenance | MaD:49 | +| windows.cpp:1116:24:1116:27 | IIDFromString output argument | windows.cpp:1117:10:1117:12 | iid | provenance | | +| windows.cpp:1120:15:1120:20 | call to source | windows.cpp:1120:15:1120:20 | call to source | provenance | | +| windows.cpp:1120:15:1120:20 | call to source | windows.cpp:1122:19:1122:21 | *iid | provenance | | +| windows.cpp:1122:19:1122:21 | *iid | windows.cpp:1122:24:1122:27 | StringFromIID output argument | provenance | MaD:63 | +| windows.cpp:1122:24:1122:27 | StringFromIID output argument | windows.cpp:1124:10:1124:13 | * ... | provenance | | +| windows.cpp:1127:19:1127:24 | call to source | windows.cpp:1127:19:1127:24 | call to source | provenance | | +| windows.cpp:1127:19:1127:24 | call to source | windows.cpp:1129:21:1129:25 | *clsid | provenance | | +| windows.cpp:1129:21:1129:25 | *clsid | windows.cpp:1129:28:1129:31 | ProgIDFromCLSID output argument | provenance | MaD:50 | +| windows.cpp:1129:28:1129:31 | ProgIDFromCLSID output argument | windows.cpp:1131:10:1131:13 | * ... | provenance | | +| windows.cpp:1135:5:1135:30 | ... = ... | windows.cpp:1137:21:1137:26 | *progID | provenance | | +| windows.cpp:1135:17:1135:30 | call to source | windows.cpp:1135:5:1135:30 | ... = ... | provenance | | +| windows.cpp:1137:21:1137:26 | *progID | windows.cpp:1137:29:1137:34 | CLSIDFromProgID output argument | provenance | MaD:42 | +| windows.cpp:1137:29:1137:34 | CLSIDFromProgID output argument | windows.cpp:1138:10:1138:14 | clsid | provenance | | +| windows.cpp:1142:5:1142:27 | ... = ... | windows.cpp:1144:21:1144:23 | *str | provenance | | +| windows.cpp:1142:14:1142:27 | call to source | windows.cpp:1142:5:1142:27 | ... = ... | provenance | | +| windows.cpp:1144:21:1144:23 | *str | windows.cpp:1144:26:1144:31 | CLSIDFromString output argument | provenance | MaD:43 | +| windows.cpp:1144:26:1144:31 | CLSIDFromString output argument | windows.cpp:1145:10:1145:14 | clsid | provenance | | +| windows.cpp:1148:19:1148:24 | call to source | windows.cpp:1148:19:1148:24 | call to source | provenance | | +| windows.cpp:1148:19:1148:24 | call to source | windows.cpp:1150:21:1150:25 | *clsid | provenance | | +| windows.cpp:1150:21:1150:25 | *clsid | windows.cpp:1150:28:1150:31 | StringFromCLSID output argument | provenance | MaD:60 | +| windows.cpp:1150:28:1150:31 | StringFromCLSID output argument | windows.cpp:1152:10:1152:13 | * ... | provenance | | +| windows.cpp:1155:17:1155:22 | call to source | windows.cpp:1155:17:1155:22 | call to source | provenance | | +| windows.cpp:1155:17:1155:22 | call to source | windows.cpp:1157:20:1157:23 | *guid | provenance | | +| windows.cpp:1157:20:1157:23 | *guid | windows.cpp:1157:26:1157:28 | StringFromGUID output argument | provenance | MaD:62 | +| windows.cpp:1157:26:1157:28 | StringFromGUID output argument | windows.cpp:1159:10:1159:13 | * ... | provenance | | +| windows.cpp:1163:5:1163:27 | ... = ... | windows.cpp:1165:20:1165:22 | *str | provenance | | +| windows.cpp:1163:14:1163:27 | call to source | windows.cpp:1163:5:1163:27 | ... = ... | provenance | | +| windows.cpp:1165:20:1165:22 | *str | windows.cpp:1165:25:1165:29 | GUIDFromString output argument | provenance | MaD:48 | +| windows.cpp:1165:25:1165:29 | GUIDFromString output argument | windows.cpp:1166:10:1166:13 | guid | provenance | | +| windows.cpp:1169:17:1169:22 | call to source | windows.cpp:1169:17:1169:22 | call to source | provenance | | +| windows.cpp:1169:17:1169:22 | call to source | windows.cpp:1171:21:1171:24 | *guid | provenance | | +| windows.cpp:1171:21:1171:24 | *guid | windows.cpp:1171:27:1171:29 | StringFromGUID2 output argument | provenance | MaD:61 | +| windows.cpp:1171:27:1171:29 | StringFromGUID2 output argument | windows.cpp:1173:10:1173:13 | * ... | provenance | | nodes | asio_streams.cpp:87:34:87:44 | read_until output argument | semmle.label | read_until output argument | | asio_streams.cpp:91:7:91:17 | recv_buffer | semmle.label | recv_buffer | @@ -692,6 +737,51 @@ nodes | windows.cpp:1072:10:1072:14 | * ... | semmle.label | * ... | | windows.cpp:1080:71:1080:74 | RegEnumValueW output argument | semmle.label | RegEnumValueW output argument | | windows.cpp:1082:10:1082:14 | * ... | semmle.label | * ... | +| windows.cpp:1114:5:1114:27 | ... = ... | semmle.label | ... = ... | +| windows.cpp:1114:14:1114:27 | call to source | semmle.label | call to source | +| windows.cpp:1116:19:1116:21 | *str | semmle.label | *str | +| windows.cpp:1116:24:1116:27 | IIDFromString output argument | semmle.label | IIDFromString output argument | +| windows.cpp:1117:10:1117:12 | iid | semmle.label | iid | +| windows.cpp:1120:15:1120:20 | call to source | semmle.label | call to source | +| windows.cpp:1120:15:1120:20 | call to source | semmle.label | call to source | +| windows.cpp:1122:19:1122:21 | *iid | semmle.label | *iid | +| windows.cpp:1122:24:1122:27 | StringFromIID output argument | semmle.label | StringFromIID output argument | +| windows.cpp:1124:10:1124:13 | * ... | semmle.label | * ... | +| windows.cpp:1127:19:1127:24 | call to source | semmle.label | call to source | +| windows.cpp:1127:19:1127:24 | call to source | semmle.label | call to source | +| windows.cpp:1129:21:1129:25 | *clsid | semmle.label | *clsid | +| windows.cpp:1129:28:1129:31 | ProgIDFromCLSID output argument | semmle.label | ProgIDFromCLSID output argument | +| windows.cpp:1131:10:1131:13 | * ... | semmle.label | * ... | +| windows.cpp:1135:5:1135:30 | ... = ... | semmle.label | ... = ... | +| windows.cpp:1135:17:1135:30 | call to source | semmle.label | call to source | +| windows.cpp:1137:21:1137:26 | *progID | semmle.label | *progID | +| windows.cpp:1137:29:1137:34 | CLSIDFromProgID output argument | semmle.label | CLSIDFromProgID output argument | +| windows.cpp:1138:10:1138:14 | clsid | semmle.label | clsid | +| windows.cpp:1142:5:1142:27 | ... = ... | semmle.label | ... = ... | +| windows.cpp:1142:14:1142:27 | call to source | semmle.label | call to source | +| windows.cpp:1144:21:1144:23 | *str | semmle.label | *str | +| windows.cpp:1144:26:1144:31 | CLSIDFromString output argument | semmle.label | CLSIDFromString output argument | +| windows.cpp:1145:10:1145:14 | clsid | semmle.label | clsid | +| windows.cpp:1148:19:1148:24 | call to source | semmle.label | call to source | +| windows.cpp:1148:19:1148:24 | call to source | semmle.label | call to source | +| windows.cpp:1150:21:1150:25 | *clsid | semmle.label | *clsid | +| windows.cpp:1150:28:1150:31 | StringFromCLSID output argument | semmle.label | StringFromCLSID output argument | +| windows.cpp:1152:10:1152:13 | * ... | semmle.label | * ... | +| windows.cpp:1155:17:1155:22 | call to source | semmle.label | call to source | +| windows.cpp:1155:17:1155:22 | call to source | semmle.label | call to source | +| windows.cpp:1157:20:1157:23 | *guid | semmle.label | *guid | +| windows.cpp:1157:26:1157:28 | StringFromGUID output argument | semmle.label | StringFromGUID output argument | +| windows.cpp:1159:10:1159:13 | * ... | semmle.label | * ... | +| windows.cpp:1163:5:1163:27 | ... = ... | semmle.label | ... = ... | +| windows.cpp:1163:14:1163:27 | call to source | semmle.label | call to source | +| windows.cpp:1165:20:1165:22 | *str | semmle.label | *str | +| windows.cpp:1165:25:1165:29 | GUIDFromString output argument | semmle.label | GUIDFromString output argument | +| windows.cpp:1166:10:1166:13 | guid | semmle.label | guid | +| windows.cpp:1169:17:1169:22 | call to source | semmle.label | call to source | +| windows.cpp:1169:17:1169:22 | call to source | semmle.label | call to source | +| windows.cpp:1171:21:1171:24 | *guid | semmle.label | *guid | +| windows.cpp:1171:27:1171:29 | StringFromGUID2 output argument | semmle.label | StringFromGUID2 output argument | +| windows.cpp:1173:10:1173:13 | * ... | semmle.label | * ... | subpaths | test.cpp:32:41:32:41 | x | test.cpp:7:47:7:52 | value2 | test.cpp:7:5:7:30 | *ymlStepGenerated_with_body | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | | test.cpp:172:51:172:51 | x | test.cpp:164:34:164:34 | x | test.cpp:164:7:164:7 | *templateFunction3 | test.cpp:172:13:172:44 | call to templateFunction3 | diff --git a/cpp/ql/test/library-tests/dataflow/external-models/steps.expected b/cpp/ql/test/library-tests/dataflow/external-models/steps.expected index 61b05459ade1..c6baaf658a3a 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/steps.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/steps.expected @@ -10,3 +10,12 @@ | test.cpp:28:35:28:35 | 0 | test.cpp:28:11:28:33 | call to ymlStepManual_with_body | | windows.cpp:27:36:27:38 | *cmd | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | | windows.cpp:729:35:729:35 | *x | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | +| windows.cpp:1116:19:1116:21 | *str | windows.cpp:1116:24:1116:27 | IIDFromString output argument | +| windows.cpp:1122:19:1122:21 | *iid | windows.cpp:1122:24:1122:27 | StringFromIID output argument | +| windows.cpp:1129:21:1129:25 | *clsid | windows.cpp:1129:28:1129:31 | ProgIDFromCLSID output argument | +| windows.cpp:1137:21:1137:26 | *progID | windows.cpp:1137:29:1137:34 | CLSIDFromProgID output argument | +| windows.cpp:1144:21:1144:23 | *str | windows.cpp:1144:26:1144:31 | CLSIDFromString output argument | +| windows.cpp:1150:21:1150:25 | *clsid | windows.cpp:1150:28:1150:31 | StringFromCLSID output argument | +| windows.cpp:1157:20:1157:23 | *guid | windows.cpp:1157:26:1157:28 | StringFromGUID output argument | +| windows.cpp:1165:20:1165:22 | *str | windows.cpp:1165:25:1165:29 | GUIDFromString output argument | +| windows.cpp:1171:21:1171:24 | *guid | windows.cpp:1171:27:1171:29 | StringFromGUID2 output argument | diff --git a/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp b/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp index e879beba4d33..7347a6119ff6 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp +++ b/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp @@ -1114,62 +1114,62 @@ void test_com_string_conversions() { str[0] = (char)source(); IID iid; IIDFromString(str, &iid); - sink(iid); // $ MISSING: ir + sink(iid); // $ ir } { IID iid = source(); LPOLESTR str = nullptr; StringFromIID(iid, &str); sink(str); - sink(*str); // $ MISSING: ir + sink(*str); // $ ir } { CLSID clsid = source(); LPOLESTR str = nullptr; ProgIDFromCLSID(clsid, &str); sink(str); - sink(*str); // $ MISSING: ir + sink(*str); // $ ir } { char progID[256]; progID[0] = (char)source(); CLSID clsid; CLSIDFromProgID(progID, &clsid); - sink(clsid); // $ MISSING: ir + sink(clsid); // $ ir } { char str[256]; str[0] = (char)source(); CLSID clsid; CLSIDFromString(str, &clsid); - sink(clsid); // $ MISSING: ir + sink(clsid); // $ ir } { CLSID clsid = source(); LPOLESTR str = nullptr; StringFromCLSID(clsid, &str); sink(str); - sink(*str); // $ MISSING: ir + sink(*str); // $ ir } { GUID guid = source(); char str[256]; StringFromGUID(guid, str); sink(str); - sink(*str); // $ MISSING: ir + sink(*str); // $ ir } { char str[256]; str[0] = (char)source(); GUID guid; GUIDFromString(str, &guid); - sink(guid); // $ MISSING: ir + sink(guid); // $ ir } { GUID guid = source(); char str[256]; StringFromGUID2(guid, str, 256); sink(str); - sink(*str); // $ MISSING: ir + sink(*str); // $ ir } } \ No newline at end of file From 754e40ba72950614ea7249398fb79956310c72b2 Mon Sep 17 00:00:00 2001 From: JarLob Date: Thu, 30 Jul 2026 19:05:20 +0300 Subject: [PATCH 149/188] Optimize Actions event source matching Bind event-property and event-context matching to source expressions so code-injection queries avoid materializing global source/event relations. --- .../codeql/actions/dataflow/FlowSources.qll | 64 ++++++++++++------- 1 file changed, 42 insertions(+), 22 deletions(-) diff --git a/actions/ql/lib/codeql/actions/dataflow/FlowSources.qll b/actions/ql/lib/codeql/actions/dataflow/FlowSources.qll index 18cc4322c81b..b4a279ac1151 100644 --- a/actions/ql/lib/codeql/actions/dataflow/FlowSources.qll +++ b/actions/ql/lib/codeql/actions/dataflow/FlowSources.qll @@ -52,29 +52,41 @@ class GitHubCtxSource extends RemoteFlowSource { override string getEventName() { result = event } } +bindingset[expression] +private predicate untrustedEventProperty(Expression expression, string kind) { + exists(string regexp | + untrustedEventPropertiesDataModel(regexp, kind) and + not kind = "json" and + normalizeExpr(expression.getExpression()).regexpMatch("(?i)\\s*" + wrapRegexp(regexp) + ".*") + ) +} + +bindingset[expression, event] +private predicate expressionContainsEventContext(Expression expression, string event) { + exists(string contextPrefix | + contextTriggerDataModel(event, contextPrefix) and + normalizeExpr(expression.getExpression()).matches("%" + contextPrefix + "%") + ) +} + class GitHubEventCtxSource extends RemoteFlowSource { string flag; string context; string event; GitHubEventCtxSource() { - exists(Expression e, string regexp | + exists(Expression e | this.asExpr() = e and context = e.getExpression() and ( // the context is available for the job trigger events event = e.getATriggerEvent().getName() and - exists(string context_prefix | - contextTriggerDataModel(event, context_prefix) and - normalizeExpr(context).matches("%" + context_prefix + "%") - ) + expressionContainsEventContext(e, event) or not exists(e.getATriggerEvent()) and event = "unknown" ) and - untrustedEventPropertiesDataModel(regexp, flag) and - not flag = "json" and - normalizeExpr(context).regexpMatch("(?i)\\s*" + wrapRegexp(regexp) + ".*") + untrustedEventProperty(e, flag) ) } @@ -177,32 +189,40 @@ class GitHubEventPathSource extends RemoteFlowSource, CommandSource { override Run getEnclosingRun() { result = run } } +bindingset[expression, event] +private predicate jsonSourceForEvent(Expression expression, string event) { + exists(string context, string regexp, string contextPrefix | + context = expression.getExpression() and + untrustedEventPropertiesDataModel(regexp, _) and + contextTriggerDataModel(event, contextPrefix) and + normalizeExpr(context).matches("%" + contextPrefix + "%") and + normalizeExpr(context).regexpMatch("(?i).*" + wrapJsonRegexp(regexp) + ".*") + ) + or + exists(string context, string regexp, string kind | + context = expression.getExpression() and + untrustedEventPropertiesDataModel(regexp, kind) and + contextTriggerDataModel(event, _) and + normalizeExpr(context).regexpMatch("(?i).*" + wrapJsonRegexp("\\bgithub.event\\b") + ".*") + ) +} + class GitHubEventJsonSource extends RemoteFlowSource { string flag; string event; GitHubEventJsonSource() { - exists(Expression e, string context, string regexp | + exists(Expression e | this.asExpr() = e and - context = e.getExpression() and - untrustedEventPropertiesDataModel(regexp, _) and ( // only contexts for the triggering events are considered tainted. // eg: for `pull_request`, we only consider `github.event.pull_request` event = e.getEnclosingWorkflow().getATriggerEvent().getName() and - exists(string context_prefix | - contextTriggerDataModel(event, context_prefix) and - normalizeExpr(context).matches("%" + context_prefix + "%") - ) and - normalizeExpr(context).regexpMatch("(?i).*" + wrapJsonRegexp(regexp) + ".*") - or - // github.event is tainted for all triggers - event = e.getEnclosingWorkflow().getATriggerEvent().getName() and - contextTriggerDataModel(e.getEnclosingWorkflow().getATriggerEvent().getName(), _) and - normalizeExpr(context).regexpMatch("(?i).*" + wrapJsonRegexp("\\bgithub.event\\b") + ".*") + jsonSourceForEvent(e, event) or not exists(e.getATriggerEvent()) and - event = "unknown" + event = "unknown" and + exists(string regexp, string kind | untrustedEventPropertiesDataModel(regexp, kind)) ) and flag = "json" ) From b4974ff19b4c4c93dfe59ee80b73afce07e42570 Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Thu, 30 Jul 2026 18:24:37 +0200 Subject: [PATCH 150/188] Add arm64 Linux support to prebuilt ripunzip The `ripunzip_archive` repository rule downloaded a prebuilt ripunzip for the host platform, but the Linux branch was hardcoded to the amd64 deb, so on an arm64 Linux host it would fetch an x86 binary. Switch on `repository_ctx.os.arch` (mirroring the macOS branch) to select the arm64 deb, which ripunzip publishes for the pinned version. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: c6404a7a-35d7-4294-b3b6-9231ca15ef25 --- MODULE.bazel | 1 + misc/ripunzip/ripunzip.bzl | 17 ++++++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index 24260271ecad..57a43361a11a 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -327,6 +327,7 @@ ripunzip_archive = use_repo_rule("//misc/ripunzip:ripunzip.bzl", "ripunzip_archi ripunzip_archive( name = "ripunzip", sha256_linux = "71482d7a7e4ea9176d5596161c49250c34b136b157c45f632b1111323fbfc0de", + sha256_linux_arm = "a282740ef376ff8dc0de3c589b7457598db15cc045b7daa688f15531612e0bbe", sha256_macos_arm = "604194ab13f0aba3972995d995f11002b8fc285c8170401fcd46655065df20c9", sha256_macos_intel = "65367b94fd579d93d46f2d2595cc4c9a60cfcf497e3c824f9d1a7b80fa8bd38a", sha256_windows = "ac3874075def2b9e5074a3b5945005ab082cc6e689e1de658da8965bc23e643e", diff --git a/misc/ripunzip/ripunzip.bzl b/misc/ripunzip/ripunzip.bzl index 2e707c267e24..faf42fa8199f 100644 --- a/misc/ripunzip/ripunzip.bzl +++ b/misc/ripunzip/ripunzip.bzl @@ -3,12 +3,22 @@ def _ripunzip_archive_impl(repository_ctx): url_prefix = "https://github.com/GoogleChrome/ripunzip/releases/download/v%s" % version build_file = Label("//misc/ripunzip:BUILD.ripunzip.bazel") if "linux" in repository_ctx.os.name: + arch = repository_ctx.os.arch + if arch in ("aarch64", "arm64"): + deb_arch = "arm64" + sha256 = repository_ctx.attr.sha256_linux_arm + canonical_id = "ripunzip-linux-arm" + else: + deb_arch = "amd64" + sha256 = repository_ctx.attr.sha256_linux + canonical_id = "ripunzip-linux" + # ripunzip only provides a deb package for Linux: we fish the binary out of it # a deb archive contains a data.tar.xz one which contains the files to be installed under usr/bin repository_ctx.download_and_extract( - url = "%s/ripunzip_%s-1_amd64.deb" % (url_prefix, version), - sha256 = repository_ctx.attr.sha256_linux, - canonical_id = "ripunzip-linux", + url = "%s/ripunzip_%s-1_%s.deb" % (url_prefix, version, deb_arch), + sha256 = sha256, + canonical_id = canonical_id, output = "deb", ) repository_ctx.extract( @@ -52,6 +62,7 @@ ripunzip_archive = repository_rule( attrs = { "version": attr.string(mandatory = True), "sha256_linux": attr.string(mandatory = True), + "sha256_linux_arm": attr.string(mandatory = True), "sha256_windows": attr.string(mandatory = True), "sha256_macos_intel": attr.string(mandatory = True), "sha256_macos_arm": attr.string(mandatory = True), From 343a8db4dac125f23245cdd07d53f825d89f9475 Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Thu, 30 Jul 2026 18:26:01 +0200 Subject: [PATCH 151/188] Match aarch64 only for Linux arch, per bazel os.arch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit repository_ctx.os.arch reports the lower-cased Java os.arch property, which is "aarch64" on Linux arm64 — same as the macOS branch below. Drop the redundant "arm64" alternative. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: c6404a7a-35d7-4294-b3b6-9231ca15ef25 --- misc/ripunzip/ripunzip.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/ripunzip/ripunzip.bzl b/misc/ripunzip/ripunzip.bzl index faf42fa8199f..148c4dfbc7fe 100644 --- a/misc/ripunzip/ripunzip.bzl +++ b/misc/ripunzip/ripunzip.bzl @@ -4,7 +4,7 @@ def _ripunzip_archive_impl(repository_ctx): build_file = Label("//misc/ripunzip:BUILD.ripunzip.bazel") if "linux" in repository_ctx.os.name: arch = repository_ctx.os.arch - if arch in ("aarch64", "arm64"): + if arch == "aarch64": deb_arch = "arm64" sha256 = repository_ctx.attr.sha256_linux_arm canonical_id = "ripunzip-linux-arm" From 9f272f24f133c9d4801ce81ab5b404b06f482bc5 Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Thu, 30 Jul 2026 18:27:59 +0200 Subject: [PATCH 152/188] Use consistent x64/arm64 arch suffixes for ripunzip sha attrs Rename the sha256 attributes (and matching canonical_ids) to a single scheme across all platforms: _x64 / _arm64. This replaces the inconsistent sha256_linux (no suffix), sha256_macos_intel and sha256_macos_arm. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: c6404a7a-35d7-4294-b3b6-9231ca15ef25 --- MODULE.bazel | 10 +++++----- misc/ripunzip/ripunzip.bzl | 30 +++++++++++++++--------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index 57a43361a11a..e8d49c11bcb4 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -326,11 +326,11 @@ ripunzip_archive = use_repo_rule("//misc/ripunzip:ripunzip.bzl", "ripunzip_archi # go to https://github.com/GoogleChrome/ripunzip/releases to find latest version and corresponding sha256s ripunzip_archive( name = "ripunzip", - sha256_linux = "71482d7a7e4ea9176d5596161c49250c34b136b157c45f632b1111323fbfc0de", - sha256_linux_arm = "a282740ef376ff8dc0de3c589b7457598db15cc045b7daa688f15531612e0bbe", - sha256_macos_arm = "604194ab13f0aba3972995d995f11002b8fc285c8170401fcd46655065df20c9", - sha256_macos_intel = "65367b94fd579d93d46f2d2595cc4c9a60cfcf497e3c824f9d1a7b80fa8bd38a", - sha256_windows = "ac3874075def2b9e5074a3b5945005ab082cc6e689e1de658da8965bc23e643e", + sha256_linux_arm64 = "a282740ef376ff8dc0de3c589b7457598db15cc045b7daa688f15531612e0bbe", + sha256_linux_x64 = "71482d7a7e4ea9176d5596161c49250c34b136b157c45f632b1111323fbfc0de", + sha256_macos_arm64 = "604194ab13f0aba3972995d995f11002b8fc285c8170401fcd46655065df20c9", + sha256_macos_x64 = "65367b94fd579d93d46f2d2595cc4c9a60cfcf497e3c824f9d1a7b80fa8bd38a", + sha256_windows_x64 = "ac3874075def2b9e5074a3b5945005ab082cc6e689e1de658da8965bc23e643e", version = "2.0.4", ) diff --git a/misc/ripunzip/ripunzip.bzl b/misc/ripunzip/ripunzip.bzl index 148c4dfbc7fe..53f22c53e0a3 100644 --- a/misc/ripunzip/ripunzip.bzl +++ b/misc/ripunzip/ripunzip.bzl @@ -6,12 +6,12 @@ def _ripunzip_archive_impl(repository_ctx): arch = repository_ctx.os.arch if arch == "aarch64": deb_arch = "arm64" - sha256 = repository_ctx.attr.sha256_linux_arm - canonical_id = "ripunzip-linux-arm" + sha256 = repository_ctx.attr.sha256_linux_arm64 + canonical_id = "ripunzip-linux-arm64" else: deb_arch = "amd64" - sha256 = repository_ctx.attr.sha256_linux - canonical_id = "ripunzip-linux" + sha256 = repository_ctx.attr.sha256_linux_x64 + canonical_id = "ripunzip-linux-x64" # ripunzip only provides a deb package for Linux: we fish the binary out of it # a deb archive contains a data.tar.xz one which contains the files to be installed under usr/bin @@ -29,20 +29,20 @@ def _ripunzip_archive_impl(repository_ctx): elif "windows" in repository_ctx.os.name: repository_ctx.download_and_extract( url = "%s/ripunzip_v%s_x86_64-pc-windows-msvc.zip" % (url_prefix, version), - canonical_id = "ripunzip-windows", - sha256 = repository_ctx.attr.sha256_windows, + canonical_id = "ripunzip-windows-x64", + sha256 = repository_ctx.attr.sha256_windows_x64, output = "bin", ) elif "mac os" in repository_ctx.os.name: arch = repository_ctx.os.arch if arch == "x86_64": suffix = "x86_64-apple-darwin" - sha256 = repository_ctx.attr.sha256_macos_intel - canonical_id = "ripunzip-macos-intel" + sha256 = repository_ctx.attr.sha256_macos_x64 + canonical_id = "ripunzip-macos-x64" elif arch == "aarch64": suffix = "aarch64-apple-darwin" - sha256 = repository_ctx.attr.sha256_macos_arm - canonical_id = "ripunzip-macos-arm" + sha256 = repository_ctx.attr.sha256_macos_arm64 + canonical_id = "ripunzip-macos-arm64" else: fail("Unsupported macOS architecture: %s" % arch) repository_ctx.download_and_extract( @@ -61,10 +61,10 @@ ripunzip_archive = repository_rule( doc = "Downloads a prebuilt ripunzip binary for the host platform from https://github.com/GoogleChrome/ripunzip/releases", attrs = { "version": attr.string(mandatory = True), - "sha256_linux": attr.string(mandatory = True), - "sha256_linux_arm": attr.string(mandatory = True), - "sha256_windows": attr.string(mandatory = True), - "sha256_macos_intel": attr.string(mandatory = True), - "sha256_macos_arm": attr.string(mandatory = True), + "sha256_linux_x64": attr.string(mandatory = True), + "sha256_linux_arm64": attr.string(mandatory = True), + "sha256_windows_x64": attr.string(mandatory = True), + "sha256_macos_x64": attr.string(mandatory = True), + "sha256_macos_arm64": attr.string(mandatory = True), }, ) From 8aff07cdcf9eb8ace3dd71f1c0be759393a33312 Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Thu, 30 Jul 2026 18:32:25 +0200 Subject: [PATCH 153/188] Fail explicitly on unsupported Linux architectures for ripunzip Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: c6404a7a-35d7-4294-b3b6-9231ca15ef25 --- misc/ripunzip/ripunzip.bzl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/misc/ripunzip/ripunzip.bzl b/misc/ripunzip/ripunzip.bzl index 53f22c53e0a3..5b049d901273 100644 --- a/misc/ripunzip/ripunzip.bzl +++ b/misc/ripunzip/ripunzip.bzl @@ -8,10 +8,12 @@ def _ripunzip_archive_impl(repository_ctx): deb_arch = "arm64" sha256 = repository_ctx.attr.sha256_linux_arm64 canonical_id = "ripunzip-linux-arm64" - else: + elif arch in ("x86_64", "amd64"): deb_arch = "amd64" sha256 = repository_ctx.attr.sha256_linux_x64 canonical_id = "ripunzip-linux-x64" + else: + fail("Unsupported Linux architecture: %s" % arch) # ripunzip only provides a deb package for Linux: we fish the binary out of it # a deb archive contains a data.tar.xz one which contains the files to be installed under usr/bin From d2f52440807585a8637906c720f8b6c3147c342c Mon Sep 17 00:00:00 2001 From: JarLob Date: Thu, 30 Jul 2026 19:39:25 +0300 Subject: [PATCH 154/188] Address cache poisoning review feedback --- .../ql/lib/codeql/actions/dataflow/FlowSources.qll | 6 +++--- .../cache_write_capable_workflow_dispatch.yml | 12 ++++++++++-- .../CWE-349/CachePoisoningViaDirectCache.expected | 7 ++++--- .../CWE-349/CachePoisoningViaPoisonableStep.expected | 7 ++++--- 4 files changed, 21 insertions(+), 11 deletions(-) diff --git a/actions/ql/lib/codeql/actions/dataflow/FlowSources.qll b/actions/ql/lib/codeql/actions/dataflow/FlowSources.qll index b4a279ac1151..f44a4603df19 100644 --- a/actions/ql/lib/codeql/actions/dataflow/FlowSources.qll +++ b/actions/ql/lib/codeql/actions/dataflow/FlowSources.qll @@ -199,9 +199,9 @@ private predicate jsonSourceForEvent(Expression expression, string event) { normalizeExpr(context).regexpMatch("(?i).*" + wrapJsonRegexp(regexp) + ".*") ) or - exists(string context, string regexp, string kind | + exists(string context | context = expression.getExpression() and - untrustedEventPropertiesDataModel(regexp, kind) and + untrustedEventPropertiesDataModel(_, _) and contextTriggerDataModel(event, _) and normalizeExpr(context).regexpMatch("(?i).*" + wrapJsonRegexp("\\bgithub.event\\b") + ".*") ) @@ -222,7 +222,7 @@ class GitHubEventJsonSource extends RemoteFlowSource { or not exists(e.getATriggerEvent()) and event = "unknown" and - exists(string regexp, string kind | untrustedEventPropertiesDataModel(regexp, kind)) + untrustedEventPropertiesDataModel(_, _) ) and flag = "json" ) diff --git a/actions/ql/test/query-tests/Security/CWE-349/.github/workflows/cache_write_capable_workflow_dispatch.yml b/actions/ql/test/query-tests/Security/CWE-349/.github/workflows/cache_write_capable_workflow_dispatch.yml index 74695bc76942..5b9510222ac7 100644 --- a/actions/ql/test/query-tests/Security/CWE-349/.github/workflows/cache_write_capable_workflow_dispatch.yml +++ b/actions/ql/test/query-tests/Security/CWE-349/.github/workflows/cache_write_capable_workflow_dispatch.yml @@ -1,15 +1,23 @@ -on: workflow_dispatch +on: + workflow_dispatch: + inputs: + head_sha: + description: Commit SHA to test + required: true + type: string jobs: cache: permissions: {} runs-on: ubuntu-latest steps: + - uses: actions/checkout@v4 - env: HEAD_SHA: ${{ github.event.inputs.head_sha }} run: | + [[ "$HEAD_SHA" =~ ^[0-9a-fA-F]{40}$ ]] || exit 1 git fetch origin "$HEAD_SHA" - git checkout "$HEAD_SHA" + git checkout --detach "$HEAD_SHA" - run: npm install - uses: actions/cache@v4 with: diff --git a/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaDirectCache.expected b/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaDirectCache.expected index 8d0b858d0035..0491a0de4e8d 100644 --- a/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaDirectCache.expected +++ b/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaDirectCache.expected @@ -1,6 +1,7 @@ edges -| .github/workflows/cache_write_capable_workflow_dispatch.yml:8:9:13:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:13:9:14:6 | Run Step | -| .github/workflows/cache_write_capable_workflow_dispatch.yml:13:9:14:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:14:9:17:33 | Uses Step | +| .github/workflows/cache_write_capable_workflow_dispatch.yml:14:9:15:6 | Uses Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:15:9:21:6 | Run Step | +| .github/workflows/cache_write_capable_workflow_dispatch.yml:15:9:21:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:21:9:22:6 | Run Step | +| .github/workflows/cache_write_capable_workflow_dispatch.yml:21:9:22:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:22:9:25:33 | Uses Step | | .github/workflows/code_injection2.yml:12:9:16:6 | Uses Step: modified_files | .github/workflows/code_injection2.yml:16:9:16:71 | Run Step | | .github/workflows/direct_cache1.yml:10:9:13:6 | Uses Step: comment-branch | .github/workflows/direct_cache1.yml:13:9:18:6 | Uses Step | | .github/workflows/direct_cache1.yml:13:9:18:6 | Uses Step | .github/workflows/direct_cache1.yml:18:9:22:6 | Uses Step | @@ -46,4 +47,4 @@ edges | .github/workflows/poisonable_step5.yml:17:9:22:6 | Uses Step | .github/workflows/poisonable_step5.yml:22:9:24:6 | Uses Step | | .github/workflows/poisonable_step5.yml:22:9:24:6 | Uses Step | .github/workflows/poisonable_step5.yml:24:9:28:31 | Uses Step | #select -| .github/workflows/cache_write_capable_workflow_dispatch.yml:14:9:17:33 | Uses Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:8:9:13:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:14:9:17:33 | Uses Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/cache_write_capable_workflow_dispatch.yml:1:5:1:21 | workflow_dispatch | workflow_dispatch | +| .github/workflows/cache_write_capable_workflow_dispatch.yml:22:9:25:33 | Uses Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:15:9:21:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:22:9:25:33 | Uses Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/cache_write_capable_workflow_dispatch.yml:2:3:2:19 | workflow_dispatch | workflow_dispatch | diff --git a/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaPoisonableStep.expected b/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaPoisonableStep.expected index ba48d939eda7..0b637891d8e0 100644 --- a/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaPoisonableStep.expected +++ b/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaPoisonableStep.expected @@ -1,6 +1,7 @@ edges -| .github/workflows/cache_write_capable_workflow_dispatch.yml:8:9:13:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:13:9:14:6 | Run Step | -| .github/workflows/cache_write_capable_workflow_dispatch.yml:13:9:14:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:14:9:17:33 | Uses Step | +| .github/workflows/cache_write_capable_workflow_dispatch.yml:14:9:15:6 | Uses Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:15:9:21:6 | Run Step | +| .github/workflows/cache_write_capable_workflow_dispatch.yml:15:9:21:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:21:9:22:6 | Run Step | +| .github/workflows/cache_write_capable_workflow_dispatch.yml:21:9:22:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:22:9:25:33 | Uses Step | | .github/workflows/code_injection2.yml:12:9:16:6 | Uses Step: modified_files | .github/workflows/code_injection2.yml:16:9:16:71 | Run Step | | .github/workflows/direct_cache1.yml:10:9:13:6 | Uses Step: comment-branch | .github/workflows/direct_cache1.yml:13:9:18:6 | Uses Step | | .github/workflows/direct_cache1.yml:13:9:18:6 | Uses Step | .github/workflows/direct_cache1.yml:18:9:22:6 | Uses Step | @@ -46,4 +47,4 @@ edges | .github/workflows/poisonable_step5.yml:17:9:22:6 | Uses Step | .github/workflows/poisonable_step5.yml:22:9:24:6 | Uses Step | | .github/workflows/poisonable_step5.yml:22:9:24:6 | Uses Step | .github/workflows/poisonable_step5.yml:24:9:28:31 | Uses Step | #select -| .github/workflows/cache_write_capable_workflow_dispatch.yml:13:9:14:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:8:9:13:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:13:9:14:6 | Run Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/cache_write_capable_workflow_dispatch.yml:1:5:1:21 | workflow_dispatch | workflow_dispatch | +| .github/workflows/cache_write_capable_workflow_dispatch.yml:21:9:22:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:15:9:21:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:21:9:22:6 | Run Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/cache_write_capable_workflow_dispatch.yml:2:3:2:19 | workflow_dispatch | workflow_dispatch | From b1867d8e13d892a32ffc55d80e97cc8ed99a9cf7 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 30 Jul 2026 23:01:58 +0100 Subject: [PATCH 155/188] C++: Respond to Copilot comments. --- cpp/ql/lib/ext/Windows.model.yml | 4 +- .../dataflow/external-models/flow.expected | 489 +++++++++--------- .../dataflow/external-models/sources.expected | 22 +- .../dataflow/external-models/steps.expected | 18 +- .../dataflow/external-models/windows.cpp | 11 +- 5 files changed, 281 insertions(+), 263 deletions(-) diff --git a/cpp/ql/lib/ext/Windows.model.yml b/cpp/ql/lib/ext/Windows.model.yml index d62e5e9e73b8..8e46aa79323b 100644 --- a/cpp/ql/lib/ext/Windows.model.yml +++ b/cpp/ql/lib/ext/Windows.model.yml @@ -45,8 +45,8 @@ extensions: - ["", "", False, "RegQueryMultipleValuesA", "", "", "Argument[*3]", "windows-registry", "manual"] # TODO: Once we support access paths at sources we should also mark Argument[*1].Field[*ve_valueptr] - ["", "", False, "RegQueryMultipleValuesW", "", "", "Argument[*3]", "windows-registry", "manual"] - - ["", "", False, "RegEnumValueA", "", "", "Argument[*6]", "windows-registry", "manual"] - - ["", "", False, "RegEnumValueW", "", "", "Argument[*6]", "windows-registry", "manual"] + - ["", "", False, "RegEnumValueA", "", "", "Argument[*2,*6]", "windows-registry", "manual"] + - ["", "", False, "RegEnumValueW", "", "", "Argument[*2,*6]", "windows-registry", "manual"] - addsTo: pack: codeql/cpp-all extensible: summaryModel diff --git a/cpp/ql/test/library-tests/dataflow/external-models/flow.expected b/cpp/ql/test/library-tests/dataflow/external-models/flow.expected index 9a5d1131a613..cd9aad336ebe 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/flow.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/flow.expected @@ -17,122 +17,123 @@ models | 16 | Source: ; ; false; NtReadFile; ; ; Argument[*5]; local; manual | | 17 | Source: ; ; false; ReadFile; ; ; Argument[*1]; local; manual | | 18 | Source: ; ; false; ReadFileEx; ; ; Argument[*1]; local; manual | -| 19 | Source: ; ; false; RegEnumValueA; ; ; Argument[*6]; windows-registry; manual | -| 20 | Source: ; ; false; RegEnumValueW; ; ; Argument[*6]; windows-registry; manual | +| 19 | Source: ; ; false; RegEnumValueA; ; ; Argument[*2,*6]; windows-registry; manual | +| 20 | Source: ; ; false; RegEnumValueW; ; ; Argument[*2,*6]; windows-registry; manual | | 21 | Source: ; ; false; RegGetValueA; ; ; Argument[*5]; windows-registry; manual | -| 22 | Source: ; ; false; RegQueryMultipleValuesA; ; ; Argument[*3]; windows-registry; manual | -| 23 | Source: ; ; false; RegQueryMultipleValuesW; ; ; Argument[*3]; windows-registry; manual | -| 24 | Source: ; ; false; RegQueryValueA; ; ; Argument[*2]; windows-registry; manual | -| 25 | Source: ; ; false; RegQueryValueExA; ; ; Argument[*4]; windows-registry; manual | -| 26 | Source: ; ; false; RegQueryValueExW; ; ; Argument[*4]; windows-registry; manual | -| 27 | Source: ; ; false; RegQueryValueW; ; ; Argument[*2]; windows-registry; manual | -| 28 | Source: ; ; false; WinHttpQueryHeaders; ; ; Argument[*3]; remote; manual | -| 29 | Source: ; ; false; WinHttpQueryHeadersEx; ; ; Argument[**8]; remote; manual | -| 30 | Source: ; ; false; WinHttpQueryHeadersEx; ; ; Argument[*5]; remote; manual | -| 31 | Source: ; ; false; WinHttpQueryHeadersEx; ; ; Argument[*6]; remote; manual | -| 32 | Source: ; ; false; WinHttpReadData; ; ; Argument[*1]; remote; manual | -| 33 | Source: ; ; false; WinHttpReadDataEx; ; ; Argument[*1]; remote; manual | -| 34 | Source: ; ; false; ymlSource; ; ; ReturnValue; local; manual | -| 35 | Source: Azure::Core::Http; RawResponse; true; ExtractBodyStream; ; ; ReturnValue[*]; remote; manual | -| 36 | Source: Azure::Core::Http; RawResponse; true; GetBody; ; ; ReturnValue[*]; remote; manual | -| 37 | Source: Azure::Core::Http; RawResponse; true; GetHeaders; ; ; ReturnValue[*]; remote; manual | -| 38 | Source: Azure::Core::Http; Request; true; GetBodyStream; ; ; ReturnValue[*]; remote; manual | -| 39 | Source: Azure::Core::Http; Request; true; GetHeader; ; ; ReturnValue; remote; manual | -| 40 | Source: Azure::Core::Http; Request; true; GetHeaders; ; ; ReturnValue; remote; manual | -| 41 | Source: boost::asio; ; false; read_until; ; ; Argument[*1]; remote; manual | -| 42 | Summary: ; ; false; CLSIDFromProgID; ; ; Argument[*0]; Argument[*1]; taint; manual | -| 43 | Summary: ; ; false; CLSIDFromString; ; ; Argument[*0]; Argument[*1]; taint; manual | -| 44 | Summary: ; ; false; CommandLineToArgvA; ; ; Argument[*0]; ReturnValue[**]; taint; manual | -| 45 | Summary: ; ; false; CreateRemoteThread; ; ; Argument[@4]; Argument[3].Parameter[@0]; value; manual | -| 46 | Summary: ; ; false; CreateRemoteThreadEx; ; ; Argument[@4]; Argument[3].Parameter[@0]; value; manual | -| 47 | Summary: ; ; false; CreateThread; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual | -| 48 | Summary: ; ; false; GUIDFromString; ; ; Argument[*0]; Argument[*1]; taint; manual | -| 49 | Summary: ; ; false; IIDFromString; ; ; Argument[*0]; Argument[*1]; taint; manual | -| 50 | Summary: ; ; false; ProgIDFromCLSID; ; ; Argument[*0]; Argument[**1]; taint; manual | -| 51 | Summary: ; ; false; ReadFileEx; ; ; Argument[*3].Field[@hEvent]; Argument[4].Parameter[*2].Field[@hEvent]; value; manual | -| 52 | Summary: ; ; false; RtlCopyDeviceMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | -| 53 | Summary: ; ; false; RtlCopyMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | -| 54 | Summary: ; ; false; RtlCopyMemoryNonTemporal; ; ; Argument[*@1]; Argument[*@0]; value; manual | -| 55 | Summary: ; ; false; RtlCopyUnicodeString; ; ; Argument[*1].Field[*Buffer]; Argument[*0].Field[*Buffer]; value; manual | -| 56 | Summary: ; ; false; RtlCopyVolatileMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | -| 57 | Summary: ; ; false; RtlInitUnicodeString; ; ; Argument[*1]; Argument[*0].Field[*Buffer]; value; manual | -| 58 | Summary: ; ; false; RtlMoveMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | -| 59 | Summary: ; ; false; RtlMoveVolatileMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | -| 60 | Summary: ; ; false; StringFromCLSID; ; ; Argument[*0]; Argument[**1]; taint; manual | -| 61 | Summary: ; ; false; StringFromGUID2; ; ; Argument[*0]; Argument[*1]; taint; manual | -| 62 | Summary: ; ; false; StringFromGUID; ; ; Argument[*0]; Argument[*1]; taint; manual | -| 63 | Summary: ; ; false; StringFromIID; ; ; Argument[*0]; Argument[**1]; taint; manual | -| 64 | Summary: ; ; false; WinHttpCrackUrl; ; ; Argument[*0]; Argument[*3]; taint; manual | -| 65 | Summary: ; ; false; callWithArgument; ; ; Argument[1]; Argument[0].Parameter[0]; value; manual | -| 66 | Summary: ; ; false; callWithNonTypeTemplate; (const T &); ; Argument[*0]; ReturnValue; value; manual | -| 67 | Summary: ; ; false; pthread_create; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual | -| 68 | Summary: ; ; false; read_field_from_struct; ; ; Argument[*0].Field[MyNamespace::MyStructInNamespace::myField]; ReturnValue; value; manual | -| 69 | Summary: ; ; false; read_field_from_struct_2; ; ; Argument[*0].Field[MyGlobalStruct::myField]; ReturnValue; value; manual | -| 70 | Summary: ; ; false; ymlStepGenerated; ; ; Argument[0]; ReturnValue; taint; df-generated | -| 71 | Summary: ; ; false; ymlStepManual; ; ; Argument[0]; ReturnValue; taint; manual | -| 72 | Summary: ; ; false; ymlStepManual_with_body; ; ; Argument[0]; ReturnValue; taint; manual | -| 73 | Summary: ; MyString; true; operator[]; ; ; Argument[-1]; ReturnValue[*]; taint; manual | -| 74 | Summary: ; MyString; true; operator[]; ; ; ReturnValue[*]; Argument[-1]; taint; manual | -| 75 | Summary: ; ReverseFlow; true; get_ptr; ; ; ReturnValue[*]; Argument[-1].Field[ReverseFlow::value]; value; manual | -| 76 | Summary: ; TemplateClass1; true; templateFunction2; (U,V); ; Argument[1]; ReturnValue; value; manual | -| 77 | Summary: ; TemplateClass1; false; templateFunction; (T,U); ; Argument[0]; ReturnValue; value; manual | -| 78 | Summary: ; TemplateClass2; true; function; (U,T); ; Argument[1]; ReturnValue; value; manual | -| 79 | Summary: Azure::Core::IO; BodyStream; true; Read; ; ; Argument[-1]; Argument[*0]; taint; manual | -| 80 | Summary: Azure::Core::IO; BodyStream; true; ReadToCount; ; ; Argument[-1]; Argument[*0]; taint; manual | -| 81 | Summary: Azure::Core::IO; BodyStream; true; ReadToEnd; ; ; Argument[-1]; ReturnValue.Element; taint; manual | -| 82 | Summary: Azure; Nullable; true; Value; ; ; Argument[-1]; ReturnValue[*]; taint; manual | -| 83 | Summary: boost::asio; ; false; buffer; ; ; Argument[*0]; ReturnValue; taint; manual | +| 22 | Source: ; ; false; RegGetValueW; ; ; Argument[*5]; windows-registry; manual | +| 23 | Source: ; ; false; RegQueryMultipleValuesA; ; ; Argument[*3]; windows-registry; manual | +| 24 | Source: ; ; false; RegQueryMultipleValuesW; ; ; Argument[*3]; windows-registry; manual | +| 25 | Source: ; ; false; RegQueryValueA; ; ; Argument[*2]; windows-registry; manual | +| 26 | Source: ; ; false; RegQueryValueExA; ; ; Argument[*4]; windows-registry; manual | +| 27 | Source: ; ; false; RegQueryValueExW; ; ; Argument[*4]; windows-registry; manual | +| 28 | Source: ; ; false; RegQueryValueW; ; ; Argument[*2]; windows-registry; manual | +| 29 | Source: ; ; false; WinHttpQueryHeaders; ; ; Argument[*3]; remote; manual | +| 30 | Source: ; ; false; WinHttpQueryHeadersEx; ; ; Argument[**8]; remote; manual | +| 31 | Source: ; ; false; WinHttpQueryHeadersEx; ; ; Argument[*5]; remote; manual | +| 32 | Source: ; ; false; WinHttpQueryHeadersEx; ; ; Argument[*6]; remote; manual | +| 33 | Source: ; ; false; WinHttpReadData; ; ; Argument[*1]; remote; manual | +| 34 | Source: ; ; false; WinHttpReadDataEx; ; ; Argument[*1]; remote; manual | +| 35 | Source: ; ; false; ymlSource; ; ; ReturnValue; local; manual | +| 36 | Source: Azure::Core::Http; RawResponse; true; ExtractBodyStream; ; ; ReturnValue[*]; remote; manual | +| 37 | Source: Azure::Core::Http; RawResponse; true; GetBody; ; ; ReturnValue[*]; remote; manual | +| 38 | Source: Azure::Core::Http; RawResponse; true; GetHeaders; ; ; ReturnValue[*]; remote; manual | +| 39 | Source: Azure::Core::Http; Request; true; GetBodyStream; ; ; ReturnValue[*]; remote; manual | +| 40 | Source: Azure::Core::Http; Request; true; GetHeader; ; ; ReturnValue; remote; manual | +| 41 | Source: Azure::Core::Http; Request; true; GetHeaders; ; ; ReturnValue; remote; manual | +| 42 | Source: boost::asio; ; false; read_until; ; ; Argument[*1]; remote; manual | +| 43 | Summary: ; ; false; CLSIDFromProgID; ; ; Argument[*0]; Argument[*1]; taint; manual | +| 44 | Summary: ; ; false; CLSIDFromString; ; ; Argument[*0]; Argument[*1]; taint; manual | +| 45 | Summary: ; ; false; CommandLineToArgvA; ; ; Argument[*0]; ReturnValue[**]; taint; manual | +| 46 | Summary: ; ; false; CreateRemoteThread; ; ; Argument[@4]; Argument[3].Parameter[@0]; value; manual | +| 47 | Summary: ; ; false; CreateRemoteThreadEx; ; ; Argument[@4]; Argument[3].Parameter[@0]; value; manual | +| 48 | Summary: ; ; false; CreateThread; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual | +| 49 | Summary: ; ; false; GUIDFromString; ; ; Argument[*0]; Argument[*1]; taint; manual | +| 50 | Summary: ; ; false; IIDFromString; ; ; Argument[*0]; Argument[*1]; taint; manual | +| 51 | Summary: ; ; false; ProgIDFromCLSID; ; ; Argument[*0]; Argument[**1]; taint; manual | +| 52 | Summary: ; ; false; ReadFileEx; ; ; Argument[*3].Field[@hEvent]; Argument[4].Parameter[*2].Field[@hEvent]; value; manual | +| 53 | Summary: ; ; false; RtlCopyDeviceMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | +| 54 | Summary: ; ; false; RtlCopyMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | +| 55 | Summary: ; ; false; RtlCopyMemoryNonTemporal; ; ; Argument[*@1]; Argument[*@0]; value; manual | +| 56 | Summary: ; ; false; RtlCopyUnicodeString; ; ; Argument[*1].Field[*Buffer]; Argument[*0].Field[*Buffer]; value; manual | +| 57 | Summary: ; ; false; RtlCopyVolatileMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | +| 58 | Summary: ; ; false; RtlInitUnicodeString; ; ; Argument[*1]; Argument[*0].Field[*Buffer]; value; manual | +| 59 | Summary: ; ; false; RtlMoveMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | +| 60 | Summary: ; ; false; RtlMoveVolatileMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | +| 61 | Summary: ; ; false; StringFromCLSID; ; ; Argument[*0]; Argument[**1]; taint; manual | +| 62 | Summary: ; ; false; StringFromGUID2; ; ; Argument[*0]; Argument[*1]; taint; manual | +| 63 | Summary: ; ; false; StringFromGUID; ; ; Argument[*0]; Argument[*1]; taint; manual | +| 64 | Summary: ; ; false; StringFromIID; ; ; Argument[*0]; Argument[**1]; taint; manual | +| 65 | Summary: ; ; false; WinHttpCrackUrl; ; ; Argument[*0]; Argument[*3]; taint; manual | +| 66 | Summary: ; ; false; callWithArgument; ; ; Argument[1]; Argument[0].Parameter[0]; value; manual | +| 67 | Summary: ; ; false; callWithNonTypeTemplate; (const T &); ; Argument[*0]; ReturnValue; value; manual | +| 68 | Summary: ; ; false; pthread_create; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual | +| 69 | Summary: ; ; false; read_field_from_struct; ; ; Argument[*0].Field[MyNamespace::MyStructInNamespace::myField]; ReturnValue; value; manual | +| 70 | Summary: ; ; false; read_field_from_struct_2; ; ; Argument[*0].Field[MyGlobalStruct::myField]; ReturnValue; value; manual | +| 71 | Summary: ; ; false; ymlStepGenerated; ; ; Argument[0]; ReturnValue; taint; df-generated | +| 72 | Summary: ; ; false; ymlStepManual; ; ; Argument[0]; ReturnValue; taint; manual | +| 73 | Summary: ; ; false; ymlStepManual_with_body; ; ; Argument[0]; ReturnValue; taint; manual | +| 74 | Summary: ; MyString; true; operator[]; ; ; Argument[-1]; ReturnValue[*]; taint; manual | +| 75 | Summary: ; MyString; true; operator[]; ; ; ReturnValue[*]; Argument[-1]; taint; manual | +| 76 | Summary: ; ReverseFlow; true; get_ptr; ; ; ReturnValue[*]; Argument[-1].Field[ReverseFlow::value]; value; manual | +| 77 | Summary: ; TemplateClass1; true; templateFunction2; (U,V); ; Argument[1]; ReturnValue; value; manual | +| 78 | Summary: ; TemplateClass1; false; templateFunction; (T,U); ; Argument[0]; ReturnValue; value; manual | +| 79 | Summary: ; TemplateClass2; true; function; (U,T); ; Argument[1]; ReturnValue; value; manual | +| 80 | Summary: Azure::Core::IO; BodyStream; true; Read; ; ; Argument[-1]; Argument[*0]; taint; manual | +| 81 | Summary: Azure::Core::IO; BodyStream; true; ReadToCount; ; ; Argument[-1]; Argument[*0]; taint; manual | +| 82 | Summary: Azure::Core::IO; BodyStream; true; ReadToEnd; ; ; Argument[-1]; ReturnValue.Element; taint; manual | +| 83 | Summary: Azure; Nullable; true; Value; ; ; Argument[-1]; ReturnValue[*]; taint; manual | +| 84 | Summary: boost::asio; ; false; buffer; ; ; Argument[*0]; ReturnValue; taint; manual | edges -| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:91:7:91:17 | recv_buffer | provenance | Src:MaD:41 | -| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:93:29:93:39 | *recv_buffer | provenance | Src:MaD:41 Sink:MaD:2 | +| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:91:7:91:17 | recv_buffer | provenance | Src:MaD:42 | +| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:93:29:93:39 | *recv_buffer | provenance | Src:MaD:42 Sink:MaD:2 | | asio_streams.cpp:97:37:97:44 | call to source | asio_streams.cpp:98:7:98:14 | send_str | provenance | TaintFunction | | asio_streams.cpp:97:37:97:44 | call to source | asio_streams.cpp:100:64:100:71 | *send_str | provenance | TaintFunction | | asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | | | asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:101:7:101:17 | send_buffer | provenance | | | asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:103:29:103:39 | *send_buffer | provenance | Sink:MaD:2 | -| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:83 | -| azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:253:48:253:60 | *call to GetBodyStream | provenance | Src:MaD:38 | +| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:84 | +| azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:253:48:253:60 | *call to GetBodyStream | provenance | Src:MaD:39 | | azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:257:5:257:8 | *resp | provenance | | | azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:262:5:262:8 | *resp | provenance | | | azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:266:38:266:41 | *resp | provenance | | -| azure.cpp:257:5:257:8 | *resp | azure.cpp:257:16:257:21 | Read output argument | provenance | MaD:79 | +| azure.cpp:257:5:257:8 | *resp | azure.cpp:257:16:257:21 | Read output argument | provenance | MaD:80 | | azure.cpp:257:16:257:21 | Read output argument | azure.cpp:258:10:258:16 | * ... | provenance | | -| azure.cpp:262:5:262:8 | *resp | azure.cpp:262:23:262:28 | ReadToCount output argument | provenance | MaD:80 | +| azure.cpp:262:5:262:8 | *resp | azure.cpp:262:23:262:28 | ReadToCount output argument | provenance | MaD:81 | | azure.cpp:262:23:262:28 | ReadToCount output argument | azure.cpp:263:10:263:16 | * ... | provenance | | -| azure.cpp:266:38:266:41 | *resp | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | provenance | MaD:81 | +| azure.cpp:266:38:266:41 | *resp | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | provenance | MaD:82 | | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | provenance | | | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | azure.cpp:267:10:267:12 | vec [element] | provenance | | | azure.cpp:267:10:267:12 | vec [element] | azure.cpp:267:10:267:12 | vec | provenance | | -| azure.cpp:273:62:273:64 | call to GetHeaders | azure.cpp:273:62:273:64 | call to GetHeaders | provenance | Src:MaD:37 | +| azure.cpp:273:62:273:64 | call to GetHeaders | azure.cpp:273:62:273:64 | call to GetHeaders | provenance | Src:MaD:38 | | azure.cpp:273:62:273:64 | call to GetHeaders | azure.cpp:274:14:274:29 | call to operator[] | provenance | TaintFunction | | azure.cpp:273:62:273:64 | call to GetHeaders | azure.cpp:274:14:274:29 | call to operator[] | provenance | TaintFunction | | azure.cpp:273:62:273:64 | call to GetHeaders | azure.cpp:274:14:274:29 | call to operator[] | provenance | TaintFunction | | azure.cpp:274:14:274:29 | call to operator[] | azure.cpp:274:10:274:29 | call to operator[] | provenance | | | azure.cpp:274:14:274:29 | call to operator[] | azure.cpp:274:14:274:29 | call to operator[] | provenance | | -| azure.cpp:277:45:277:47 | call to GetBody | azure.cpp:277:45:277:47 | call to GetBody | provenance | Src:MaD:36 | +| azure.cpp:277:45:277:47 | call to GetBody | azure.cpp:277:45:277:47 | call to GetBody | provenance | Src:MaD:37 | | azure.cpp:277:45:277:47 | call to GetBody | azure.cpp:278:10:278:13 | body | provenance | | | azure.cpp:277:45:277:47 | call to GetBody | azure.cpp:278:10:278:13 | body | provenance | | | azure.cpp:278:10:278:13 | body | azure.cpp:278:10:278:13 | body | provenance | | -| azure.cpp:281:68:281:84 | *call to ExtractBodyStream | azure.cpp:281:68:281:84 | *call to ExtractBodyStream | provenance | Src:MaD:35 | +| azure.cpp:281:68:281:84 | *call to ExtractBodyStream | azure.cpp:281:68:281:84 | *call to ExtractBodyStream | provenance | Src:MaD:36 | | azure.cpp:281:68:281:84 | *call to ExtractBodyStream | azure.cpp:282:21:282:23 | *call to get | provenance | | -| azure.cpp:282:21:282:23 | *call to get | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | provenance | MaD:81 | +| azure.cpp:282:21:282:23 | *call to get | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | provenance | MaD:82 | | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | azure.cpp:282:10:282:38 | call to ReadToEnd | provenance | | | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | provenance | | -| azure.cpp:289:24:289:56 | call to GetHeader | azure.cpp:289:63:289:65 | call to Value | provenance | MaD:82 | +| azure.cpp:289:24:289:56 | call to GetHeader | azure.cpp:289:63:289:65 | call to Value | provenance | MaD:83 | | azure.cpp:289:32:289:40 | call to GetHeader | azure.cpp:289:24:289:56 | call to GetHeader | provenance | | -| azure.cpp:289:32:289:40 | call to GetHeader | azure.cpp:289:32:289:40 | call to GetHeader | provenance | Src:MaD:39 | +| azure.cpp:289:32:289:40 | call to GetHeader | azure.cpp:289:32:289:40 | call to GetHeader | provenance | Src:MaD:40 | | azure.cpp:289:63:289:65 | call to Value | azure.cpp:289:63:289:65 | call to Value | provenance | | | azure.cpp:289:63:289:65 | call to Value | azure.cpp:290:10:290:20 | headerValue | provenance | | | azure.cpp:289:63:289:65 | call to Value | azure.cpp:290:10:290:20 | headerValue | provenance | | | azure.cpp:290:10:290:20 | headerValue | azure.cpp:290:10:290:20 | headerValue | provenance | | -| azure.cpp:293:58:293:67 | call to GetHeaders | azure.cpp:293:58:293:67 | call to GetHeaders | provenance | Src:MaD:40 | +| azure.cpp:293:58:293:67 | call to GetHeaders | azure.cpp:293:58:293:67 | call to GetHeaders | provenance | Src:MaD:41 | | azure.cpp:293:58:293:67 | call to GetHeaders | azure.cpp:294:38:294:53 | call to operator[] | provenance | TaintFunction | | azure.cpp:294:38:294:53 | call to operator[] | azure.cpp:295:10:295:20 | contentType | provenance | | | azure.cpp:294:38:294:53 | call to operator[] | azure.cpp:295:10:295:20 | contentType | provenance | | | azure.cpp:295:10:295:20 | contentType | azure.cpp:295:10:295:20 | contentType | provenance | | | test.cpp:7:47:7:52 | value2 | test.cpp:7:64:7:69 | value2 | provenance | | | test.cpp:7:64:7:69 | value2 | test.cpp:7:5:7:30 | *ymlStepGenerated_with_body | provenance | | -| test.cpp:10:10:10:18 | call to ymlSource | test.cpp:10:10:10:18 | call to ymlSource | provenance | Src:MaD:34 | +| test.cpp:10:10:10:18 | call to ymlSource | test.cpp:10:10:10:18 | call to ymlSource | provenance | Src:MaD:35 | | test.cpp:10:10:10:18 | call to ymlSource | test.cpp:14:10:14:10 | x | provenance | Sink:MaD:1 | | test.cpp:10:10:10:18 | call to ymlSource | test.cpp:17:24:17:24 | x | provenance | | | test.cpp:10:10:10:18 | call to ymlSource | test.cpp:21:27:21:27 | x | provenance | | @@ -140,13 +141,13 @@ edges | test.cpp:10:10:10:18 | call to ymlSource | test.cpp:32:41:32:41 | x | provenance | | | test.cpp:17:10:17:22 | call to ymlStepManual | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | | | test.cpp:17:10:17:22 | call to ymlStepManual | test.cpp:18:10:18:10 | y | provenance | Sink:MaD:1 | -| test.cpp:17:24:17:24 | x | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | MaD:71 | +| test.cpp:17:24:17:24 | x | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | MaD:72 | | test.cpp:21:10:21:25 | call to ymlStepGenerated | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | | | test.cpp:21:10:21:25 | call to ymlStepGenerated | test.cpp:22:10:22:10 | z | provenance | Sink:MaD:1 | -| test.cpp:21:27:21:27 | x | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | MaD:70 | +| test.cpp:21:27:21:27 | x | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | MaD:71 | | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | | | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | test.cpp:26:10:26:11 | y2 | provenance | Sink:MaD:1 | -| test.cpp:25:35:25:35 | x | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | MaD:72 | +| test.cpp:25:35:25:35 | x | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | MaD:73 | | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | provenance | | | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | test.cpp:33:10:33:11 | z2 | provenance | Sink:MaD:1 | | test.cpp:32:41:32:41 | x | test.cpp:7:47:7:52 | value2 | provenance | | @@ -156,73 +157,73 @@ edges | test.cpp:48:13:48:13 | *s [x] | test.cpp:48:16:48:16 | x | provenance | Sink:MaD:1 | | test.cpp:56:2:56:2 | *s [post update] [x] | test.cpp:59:55:59:64 | *& ... [x] | provenance | | | test.cpp:56:2:56:18 | ... = ... | test.cpp:56:2:56:2 | *s [post update] [x] | provenance | | -| test.cpp:56:8:56:16 | call to ymlSource | test.cpp:56:2:56:18 | ... = ... | provenance | Src:MaD:34 | -| test.cpp:59:55:59:64 | *& ... [x] | test.cpp:46:30:46:32 | *arg [x] | provenance | MaD:67 | +| test.cpp:56:8:56:16 | call to ymlSource | test.cpp:56:2:56:18 | ... = ... | provenance | Src:MaD:35 | +| test.cpp:59:55:59:64 | *& ... [x] | test.cpp:46:30:46:32 | *arg [x] | provenance | MaD:68 | | test.cpp:68:22:68:22 | y | test.cpp:69:11:69:11 | y | provenance | Sink:MaD:1 | | test.cpp:74:22:74:22 | y | test.cpp:75:11:75:11 | y | provenance | Sink:MaD:1 | | test.cpp:82:22:82:22 | y | test.cpp:83:11:83:11 | y | provenance | Sink:MaD:1 | | test.cpp:88:22:88:22 | y | test.cpp:89:11:89:11 | y | provenance | Sink:MaD:1 | -| test.cpp:94:10:94:18 | call to ymlSource | test.cpp:94:10:94:18 | call to ymlSource | provenance | Src:MaD:34 | +| test.cpp:94:10:94:18 | call to ymlSource | test.cpp:94:10:94:18 | call to ymlSource | provenance | Src:MaD:35 | | test.cpp:94:10:94:18 | call to ymlSource | test.cpp:97:26:97:26 | x | provenance | | | test.cpp:94:10:94:18 | call to ymlSource | test.cpp:101:26:101:26 | x | provenance | | | test.cpp:94:10:94:18 | call to ymlSource | test.cpp:103:63:103:63 | x | provenance | | | test.cpp:94:10:94:18 | call to ymlSource | test.cpp:104:62:104:62 | x | provenance | | -| test.cpp:97:26:97:26 | x | test.cpp:68:22:68:22 | y | provenance | MaD:65 | -| test.cpp:101:26:101:26 | x | test.cpp:74:22:74:22 | y | provenance | MaD:65 | -| test.cpp:103:63:103:63 | x | test.cpp:82:22:82:22 | y | provenance | MaD:65 | -| test.cpp:104:62:104:62 | x | test.cpp:88:22:88:22 | y | provenance | MaD:65 | -| test.cpp:114:10:114:18 | call to ymlSource | test.cpp:114:10:114:18 | call to ymlSource | provenance | Src:MaD:34 | +| test.cpp:97:26:97:26 | x | test.cpp:68:22:68:22 | y | provenance | MaD:66 | +| test.cpp:101:26:101:26 | x | test.cpp:74:22:74:22 | y | provenance | MaD:66 | +| test.cpp:103:63:103:63 | x | test.cpp:82:22:82:22 | y | provenance | MaD:66 | +| test.cpp:104:62:104:62 | x | test.cpp:88:22:88:22 | y | provenance | MaD:66 | +| test.cpp:114:10:114:18 | call to ymlSource | test.cpp:114:10:114:18 | call to ymlSource | provenance | Src:MaD:35 | | test.cpp:114:10:114:18 | call to ymlSource | test.cpp:118:44:118:44 | *x | provenance | | | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | provenance | | | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | test.cpp:119:10:119:11 | y2 | provenance | Sink:MaD:1 | -| test.cpp:118:44:118:44 | *x | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | provenance | MaD:66 | -| test.cpp:133:10:133:18 | call to ymlSource | test.cpp:133:10:133:18 | call to ymlSource | provenance | Src:MaD:34 | +| test.cpp:118:44:118:44 | *x | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | provenance | MaD:67 | +| test.cpp:133:10:133:18 | call to ymlSource | test.cpp:133:10:133:18 | call to ymlSource | provenance | Src:MaD:35 | | test.cpp:133:10:133:18 | call to ymlSource | test.cpp:134:45:134:45 | x | provenance | | | test.cpp:134:13:134:43 | call to templateFunction | test.cpp:134:13:134:43 | call to templateFunction | provenance | | | test.cpp:134:13:134:43 | call to templateFunction | test.cpp:135:10:135:10 | y | provenance | Sink:MaD:1 | -| test.cpp:134:45:134:45 | x | test.cpp:134:13:134:43 | call to templateFunction | provenance | MaD:77 | -| test.cpp:146:10:146:18 | call to ymlSource | test.cpp:146:10:146:18 | call to ymlSource | provenance | Src:MaD:34 | +| test.cpp:134:45:134:45 | x | test.cpp:134:13:134:43 | call to templateFunction | provenance | MaD:78 | +| test.cpp:146:10:146:18 | call to ymlSource | test.cpp:146:10:146:18 | call to ymlSource | provenance | Src:MaD:35 | | test.cpp:146:10:146:18 | call to ymlSource | test.cpp:148:26:148:26 | x | provenance | | | test.cpp:148:10:148:27 | call to function | test.cpp:148:10:148:27 | call to function | provenance | | | test.cpp:148:10:148:27 | call to function | test.cpp:149:10:149:10 | z | provenance | Sink:MaD:1 | -| test.cpp:148:26:148:26 | x | test.cpp:148:10:148:27 | call to function | provenance | MaD:78 | -| test.cpp:155:10:155:18 | call to ymlSource | test.cpp:155:10:155:18 | call to ymlSource | provenance | Src:MaD:34 | +| test.cpp:148:26:148:26 | x | test.cpp:148:10:148:27 | call to function | provenance | MaD:79 | +| test.cpp:155:10:155:18 | call to ymlSource | test.cpp:155:10:155:18 | call to ymlSource | provenance | Src:MaD:35 | | test.cpp:155:10:155:18 | call to ymlSource | test.cpp:157:26:157:26 | x | provenance | | | test.cpp:157:13:157:20 | call to function | test.cpp:157:13:157:20 | call to function | provenance | | | test.cpp:157:13:157:20 | call to function | test.cpp:158:10:158:10 | z | provenance | Sink:MaD:1 | -| test.cpp:157:26:157:26 | x | test.cpp:157:13:157:20 | call to function | provenance | MaD:78 | +| test.cpp:157:26:157:26 | x | test.cpp:157:13:157:20 | call to function | provenance | MaD:79 | | test.cpp:164:34:164:34 | x | test.cpp:165:69:165:69 | x | provenance | | | test.cpp:165:12:165:64 | call to templateFunction2 | test.cpp:164:7:164:7 | *templateFunction3 | provenance | | | test.cpp:165:12:165:64 | call to templateFunction2 | test.cpp:165:12:165:64 | call to templateFunction2 | provenance | | -| test.cpp:165:69:165:69 | x | test.cpp:165:12:165:64 | call to templateFunction2 | provenance | MaD:76 | -| test.cpp:170:10:170:18 | call to ymlSource | test.cpp:170:10:170:18 | call to ymlSource | provenance | Src:MaD:34 | +| test.cpp:165:69:165:69 | x | test.cpp:165:12:165:64 | call to templateFunction2 | provenance | MaD:77 | +| test.cpp:170:10:170:18 | call to ymlSource | test.cpp:170:10:170:18 | call to ymlSource | provenance | Src:MaD:35 | | test.cpp:170:10:170:18 | call to ymlSource | test.cpp:172:51:172:51 | x | provenance | | | test.cpp:172:13:172:44 | call to templateFunction3 | test.cpp:172:13:172:44 | call to templateFunction3 | provenance | | | test.cpp:172:13:172:44 | call to templateFunction3 | test.cpp:173:10:173:10 | y | provenance | Sink:MaD:1 | | test.cpp:172:51:172:51 | x | test.cpp:164:34:164:34 | x | provenance | | -| test.cpp:172:51:172:51 | x | test.cpp:172:13:172:44 | call to templateFunction3 | provenance | MaD:76 | +| test.cpp:172:51:172:51 | x | test.cpp:172:13:172:44 | call to templateFunction3 | provenance | MaD:77 | | test.cpp:186:2:186:2 | *s [post update] [myField] | test.cpp:187:33:187:34 | *& ... [myField] | provenance | | | test.cpp:186:2:186:24 | ... = ... | test.cpp:186:2:186:2 | *s [post update] [myField] | provenance | | -| test.cpp:186:14:186:22 | call to ymlSource | test.cpp:186:2:186:24 | ... = ... | provenance | Src:MaD:34 | +| test.cpp:186:14:186:22 | call to ymlSource | test.cpp:186:2:186:24 | ... = ... | provenance | Src:MaD:35 | | test.cpp:187:10:187:31 | call to read_field_from_struct | test.cpp:187:10:187:31 | call to read_field_from_struct | provenance | | | test.cpp:187:10:187:31 | call to read_field_from_struct | test.cpp:188:10:188:10 | x | provenance | Sink:MaD:1 | -| test.cpp:187:33:187:34 | *& ... [myField] | test.cpp:187:10:187:31 | call to read_field_from_struct | provenance | MaD:68 | +| test.cpp:187:33:187:34 | *& ... [myField] | test.cpp:187:10:187:31 | call to read_field_from_struct | provenance | MaD:69 | | test.cpp:199:2:199:2 | *s [post update] [myField] | test.cpp:200:35:200:36 | *& ... [myField] | provenance | | | test.cpp:199:2:199:24 | ... = ... | test.cpp:199:2:199:2 | *s [post update] [myField] | provenance | | -| test.cpp:199:14:199:22 | call to ymlSource | test.cpp:199:2:199:24 | ... = ... | provenance | Src:MaD:34 | +| test.cpp:199:14:199:22 | call to ymlSource | test.cpp:199:2:199:24 | ... = ... | provenance | Src:MaD:35 | | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | provenance | | | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | test.cpp:201:10:201:10 | x | provenance | Sink:MaD:1 | -| test.cpp:200:35:200:36 | *& ... [myField] | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | provenance | MaD:69 | +| test.cpp:200:35:200:36 | *& ... [myField] | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | provenance | MaD:70 | | test.cpp:216:3:216:4 | get_ptr output argument [value] | test.cpp:217:11:217:12 | *rf [value] | provenance | | -| test.cpp:216:3:216:28 | ... = ... | test.cpp:216:3:216:4 | get_ptr output argument [value] | provenance | MaD:75 | -| test.cpp:216:18:216:26 | call to ymlSource | test.cpp:216:3:216:28 | ... = ... | provenance | Src:MaD:34 | +| test.cpp:216:3:216:28 | ... = ... | test.cpp:216:3:216:4 | get_ptr output argument [value] | provenance | MaD:76 | +| test.cpp:216:18:216:26 | call to ymlSource | test.cpp:216:3:216:28 | ... = ... | provenance | Src:MaD:35 | | test.cpp:217:11:217:12 | *rf [value] | test.cpp:217:14:217:18 | value | provenance | | | test.cpp:217:14:217:18 | value | test.cpp:217:14:217:18 | value | provenance | | | test.cpp:217:14:217:18 | value | test.cpp:218:11:218:11 | x | provenance | Sink:MaD:1 | | test.cpp:222:3:222:3 | operator[] output argument | test.cpp:223:12:223:12 | *s | provenance | | -| test.cpp:222:3:222:20 | ... = ... | test.cpp:222:3:222:3 | operator[] output argument | provenance | MaD:74 | -| test.cpp:222:10:222:20 | call to ymlSource | test.cpp:222:3:222:20 | ... = ... | provenance | Src:MaD:34 | -| test.cpp:223:12:223:12 | *s | test.cpp:223:13:223:15 | call to operator[] | provenance | MaD:73 | +| test.cpp:222:3:222:20 | ... = ... | test.cpp:222:3:222:3 | operator[] output argument | provenance | MaD:75 | +| test.cpp:222:10:222:20 | call to ymlSource | test.cpp:222:3:222:20 | ... = ... | provenance | Src:MaD:35 | +| test.cpp:223:12:223:12 | *s | test.cpp:223:13:223:15 | call to operator[] | provenance | MaD:74 | | test.cpp:223:13:223:15 | call to operator[] | test.cpp:223:13:223:15 | call to operator[] | provenance | | | test.cpp:223:13:223:15 | call to operator[] | test.cpp:224:11:224:11 | c | provenance | Sink:MaD:1 | | windows.cpp:22:15:22:29 | *call to GetCommandLineA | windows.cpp:22:15:22:29 | *call to GetCommandLineA | provenance | Src:MaD:3 | @@ -230,7 +231,7 @@ edges | windows.cpp:22:15:22:29 | *call to GetCommandLineA | windows.cpp:27:36:27:38 | *cmd | provenance | | | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | provenance | | | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | windows.cpp:30:8:30:15 | * ... | provenance | | -| windows.cpp:27:36:27:38 | *cmd | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | provenance | MaD:44 | +| windows.cpp:27:36:27:38 | *cmd | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | provenance | MaD:45 | | windows.cpp:34:17:34:38 | *call to GetEnvironmentStringsA | windows.cpp:34:17:34:38 | *call to GetEnvironmentStringsA | provenance | Src:MaD:4 | | windows.cpp:34:17:34:38 | *call to GetEnvironmentStringsA | windows.cpp:36:10:36:13 | * ... | provenance | | | windows.cpp:39:36:39:38 | GetEnvironmentVariableA output argument | windows.cpp:41:10:41:13 | * ... | provenance | Src:MaD:5 | @@ -250,11 +251,11 @@ edges | windows.cpp:189:21:189:26 | ReadFile output argument | windows.cpp:190:5:190:56 | *... = ... | provenance | Src:MaD:17 | | windows.cpp:190:5:190:14 | *overlapped [post update] [*hEvent] | windows.cpp:192:53:192:63 | *& ... [*hEvent] | provenance | | | windows.cpp:190:5:190:56 | *... = ... | windows.cpp:190:5:190:14 | *overlapped [post update] [*hEvent] | provenance | | -| windows.cpp:192:53:192:63 | *& ... [*hEvent] | windows.cpp:147:16:147:27 | *lpOverlapped [*hEvent] | provenance | MaD:51 | +| windows.cpp:192:53:192:63 | *& ... [*hEvent] | windows.cpp:147:16:147:27 | *lpOverlapped [*hEvent] | provenance | MaD:52 | | windows.cpp:198:21:198:26 | ReadFile output argument | windows.cpp:199:5:199:57 | ... = ... | provenance | Src:MaD:17 | | windows.cpp:199:5:199:14 | *overlapped [post update] [hEvent] | windows.cpp:201:53:201:63 | *& ... [hEvent] | provenance | | | windows.cpp:199:5:199:57 | ... = ... | windows.cpp:199:5:199:14 | *overlapped [post update] [hEvent] | provenance | | -| windows.cpp:201:53:201:63 | *& ... [hEvent] | windows.cpp:157:16:157:27 | *lpOverlapped [hEvent] | provenance | MaD:51 | +| windows.cpp:201:53:201:63 | *& ... [hEvent] | windows.cpp:157:16:157:27 | *lpOverlapped [hEvent] | provenance | MaD:52 | | windows.cpp:209:84:209:89 | NtReadFile output argument | windows.cpp:211:10:211:16 | * ... | provenance | Src:MaD:16 | | windows.cpp:286:23:286:35 | *call to MapViewOfFile | windows.cpp:286:23:286:35 | *call to MapViewOfFile | provenance | Src:MaD:12 | | windows.cpp:286:23:286:35 | *call to MapViewOfFile | windows.cpp:287:20:287:52 | *pMapView | provenance | | @@ -291,9 +292,9 @@ edges | windows.cpp:431:3:431:3 | *s [post update] [x] | windows.cpp:464:7:464:8 | *& ... [x] | provenance | | | windows.cpp:431:3:431:16 | ... = ... | windows.cpp:431:3:431:3 | *s [post update] [x] | provenance | | | windows.cpp:431:9:431:14 | call to source | windows.cpp:431:3:431:16 | ... = ... | provenance | | -| windows.cpp:439:7:439:8 | *& ... [x] | windows.cpp:403:26:403:36 | *lpParameter [x] | provenance | MaD:47 | -| windows.cpp:451:7:451:8 | *& ... [x] | windows.cpp:410:26:410:36 | *lpParameter [x] | provenance | MaD:45 | -| windows.cpp:464:7:464:8 | *& ... [x] | windows.cpp:417:26:417:36 | *lpParameter [x] | provenance | MaD:46 | +| windows.cpp:439:7:439:8 | *& ... [x] | windows.cpp:403:26:403:36 | *lpParameter [x] | provenance | MaD:48 | +| windows.cpp:451:7:451:8 | *& ... [x] | windows.cpp:410:26:410:36 | *lpParameter [x] | provenance | MaD:46 | +| windows.cpp:464:7:464:8 | *& ... [x] | windows.cpp:417:26:417:36 | *lpParameter [x] | provenance | MaD:47 | | windows.cpp:533:11:533:16 | call to source | windows.cpp:533:11:533:16 | call to source | provenance | | | windows.cpp:533:11:533:16 | call to source | windows.cpp:537:40:537:41 | *& ... | provenance | | | windows.cpp:533:11:533:16 | call to source | windows.cpp:542:38:542:39 | *& ... | provenance | | @@ -302,39 +303,39 @@ edges | windows.cpp:533:11:533:16 | call to source | windows.cpp:568:32:568:33 | *& ... | provenance | | | windows.cpp:533:11:533:16 | call to source | windows.cpp:573:40:573:41 | *& ... | provenance | | | windows.cpp:537:27:537:37 | RtlCopyVolatileMemory output argument | windows.cpp:538:10:538:23 | access to array | provenance | | -| windows.cpp:537:40:537:41 | *& ... | windows.cpp:537:27:537:37 | RtlCopyVolatileMemory output argument | provenance | MaD:56 | +| windows.cpp:537:40:537:41 | *& ... | windows.cpp:537:27:537:37 | RtlCopyVolatileMemory output argument | provenance | MaD:57 | | windows.cpp:542:25:542:35 | RtlCopyDeviceMemory output argument | windows.cpp:543:10:543:23 | access to array | provenance | | -| windows.cpp:542:38:542:39 | *& ... | windows.cpp:542:25:542:35 | RtlCopyDeviceMemory output argument | provenance | MaD:52 | +| windows.cpp:542:38:542:39 | *& ... | windows.cpp:542:25:542:35 | RtlCopyDeviceMemory output argument | provenance | MaD:53 | | windows.cpp:547:19:547:29 | RtlCopyMemory output argument | windows.cpp:548:10:548:23 | access to array | provenance | | -| windows.cpp:547:32:547:33 | *& ... | windows.cpp:547:19:547:29 | RtlCopyMemory output argument | provenance | MaD:53 | +| windows.cpp:547:32:547:33 | *& ... | windows.cpp:547:19:547:29 | RtlCopyMemory output argument | provenance | MaD:54 | | windows.cpp:552:30:552:40 | RtlCopyMemoryNonTemporal output argument | windows.cpp:553:10:553:23 | access to array | provenance | | -| windows.cpp:552:43:552:44 | *& ... | windows.cpp:552:30:552:40 | RtlCopyMemoryNonTemporal output argument | provenance | MaD:54 | +| windows.cpp:552:43:552:44 | *& ... | windows.cpp:552:30:552:40 | RtlCopyMemoryNonTemporal output argument | provenance | MaD:55 | | windows.cpp:559:5:559:24 | ... = ... | windows.cpp:561:39:561:44 | *buffer | provenance | | | windows.cpp:559:17:559:24 | call to source | windows.cpp:559:5:559:24 | ... = ... | provenance | | | windows.cpp:561:26:561:36 | RtlInitUnicodeString output argument [*Buffer] | windows.cpp:562:10:562:19 | *src_string [*Buffer] | provenance | | | windows.cpp:561:26:561:36 | RtlInitUnicodeString output argument [*Buffer] | windows.cpp:563:40:563:50 | *& ... [*Buffer] | provenance | | -| windows.cpp:561:39:561:44 | *buffer | windows.cpp:561:26:561:36 | RtlInitUnicodeString output argument [*Buffer] | provenance | MaD:57 | +| windows.cpp:561:39:561:44 | *buffer | windows.cpp:561:26:561:36 | RtlInitUnicodeString output argument [*Buffer] | provenance | MaD:58 | | windows.cpp:562:10:562:19 | *src_string [*Buffer] | windows.cpp:562:10:562:29 | access to array | provenance | | | windows.cpp:562:10:562:19 | *src_string [*Buffer] | windows.cpp:562:21:562:26 | *Buffer | provenance | | | windows.cpp:562:21:562:26 | *Buffer | windows.cpp:562:10:562:29 | access to array | provenance | | | windows.cpp:563:26:563:37 | RtlCopyUnicodeString output argument [*Buffer] | windows.cpp:564:10:564:20 | *dest_string [*Buffer] | provenance | | -| windows.cpp:563:40:563:50 | *& ... [*Buffer] | windows.cpp:563:26:563:37 | RtlCopyUnicodeString output argument [*Buffer] | provenance | MaD:55 | +| windows.cpp:563:40:563:50 | *& ... [*Buffer] | windows.cpp:563:26:563:37 | RtlCopyUnicodeString output argument [*Buffer] | provenance | MaD:56 | | windows.cpp:564:10:564:20 | *dest_string [*Buffer] | windows.cpp:564:10:564:30 | access to array | provenance | | | windows.cpp:564:10:564:20 | *dest_string [*Buffer] | windows.cpp:564:22:564:27 | *Buffer | provenance | | | windows.cpp:564:22:564:27 | *Buffer | windows.cpp:564:10:564:30 | access to array | provenance | | | windows.cpp:568:19:568:29 | RtlMoveMemory output argument | windows.cpp:569:10:569:23 | access to array | provenance | | -| windows.cpp:568:32:568:33 | *& ... | windows.cpp:568:19:568:29 | RtlMoveMemory output argument | provenance | MaD:58 | +| windows.cpp:568:32:568:33 | *& ... | windows.cpp:568:19:568:29 | RtlMoveMemory output argument | provenance | MaD:59 | | windows.cpp:573:27:573:37 | RtlMoveVolatileMemory output argument | windows.cpp:574:10:574:23 | access to array | provenance | | -| windows.cpp:573:40:573:41 | *& ... | windows.cpp:573:27:573:37 | RtlMoveVolatileMemory output argument | provenance | MaD:59 | -| windows.cpp:645:45:645:50 | WinHttpReadData output argument | windows.cpp:647:10:647:16 | * ... | provenance | Src:MaD:32 | -| windows.cpp:652:48:652:53 | WinHttpReadDataEx output argument | windows.cpp:654:10:654:16 | * ... | provenance | Src:MaD:33 | -| windows.cpp:659:47:659:52 | WinHttpQueryHeaders output argument | windows.cpp:661:10:661:16 | * ... | provenance | Src:MaD:28 | -| windows.cpp:669:70:669:79 | WinHttpQueryHeadersEx output argument | windows.cpp:673:10:673:29 | * ... | provenance | Src:MaD:30 | -| windows.cpp:669:82:669:87 | WinHttpQueryHeadersEx output argument | windows.cpp:671:10:671:16 | * ... | provenance | Src:MaD:31 | -| windows.cpp:669:105:669:112 | WinHttpQueryHeadersEx output argument | windows.cpp:675:10:675:27 | * ... | provenance | Src:MaD:29 | +| windows.cpp:573:40:573:41 | *& ... | windows.cpp:573:27:573:37 | RtlMoveVolatileMemory output argument | provenance | MaD:60 | +| windows.cpp:645:45:645:50 | WinHttpReadData output argument | windows.cpp:647:10:647:16 | * ... | provenance | Src:MaD:33 | +| windows.cpp:652:48:652:53 | WinHttpReadDataEx output argument | windows.cpp:654:10:654:16 | * ... | provenance | Src:MaD:34 | +| windows.cpp:659:47:659:52 | WinHttpQueryHeaders output argument | windows.cpp:661:10:661:16 | * ... | provenance | Src:MaD:29 | +| windows.cpp:669:70:669:79 | WinHttpQueryHeadersEx output argument | windows.cpp:673:10:673:29 | * ... | provenance | Src:MaD:31 | +| windows.cpp:669:82:669:87 | WinHttpQueryHeadersEx output argument | windows.cpp:671:10:671:16 | * ... | provenance | Src:MaD:32 | +| windows.cpp:669:105:669:112 | WinHttpQueryHeadersEx output argument | windows.cpp:675:10:675:27 | * ... | provenance | Src:MaD:30 | | windows.cpp:728:5:728:28 | ... = ... | windows.cpp:729:35:729:35 | *x | provenance | | | windows.cpp:728:12:728:28 | call to source | windows.cpp:728:5:728:28 | ... = ... | provenance | | -| windows.cpp:729:35:729:35 | *x | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | provenance | MaD:64 | +| windows.cpp:729:35:729:35 | *x | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | provenance | MaD:65 | | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | windows.cpp:731:10:731:36 | * ... | provenance | | | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | windows.cpp:733:10:733:35 | * ... | provenance | | | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | windows.cpp:735:10:735:37 | * ... | provenance | | @@ -355,52 +356,54 @@ edges | windows.cpp:936:70:936:78 | HttpReceiveClientCertificate output argument | windows.cpp:937:15:937:48 | *& ... | provenance | Src:MaD:6 | | windows.cpp:936:70:936:78 | HttpReceiveClientCertificate output argument | windows.cpp:941:10:941:31 | * ... | provenance | Src:MaD:6 | | windows.cpp:937:15:937:48 | *& ... | windows.cpp:939:10:939:11 | * ... | provenance | | -| windows.cpp:1004:35:1004:38 | RegQueryValueA output argument | windows.cpp:1006:10:1006:14 | * ... | provenance | Src:MaD:24 | -| windows.cpp:1011:36:1011:39 | RegQueryValueW output argument | windows.cpp:1013:10:1013:14 | * ... | provenance | Src:MaD:27 | -| windows.cpp:1019:53:1019:56 | RegQueryValueExA output argument | windows.cpp:1021:10:1021:14 | * ... | provenance | Src:MaD:25 | -| windows.cpp:1027:54:1027:57 | RegQueryValueExW output argument | windows.cpp:1029:10:1029:14 | * ... | provenance | Src:MaD:26 | -| windows.cpp:1035:46:1035:49 | RegQueryMultipleValuesA output argument | windows.cpp:1037:10:1037:14 | * ... | provenance | Src:MaD:22 | -| windows.cpp:1043:46:1043:49 | RegQueryMultipleValuesW output argument | windows.cpp:1045:10:1045:14 | * ... | provenance | Src:MaD:23 | -| windows.cpp:1051:53:1051:56 | RegGetValueA output argument | windows.cpp:1053:10:1053:14 | * ... | provenance | Src:MaD:21 | -| windows.cpp:1060:53:1060:56 | RegGetValueA output argument | windows.cpp:1062:10:1062:14 | * ... | provenance | Src:MaD:21 | -| windows.cpp:1070:71:1070:74 | RegEnumValueA output argument | windows.cpp:1072:10:1072:14 | * ... | provenance | Src:MaD:19 | -| windows.cpp:1080:71:1080:74 | RegEnumValueW output argument | windows.cpp:1082:10:1082:14 | * ... | provenance | Src:MaD:20 | -| windows.cpp:1114:5:1114:27 | ... = ... | windows.cpp:1116:19:1116:21 | *str | provenance | | -| windows.cpp:1114:14:1114:27 | call to source | windows.cpp:1114:5:1114:27 | ... = ... | provenance | | -| windows.cpp:1116:19:1116:21 | *str | windows.cpp:1116:24:1116:27 | IIDFromString output argument | provenance | MaD:49 | -| windows.cpp:1116:24:1116:27 | IIDFromString output argument | windows.cpp:1117:10:1117:12 | iid | provenance | | -| windows.cpp:1120:15:1120:20 | call to source | windows.cpp:1120:15:1120:20 | call to source | provenance | | -| windows.cpp:1120:15:1120:20 | call to source | windows.cpp:1122:19:1122:21 | *iid | provenance | | -| windows.cpp:1122:19:1122:21 | *iid | windows.cpp:1122:24:1122:27 | StringFromIID output argument | provenance | MaD:63 | -| windows.cpp:1122:24:1122:27 | StringFromIID output argument | windows.cpp:1124:10:1124:13 | * ... | provenance | | -| windows.cpp:1127:19:1127:24 | call to source | windows.cpp:1127:19:1127:24 | call to source | provenance | | -| windows.cpp:1127:19:1127:24 | call to source | windows.cpp:1129:21:1129:25 | *clsid | provenance | | -| windows.cpp:1129:21:1129:25 | *clsid | windows.cpp:1129:28:1129:31 | ProgIDFromCLSID output argument | provenance | MaD:50 | -| windows.cpp:1129:28:1129:31 | ProgIDFromCLSID output argument | windows.cpp:1131:10:1131:13 | * ... | provenance | | -| windows.cpp:1135:5:1135:30 | ... = ... | windows.cpp:1137:21:1137:26 | *progID | provenance | | -| windows.cpp:1135:17:1135:30 | call to source | windows.cpp:1135:5:1135:30 | ... = ... | provenance | | -| windows.cpp:1137:21:1137:26 | *progID | windows.cpp:1137:29:1137:34 | CLSIDFromProgID output argument | provenance | MaD:42 | -| windows.cpp:1137:29:1137:34 | CLSIDFromProgID output argument | windows.cpp:1138:10:1138:14 | clsid | provenance | | -| windows.cpp:1142:5:1142:27 | ... = ... | windows.cpp:1144:21:1144:23 | *str | provenance | | -| windows.cpp:1142:14:1142:27 | call to source | windows.cpp:1142:5:1142:27 | ... = ... | provenance | | -| windows.cpp:1144:21:1144:23 | *str | windows.cpp:1144:26:1144:31 | CLSIDFromString output argument | provenance | MaD:43 | -| windows.cpp:1144:26:1144:31 | CLSIDFromString output argument | windows.cpp:1145:10:1145:14 | clsid | provenance | | -| windows.cpp:1148:19:1148:24 | call to source | windows.cpp:1148:19:1148:24 | call to source | provenance | | -| windows.cpp:1148:19:1148:24 | call to source | windows.cpp:1150:21:1150:25 | *clsid | provenance | | -| windows.cpp:1150:21:1150:25 | *clsid | windows.cpp:1150:28:1150:31 | StringFromCLSID output argument | provenance | MaD:60 | -| windows.cpp:1150:28:1150:31 | StringFromCLSID output argument | windows.cpp:1152:10:1152:13 | * ... | provenance | | -| windows.cpp:1155:17:1155:22 | call to source | windows.cpp:1155:17:1155:22 | call to source | provenance | | -| windows.cpp:1155:17:1155:22 | call to source | windows.cpp:1157:20:1157:23 | *guid | provenance | | -| windows.cpp:1157:20:1157:23 | *guid | windows.cpp:1157:26:1157:28 | StringFromGUID output argument | provenance | MaD:62 | -| windows.cpp:1157:26:1157:28 | StringFromGUID output argument | windows.cpp:1159:10:1159:13 | * ... | provenance | | -| windows.cpp:1163:5:1163:27 | ... = ... | windows.cpp:1165:20:1165:22 | *str | provenance | | -| windows.cpp:1163:14:1163:27 | call to source | windows.cpp:1163:5:1163:27 | ... = ... | provenance | | -| windows.cpp:1165:20:1165:22 | *str | windows.cpp:1165:25:1165:29 | GUIDFromString output argument | provenance | MaD:48 | -| windows.cpp:1165:25:1165:29 | GUIDFromString output argument | windows.cpp:1166:10:1166:13 | guid | provenance | | -| windows.cpp:1169:17:1169:22 | call to source | windows.cpp:1169:17:1169:22 | call to source | provenance | | -| windows.cpp:1169:17:1169:22 | call to source | windows.cpp:1171:21:1171:24 | *guid | provenance | | -| windows.cpp:1171:21:1171:24 | *guid | windows.cpp:1171:27:1171:29 | StringFromGUID2 output argument | provenance | MaD:61 | -| windows.cpp:1171:27:1171:29 | StringFromGUID2 output argument | windows.cpp:1173:10:1173:13 | * ... | provenance | | +| windows.cpp:1009:35:1009:38 | RegQueryValueA output argument | windows.cpp:1011:10:1011:14 | * ... | provenance | Src:MaD:25 | +| windows.cpp:1016:36:1016:39 | RegQueryValueW output argument | windows.cpp:1018:10:1018:14 | * ... | provenance | Src:MaD:28 | +| windows.cpp:1024:53:1024:56 | RegQueryValueExA output argument | windows.cpp:1026:10:1026:14 | * ... | provenance | Src:MaD:26 | +| windows.cpp:1032:54:1032:57 | RegQueryValueExW output argument | windows.cpp:1034:10:1034:14 | * ... | provenance | Src:MaD:27 | +| windows.cpp:1040:46:1040:49 | RegQueryMultipleValuesA output argument | windows.cpp:1042:10:1042:14 | * ... | provenance | Src:MaD:23 | +| windows.cpp:1048:46:1048:49 | RegQueryMultipleValuesW output argument | windows.cpp:1050:10:1050:14 | * ... | provenance | Src:MaD:24 | +| windows.cpp:1056:53:1056:56 | RegGetValueA output argument | windows.cpp:1058:10:1058:14 | * ... | provenance | Src:MaD:21 | +| windows.cpp:1065:55:1065:58 | RegGetValueW output argument | windows.cpp:1067:10:1067:14 | * ... | provenance | Src:MaD:22 | +| windows.cpp:1075:28:1075:36 | RegEnumValueA output argument | windows.cpp:1079:10:1079:19 | * ... | provenance | Src:MaD:19 | +| windows.cpp:1075:71:1075:74 | RegEnumValueA output argument | windows.cpp:1077:10:1077:14 | * ... | provenance | Src:MaD:19 | +| windows.cpp:1087:28:1087:36 | RegEnumValueW output argument | windows.cpp:1091:10:1091:19 | * ... | provenance | Src:MaD:20 | +| windows.cpp:1087:71:1087:74 | RegEnumValueW output argument | windows.cpp:1089:10:1089:14 | * ... | provenance | Src:MaD:20 | +| windows.cpp:1123:5:1123:27 | ... = ... | windows.cpp:1125:19:1125:21 | *str | provenance | | +| windows.cpp:1123:14:1123:27 | call to source | windows.cpp:1123:5:1123:27 | ... = ... | provenance | | +| windows.cpp:1125:19:1125:21 | *str | windows.cpp:1125:24:1125:27 | IIDFromString output argument | provenance | MaD:50 | +| windows.cpp:1125:24:1125:27 | IIDFromString output argument | windows.cpp:1126:10:1126:12 | iid | provenance | | +| windows.cpp:1129:15:1129:20 | call to source | windows.cpp:1129:15:1129:20 | call to source | provenance | | +| windows.cpp:1129:15:1129:20 | call to source | windows.cpp:1131:19:1131:21 | *iid | provenance | | +| windows.cpp:1131:19:1131:21 | *iid | windows.cpp:1131:24:1131:27 | StringFromIID output argument | provenance | MaD:64 | +| windows.cpp:1131:24:1131:27 | StringFromIID output argument | windows.cpp:1133:10:1133:13 | * ... | provenance | | +| windows.cpp:1136:19:1136:24 | call to source | windows.cpp:1136:19:1136:24 | call to source | provenance | | +| windows.cpp:1136:19:1136:24 | call to source | windows.cpp:1138:21:1138:25 | *clsid | provenance | | +| windows.cpp:1138:21:1138:25 | *clsid | windows.cpp:1138:28:1138:31 | ProgIDFromCLSID output argument | provenance | MaD:51 | +| windows.cpp:1138:28:1138:31 | ProgIDFromCLSID output argument | windows.cpp:1140:10:1140:13 | * ... | provenance | | +| windows.cpp:1144:5:1144:30 | ... = ... | windows.cpp:1146:21:1146:26 | *progID | provenance | | +| windows.cpp:1144:17:1144:30 | call to source | windows.cpp:1144:5:1144:30 | ... = ... | provenance | | +| windows.cpp:1146:21:1146:26 | *progID | windows.cpp:1146:29:1146:34 | CLSIDFromProgID output argument | provenance | MaD:43 | +| windows.cpp:1146:29:1146:34 | CLSIDFromProgID output argument | windows.cpp:1147:10:1147:14 | clsid | provenance | | +| windows.cpp:1151:5:1151:27 | ... = ... | windows.cpp:1153:21:1153:23 | *str | provenance | | +| windows.cpp:1151:14:1151:27 | call to source | windows.cpp:1151:5:1151:27 | ... = ... | provenance | | +| windows.cpp:1153:21:1153:23 | *str | windows.cpp:1153:26:1153:31 | CLSIDFromString output argument | provenance | MaD:44 | +| windows.cpp:1153:26:1153:31 | CLSIDFromString output argument | windows.cpp:1154:10:1154:14 | clsid | provenance | | +| windows.cpp:1157:19:1157:24 | call to source | windows.cpp:1157:19:1157:24 | call to source | provenance | | +| windows.cpp:1157:19:1157:24 | call to source | windows.cpp:1159:21:1159:25 | *clsid | provenance | | +| windows.cpp:1159:21:1159:25 | *clsid | windows.cpp:1159:28:1159:31 | StringFromCLSID output argument | provenance | MaD:61 | +| windows.cpp:1159:28:1159:31 | StringFromCLSID output argument | windows.cpp:1161:10:1161:13 | * ... | provenance | | +| windows.cpp:1164:17:1164:22 | call to source | windows.cpp:1164:17:1164:22 | call to source | provenance | | +| windows.cpp:1164:17:1164:22 | call to source | windows.cpp:1166:20:1166:23 | *guid | provenance | | +| windows.cpp:1166:20:1166:23 | *guid | windows.cpp:1166:26:1166:28 | StringFromGUID output argument | provenance | MaD:63 | +| windows.cpp:1166:26:1166:28 | StringFromGUID output argument | windows.cpp:1168:10:1168:13 | * ... | provenance | | +| windows.cpp:1172:5:1172:27 | ... = ... | windows.cpp:1174:20:1174:22 | *str | provenance | | +| windows.cpp:1172:14:1172:27 | call to source | windows.cpp:1172:5:1172:27 | ... = ... | provenance | | +| windows.cpp:1174:20:1174:22 | *str | windows.cpp:1174:25:1174:29 | GUIDFromString output argument | provenance | MaD:49 | +| windows.cpp:1174:25:1174:29 | GUIDFromString output argument | windows.cpp:1175:10:1175:13 | guid | provenance | | +| windows.cpp:1178:17:1178:22 | call to source | windows.cpp:1178:17:1178:22 | call to source | provenance | | +| windows.cpp:1178:17:1178:22 | call to source | windows.cpp:1180:21:1180:24 | *guid | provenance | | +| windows.cpp:1180:21:1180:24 | *guid | windows.cpp:1180:27:1180:29 | StringFromGUID2 output argument | provenance | MaD:62 | +| windows.cpp:1180:27:1180:29 | StringFromGUID2 output argument | windows.cpp:1182:10:1182:13 | * ... | provenance | | nodes | asio_streams.cpp:87:34:87:44 | read_until output argument | semmle.label | read_until output argument | | asio_streams.cpp:91:7:91:17 | recv_buffer | semmle.label | recv_buffer | @@ -717,71 +720,75 @@ nodes | windows.cpp:937:15:937:48 | *& ... | semmle.label | *& ... | | windows.cpp:939:10:939:11 | * ... | semmle.label | * ... | | windows.cpp:941:10:941:31 | * ... | semmle.label | * ... | -| windows.cpp:1004:35:1004:38 | RegQueryValueA output argument | semmle.label | RegQueryValueA output argument | -| windows.cpp:1006:10:1006:14 | * ... | semmle.label | * ... | -| windows.cpp:1011:36:1011:39 | RegQueryValueW output argument | semmle.label | RegQueryValueW output argument | -| windows.cpp:1013:10:1013:14 | * ... | semmle.label | * ... | -| windows.cpp:1019:53:1019:56 | RegQueryValueExA output argument | semmle.label | RegQueryValueExA output argument | -| windows.cpp:1021:10:1021:14 | * ... | semmle.label | * ... | -| windows.cpp:1027:54:1027:57 | RegQueryValueExW output argument | semmle.label | RegQueryValueExW output argument | -| windows.cpp:1029:10:1029:14 | * ... | semmle.label | * ... | -| windows.cpp:1035:46:1035:49 | RegQueryMultipleValuesA output argument | semmle.label | RegQueryMultipleValuesA output argument | -| windows.cpp:1037:10:1037:14 | * ... | semmle.label | * ... | -| windows.cpp:1043:46:1043:49 | RegQueryMultipleValuesW output argument | semmle.label | RegQueryMultipleValuesW output argument | -| windows.cpp:1045:10:1045:14 | * ... | semmle.label | * ... | -| windows.cpp:1051:53:1051:56 | RegGetValueA output argument | semmle.label | RegGetValueA output argument | -| windows.cpp:1053:10:1053:14 | * ... | semmle.label | * ... | -| windows.cpp:1060:53:1060:56 | RegGetValueA output argument | semmle.label | RegGetValueA output argument | -| windows.cpp:1062:10:1062:14 | * ... | semmle.label | * ... | -| windows.cpp:1070:71:1070:74 | RegEnumValueA output argument | semmle.label | RegEnumValueA output argument | -| windows.cpp:1072:10:1072:14 | * ... | semmle.label | * ... | -| windows.cpp:1080:71:1080:74 | RegEnumValueW output argument | semmle.label | RegEnumValueW output argument | -| windows.cpp:1082:10:1082:14 | * ... | semmle.label | * ... | -| windows.cpp:1114:5:1114:27 | ... = ... | semmle.label | ... = ... | -| windows.cpp:1114:14:1114:27 | call to source | semmle.label | call to source | -| windows.cpp:1116:19:1116:21 | *str | semmle.label | *str | -| windows.cpp:1116:24:1116:27 | IIDFromString output argument | semmle.label | IIDFromString output argument | -| windows.cpp:1117:10:1117:12 | iid | semmle.label | iid | -| windows.cpp:1120:15:1120:20 | call to source | semmle.label | call to source | -| windows.cpp:1120:15:1120:20 | call to source | semmle.label | call to source | -| windows.cpp:1122:19:1122:21 | *iid | semmle.label | *iid | -| windows.cpp:1122:24:1122:27 | StringFromIID output argument | semmle.label | StringFromIID output argument | -| windows.cpp:1124:10:1124:13 | * ... | semmle.label | * ... | -| windows.cpp:1127:19:1127:24 | call to source | semmle.label | call to source | -| windows.cpp:1127:19:1127:24 | call to source | semmle.label | call to source | -| windows.cpp:1129:21:1129:25 | *clsid | semmle.label | *clsid | -| windows.cpp:1129:28:1129:31 | ProgIDFromCLSID output argument | semmle.label | ProgIDFromCLSID output argument | -| windows.cpp:1131:10:1131:13 | * ... | semmle.label | * ... | -| windows.cpp:1135:5:1135:30 | ... = ... | semmle.label | ... = ... | -| windows.cpp:1135:17:1135:30 | call to source | semmle.label | call to source | -| windows.cpp:1137:21:1137:26 | *progID | semmle.label | *progID | -| windows.cpp:1137:29:1137:34 | CLSIDFromProgID output argument | semmle.label | CLSIDFromProgID output argument | -| windows.cpp:1138:10:1138:14 | clsid | semmle.label | clsid | -| windows.cpp:1142:5:1142:27 | ... = ... | semmle.label | ... = ... | -| windows.cpp:1142:14:1142:27 | call to source | semmle.label | call to source | -| windows.cpp:1144:21:1144:23 | *str | semmle.label | *str | -| windows.cpp:1144:26:1144:31 | CLSIDFromString output argument | semmle.label | CLSIDFromString output argument | -| windows.cpp:1145:10:1145:14 | clsid | semmle.label | clsid | -| windows.cpp:1148:19:1148:24 | call to source | semmle.label | call to source | -| windows.cpp:1148:19:1148:24 | call to source | semmle.label | call to source | -| windows.cpp:1150:21:1150:25 | *clsid | semmle.label | *clsid | -| windows.cpp:1150:28:1150:31 | StringFromCLSID output argument | semmle.label | StringFromCLSID output argument | -| windows.cpp:1152:10:1152:13 | * ... | semmle.label | * ... | -| windows.cpp:1155:17:1155:22 | call to source | semmle.label | call to source | -| windows.cpp:1155:17:1155:22 | call to source | semmle.label | call to source | -| windows.cpp:1157:20:1157:23 | *guid | semmle.label | *guid | -| windows.cpp:1157:26:1157:28 | StringFromGUID output argument | semmle.label | StringFromGUID output argument | -| windows.cpp:1159:10:1159:13 | * ... | semmle.label | * ... | -| windows.cpp:1163:5:1163:27 | ... = ... | semmle.label | ... = ... | -| windows.cpp:1163:14:1163:27 | call to source | semmle.label | call to source | -| windows.cpp:1165:20:1165:22 | *str | semmle.label | *str | -| windows.cpp:1165:25:1165:29 | GUIDFromString output argument | semmle.label | GUIDFromString output argument | -| windows.cpp:1166:10:1166:13 | guid | semmle.label | guid | -| windows.cpp:1169:17:1169:22 | call to source | semmle.label | call to source | -| windows.cpp:1169:17:1169:22 | call to source | semmle.label | call to source | -| windows.cpp:1171:21:1171:24 | *guid | semmle.label | *guid | -| windows.cpp:1171:27:1171:29 | StringFromGUID2 output argument | semmle.label | StringFromGUID2 output argument | -| windows.cpp:1173:10:1173:13 | * ... | semmle.label | * ... | +| windows.cpp:1009:35:1009:38 | RegQueryValueA output argument | semmle.label | RegQueryValueA output argument | +| windows.cpp:1011:10:1011:14 | * ... | semmle.label | * ... | +| windows.cpp:1016:36:1016:39 | RegQueryValueW output argument | semmle.label | RegQueryValueW output argument | +| windows.cpp:1018:10:1018:14 | * ... | semmle.label | * ... | +| windows.cpp:1024:53:1024:56 | RegQueryValueExA output argument | semmle.label | RegQueryValueExA output argument | +| windows.cpp:1026:10:1026:14 | * ... | semmle.label | * ... | +| windows.cpp:1032:54:1032:57 | RegQueryValueExW output argument | semmle.label | RegQueryValueExW output argument | +| windows.cpp:1034:10:1034:14 | * ... | semmle.label | * ... | +| windows.cpp:1040:46:1040:49 | RegQueryMultipleValuesA output argument | semmle.label | RegQueryMultipleValuesA output argument | +| windows.cpp:1042:10:1042:14 | * ... | semmle.label | * ... | +| windows.cpp:1048:46:1048:49 | RegQueryMultipleValuesW output argument | semmle.label | RegQueryMultipleValuesW output argument | +| windows.cpp:1050:10:1050:14 | * ... | semmle.label | * ... | +| windows.cpp:1056:53:1056:56 | RegGetValueA output argument | semmle.label | RegGetValueA output argument | +| windows.cpp:1058:10:1058:14 | * ... | semmle.label | * ... | +| windows.cpp:1065:55:1065:58 | RegGetValueW output argument | semmle.label | RegGetValueW output argument | +| windows.cpp:1067:10:1067:14 | * ... | semmle.label | * ... | +| windows.cpp:1075:28:1075:36 | RegEnumValueA output argument | semmle.label | RegEnumValueA output argument | +| windows.cpp:1075:71:1075:74 | RegEnumValueA output argument | semmle.label | RegEnumValueA output argument | +| windows.cpp:1077:10:1077:14 | * ... | semmle.label | * ... | +| windows.cpp:1079:10:1079:19 | * ... | semmle.label | * ... | +| windows.cpp:1087:28:1087:36 | RegEnumValueW output argument | semmle.label | RegEnumValueW output argument | +| windows.cpp:1087:71:1087:74 | RegEnumValueW output argument | semmle.label | RegEnumValueW output argument | +| windows.cpp:1089:10:1089:14 | * ... | semmle.label | * ... | +| windows.cpp:1091:10:1091:19 | * ... | semmle.label | * ... | +| windows.cpp:1123:5:1123:27 | ... = ... | semmle.label | ... = ... | +| windows.cpp:1123:14:1123:27 | call to source | semmle.label | call to source | +| windows.cpp:1125:19:1125:21 | *str | semmle.label | *str | +| windows.cpp:1125:24:1125:27 | IIDFromString output argument | semmle.label | IIDFromString output argument | +| windows.cpp:1126:10:1126:12 | iid | semmle.label | iid | +| windows.cpp:1129:15:1129:20 | call to source | semmle.label | call to source | +| windows.cpp:1129:15:1129:20 | call to source | semmle.label | call to source | +| windows.cpp:1131:19:1131:21 | *iid | semmle.label | *iid | +| windows.cpp:1131:24:1131:27 | StringFromIID output argument | semmle.label | StringFromIID output argument | +| windows.cpp:1133:10:1133:13 | * ... | semmle.label | * ... | +| windows.cpp:1136:19:1136:24 | call to source | semmle.label | call to source | +| windows.cpp:1136:19:1136:24 | call to source | semmle.label | call to source | +| windows.cpp:1138:21:1138:25 | *clsid | semmle.label | *clsid | +| windows.cpp:1138:28:1138:31 | ProgIDFromCLSID output argument | semmle.label | ProgIDFromCLSID output argument | +| windows.cpp:1140:10:1140:13 | * ... | semmle.label | * ... | +| windows.cpp:1144:5:1144:30 | ... = ... | semmle.label | ... = ... | +| windows.cpp:1144:17:1144:30 | call to source | semmle.label | call to source | +| windows.cpp:1146:21:1146:26 | *progID | semmle.label | *progID | +| windows.cpp:1146:29:1146:34 | CLSIDFromProgID output argument | semmle.label | CLSIDFromProgID output argument | +| windows.cpp:1147:10:1147:14 | clsid | semmle.label | clsid | +| windows.cpp:1151:5:1151:27 | ... = ... | semmle.label | ... = ... | +| windows.cpp:1151:14:1151:27 | call to source | semmle.label | call to source | +| windows.cpp:1153:21:1153:23 | *str | semmle.label | *str | +| windows.cpp:1153:26:1153:31 | CLSIDFromString output argument | semmle.label | CLSIDFromString output argument | +| windows.cpp:1154:10:1154:14 | clsid | semmle.label | clsid | +| windows.cpp:1157:19:1157:24 | call to source | semmle.label | call to source | +| windows.cpp:1157:19:1157:24 | call to source | semmle.label | call to source | +| windows.cpp:1159:21:1159:25 | *clsid | semmle.label | *clsid | +| windows.cpp:1159:28:1159:31 | StringFromCLSID output argument | semmle.label | StringFromCLSID output argument | +| windows.cpp:1161:10:1161:13 | * ... | semmle.label | * ... | +| windows.cpp:1164:17:1164:22 | call to source | semmle.label | call to source | +| windows.cpp:1164:17:1164:22 | call to source | semmle.label | call to source | +| windows.cpp:1166:20:1166:23 | *guid | semmle.label | *guid | +| windows.cpp:1166:26:1166:28 | StringFromGUID output argument | semmle.label | StringFromGUID output argument | +| windows.cpp:1168:10:1168:13 | * ... | semmle.label | * ... | +| windows.cpp:1172:5:1172:27 | ... = ... | semmle.label | ... = ... | +| windows.cpp:1172:14:1172:27 | call to source | semmle.label | call to source | +| windows.cpp:1174:20:1174:22 | *str | semmle.label | *str | +| windows.cpp:1174:25:1174:29 | GUIDFromString output argument | semmle.label | GUIDFromString output argument | +| windows.cpp:1175:10:1175:13 | guid | semmle.label | guid | +| windows.cpp:1178:17:1178:22 | call to source | semmle.label | call to source | +| windows.cpp:1178:17:1178:22 | call to source | semmle.label | call to source | +| windows.cpp:1180:21:1180:24 | *guid | semmle.label | *guid | +| windows.cpp:1180:27:1180:29 | StringFromGUID2 output argument | semmle.label | StringFromGUID2 output argument | +| windows.cpp:1182:10:1182:13 | * ... | semmle.label | * ... | subpaths | test.cpp:32:41:32:41 | x | test.cpp:7:47:7:52 | value2 | test.cpp:7:5:7:30 | *ymlStepGenerated_with_body | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | | test.cpp:172:51:172:51 | x | test.cpp:164:34:164:34 | x | test.cpp:164:7:164:7 | *templateFunction3 | test.cpp:172:13:172:44 | call to templateFunction3 | diff --git a/cpp/ql/test/library-tests/dataflow/external-models/sources.expected b/cpp/ql/test/library-tests/dataflow/external-models/sources.expected index e35d79d23271..3556bd9d51dd 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/sources.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/sources.expected @@ -43,13 +43,15 @@ | windows.cpp:900:64:900:77 | HttpReceiveHttpRequest output argument | remote | | windows.cpp:929:70:929:75 | HttpReceiveRequestEntityBody output argument | remote | | windows.cpp:936:70:936:78 | HttpReceiveClientCertificate output argument | remote | -| windows.cpp:1004:35:1004:38 | RegQueryValueA output argument | windows-registry | -| windows.cpp:1011:36:1011:39 | RegQueryValueW output argument | windows-registry | -| windows.cpp:1019:53:1019:56 | RegQueryValueExA output argument | windows-registry | -| windows.cpp:1027:54:1027:57 | RegQueryValueExW output argument | windows-registry | -| windows.cpp:1035:46:1035:49 | RegQueryMultipleValuesA output argument | windows-registry | -| windows.cpp:1043:46:1043:49 | RegQueryMultipleValuesW output argument | windows-registry | -| windows.cpp:1051:53:1051:56 | RegGetValueA output argument | windows-registry | -| windows.cpp:1060:53:1060:56 | RegGetValueA output argument | windows-registry | -| windows.cpp:1070:71:1070:74 | RegEnumValueA output argument | windows-registry | -| windows.cpp:1080:71:1080:74 | RegEnumValueW output argument | windows-registry | +| windows.cpp:1009:35:1009:38 | RegQueryValueA output argument | windows-registry | +| windows.cpp:1016:36:1016:39 | RegQueryValueW output argument | windows-registry | +| windows.cpp:1024:53:1024:56 | RegQueryValueExA output argument | windows-registry | +| windows.cpp:1032:54:1032:57 | RegQueryValueExW output argument | windows-registry | +| windows.cpp:1040:46:1040:49 | RegQueryMultipleValuesA output argument | windows-registry | +| windows.cpp:1048:46:1048:49 | RegQueryMultipleValuesW output argument | windows-registry | +| windows.cpp:1056:53:1056:56 | RegGetValueA output argument | windows-registry | +| windows.cpp:1065:55:1065:58 | RegGetValueW output argument | windows-registry | +| windows.cpp:1075:28:1075:36 | RegEnumValueA output argument | windows-registry | +| windows.cpp:1075:71:1075:74 | RegEnumValueA output argument | windows-registry | +| windows.cpp:1087:28:1087:36 | RegEnumValueW output argument | windows-registry | +| windows.cpp:1087:71:1087:74 | RegEnumValueW output argument | windows-registry | diff --git a/cpp/ql/test/library-tests/dataflow/external-models/steps.expected b/cpp/ql/test/library-tests/dataflow/external-models/steps.expected index c6baaf658a3a..75d64445ac9a 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/steps.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/steps.expected @@ -10,12 +10,12 @@ | test.cpp:28:35:28:35 | 0 | test.cpp:28:11:28:33 | call to ymlStepManual_with_body | | windows.cpp:27:36:27:38 | *cmd | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | | windows.cpp:729:35:729:35 | *x | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | -| windows.cpp:1116:19:1116:21 | *str | windows.cpp:1116:24:1116:27 | IIDFromString output argument | -| windows.cpp:1122:19:1122:21 | *iid | windows.cpp:1122:24:1122:27 | StringFromIID output argument | -| windows.cpp:1129:21:1129:25 | *clsid | windows.cpp:1129:28:1129:31 | ProgIDFromCLSID output argument | -| windows.cpp:1137:21:1137:26 | *progID | windows.cpp:1137:29:1137:34 | CLSIDFromProgID output argument | -| windows.cpp:1144:21:1144:23 | *str | windows.cpp:1144:26:1144:31 | CLSIDFromString output argument | -| windows.cpp:1150:21:1150:25 | *clsid | windows.cpp:1150:28:1150:31 | StringFromCLSID output argument | -| windows.cpp:1157:20:1157:23 | *guid | windows.cpp:1157:26:1157:28 | StringFromGUID output argument | -| windows.cpp:1165:20:1165:22 | *str | windows.cpp:1165:25:1165:29 | GUIDFromString output argument | -| windows.cpp:1171:21:1171:24 | *guid | windows.cpp:1171:27:1171:29 | StringFromGUID2 output argument | +| windows.cpp:1125:19:1125:21 | *str | windows.cpp:1125:24:1125:27 | IIDFromString output argument | +| windows.cpp:1131:19:1131:21 | *iid | windows.cpp:1131:24:1131:27 | StringFromIID output argument | +| windows.cpp:1138:21:1138:25 | *clsid | windows.cpp:1138:28:1138:31 | ProgIDFromCLSID output argument | +| windows.cpp:1146:21:1146:26 | *progID | windows.cpp:1146:29:1146:34 | CLSIDFromProgID output argument | +| windows.cpp:1153:21:1153:23 | *str | windows.cpp:1153:26:1153:31 | CLSIDFromString output argument | +| windows.cpp:1159:21:1159:25 | *clsid | windows.cpp:1159:28:1159:31 | StringFromCLSID output argument | +| windows.cpp:1166:20:1166:23 | *guid | windows.cpp:1166:26:1166:28 | StringFromGUID output argument | +| windows.cpp:1174:20:1174:22 | *str | windows.cpp:1174:25:1174:29 | GUIDFromString output argument | +| windows.cpp:1180:21:1180:24 | *guid | windows.cpp:1180:27:1180:29 | StringFromGUID2 output argument | diff --git a/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp b/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp index 7347a6119ff6..e956495cfb96 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp +++ b/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp @@ -979,6 +979,11 @@ LONG RegGetValueA( LPDWORD lpcbData ); +LONG RegGetValueW( + HKEY hKey, LPCWSTR lpSubKey, LPCWSTR lpValue, DWORD flags, LPDWORD lpType, PVOID lpData, + LPDWORD lpcbData +); + LONG RegQueryMultipleValuesA( HKEY hKey, PVALENTA valList, DWORD numVals, LPSTR valueBuffer, LPDWORD totalSize ); @@ -1057,7 +1062,7 @@ void test_registry_queries(HKEY hKey) { BYTE data[256]; DWORD dataSize = sizeof(data); DWORD type; - RegGetValueA(hKey, "subkey", "value", 0, &type, data, &dataSize); + RegGetValueW(hKey, L"subkey", L"value", 0, &type, data, &dataSize); sink(data); // clean sink(*data); // $ ir } @@ -1070,6 +1075,8 @@ void test_registry_queries(HKEY hKey) { RegEnumValueA(hKey, 0, valueName, &valueNameSize, nullptr, &type, data, &dataSize); sink(data); // clean sink(*data); // $ ir + sink(valueName); // clean + sink(*valueName); // $ ir } { wchar_t valueName[256]; @@ -1080,6 +1087,8 @@ void test_registry_queries(HKEY hKey) { RegEnumValueW(hKey, 0, valueName, &valueNameSize, nullptr, &type, data, &dataSize); sink(data); // clean sink(*data); // $ ir + sink(valueName); // clean + sink(*valueName); // $ ir } } From 285e61fea95a02d36cfff96e4df79f37cd1e3e61 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 30 Jul 2026 23:09:25 +0100 Subject: [PATCH 156/188] C++: Fix QLDoc. --- cpp/ql/lib/semmle/code/cpp/security/FlowSources.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/lib/semmle/code/cpp/security/FlowSources.qll b/cpp/ql/lib/semmle/code/cpp/security/FlowSources.qll index e0890064aa75..1d085f458dec 100644 --- a/cpp/ql/lib/semmle/code/cpp/security/FlowSources.qll +++ b/cpp/ql/lib/semmle/code/cpp/security/FlowSources.qll @@ -20,7 +20,7 @@ abstract class RemoteFlowSource extends FlowSource { } /** A data flow source of local user input. */ abstract class LocalFlowSource extends FlowSource { } -/** A data flow source of local user input. */ +/** A data flow source that represents the access of a value from the Windows registry. */ abstract class WindowsRegistrySource extends LocalFlowSource { } /** From 9cf4d07acb58f4a2df4c959cb17305f34d0f0fe4 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 30 Jul 2026 23:10:33 +0100 Subject: [PATCH 157/188] C++: Remove 'StringFromGUID'. --- .../dataflow/external-models/flow.expected | 248 +++++++++--------- .../dataflow/external-models/steps.expected | 17 +- .../dataflow/external-models/windows.cpp | 8 - 3 files changed, 127 insertions(+), 146 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/external-models/flow.expected b/cpp/ql/test/library-tests/dataflow/external-models/flow.expected index cd9aad336ebe..24ba3b2aa686 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/flow.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/flow.expected @@ -61,28 +61,27 @@ models | 60 | Summary: ; ; false; RtlMoveVolatileMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | | 61 | Summary: ; ; false; StringFromCLSID; ; ; Argument[*0]; Argument[**1]; taint; manual | | 62 | Summary: ; ; false; StringFromGUID2; ; ; Argument[*0]; Argument[*1]; taint; manual | -| 63 | Summary: ; ; false; StringFromGUID; ; ; Argument[*0]; Argument[*1]; taint; manual | -| 64 | Summary: ; ; false; StringFromIID; ; ; Argument[*0]; Argument[**1]; taint; manual | -| 65 | Summary: ; ; false; WinHttpCrackUrl; ; ; Argument[*0]; Argument[*3]; taint; manual | -| 66 | Summary: ; ; false; callWithArgument; ; ; Argument[1]; Argument[0].Parameter[0]; value; manual | -| 67 | Summary: ; ; false; callWithNonTypeTemplate; (const T &); ; Argument[*0]; ReturnValue; value; manual | -| 68 | Summary: ; ; false; pthread_create; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual | -| 69 | Summary: ; ; false; read_field_from_struct; ; ; Argument[*0].Field[MyNamespace::MyStructInNamespace::myField]; ReturnValue; value; manual | -| 70 | Summary: ; ; false; read_field_from_struct_2; ; ; Argument[*0].Field[MyGlobalStruct::myField]; ReturnValue; value; manual | -| 71 | Summary: ; ; false; ymlStepGenerated; ; ; Argument[0]; ReturnValue; taint; df-generated | -| 72 | Summary: ; ; false; ymlStepManual; ; ; Argument[0]; ReturnValue; taint; manual | -| 73 | Summary: ; ; false; ymlStepManual_with_body; ; ; Argument[0]; ReturnValue; taint; manual | -| 74 | Summary: ; MyString; true; operator[]; ; ; Argument[-1]; ReturnValue[*]; taint; manual | -| 75 | Summary: ; MyString; true; operator[]; ; ; ReturnValue[*]; Argument[-1]; taint; manual | -| 76 | Summary: ; ReverseFlow; true; get_ptr; ; ; ReturnValue[*]; Argument[-1].Field[ReverseFlow::value]; value; manual | -| 77 | Summary: ; TemplateClass1; true; templateFunction2; (U,V); ; Argument[1]; ReturnValue; value; manual | -| 78 | Summary: ; TemplateClass1; false; templateFunction; (T,U); ; Argument[0]; ReturnValue; value; manual | -| 79 | Summary: ; TemplateClass2; true; function; (U,T); ; Argument[1]; ReturnValue; value; manual | -| 80 | Summary: Azure::Core::IO; BodyStream; true; Read; ; ; Argument[-1]; Argument[*0]; taint; manual | -| 81 | Summary: Azure::Core::IO; BodyStream; true; ReadToCount; ; ; Argument[-1]; Argument[*0]; taint; manual | -| 82 | Summary: Azure::Core::IO; BodyStream; true; ReadToEnd; ; ; Argument[-1]; ReturnValue.Element; taint; manual | -| 83 | Summary: Azure; Nullable; true; Value; ; ; Argument[-1]; ReturnValue[*]; taint; manual | -| 84 | Summary: boost::asio; ; false; buffer; ; ; Argument[*0]; ReturnValue; taint; manual | +| 63 | Summary: ; ; false; StringFromIID; ; ; Argument[*0]; Argument[**1]; taint; manual | +| 64 | Summary: ; ; false; WinHttpCrackUrl; ; ; Argument[*0]; Argument[*3]; taint; manual | +| 65 | Summary: ; ; false; callWithArgument; ; ; Argument[1]; Argument[0].Parameter[0]; value; manual | +| 66 | Summary: ; ; false; callWithNonTypeTemplate; (const T &); ; Argument[*0]; ReturnValue; value; manual | +| 67 | Summary: ; ; false; pthread_create; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual | +| 68 | Summary: ; ; false; read_field_from_struct; ; ; Argument[*0].Field[MyNamespace::MyStructInNamespace::myField]; ReturnValue; value; manual | +| 69 | Summary: ; ; false; read_field_from_struct_2; ; ; Argument[*0].Field[MyGlobalStruct::myField]; ReturnValue; value; manual | +| 70 | Summary: ; ; false; ymlStepGenerated; ; ; Argument[0]; ReturnValue; taint; df-generated | +| 71 | Summary: ; ; false; ymlStepManual; ; ; Argument[0]; ReturnValue; taint; manual | +| 72 | Summary: ; ; false; ymlStepManual_with_body; ; ; Argument[0]; ReturnValue; taint; manual | +| 73 | Summary: ; MyString; true; operator[]; ; ; Argument[-1]; ReturnValue[*]; taint; manual | +| 74 | Summary: ; MyString; true; operator[]; ; ; ReturnValue[*]; Argument[-1]; taint; manual | +| 75 | Summary: ; ReverseFlow; true; get_ptr; ; ; ReturnValue[*]; Argument[-1].Field[ReverseFlow::value]; value; manual | +| 76 | Summary: ; TemplateClass1; true; templateFunction2; (U,V); ; Argument[1]; ReturnValue; value; manual | +| 77 | Summary: ; TemplateClass1; false; templateFunction; (T,U); ; Argument[0]; ReturnValue; value; manual | +| 78 | Summary: ; TemplateClass2; true; function; (U,T); ; Argument[1]; ReturnValue; value; manual | +| 79 | Summary: Azure::Core::IO; BodyStream; true; Read; ; ; Argument[-1]; Argument[*0]; taint; manual | +| 80 | Summary: Azure::Core::IO; BodyStream; true; ReadToCount; ; ; Argument[-1]; Argument[*0]; taint; manual | +| 81 | Summary: Azure::Core::IO; BodyStream; true; ReadToEnd; ; ; Argument[-1]; ReturnValue.Element; taint; manual | +| 82 | Summary: Azure; Nullable; true; Value; ; ; Argument[-1]; ReturnValue[*]; taint; manual | +| 83 | Summary: boost::asio; ; false; buffer; ; ; Argument[*0]; ReturnValue; taint; manual | edges | asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:91:7:91:17 | recv_buffer | provenance | Src:MaD:42 | | asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:93:29:93:39 | *recv_buffer | provenance | Src:MaD:42 Sink:MaD:2 | @@ -91,16 +90,16 @@ edges | asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | | | asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:101:7:101:17 | send_buffer | provenance | | | asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:103:29:103:39 | *send_buffer | provenance | Sink:MaD:2 | -| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:84 | +| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:83 | | azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:253:48:253:60 | *call to GetBodyStream | provenance | Src:MaD:39 | | azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:257:5:257:8 | *resp | provenance | | | azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:262:5:262:8 | *resp | provenance | | | azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:266:38:266:41 | *resp | provenance | | -| azure.cpp:257:5:257:8 | *resp | azure.cpp:257:16:257:21 | Read output argument | provenance | MaD:80 | +| azure.cpp:257:5:257:8 | *resp | azure.cpp:257:16:257:21 | Read output argument | provenance | MaD:79 | | azure.cpp:257:16:257:21 | Read output argument | azure.cpp:258:10:258:16 | * ... | provenance | | -| azure.cpp:262:5:262:8 | *resp | azure.cpp:262:23:262:28 | ReadToCount output argument | provenance | MaD:81 | +| azure.cpp:262:5:262:8 | *resp | azure.cpp:262:23:262:28 | ReadToCount output argument | provenance | MaD:80 | | azure.cpp:262:23:262:28 | ReadToCount output argument | azure.cpp:263:10:263:16 | * ... | provenance | | -| azure.cpp:266:38:266:41 | *resp | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | provenance | MaD:82 | +| azure.cpp:266:38:266:41 | *resp | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | provenance | MaD:81 | | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | provenance | | | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | azure.cpp:267:10:267:12 | vec [element] | provenance | | | azure.cpp:267:10:267:12 | vec [element] | azure.cpp:267:10:267:12 | vec | provenance | | @@ -116,10 +115,10 @@ edges | azure.cpp:278:10:278:13 | body | azure.cpp:278:10:278:13 | body | provenance | | | azure.cpp:281:68:281:84 | *call to ExtractBodyStream | azure.cpp:281:68:281:84 | *call to ExtractBodyStream | provenance | Src:MaD:36 | | azure.cpp:281:68:281:84 | *call to ExtractBodyStream | azure.cpp:282:21:282:23 | *call to get | provenance | | -| azure.cpp:282:21:282:23 | *call to get | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | provenance | MaD:82 | +| azure.cpp:282:21:282:23 | *call to get | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | provenance | MaD:81 | | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | azure.cpp:282:10:282:38 | call to ReadToEnd | provenance | | | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | provenance | | -| azure.cpp:289:24:289:56 | call to GetHeader | azure.cpp:289:63:289:65 | call to Value | provenance | MaD:83 | +| azure.cpp:289:24:289:56 | call to GetHeader | azure.cpp:289:63:289:65 | call to Value | provenance | MaD:82 | | azure.cpp:289:32:289:40 | call to GetHeader | azure.cpp:289:24:289:56 | call to GetHeader | provenance | | | azure.cpp:289:32:289:40 | call to GetHeader | azure.cpp:289:32:289:40 | call to GetHeader | provenance | Src:MaD:40 | | azure.cpp:289:63:289:65 | call to Value | azure.cpp:289:63:289:65 | call to Value | provenance | | @@ -141,13 +140,13 @@ edges | test.cpp:10:10:10:18 | call to ymlSource | test.cpp:32:41:32:41 | x | provenance | | | test.cpp:17:10:17:22 | call to ymlStepManual | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | | | test.cpp:17:10:17:22 | call to ymlStepManual | test.cpp:18:10:18:10 | y | provenance | Sink:MaD:1 | -| test.cpp:17:24:17:24 | x | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | MaD:72 | +| test.cpp:17:24:17:24 | x | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | MaD:71 | | test.cpp:21:10:21:25 | call to ymlStepGenerated | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | | | test.cpp:21:10:21:25 | call to ymlStepGenerated | test.cpp:22:10:22:10 | z | provenance | Sink:MaD:1 | -| test.cpp:21:27:21:27 | x | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | MaD:71 | +| test.cpp:21:27:21:27 | x | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | MaD:70 | | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | | | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | test.cpp:26:10:26:11 | y2 | provenance | Sink:MaD:1 | -| test.cpp:25:35:25:35 | x | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | MaD:73 | +| test.cpp:25:35:25:35 | x | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | MaD:72 | | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | provenance | | | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | test.cpp:33:10:33:11 | z2 | provenance | Sink:MaD:1 | | test.cpp:32:41:32:41 | x | test.cpp:7:47:7:52 | value2 | provenance | | @@ -158,7 +157,7 @@ edges | test.cpp:56:2:56:2 | *s [post update] [x] | test.cpp:59:55:59:64 | *& ... [x] | provenance | | | test.cpp:56:2:56:18 | ... = ... | test.cpp:56:2:56:2 | *s [post update] [x] | provenance | | | test.cpp:56:8:56:16 | call to ymlSource | test.cpp:56:2:56:18 | ... = ... | provenance | Src:MaD:35 | -| test.cpp:59:55:59:64 | *& ... [x] | test.cpp:46:30:46:32 | *arg [x] | provenance | MaD:68 | +| test.cpp:59:55:59:64 | *& ... [x] | test.cpp:46:30:46:32 | *arg [x] | provenance | MaD:67 | | test.cpp:68:22:68:22 | y | test.cpp:69:11:69:11 | y | provenance | Sink:MaD:1 | | test.cpp:74:22:74:22 | y | test.cpp:75:11:75:11 | y | provenance | Sink:MaD:1 | | test.cpp:82:22:82:22 | y | test.cpp:83:11:83:11 | y | provenance | Sink:MaD:1 | @@ -168,62 +167,62 @@ edges | test.cpp:94:10:94:18 | call to ymlSource | test.cpp:101:26:101:26 | x | provenance | | | test.cpp:94:10:94:18 | call to ymlSource | test.cpp:103:63:103:63 | x | provenance | | | test.cpp:94:10:94:18 | call to ymlSource | test.cpp:104:62:104:62 | x | provenance | | -| test.cpp:97:26:97:26 | x | test.cpp:68:22:68:22 | y | provenance | MaD:66 | -| test.cpp:101:26:101:26 | x | test.cpp:74:22:74:22 | y | provenance | MaD:66 | -| test.cpp:103:63:103:63 | x | test.cpp:82:22:82:22 | y | provenance | MaD:66 | -| test.cpp:104:62:104:62 | x | test.cpp:88:22:88:22 | y | provenance | MaD:66 | +| test.cpp:97:26:97:26 | x | test.cpp:68:22:68:22 | y | provenance | MaD:65 | +| test.cpp:101:26:101:26 | x | test.cpp:74:22:74:22 | y | provenance | MaD:65 | +| test.cpp:103:63:103:63 | x | test.cpp:82:22:82:22 | y | provenance | MaD:65 | +| test.cpp:104:62:104:62 | x | test.cpp:88:22:88:22 | y | provenance | MaD:65 | | test.cpp:114:10:114:18 | call to ymlSource | test.cpp:114:10:114:18 | call to ymlSource | provenance | Src:MaD:35 | | test.cpp:114:10:114:18 | call to ymlSource | test.cpp:118:44:118:44 | *x | provenance | | | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | provenance | | | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | test.cpp:119:10:119:11 | y2 | provenance | Sink:MaD:1 | -| test.cpp:118:44:118:44 | *x | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | provenance | MaD:67 | +| test.cpp:118:44:118:44 | *x | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | provenance | MaD:66 | | test.cpp:133:10:133:18 | call to ymlSource | test.cpp:133:10:133:18 | call to ymlSource | provenance | Src:MaD:35 | | test.cpp:133:10:133:18 | call to ymlSource | test.cpp:134:45:134:45 | x | provenance | | | test.cpp:134:13:134:43 | call to templateFunction | test.cpp:134:13:134:43 | call to templateFunction | provenance | | | test.cpp:134:13:134:43 | call to templateFunction | test.cpp:135:10:135:10 | y | provenance | Sink:MaD:1 | -| test.cpp:134:45:134:45 | x | test.cpp:134:13:134:43 | call to templateFunction | provenance | MaD:78 | +| test.cpp:134:45:134:45 | x | test.cpp:134:13:134:43 | call to templateFunction | provenance | MaD:77 | | test.cpp:146:10:146:18 | call to ymlSource | test.cpp:146:10:146:18 | call to ymlSource | provenance | Src:MaD:35 | | test.cpp:146:10:146:18 | call to ymlSource | test.cpp:148:26:148:26 | x | provenance | | | test.cpp:148:10:148:27 | call to function | test.cpp:148:10:148:27 | call to function | provenance | | | test.cpp:148:10:148:27 | call to function | test.cpp:149:10:149:10 | z | provenance | Sink:MaD:1 | -| test.cpp:148:26:148:26 | x | test.cpp:148:10:148:27 | call to function | provenance | MaD:79 | +| test.cpp:148:26:148:26 | x | test.cpp:148:10:148:27 | call to function | provenance | MaD:78 | | test.cpp:155:10:155:18 | call to ymlSource | test.cpp:155:10:155:18 | call to ymlSource | provenance | Src:MaD:35 | | test.cpp:155:10:155:18 | call to ymlSource | test.cpp:157:26:157:26 | x | provenance | | | test.cpp:157:13:157:20 | call to function | test.cpp:157:13:157:20 | call to function | provenance | | | test.cpp:157:13:157:20 | call to function | test.cpp:158:10:158:10 | z | provenance | Sink:MaD:1 | -| test.cpp:157:26:157:26 | x | test.cpp:157:13:157:20 | call to function | provenance | MaD:79 | +| test.cpp:157:26:157:26 | x | test.cpp:157:13:157:20 | call to function | provenance | MaD:78 | | test.cpp:164:34:164:34 | x | test.cpp:165:69:165:69 | x | provenance | | | test.cpp:165:12:165:64 | call to templateFunction2 | test.cpp:164:7:164:7 | *templateFunction3 | provenance | | | test.cpp:165:12:165:64 | call to templateFunction2 | test.cpp:165:12:165:64 | call to templateFunction2 | provenance | | -| test.cpp:165:69:165:69 | x | test.cpp:165:12:165:64 | call to templateFunction2 | provenance | MaD:77 | +| test.cpp:165:69:165:69 | x | test.cpp:165:12:165:64 | call to templateFunction2 | provenance | MaD:76 | | test.cpp:170:10:170:18 | call to ymlSource | test.cpp:170:10:170:18 | call to ymlSource | provenance | Src:MaD:35 | | test.cpp:170:10:170:18 | call to ymlSource | test.cpp:172:51:172:51 | x | provenance | | | test.cpp:172:13:172:44 | call to templateFunction3 | test.cpp:172:13:172:44 | call to templateFunction3 | provenance | | | test.cpp:172:13:172:44 | call to templateFunction3 | test.cpp:173:10:173:10 | y | provenance | Sink:MaD:1 | | test.cpp:172:51:172:51 | x | test.cpp:164:34:164:34 | x | provenance | | -| test.cpp:172:51:172:51 | x | test.cpp:172:13:172:44 | call to templateFunction3 | provenance | MaD:77 | +| test.cpp:172:51:172:51 | x | test.cpp:172:13:172:44 | call to templateFunction3 | provenance | MaD:76 | | test.cpp:186:2:186:2 | *s [post update] [myField] | test.cpp:187:33:187:34 | *& ... [myField] | provenance | | | test.cpp:186:2:186:24 | ... = ... | test.cpp:186:2:186:2 | *s [post update] [myField] | provenance | | | test.cpp:186:14:186:22 | call to ymlSource | test.cpp:186:2:186:24 | ... = ... | provenance | Src:MaD:35 | | test.cpp:187:10:187:31 | call to read_field_from_struct | test.cpp:187:10:187:31 | call to read_field_from_struct | provenance | | | test.cpp:187:10:187:31 | call to read_field_from_struct | test.cpp:188:10:188:10 | x | provenance | Sink:MaD:1 | -| test.cpp:187:33:187:34 | *& ... [myField] | test.cpp:187:10:187:31 | call to read_field_from_struct | provenance | MaD:69 | +| test.cpp:187:33:187:34 | *& ... [myField] | test.cpp:187:10:187:31 | call to read_field_from_struct | provenance | MaD:68 | | test.cpp:199:2:199:2 | *s [post update] [myField] | test.cpp:200:35:200:36 | *& ... [myField] | provenance | | | test.cpp:199:2:199:24 | ... = ... | test.cpp:199:2:199:2 | *s [post update] [myField] | provenance | | | test.cpp:199:14:199:22 | call to ymlSource | test.cpp:199:2:199:24 | ... = ... | provenance | Src:MaD:35 | | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | provenance | | | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | test.cpp:201:10:201:10 | x | provenance | Sink:MaD:1 | -| test.cpp:200:35:200:36 | *& ... [myField] | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | provenance | MaD:70 | +| test.cpp:200:35:200:36 | *& ... [myField] | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | provenance | MaD:69 | | test.cpp:216:3:216:4 | get_ptr output argument [value] | test.cpp:217:11:217:12 | *rf [value] | provenance | | -| test.cpp:216:3:216:28 | ... = ... | test.cpp:216:3:216:4 | get_ptr output argument [value] | provenance | MaD:76 | +| test.cpp:216:3:216:28 | ... = ... | test.cpp:216:3:216:4 | get_ptr output argument [value] | provenance | MaD:75 | | test.cpp:216:18:216:26 | call to ymlSource | test.cpp:216:3:216:28 | ... = ... | provenance | Src:MaD:35 | | test.cpp:217:11:217:12 | *rf [value] | test.cpp:217:14:217:18 | value | provenance | | | test.cpp:217:14:217:18 | value | test.cpp:217:14:217:18 | value | provenance | | | test.cpp:217:14:217:18 | value | test.cpp:218:11:218:11 | x | provenance | Sink:MaD:1 | | test.cpp:222:3:222:3 | operator[] output argument | test.cpp:223:12:223:12 | *s | provenance | | -| test.cpp:222:3:222:20 | ... = ... | test.cpp:222:3:222:3 | operator[] output argument | provenance | MaD:75 | +| test.cpp:222:3:222:20 | ... = ... | test.cpp:222:3:222:3 | operator[] output argument | provenance | MaD:74 | | test.cpp:222:10:222:20 | call to ymlSource | test.cpp:222:3:222:20 | ... = ... | provenance | Src:MaD:35 | -| test.cpp:223:12:223:12 | *s | test.cpp:223:13:223:15 | call to operator[] | provenance | MaD:74 | +| test.cpp:223:12:223:12 | *s | test.cpp:223:13:223:15 | call to operator[] | provenance | MaD:73 | | test.cpp:223:13:223:15 | call to operator[] | test.cpp:223:13:223:15 | call to operator[] | provenance | | | test.cpp:223:13:223:15 | call to operator[] | test.cpp:224:11:224:11 | c | provenance | Sink:MaD:1 | | windows.cpp:22:15:22:29 | *call to GetCommandLineA | windows.cpp:22:15:22:29 | *call to GetCommandLineA | provenance | Src:MaD:3 | @@ -335,7 +334,7 @@ edges | windows.cpp:669:105:669:112 | WinHttpQueryHeadersEx output argument | windows.cpp:675:10:675:27 | * ... | provenance | Src:MaD:30 | | windows.cpp:728:5:728:28 | ... = ... | windows.cpp:729:35:729:35 | *x | provenance | | | windows.cpp:728:12:728:28 | call to source | windows.cpp:728:5:728:28 | ... = ... | provenance | | -| windows.cpp:729:35:729:35 | *x | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | provenance | MaD:65 | +| windows.cpp:729:35:729:35 | *x | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | provenance | MaD:64 | | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | windows.cpp:731:10:731:36 | * ... | provenance | | | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | windows.cpp:733:10:733:35 | * ... | provenance | | | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | windows.cpp:735:10:735:37 | * ... | provenance | | @@ -368,42 +367,38 @@ edges | windows.cpp:1075:71:1075:74 | RegEnumValueA output argument | windows.cpp:1077:10:1077:14 | * ... | provenance | Src:MaD:19 | | windows.cpp:1087:28:1087:36 | RegEnumValueW output argument | windows.cpp:1091:10:1091:19 | * ... | provenance | Src:MaD:20 | | windows.cpp:1087:71:1087:74 | RegEnumValueW output argument | windows.cpp:1089:10:1089:14 | * ... | provenance | Src:MaD:20 | -| windows.cpp:1123:5:1123:27 | ... = ... | windows.cpp:1125:19:1125:21 | *str | provenance | | -| windows.cpp:1123:14:1123:27 | call to source | windows.cpp:1123:5:1123:27 | ... = ... | provenance | | -| windows.cpp:1125:19:1125:21 | *str | windows.cpp:1125:24:1125:27 | IIDFromString output argument | provenance | MaD:50 | -| windows.cpp:1125:24:1125:27 | IIDFromString output argument | windows.cpp:1126:10:1126:12 | iid | provenance | | -| windows.cpp:1129:15:1129:20 | call to source | windows.cpp:1129:15:1129:20 | call to source | provenance | | -| windows.cpp:1129:15:1129:20 | call to source | windows.cpp:1131:19:1131:21 | *iid | provenance | | -| windows.cpp:1131:19:1131:21 | *iid | windows.cpp:1131:24:1131:27 | StringFromIID output argument | provenance | MaD:64 | -| windows.cpp:1131:24:1131:27 | StringFromIID output argument | windows.cpp:1133:10:1133:13 | * ... | provenance | | -| windows.cpp:1136:19:1136:24 | call to source | windows.cpp:1136:19:1136:24 | call to source | provenance | | -| windows.cpp:1136:19:1136:24 | call to source | windows.cpp:1138:21:1138:25 | *clsid | provenance | | -| windows.cpp:1138:21:1138:25 | *clsid | windows.cpp:1138:28:1138:31 | ProgIDFromCLSID output argument | provenance | MaD:51 | -| windows.cpp:1138:28:1138:31 | ProgIDFromCLSID output argument | windows.cpp:1140:10:1140:13 | * ... | provenance | | -| windows.cpp:1144:5:1144:30 | ... = ... | windows.cpp:1146:21:1146:26 | *progID | provenance | | -| windows.cpp:1144:17:1144:30 | call to source | windows.cpp:1144:5:1144:30 | ... = ... | provenance | | -| windows.cpp:1146:21:1146:26 | *progID | windows.cpp:1146:29:1146:34 | CLSIDFromProgID output argument | provenance | MaD:43 | -| windows.cpp:1146:29:1146:34 | CLSIDFromProgID output argument | windows.cpp:1147:10:1147:14 | clsid | provenance | | -| windows.cpp:1151:5:1151:27 | ... = ... | windows.cpp:1153:21:1153:23 | *str | provenance | | -| windows.cpp:1151:14:1151:27 | call to source | windows.cpp:1151:5:1151:27 | ... = ... | provenance | | -| windows.cpp:1153:21:1153:23 | *str | windows.cpp:1153:26:1153:31 | CLSIDFromString output argument | provenance | MaD:44 | -| windows.cpp:1153:26:1153:31 | CLSIDFromString output argument | windows.cpp:1154:10:1154:14 | clsid | provenance | | -| windows.cpp:1157:19:1157:24 | call to source | windows.cpp:1157:19:1157:24 | call to source | provenance | | -| windows.cpp:1157:19:1157:24 | call to source | windows.cpp:1159:21:1159:25 | *clsid | provenance | | -| windows.cpp:1159:21:1159:25 | *clsid | windows.cpp:1159:28:1159:31 | StringFromCLSID output argument | provenance | MaD:61 | -| windows.cpp:1159:28:1159:31 | StringFromCLSID output argument | windows.cpp:1161:10:1161:13 | * ... | provenance | | -| windows.cpp:1164:17:1164:22 | call to source | windows.cpp:1164:17:1164:22 | call to source | provenance | | -| windows.cpp:1164:17:1164:22 | call to source | windows.cpp:1166:20:1166:23 | *guid | provenance | | -| windows.cpp:1166:20:1166:23 | *guid | windows.cpp:1166:26:1166:28 | StringFromGUID output argument | provenance | MaD:63 | -| windows.cpp:1166:26:1166:28 | StringFromGUID output argument | windows.cpp:1168:10:1168:13 | * ... | provenance | | -| windows.cpp:1172:5:1172:27 | ... = ... | windows.cpp:1174:20:1174:22 | *str | provenance | | -| windows.cpp:1172:14:1172:27 | call to source | windows.cpp:1172:5:1172:27 | ... = ... | provenance | | -| windows.cpp:1174:20:1174:22 | *str | windows.cpp:1174:25:1174:29 | GUIDFromString output argument | provenance | MaD:49 | -| windows.cpp:1174:25:1174:29 | GUIDFromString output argument | windows.cpp:1175:10:1175:13 | guid | provenance | | -| windows.cpp:1178:17:1178:22 | call to source | windows.cpp:1178:17:1178:22 | call to source | provenance | | -| windows.cpp:1178:17:1178:22 | call to source | windows.cpp:1180:21:1180:24 | *guid | provenance | | -| windows.cpp:1180:21:1180:24 | *guid | windows.cpp:1180:27:1180:29 | StringFromGUID2 output argument | provenance | MaD:62 | -| windows.cpp:1180:27:1180:29 | StringFromGUID2 output argument | windows.cpp:1182:10:1182:13 | * ... | provenance | | +| windows.cpp:1122:5:1122:27 | ... = ... | windows.cpp:1124:19:1124:21 | *str | provenance | | +| windows.cpp:1122:14:1122:27 | call to source | windows.cpp:1122:5:1122:27 | ... = ... | provenance | | +| windows.cpp:1124:19:1124:21 | *str | windows.cpp:1124:24:1124:27 | IIDFromString output argument | provenance | MaD:50 | +| windows.cpp:1124:24:1124:27 | IIDFromString output argument | windows.cpp:1125:10:1125:12 | iid | provenance | | +| windows.cpp:1128:15:1128:20 | call to source | windows.cpp:1128:15:1128:20 | call to source | provenance | | +| windows.cpp:1128:15:1128:20 | call to source | windows.cpp:1130:19:1130:21 | *iid | provenance | | +| windows.cpp:1130:19:1130:21 | *iid | windows.cpp:1130:24:1130:27 | StringFromIID output argument | provenance | MaD:63 | +| windows.cpp:1130:24:1130:27 | StringFromIID output argument | windows.cpp:1132:10:1132:13 | * ... | provenance | | +| windows.cpp:1135:19:1135:24 | call to source | windows.cpp:1135:19:1135:24 | call to source | provenance | | +| windows.cpp:1135:19:1135:24 | call to source | windows.cpp:1137:21:1137:25 | *clsid | provenance | | +| windows.cpp:1137:21:1137:25 | *clsid | windows.cpp:1137:28:1137:31 | ProgIDFromCLSID output argument | provenance | MaD:51 | +| windows.cpp:1137:28:1137:31 | ProgIDFromCLSID output argument | windows.cpp:1139:10:1139:13 | * ... | provenance | | +| windows.cpp:1143:5:1143:30 | ... = ... | windows.cpp:1145:21:1145:26 | *progID | provenance | | +| windows.cpp:1143:17:1143:30 | call to source | windows.cpp:1143:5:1143:30 | ... = ... | provenance | | +| windows.cpp:1145:21:1145:26 | *progID | windows.cpp:1145:29:1145:34 | CLSIDFromProgID output argument | provenance | MaD:43 | +| windows.cpp:1145:29:1145:34 | CLSIDFromProgID output argument | windows.cpp:1146:10:1146:14 | clsid | provenance | | +| windows.cpp:1150:5:1150:27 | ... = ... | windows.cpp:1152:21:1152:23 | *str | provenance | | +| windows.cpp:1150:14:1150:27 | call to source | windows.cpp:1150:5:1150:27 | ... = ... | provenance | | +| windows.cpp:1152:21:1152:23 | *str | windows.cpp:1152:26:1152:31 | CLSIDFromString output argument | provenance | MaD:44 | +| windows.cpp:1152:26:1152:31 | CLSIDFromString output argument | windows.cpp:1153:10:1153:14 | clsid | provenance | | +| windows.cpp:1156:19:1156:24 | call to source | windows.cpp:1156:19:1156:24 | call to source | provenance | | +| windows.cpp:1156:19:1156:24 | call to source | windows.cpp:1158:21:1158:25 | *clsid | provenance | | +| windows.cpp:1158:21:1158:25 | *clsid | windows.cpp:1158:28:1158:31 | StringFromCLSID output argument | provenance | MaD:61 | +| windows.cpp:1158:28:1158:31 | StringFromCLSID output argument | windows.cpp:1160:10:1160:13 | * ... | provenance | | +| windows.cpp:1164:5:1164:27 | ... = ... | windows.cpp:1166:20:1166:22 | *str | provenance | | +| windows.cpp:1164:14:1164:27 | call to source | windows.cpp:1164:5:1164:27 | ... = ... | provenance | | +| windows.cpp:1166:20:1166:22 | *str | windows.cpp:1166:25:1166:29 | GUIDFromString output argument | provenance | MaD:49 | +| windows.cpp:1166:25:1166:29 | GUIDFromString output argument | windows.cpp:1167:10:1167:13 | guid | provenance | | +| windows.cpp:1170:17:1170:22 | call to source | windows.cpp:1170:17:1170:22 | call to source | provenance | | +| windows.cpp:1170:17:1170:22 | call to source | windows.cpp:1172:21:1172:24 | *guid | provenance | | +| windows.cpp:1172:21:1172:24 | *guid | windows.cpp:1172:27:1172:29 | StringFromGUID2 output argument | provenance | MaD:62 | +| windows.cpp:1172:27:1172:29 | StringFromGUID2 output argument | windows.cpp:1174:10:1174:13 | * ... | provenance | | nodes | asio_streams.cpp:87:34:87:44 | read_until output argument | semmle.label | read_until output argument | | asio_streams.cpp:91:7:91:17 | recv_buffer | semmle.label | recv_buffer | @@ -744,51 +739,46 @@ nodes | windows.cpp:1087:71:1087:74 | RegEnumValueW output argument | semmle.label | RegEnumValueW output argument | | windows.cpp:1089:10:1089:14 | * ... | semmle.label | * ... | | windows.cpp:1091:10:1091:19 | * ... | semmle.label | * ... | -| windows.cpp:1123:5:1123:27 | ... = ... | semmle.label | ... = ... | -| windows.cpp:1123:14:1123:27 | call to source | semmle.label | call to source | -| windows.cpp:1125:19:1125:21 | *str | semmle.label | *str | -| windows.cpp:1125:24:1125:27 | IIDFromString output argument | semmle.label | IIDFromString output argument | -| windows.cpp:1126:10:1126:12 | iid | semmle.label | iid | -| windows.cpp:1129:15:1129:20 | call to source | semmle.label | call to source | -| windows.cpp:1129:15:1129:20 | call to source | semmle.label | call to source | -| windows.cpp:1131:19:1131:21 | *iid | semmle.label | *iid | -| windows.cpp:1131:24:1131:27 | StringFromIID output argument | semmle.label | StringFromIID output argument | -| windows.cpp:1133:10:1133:13 | * ... | semmle.label | * ... | -| windows.cpp:1136:19:1136:24 | call to source | semmle.label | call to source | -| windows.cpp:1136:19:1136:24 | call to source | semmle.label | call to source | -| windows.cpp:1138:21:1138:25 | *clsid | semmle.label | *clsid | -| windows.cpp:1138:28:1138:31 | ProgIDFromCLSID output argument | semmle.label | ProgIDFromCLSID output argument | -| windows.cpp:1140:10:1140:13 | * ... | semmle.label | * ... | -| windows.cpp:1144:5:1144:30 | ... = ... | semmle.label | ... = ... | -| windows.cpp:1144:17:1144:30 | call to source | semmle.label | call to source | -| windows.cpp:1146:21:1146:26 | *progID | semmle.label | *progID | -| windows.cpp:1146:29:1146:34 | CLSIDFromProgID output argument | semmle.label | CLSIDFromProgID output argument | -| windows.cpp:1147:10:1147:14 | clsid | semmle.label | clsid | -| windows.cpp:1151:5:1151:27 | ... = ... | semmle.label | ... = ... | -| windows.cpp:1151:14:1151:27 | call to source | semmle.label | call to source | -| windows.cpp:1153:21:1153:23 | *str | semmle.label | *str | -| windows.cpp:1153:26:1153:31 | CLSIDFromString output argument | semmle.label | CLSIDFromString output argument | -| windows.cpp:1154:10:1154:14 | clsid | semmle.label | clsid | -| windows.cpp:1157:19:1157:24 | call to source | semmle.label | call to source | -| windows.cpp:1157:19:1157:24 | call to source | semmle.label | call to source | -| windows.cpp:1159:21:1159:25 | *clsid | semmle.label | *clsid | -| windows.cpp:1159:28:1159:31 | StringFromCLSID output argument | semmle.label | StringFromCLSID output argument | -| windows.cpp:1161:10:1161:13 | * ... | semmle.label | * ... | -| windows.cpp:1164:17:1164:22 | call to source | semmle.label | call to source | -| windows.cpp:1164:17:1164:22 | call to source | semmle.label | call to source | -| windows.cpp:1166:20:1166:23 | *guid | semmle.label | *guid | -| windows.cpp:1166:26:1166:28 | StringFromGUID output argument | semmle.label | StringFromGUID output argument | -| windows.cpp:1168:10:1168:13 | * ... | semmle.label | * ... | -| windows.cpp:1172:5:1172:27 | ... = ... | semmle.label | ... = ... | -| windows.cpp:1172:14:1172:27 | call to source | semmle.label | call to source | -| windows.cpp:1174:20:1174:22 | *str | semmle.label | *str | -| windows.cpp:1174:25:1174:29 | GUIDFromString output argument | semmle.label | GUIDFromString output argument | -| windows.cpp:1175:10:1175:13 | guid | semmle.label | guid | -| windows.cpp:1178:17:1178:22 | call to source | semmle.label | call to source | -| windows.cpp:1178:17:1178:22 | call to source | semmle.label | call to source | -| windows.cpp:1180:21:1180:24 | *guid | semmle.label | *guid | -| windows.cpp:1180:27:1180:29 | StringFromGUID2 output argument | semmle.label | StringFromGUID2 output argument | -| windows.cpp:1182:10:1182:13 | * ... | semmle.label | * ... | +| windows.cpp:1122:5:1122:27 | ... = ... | semmle.label | ... = ... | +| windows.cpp:1122:14:1122:27 | call to source | semmle.label | call to source | +| windows.cpp:1124:19:1124:21 | *str | semmle.label | *str | +| windows.cpp:1124:24:1124:27 | IIDFromString output argument | semmle.label | IIDFromString output argument | +| windows.cpp:1125:10:1125:12 | iid | semmle.label | iid | +| windows.cpp:1128:15:1128:20 | call to source | semmle.label | call to source | +| windows.cpp:1128:15:1128:20 | call to source | semmle.label | call to source | +| windows.cpp:1130:19:1130:21 | *iid | semmle.label | *iid | +| windows.cpp:1130:24:1130:27 | StringFromIID output argument | semmle.label | StringFromIID output argument | +| windows.cpp:1132:10:1132:13 | * ... | semmle.label | * ... | +| windows.cpp:1135:19:1135:24 | call to source | semmle.label | call to source | +| windows.cpp:1135:19:1135:24 | call to source | semmle.label | call to source | +| windows.cpp:1137:21:1137:25 | *clsid | semmle.label | *clsid | +| windows.cpp:1137:28:1137:31 | ProgIDFromCLSID output argument | semmle.label | ProgIDFromCLSID output argument | +| windows.cpp:1139:10:1139:13 | * ... | semmle.label | * ... | +| windows.cpp:1143:5:1143:30 | ... = ... | semmle.label | ... = ... | +| windows.cpp:1143:17:1143:30 | call to source | semmle.label | call to source | +| windows.cpp:1145:21:1145:26 | *progID | semmle.label | *progID | +| windows.cpp:1145:29:1145:34 | CLSIDFromProgID output argument | semmle.label | CLSIDFromProgID output argument | +| windows.cpp:1146:10:1146:14 | clsid | semmle.label | clsid | +| windows.cpp:1150:5:1150:27 | ... = ... | semmle.label | ... = ... | +| windows.cpp:1150:14:1150:27 | call to source | semmle.label | call to source | +| windows.cpp:1152:21:1152:23 | *str | semmle.label | *str | +| windows.cpp:1152:26:1152:31 | CLSIDFromString output argument | semmle.label | CLSIDFromString output argument | +| windows.cpp:1153:10:1153:14 | clsid | semmle.label | clsid | +| windows.cpp:1156:19:1156:24 | call to source | semmle.label | call to source | +| windows.cpp:1156:19:1156:24 | call to source | semmle.label | call to source | +| windows.cpp:1158:21:1158:25 | *clsid | semmle.label | *clsid | +| windows.cpp:1158:28:1158:31 | StringFromCLSID output argument | semmle.label | StringFromCLSID output argument | +| windows.cpp:1160:10:1160:13 | * ... | semmle.label | * ... | +| windows.cpp:1164:5:1164:27 | ... = ... | semmle.label | ... = ... | +| windows.cpp:1164:14:1164:27 | call to source | semmle.label | call to source | +| windows.cpp:1166:20:1166:22 | *str | semmle.label | *str | +| windows.cpp:1166:25:1166:29 | GUIDFromString output argument | semmle.label | GUIDFromString output argument | +| windows.cpp:1167:10:1167:13 | guid | semmle.label | guid | +| windows.cpp:1170:17:1170:22 | call to source | semmle.label | call to source | +| windows.cpp:1170:17:1170:22 | call to source | semmle.label | call to source | +| windows.cpp:1172:21:1172:24 | *guid | semmle.label | *guid | +| windows.cpp:1172:27:1172:29 | StringFromGUID2 output argument | semmle.label | StringFromGUID2 output argument | +| windows.cpp:1174:10:1174:13 | * ... | semmle.label | * ... | subpaths | test.cpp:32:41:32:41 | x | test.cpp:7:47:7:52 | value2 | test.cpp:7:5:7:30 | *ymlStepGenerated_with_body | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | | test.cpp:172:51:172:51 | x | test.cpp:164:34:164:34 | x | test.cpp:164:7:164:7 | *templateFunction3 | test.cpp:172:13:172:44 | call to templateFunction3 | diff --git a/cpp/ql/test/library-tests/dataflow/external-models/steps.expected b/cpp/ql/test/library-tests/dataflow/external-models/steps.expected index 75d64445ac9a..0fe13460cfbf 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/steps.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/steps.expected @@ -10,12 +10,11 @@ | test.cpp:28:35:28:35 | 0 | test.cpp:28:11:28:33 | call to ymlStepManual_with_body | | windows.cpp:27:36:27:38 | *cmd | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | | windows.cpp:729:35:729:35 | *x | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | -| windows.cpp:1125:19:1125:21 | *str | windows.cpp:1125:24:1125:27 | IIDFromString output argument | -| windows.cpp:1131:19:1131:21 | *iid | windows.cpp:1131:24:1131:27 | StringFromIID output argument | -| windows.cpp:1138:21:1138:25 | *clsid | windows.cpp:1138:28:1138:31 | ProgIDFromCLSID output argument | -| windows.cpp:1146:21:1146:26 | *progID | windows.cpp:1146:29:1146:34 | CLSIDFromProgID output argument | -| windows.cpp:1153:21:1153:23 | *str | windows.cpp:1153:26:1153:31 | CLSIDFromString output argument | -| windows.cpp:1159:21:1159:25 | *clsid | windows.cpp:1159:28:1159:31 | StringFromCLSID output argument | -| windows.cpp:1166:20:1166:23 | *guid | windows.cpp:1166:26:1166:28 | StringFromGUID output argument | -| windows.cpp:1174:20:1174:22 | *str | windows.cpp:1174:25:1174:29 | GUIDFromString output argument | -| windows.cpp:1180:21:1180:24 | *guid | windows.cpp:1180:27:1180:29 | StringFromGUID2 output argument | +| windows.cpp:1124:19:1124:21 | *str | windows.cpp:1124:24:1124:27 | IIDFromString output argument | +| windows.cpp:1130:19:1130:21 | *iid | windows.cpp:1130:24:1130:27 | StringFromIID output argument | +| windows.cpp:1137:21:1137:25 | *clsid | windows.cpp:1137:28:1137:31 | ProgIDFromCLSID output argument | +| windows.cpp:1145:21:1145:26 | *progID | windows.cpp:1145:29:1145:34 | CLSIDFromProgID output argument | +| windows.cpp:1152:21:1152:23 | *str | windows.cpp:1152:26:1152:31 | CLSIDFromString output argument | +| windows.cpp:1158:21:1158:25 | *clsid | windows.cpp:1158:28:1158:31 | StringFromCLSID output argument | +| windows.cpp:1166:20:1166:22 | *str | windows.cpp:1166:25:1166:29 | GUIDFromString output argument | +| windows.cpp:1172:21:1172:24 | *guid | windows.cpp:1172:27:1172:29 | StringFromGUID2 output argument | diff --git a/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp b/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp index e956495cfb96..5c5877e06b0a 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp +++ b/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp @@ -1110,7 +1110,6 @@ HRESULT ProgIDFromCLSID(REFCLSID clsid, LPOLESTR* lplpszProgID); HRESULT CLSIDFromProgID(LPCOLESTR lpszProgID, LPCLSID lpclsid); HRESULT CLSIDFromString(LPCOLESTR lpsz, LPCLSID pclsid); HRESULT StringFromCLSID(REFCLSID rclsid, LPOLESTR* lplpsz); -int StringFromGUID(REFGUID rguid, LPOLESTR lpsz); int GUIDFromString(LPCOLESTR psz, GUID* pguid); int StringFromGUID2(REFGUID rguid, LPOLESTR lpsz, int cchMax); @@ -1160,13 +1159,6 @@ void test_com_string_conversions() { sink(str); sink(*str); // $ ir } - { - GUID guid = source(); - char str[256]; - StringFromGUID(guid, str); - sink(str); - sink(*str); // $ ir - } { char str[256]; str[0] = (char)source(); From b9a5dd4f70ca4ae092d5f96dc2f6be7b7d38b2be Mon Sep 17 00:00:00 2001 From: JarLob Date: Fri, 24 Jul 2026 01:43:03 +0300 Subject: [PATCH 158/188] The regex wasn't escaping external input --- .../codeql/actions/security/OutputClobberingQuery.qll | 5 ++++- .../change-notes/2026-07-28-output-clobbering-regex.md | 4 ++++ .../Security/CWE-074/.github/workflows/output2.yml | 10 ++++++++++ .../Security/CWE-074/OutputClobberingHigh.expected | 6 ++++++ 4 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 actions/ql/src/change-notes/2026-07-28-output-clobbering-regex.md diff --git a/actions/ql/lib/codeql/actions/security/OutputClobberingQuery.qll b/actions/ql/lib/codeql/actions/security/OutputClobberingQuery.qll index 7d560f8b6242..57f0e31a25b4 100644 --- a/actions/ql/lib/codeql/actions/security/OutputClobberingQuery.qll +++ b/actions/ql/lib/codeql/actions/security/OutputClobberingQuery.qll @@ -196,7 +196,10 @@ class WorkflowCommandClobberingFromFileReadSink extends OutputClobberingSink { clobbering_cmd.regexpMatch(["ls", Bash::fileReadCommand()] + "\\s.*") and ( // - run: echo "foo=$(= 0 + ) or // A file content is printed to stdout // - run: cat pr-id.txt diff --git a/actions/ql/src/change-notes/2026-07-28-output-clobbering-regex.md b/actions/ql/src/change-notes/2026-07-28-output-clobbering-regex.md new file mode 100644 index 000000000000..d9e84a447c91 --- /dev/null +++ b/actions/ql/src/change-notes/2026-07-28-output-clobbering-regex.md @@ -0,0 +1,4 @@ +--- +category: fix +--- +* Fixed a performance issue in the `actions/output-clobbering/high` query caused by using unescaped source-code input in a regular expression. diff --git a/actions/ql/test/query-tests/Security/CWE-074/.github/workflows/output2.yml b/actions/ql/test/query-tests/Security/CWE-074/.github/workflows/output2.yml index 896f6c820152..63298fdd57b2 100644 --- a/actions/ql/test/query-tests/Security/CWE-074/.github/workflows/output2.yml +++ b/actions/ql/test/query-tests/Security/CWE-074/.github/workflows/output2.yml @@ -114,3 +114,13 @@ jobs: run: | # VULNERABLE: halt_error emits its input without JSON encoding jq '.value | halt_error(1)' pr-number.json + - id: clob18 + run: | + # VULNERABLE: the file name contains regex metacharacters + echo "VALUE=$(cat 'pr[number](final).txt')" + echo "::set-output name=OUTPUT::SAFE" + - id: clob19 + run: | + # VULNERABLE: echo is invoked through env + env echo "VALUE=$(cat 'pr[number](final).txt')" + echo "::set-output name=OUTPUT::SAFE" diff --git a/actions/ql/test/query-tests/Security/CWE-074/OutputClobberingHigh.expected b/actions/ql/test/query-tests/Security/CWE-074/OutputClobberingHigh.expected index 58b0df462e48..08ff1495a662 100644 --- a/actions/ql/test/query-tests/Security/CWE-074/OutputClobberingHigh.expected +++ b/actions/ql/test/query-tests/Security/CWE-074/OutputClobberingHigh.expected @@ -16,6 +16,8 @@ edges | .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:106:14:108:51 | # VULNERABLE: raw-output0 emits strings without JSON encoding\njq '.value' --raw-output0 pr-number.json\n | provenance | Config | | .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:110:14:112:46 | # VULNERABLE: stderr emits its input without JSON encoding\njq '.value \| stderr' pr-number.json\n | provenance | Config | | .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:114:14:116:53 | # VULNERABLE: halt_error emits its input without JSON encoding\njq '.value \| halt_error(1)' pr-number.json\n | provenance | Config | +| .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:118:14:121:48 | # VULNERABLE: the file name contains regex metacharacters\necho "VALUE=$(cat 'pr[number](final).txt')"\necho "::set-output name=OUTPUT::SAFE"\n | provenance | Config | +| .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:123:14:126:48 | # VULNERABLE: echo is invoked through env\nenv echo "VALUE=$(cat 'pr[number](final).txt')"\necho "::set-output name=OUTPUT::SAFE"\n | provenance | Config | nodes | .github/workflows/output1.yml:9:18:9:49 | github.event.comment.body | semmle.label | github.event.comment.body | | .github/workflows/output1.yml:10:14:13:50 | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$BODY" >> $GITHUB_OUTPUT\n | semmle.label | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$BODY" >> $GITHUB_OUTPUT\n | @@ -39,6 +41,8 @@ nodes | .github/workflows/output2.yml:106:14:108:51 | # VULNERABLE: raw-output0 emits strings without JSON encoding\njq '.value' --raw-output0 pr-number.json\n | semmle.label | # VULNERABLE: raw-output0 emits strings without JSON encoding\njq '.value' --raw-output0 pr-number.json\n | | .github/workflows/output2.yml:110:14:112:46 | # VULNERABLE: stderr emits its input without JSON encoding\njq '.value \| stderr' pr-number.json\n | semmle.label | # VULNERABLE: stderr emits its input without JSON encoding\njq '.value \| stderr' pr-number.json\n | | .github/workflows/output2.yml:114:14:116:53 | # VULNERABLE: halt_error emits its input without JSON encoding\njq '.value \| halt_error(1)' pr-number.json\n | semmle.label | # VULNERABLE: halt_error emits its input without JSON encoding\njq '.value \| halt_error(1)' pr-number.json\n | +| .github/workflows/output2.yml:118:14:121:48 | # VULNERABLE: the file name contains regex metacharacters\necho "VALUE=$(cat 'pr[number](final).txt')"\necho "::set-output name=OUTPUT::SAFE"\n | semmle.label | # VULNERABLE: the file name contains regex metacharacters\necho "VALUE=$(cat 'pr[number](final).txt')"\necho "::set-output name=OUTPUT::SAFE"\n | +| .github/workflows/output2.yml:123:14:126:48 | # VULNERABLE: echo is invoked through env\nenv echo "VALUE=$(cat 'pr[number](final).txt')"\necho "::set-output name=OUTPUT::SAFE"\n | semmle.label | # VULNERABLE: echo is invoked through env\nenv echo "VALUE=$(cat 'pr[number](final).txt')"\necho "::set-output name=OUTPUT::SAFE"\n | subpaths #select | .github/workflows/output1.yml:10:14:13:50 | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$BODY" >> $GITHUB_OUTPUT\n | .github/workflows/output1.yml:9:18:9:49 | github.event.comment.body | .github/workflows/output1.yml:10:14:13:50 | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$BODY" >> $GITHUB_OUTPUT\n | Potential clobbering of a step output in $@. | .github/workflows/output1.yml:10:14:13:50 | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$BODY" >> $GITHUB_OUTPUT\n | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$BODY" >> $GITHUB_OUTPUT\n | @@ -58,3 +62,5 @@ subpaths | .github/workflows/output2.yml:106:14:108:51 | # VULNERABLE: raw-output0 emits strings without JSON encoding\njq '.value' --raw-output0 pr-number.json\n | .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:106:14:108:51 | # VULNERABLE: raw-output0 emits strings without JSON encoding\njq '.value' --raw-output0 pr-number.json\n | Potential clobbering of a step output in $@. | .github/workflows/output2.yml:106:14:108:51 | # VULNERABLE: raw-output0 emits strings without JSON encoding\njq '.value' --raw-output0 pr-number.json\n | # VULNERABLE: raw-output0 emits strings without JSON encoding\njq '.value' --raw-output0 pr-number.json\n | | .github/workflows/output2.yml:110:14:112:46 | # VULNERABLE: stderr emits its input without JSON encoding\njq '.value \| stderr' pr-number.json\n | .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:110:14:112:46 | # VULNERABLE: stderr emits its input without JSON encoding\njq '.value \| stderr' pr-number.json\n | Potential clobbering of a step output in $@. | .github/workflows/output2.yml:110:14:112:46 | # VULNERABLE: stderr emits its input without JSON encoding\njq '.value \| stderr' pr-number.json\n | # VULNERABLE: stderr emits its input without JSON encoding\njq '.value \| stderr' pr-number.json\n | | .github/workflows/output2.yml:114:14:116:53 | # VULNERABLE: halt_error emits its input without JSON encoding\njq '.value \| halt_error(1)' pr-number.json\n | .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:114:14:116:53 | # VULNERABLE: halt_error emits its input without JSON encoding\njq '.value \| halt_error(1)' pr-number.json\n | Potential clobbering of a step output in $@. | .github/workflows/output2.yml:114:14:116:53 | # VULNERABLE: halt_error emits its input without JSON encoding\njq '.value \| halt_error(1)' pr-number.json\n | # VULNERABLE: halt_error emits its input without JSON encoding\njq '.value \| halt_error(1)' pr-number.json\n | +| .github/workflows/output2.yml:118:14:121:48 | # VULNERABLE: the file name contains regex metacharacters\necho "VALUE=$(cat 'pr[number](final).txt')"\necho "::set-output name=OUTPUT::SAFE"\n | .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:118:14:121:48 | # VULNERABLE: the file name contains regex metacharacters\necho "VALUE=$(cat 'pr[number](final).txt')"\necho "::set-output name=OUTPUT::SAFE"\n | Potential clobbering of a step output in $@. | .github/workflows/output2.yml:118:14:121:48 | # VULNERABLE: the file name contains regex metacharacters\necho "VALUE=$(cat 'pr[number](final).txt')"\necho "::set-output name=OUTPUT::SAFE"\n | # VULNERABLE: the file name contains regex metacharacters\necho "VALUE=$(cat 'pr[number](final).txt')"\necho "::set-output name=OUTPUT::SAFE"\n | +| .github/workflows/output2.yml:123:14:126:48 | # VULNERABLE: echo is invoked through env\nenv echo "VALUE=$(cat 'pr[number](final).txt')"\necho "::set-output name=OUTPUT::SAFE"\n | .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:123:14:126:48 | # VULNERABLE: echo is invoked through env\nenv echo "VALUE=$(cat 'pr[number](final).txt')"\necho "::set-output name=OUTPUT::SAFE"\n | Potential clobbering of a step output in $@. | .github/workflows/output2.yml:123:14:126:48 | # VULNERABLE: echo is invoked through env\nenv echo "VALUE=$(cat 'pr[number](final).txt')"\necho "::set-output name=OUTPUT::SAFE"\n | # VULNERABLE: echo is invoked through env\nenv echo "VALUE=$(cat 'pr[number](final).txt')"\necho "::set-output name=OUTPUT::SAFE"\n | From a7c19786d7b8d3e696d6c79499d64a359956a2e9 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 31 Jul 2026 11:06:20 +0100 Subject: [PATCH 159/188] C++: Remove 'StringFromGUID' model. --- cpp/ql/lib/ext/Windows.model.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/cpp/ql/lib/ext/Windows.model.yml b/cpp/ql/lib/ext/Windows.model.yml index 8e46aa79323b..c83e902cbc2c 100644 --- a/cpp/ql/lib/ext/Windows.model.yml +++ b/cpp/ql/lib/ext/Windows.model.yml @@ -79,6 +79,5 @@ extensions: - ["", "", False, "CLSIDFromProgID", "", "", "Argument[*0]", "Argument[*1]", "taint", "manual"] - ["", "", False, "CLSIDFromString", "", "", "Argument[*0]", "Argument[*1]", "taint", "manual"] - ["", "", False, "StringFromCLSID", "", "", "Argument[*0]", "Argument[**1]", "taint", "manual"] - - ["", "", False, "StringFromGUID", "", "", "Argument[*0]", "Argument[*1]", "taint", "manual"] - ["", "", False, "GUIDFromString", "", "", "Argument[*0]", "Argument[*1]", "taint", "manual"] - ["", "", False, "StringFromGUID2", "", "", "Argument[*0]", "Argument[*1]", "taint", "manual"] \ No newline at end of file From 26da3e773ddedec87fd9a6cf27c2e4e159518794 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20Loba=C4=8Devski?= Date: Sat, 18 Jul 2026 19:44:40 +0000 Subject: [PATCH 160/188] Fix FP in envvar injection --- .../ql/lib/codeql/actions/security/EnvVarInjectionQuery.qll | 2 +- actions/ql/src/Security/CWE-077/EnvVarInjectionCritical.ql | 1 + .../change-notes/2026-07-18-envvar-injection-precision.md | 4 ++++ .../Security/CWE-077/.github/workflows/test18.yml | 6 ++++++ .../Security/CWE-077/.github/workflows/test4.yml | 4 ++++ .../Security/CWE-077/EnvVarInjectionCritical.expected | 3 +++ .../Security/CWE-077/EnvVarInjectionMedium.expected | 3 +++ 7 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 actions/ql/src/change-notes/2026-07-18-envvar-injection-precision.md diff --git a/actions/ql/lib/codeql/actions/security/EnvVarInjectionQuery.qll b/actions/ql/lib/codeql/actions/security/EnvVarInjectionQuery.qll index 40810477d927..9c3d7363c0aa 100644 --- a/actions/ql/lib/codeql/actions/security/EnvVarInjectionQuery.qll +++ b/actions/ql/lib/codeql/actions/security/EnvVarInjectionQuery.qll @@ -151,7 +151,7 @@ Event getRelevantNonArtifactEventInPrivilegedContext(DataFlow::Node sink) { private module EnvVarInjectionConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource and - not source.(RemoteFlowSource).getSourceType() = ["branch", "username"] + not source.(RemoteFlowSource).getSourceType() = ["branch", "label", "username"] } predicate isSink(DataFlow::Node sink) { sink instanceof EnvVarInjectionSink } diff --git a/actions/ql/src/Security/CWE-077/EnvVarInjectionCritical.ql b/actions/ql/src/Security/CWE-077/EnvVarInjectionCritical.ql index 6f0d9729d6d3..efbd094be65a 100644 --- a/actions/ql/src/Security/CWE-077/EnvVarInjectionCritical.ql +++ b/actions/ql/src/Security/CWE-077/EnvVarInjectionCritical.ql @@ -22,6 +22,7 @@ import codeql.actions.security.ControlChecks from EnvVarInjectionFlow::PathNode source, EnvVarInjectionFlow::PathNode sink, Event event where EnvVarInjectionFlow::flowPath(source, sink) and + source.getNode().(RemoteFlowSource).getEventName() = event.getName() and // exclude paths to file read sinks from non-artifact sources ( // source is text diff --git a/actions/ql/src/change-notes/2026-07-18-envvar-injection-precision.md b/actions/ql/src/change-notes/2026-07-18-envvar-injection-precision.md new file mode 100644 index 000000000000..c5bc9ba79bf1 --- /dev/null +++ b/actions/ql/src/change-notes/2026-07-18-envvar-injection-precision.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* The `actions/envvar-injection/critical` query now requires the untrusted source and privileged context to originate from the same trigger event. The environment variable injection queries also no longer treat pull request head labels as injection-capable because they cannot contain newlines. diff --git a/actions/ql/test/query-tests/Security/CWE-077/.github/workflows/test18.yml b/actions/ql/test/query-tests/Security/CWE-077/.github/workflows/test18.yml index 1c4b1e863122..4651b33f1a21 100644 --- a/actions/ql/test/query-tests/Security/CWE-077/.github/workflows/test18.yml +++ b/actions/ql/test/query-tests/Security/CWE-077/.github/workflows/test18.yml @@ -8,6 +8,8 @@ on: jobs: tests: + permissions: + contents: write runs-on: ubuntu-latest steps: - name: Checkout Repository @@ -30,3 +32,7 @@ jobs: # Delete non-alphanumeric characters and limit to 75 chars which is the branch title limit in GitHub SAFE_PULL_REQUEST_TITLE=$(echo "${GITHUB_EVENT_PULL_REQUEST_TITLE}" | tr -cd '[:alnum:]_ -' | cut -c1-75) echo "SAFE_PULL_REQUEST_TITLE=$SAFE_PULL_REQUEST_TITLE" >> $GITHUB_ENV + - name: Keep source and privilege events correlated + env: + BODY: ${{ github.event.pull_request.body }} + run: echo "BODY=$BODY" >> $GITHUB_ENV diff --git a/actions/ql/test/query-tests/Security/CWE-077/.github/workflows/test4.yml b/actions/ql/test/query-tests/Security/CWE-077/.github/workflows/test4.yml index 7b30ec8b7e42..9b12a7b05d29 100644 --- a/actions/ql/test/query-tests/Security/CWE-077/.github/workflows/test4.yml +++ b/actions/ql/test/query-tests/Security/CWE-077/.github/workflows/test4.yml @@ -66,6 +66,10 @@ jobs: ${TITLE} EOL echo REPO_NAME=$(cat issue.txt | sed 's/\r/\n/g' | grep -ioE '\s*[a-z0-9_-]+/[a-z0-9_-]+\s*$' | tr -d ' ') >> $GITHUB_ENV + - env: + LABEL: ${{ github.event.pull_request.head.label }} + run: | + echo "PR_LABEL=$LABEL" >> $GITHUB_ENV diff --git a/actions/ql/test/query-tests/Security/CWE-077/EnvVarInjectionCritical.expected b/actions/ql/test/query-tests/Security/CWE-077/EnvVarInjectionCritical.expected index 9914ae91df12..ad79f6de12dd 100644 --- a/actions/ql/test/query-tests/Security/CWE-077/EnvVarInjectionCritical.expected +++ b/actions/ql/test/query-tests/Security/CWE-077/EnvVarInjectionCritical.expected @@ -29,6 +29,7 @@ edges | .github/workflows/test12.yml:55:9:61:6 | Uses Step | .github/workflows/test12.yml:63:14:68:29 | {\n echo 'PRERELEASE_REPORT<> "$GITHUB_ENV"\n | provenance | Config | | .github/workflows/test16.yml:10:9:15:6 | Uses Step | .github/workflows/test16.yml:15:14:17:63 | # VULNERABLE\necho "PR_NUMBER=$(cat pr_number.txt)" >> $GITHUB_ENV\n | provenance | Config | | .github/workflows/test16.yml:10:9:15:6 | Uses Step | .github/workflows/test16.yml:18:14:20:77 | # VULNERABLE\necho "PR_NUMBER=$(cat pr_number.txt \| tr ',' '\\n')" >> $GITHUB_ENV\n | provenance | Config | +| .github/workflows/test18.yml:37:18:37:54 | github.event.pull_request.body | .github/workflows/test18.yml:38:14:38:45 | echo "BODY=$BODY" >> $GITHUB_ENV | provenance | Config | nodes | .github/workflows/artifactpoisoning51.yml:13:9:15:6 | Run Step | semmle.label | Run Step | | .github/workflows/artifactpoisoning51.yml:19:14:20:57 | echo "pr_number=$(cat foo/bar)" >> $GITHUB_ENV\n | semmle.label | echo "pr_number=$(cat foo/bar)" >> $GITHUB_ENV\n | @@ -91,6 +92,8 @@ nodes | .github/workflows/test16.yml:10:9:15:6 | Uses Step | semmle.label | Uses Step | | .github/workflows/test16.yml:15:14:17:63 | # VULNERABLE\necho "PR_NUMBER=$(cat pr_number.txt)" >> $GITHUB_ENV\n | semmle.label | # VULNERABLE\necho "PR_NUMBER=$(cat pr_number.txt)" >> $GITHUB_ENV\n | | .github/workflows/test16.yml:18:14:20:77 | # VULNERABLE\necho "PR_NUMBER=$(cat pr_number.txt \| tr ',' '\\n')" >> $GITHUB_ENV\n | semmle.label | # VULNERABLE\necho "PR_NUMBER=$(cat pr_number.txt \| tr ',' '\\n')" >> $GITHUB_ENV\n | +| .github/workflows/test18.yml:37:18:37:54 | github.event.pull_request.body | semmle.label | github.event.pull_request.body | +| .github/workflows/test18.yml:38:14:38:45 | echo "BODY=$BODY" >> $GITHUB_ENV | semmle.label | echo "BODY=$BODY" >> $GITHUB_ENV | subpaths #select | .github/workflows/artifactpoisoning51.yml:19:14:20:57 | echo "pr_number=$(cat foo/bar)" >> $GITHUB_ENV\n | .github/workflows/artifactpoisoning51.yml:13:9:15:6 | Run Step | .github/workflows/artifactpoisoning51.yml:19:14:20:57 | echo "pr_number=$(cat foo/bar)" >> $GITHUB_ENV\n | Potential environment variable injection in $@, which may be controlled by an external user ($@). | .github/workflows/artifactpoisoning51.yml:19:14:20:57 | echo "pr_number=$(cat foo/bar)" >> $GITHUB_ENV\n | echo "pr_number=$(cat foo/bar)" >> $GITHUB_ENV\n | .github/workflows/artifactpoisoning51.yml:4:3:4:14 | workflow_run | workflow_run | diff --git a/actions/ql/test/query-tests/Security/CWE-077/EnvVarInjectionMedium.expected b/actions/ql/test/query-tests/Security/CWE-077/EnvVarInjectionMedium.expected index 94e2af8ecaa7..9c1c5058f43a 100644 --- a/actions/ql/test/query-tests/Security/CWE-077/EnvVarInjectionMedium.expected +++ b/actions/ql/test/query-tests/Security/CWE-077/EnvVarInjectionMedium.expected @@ -29,6 +29,7 @@ edges | .github/workflows/test12.yml:55:9:61:6 | Uses Step | .github/workflows/test12.yml:63:14:68:29 | {\n echo 'PRERELEASE_REPORT<> "$GITHUB_ENV"\n | provenance | Config | | .github/workflows/test16.yml:10:9:15:6 | Uses Step | .github/workflows/test16.yml:15:14:17:63 | # VULNERABLE\necho "PR_NUMBER=$(cat pr_number.txt)" >> $GITHUB_ENV\n | provenance | Config | | .github/workflows/test16.yml:10:9:15:6 | Uses Step | .github/workflows/test16.yml:18:14:20:77 | # VULNERABLE\necho "PR_NUMBER=$(cat pr_number.txt \| tr ',' '\\n')" >> $GITHUB_ENV\n | provenance | Config | +| .github/workflows/test18.yml:37:18:37:54 | github.event.pull_request.body | .github/workflows/test18.yml:38:14:38:45 | echo "BODY=$BODY" >> $GITHUB_ENV | provenance | Config | nodes | .github/workflows/artifactpoisoning51.yml:13:9:15:6 | Run Step | semmle.label | Run Step | | .github/workflows/artifactpoisoning51.yml:19:14:20:57 | echo "pr_number=$(cat foo/bar)" >> $GITHUB_ENV\n | semmle.label | echo "pr_number=$(cat foo/bar)" >> $GITHUB_ENV\n | @@ -91,5 +92,7 @@ nodes | .github/workflows/test16.yml:10:9:15:6 | Uses Step | semmle.label | Uses Step | | .github/workflows/test16.yml:15:14:17:63 | # VULNERABLE\necho "PR_NUMBER=$(cat pr_number.txt)" >> $GITHUB_ENV\n | semmle.label | # VULNERABLE\necho "PR_NUMBER=$(cat pr_number.txt)" >> $GITHUB_ENV\n | | .github/workflows/test16.yml:18:14:20:77 | # VULNERABLE\necho "PR_NUMBER=$(cat pr_number.txt \| tr ',' '\\n')" >> $GITHUB_ENV\n | semmle.label | # VULNERABLE\necho "PR_NUMBER=$(cat pr_number.txt \| tr ',' '\\n')" >> $GITHUB_ENV\n | +| .github/workflows/test18.yml:37:18:37:54 | github.event.pull_request.body | semmle.label | github.event.pull_request.body | +| .github/workflows/test18.yml:38:14:38:45 | echo "BODY=$BODY" >> $GITHUB_ENV | semmle.label | echo "BODY=$BODY" >> $GITHUB_ENV | subpaths #select From de688819217bf22f603fa1c2c686edd81cbb01e3 Mon Sep 17 00:00:00 2001 From: JarLob Date: Fri, 31 Jul 2026 13:11:58 +0300 Subject: [PATCH 161/188] Delay envvar event-name correlation --- .../ql/src/Security/CWE-077/EnvVarInjectionCritical.ql | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/actions/ql/src/Security/CWE-077/EnvVarInjectionCritical.ql b/actions/ql/src/Security/CWE-077/EnvVarInjectionCritical.ql index efbd094be65a..d6118075fa13 100644 --- a/actions/ql/src/Security/CWE-077/EnvVarInjectionCritical.ql +++ b/actions/ql/src/Security/CWE-077/EnvVarInjectionCritical.ql @@ -19,10 +19,16 @@ import codeql.actions.dataflow.FlowSources import EnvVarInjectionFlow::PathGraph import codeql.actions.security.ControlChecks +bindingset[source, event] +pragma[inline_late] +private predicate hasSameEventName(RemoteFlowSource source, Event event) { + source.getEventName() = event.getName() +} + from EnvVarInjectionFlow::PathNode source, EnvVarInjectionFlow::PathNode sink, Event event where EnvVarInjectionFlow::flowPath(source, sink) and - source.getNode().(RemoteFlowSource).getEventName() = event.getName() and + hasSameEventName(source.getNode(), event) and // exclude paths to file read sinks from non-artifact sources ( // source is text From 9d147bc1517babc31d94759e67649545f99b808a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20Loba=C4=8Devski?= Date: Fri, 31 Jul 2026 13:31:28 +0300 Subject: [PATCH 162/188] Apply batched suggestions from code review Co-authored-by: Anders Schack-Mulligen --- .../security/UntrustedCheckoutQuery.qll | 19 ++++++------------- .../CachePoisoningViaPoisonableStep.ql | 6 +----- .../CWE-829/UntrustedCheckoutCritical.ql | 6 +----- 3 files changed, 8 insertions(+), 23 deletions(-) diff --git a/actions/ql/lib/codeql/actions/security/UntrustedCheckoutQuery.qll b/actions/ql/lib/codeql/actions/security/UntrustedCheckoutQuery.qll index 357a55a1ec9b..bd8ec6f035e9 100644 --- a/actions/ql/lib/codeql/actions/security/UntrustedCheckoutQuery.qll +++ b/actions/ql/lib/codeql/actions/security/UntrustedCheckoutQuery.qll @@ -386,7 +386,6 @@ class GhSHACheckout extends SHACheckoutStep instanceof Run { private predicate isRunCheckoutReference( PRHeadCheckoutStep checkout, Expression reference, string variable ) { - checkout instanceof Run and reference = checkout.(Run).getInScopeEnvVarExpr(variable) and ( checkout instanceof SHACheckoutStep and containsHeadSHA(reference.getExpression()) @@ -405,13 +404,10 @@ private predicate isRunCheckoutReference( /** Gets the expression that controls the untrusted checkout, if one can be identified. */ AstNode getCheckoutReference(PRHeadCheckoutStep checkout) { - exists(UsesStep uses | - checkout = uses and - ( - result = uses.getArgumentExpr("ref") - or - not exists(uses.getArgumentExpr("ref")) and result = uses.getArgumentExpr("repository") - ) + exists(UsesStep uses | uses = checkout | + result = uses.getArgumentExpr("ref") + or + not exists(uses.getArgumentExpr("ref")) and result = uses.getArgumentExpr("repository") ) or isRunCheckoutReference(checkout, result, _) @@ -430,9 +426,6 @@ string getCheckoutReferenceText(AstNode reference) { /** Adds checkout-reference provenance before the checkout step in path queries. */ predicate checkoutReferenceEdge(AstNode predecessor, AstNode successor) { - exists(PRHeadCheckoutStep checkout | - predecessor = getCheckoutReference(checkout) and - successor = checkout and - not predecessor = successor - ) + predecessor = getCheckoutReference(successor) and + not predecessor = successor } diff --git a/actions/ql/src/Security/CWE-349/CachePoisoningViaPoisonableStep.ql b/actions/ql/src/Security/CWE-349/CachePoisoningViaPoisonableStep.ql index 148a05ef02b9..e26f309ce531 100644 --- a/actions/ql/src/Security/CWE-349/CachePoisoningViaPoisonableStep.ql +++ b/actions/ql/src/Security/CWE-349/CachePoisoningViaPoisonableStep.ql @@ -19,11 +19,7 @@ import codeql.actions.security.PoisonableSteps import codeql.actions.security.ControlChecks query predicate edges(AstNode predecessor, AstNode successor) { - exists(Step previous, Step next | - predecessor = previous and - successor = next and - previous.getNextStep() = next - ) + predecessor.(Step).getNextStep() = successor or checkoutReferenceEdge(predecessor, successor) } diff --git a/actions/ql/src/Security/CWE-829/UntrustedCheckoutCritical.ql b/actions/ql/src/Security/CWE-829/UntrustedCheckoutCritical.ql index 1f3c8813c9b5..4a05ef67117d 100644 --- a/actions/ql/src/Security/CWE-829/UntrustedCheckoutCritical.ql +++ b/actions/ql/src/Security/CWE-829/UntrustedCheckoutCritical.ql @@ -19,11 +19,7 @@ import codeql.actions.security.PoisonableSteps import codeql.actions.security.ControlChecks query predicate edges(AstNode predecessor, AstNode successor) { - exists(Step previous, Step next | - predecessor = previous and - successor = next and - previous.getNextStep() = next - ) + predecessor.(Step).getNextStep() = successor or checkoutReferenceEdge(predecessor, successor) } From 9c83964dd25369c26508d8e85a0a361897dc3ac2 Mon Sep 17 00:00:00 2001 From: JarLob Date: Fri, 31 Jul 2026 13:40:26 +0300 Subject: [PATCH 163/188] Revalidate output clobbering expectations From 8a89360ebfa998c9510b6a4c2d5fa3c7e64ce0a7 Mon Sep 17 00:00:00 2001 From: JarLob Date: Fri, 31 Jul 2026 14:45:05 +0300 Subject: [PATCH 164/188] Constrain Actions source helper evaluation --- actions/ql/lib/codeql/actions/dataflow/FlowSources.qll | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/actions/ql/lib/codeql/actions/dataflow/FlowSources.qll b/actions/ql/lib/codeql/actions/dataflow/FlowSources.qll index f44a4603df19..8b0a2a33eb55 100644 --- a/actions/ql/lib/codeql/actions/dataflow/FlowSources.qll +++ b/actions/ql/lib/codeql/actions/dataflow/FlowSources.qll @@ -53,15 +53,17 @@ class GitHubCtxSource extends RemoteFlowSource { } bindingset[expression] +pragma[inline_late] private predicate untrustedEventProperty(Expression expression, string kind) { exists(string regexp | untrustedEventPropertiesDataModel(regexp, kind) and - not kind = "json" and + kind != "json" and normalizeExpr(expression.getExpression()).regexpMatch("(?i)\\s*" + wrapRegexp(regexp) + ".*") ) } bindingset[expression, event] +pragma[inline_late] private predicate expressionContainsEventContext(Expression expression, string event) { exists(string contextPrefix | contextTriggerDataModel(event, contextPrefix) and @@ -190,6 +192,7 @@ class GitHubEventPathSource extends RemoteFlowSource, CommandSource { } bindingset[expression, event] +pragma[inline_late] private predicate jsonSourceForEvent(Expression expression, string event) { exists(string context, string regexp, string contextPrefix | context = expression.getExpression() and From 329d1980fc2fbcf423c486e21bfbd7dc8d856d65 Mon Sep 17 00:00:00 2001 From: Asger F Date: Fri, 31 Jul 2026 13:56:58 +0200 Subject: [PATCH 165/188] unified: Convert TypeCheckContext to a struct --- shared/yeast/src/dump.rs | 63 ++++++++++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 22 deletions(-) diff --git a/shared/yeast/src/dump.rs b/shared/yeast/src/dump.rs index 06ede1fa3438..0e2e57e6f82a 100644 --- a/shared/yeast/src/dump.rs +++ b/shared/yeast/src/dump.rs @@ -2,11 +2,12 @@ use std::fmt::Write; use crate::{schema::Schema, Ast, Id, Node, NodeContent, CHILD_FIELD}; -type TypeCheckContext<'a> = ( - &'a Schema, - Option<&'a [crate::schema::NodeType]>, - Option<(&'a str, &'a str)>, -); +#[derive(Clone, Copy)] +struct TypeCheckContext<'a> { + schema: &'a Schema, + expected: Option<&'a [crate::schema::NodeType]>, + parent_field: Option<(&'a str, &'a str)>, +} /// Options for controlling AST dump output. pub struct DumpOptions { @@ -76,7 +77,11 @@ pub fn dump_ast_with_type_errors_and_options( source, options, 0, - Some((schema, None, None)), + Some(TypeCheckContext { + schema, + expected: None, + parent_field: None, + }), &mut out, ); out @@ -221,8 +226,10 @@ fn dump_node( } } - if let Some((schema, expected, parent_field)) = type_check { - if let Some(err) = type_error_for_node(schema, node, expected, parent_field) { + if let Some(context) = type_check { + if let Some(err) = + type_error_for_node(context.schema, node, context.expected, context.parent_field) + { write!(out, " <-- ERROR: {err}").unwrap(); } } @@ -244,10 +251,11 @@ fn dump_node( .copied() .filter(|&f| f != CHILD_FIELD) .collect(); - match type_check.and_then(|(schema, _, _)| { - schema + match type_check.and_then(|context| { + context + .schema .field_order(node.kind_name()) - .map(|order| (schema, order)) + .map(|order| (context.schema, order)) }) { Some((schema, order)) => { let mut result: Vec = order @@ -269,11 +277,15 @@ fn dump_node( for field_id in named_field_ids { let children = &node.fields[&field_id]; let field_name = ast.field_name_for_id(field_id).unwrap_or("?"); - let child_type_check = type_check.map(|(schema, _, _)| { - let expected = - expected_for_field(schema, node.kind_name(), field_name).or(Some(EMPTY_NODE_TYPES)); + let child_type_check = type_check.map(|context| { + let expected = expected_for_field(context.schema, node.kind_name(), field_name) + .or(Some(EMPTY_NODE_TYPES)); let parent_field = Some((node.kind_name(), field_name)); - (schema, expected, parent_field) + TypeCheckContext { + schema: context.schema, + expected, + parent_field, + } }); if children.len() == 1 { @@ -312,8 +324,8 @@ fn dump_node( } // Check for required fields that are absent - if let Some((schema, _, _)) = type_check { - for (_field_id, field_name) in schema.required_fields_for_kind(node.kind_name()) { + if let Some(context) = type_check { + for (_field_id, field_name) in context.schema.required_fields_for_kind(node.kind_name()) { let present = match field_name { Some(n) => ast .field_id_for_name(n) @@ -329,13 +341,18 @@ fn dump_node( // Unnamed children — skip unnamed tokens (keywords, punctuation) if let Some(children) = node.fields.get(&CHILD_FIELD) { - let child_type_check = type_check.map(|(schema, _, _)| { - let expected = schema + let child_type_check = type_check.map(|context| { + let expected = context + .schema .field_types(node.kind_name(), CHILD_FIELD) .map(|v| v.as_slice()) .or(Some(EMPTY_NODE_TYPES)); let parent_field = Some((node.kind_name(), "children")); - (schema, expected, parent_field) + TypeCheckContext { + schema: context.schema, + expected, + parent_field, + } }); for &child_id in children { if let Some(child) = ast.get_node(child_id) { @@ -392,8 +409,10 @@ fn dump_node_inline( } } - if let Some((schema, expected, parent_field)) = type_check { - if let Some(err) = type_error_for_node(schema, node, expected, parent_field) { + if let Some(context) = type_check { + if let Some(err) = + type_error_for_node(context.schema, node, context.expected, context.parent_field) + { write!(out, " <-- ERROR: {err}").unwrap(); } } From 1900b61ce01df5f1505f5a0212f7182f724baebc Mon Sep 17 00:00:00 2001 From: JarLob Date: Fri, 31 Jul 2026 15:11:22 +0300 Subject: [PATCH 166/188] Add tests --- .../cache_write_capable_reusable_workflow.yml | 45 +++++++++++++++++++ ...write_capable_reusable_workflow_caller.yml | 16 +++++++ .../CachePoisoningViaCodeInjection.expected | 2 + .../CachePoisoningViaDirectCache.expected | 5 +++ .../CachePoisoningViaPoisonableStep.expected | 5 +++ 5 files changed, 73 insertions(+) create mode 100644 actions/ql/test/query-tests/Security/CWE-349/.github/workflows/cache_write_capable_reusable_workflow.yml create mode 100644 actions/ql/test/query-tests/Security/CWE-349/.github/workflows/cache_write_capable_reusable_workflow_caller.yml diff --git a/actions/ql/test/query-tests/Security/CWE-349/.github/workflows/cache_write_capable_reusable_workflow.yml b/actions/ql/test/query-tests/Security/CWE-349/.github/workflows/cache_write_capable_reusable_workflow.yml new file mode 100644 index 000000000000..99a474f99508 --- /dev/null +++ b/actions/ql/test/query-tests/Security/CWE-349/.github/workflows/cache_write_capable_reusable_workflow.yml @@ -0,0 +1,45 @@ +on: + workflow_call: + inputs: + head_sha: + required: false + type: string + +jobs: + direct-cache: + if: github.event_name == 'workflow_dispatch' + permissions: {} + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - env: + HEAD_SHA: ${{ inputs.head_sha }} + run: | + [[ "$HEAD_SHA" =~ ^[0-9a-fA-F]{40}$ ]] || exit 1 + git fetch origin "$HEAD_SHA" + git checkout --detach "$HEAD_SHA" + - uses: actions/cache@v4 + with: + path: .npm + key: reusable-direct-cache + + poisonable-step: + if: github.event_name == 'workflow_dispatch' + permissions: {} + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - env: + HEAD_SHA: ${{ inputs.head_sha }} + run: | + [[ "$HEAD_SHA" =~ ^[0-9a-fA-F]{40}$ ]] || exit 1 + git fetch origin "$HEAD_SHA" + git checkout --detach "$HEAD_SHA" + - run: npm install + + code-injection: + if: github.event_name == 'push' + permissions: {} + runs-on: ubuntu-latest + steps: + - run: echo "${{ github.event.head_commit.message }}" \ No newline at end of file diff --git a/actions/ql/test/query-tests/Security/CWE-349/.github/workflows/cache_write_capable_reusable_workflow_caller.yml b/actions/ql/test/query-tests/Security/CWE-349/.github/workflows/cache_write_capable_reusable_workflow_caller.yml new file mode 100644 index 000000000000..9f0f5841f89e --- /dev/null +++ b/actions/ql/test/query-tests/Security/CWE-349/.github/workflows/cache_write_capable_reusable_workflow_caller.yml @@ -0,0 +1,16 @@ +on: + push: + branches: [main] + workflow_dispatch: + inputs: + head_sha: + description: Commit SHA to test + required: true + type: string + +jobs: + reusable: + permissions: {} + uses: ./.github/workflows/cache_write_capable_reusable_workflow.yml + with: + head_sha: ${{ github.event.inputs.head_sha }} \ No newline at end of file diff --git a/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaCodeInjection.expected b/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaCodeInjection.expected index 8cfbf6c2965c..e8d1d96486ab 100644 --- a/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaCodeInjection.expected +++ b/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaCodeInjection.expected @@ -2,6 +2,7 @@ edges | .github/workflows/code_injection2.yml:12:9:16:6 | Uses Step: modified_files | .github/workflows/code_injection2.yml:16:21:16:70 | steps.modified_files.outputs.files_modified | provenance | | nodes | .github/workflows/cache_write_capable_push.yml:10:21:10:59 | github.event.head_commit.message | semmle.label | github.event.head_commit.message | +| .github/workflows/cache_write_capable_reusable_workflow.yml:45:21:45:59 | github.event.head_commit.message | semmle.label | github.event.head_commit.message | | .github/workflows/code_injection1.yml:11:17:11:48 | github.event.comment.body | semmle.label | github.event.comment.body | | .github/workflows/code_injection2.yml:12:9:16:6 | Uses Step: modified_files | semmle.label | Uses Step: modified_files | | .github/workflows/code_injection2.yml:16:21:16:70 | steps.modified_files.outputs.files_modified | semmle.label | steps.modified_files.outputs.files_modified | @@ -9,3 +10,4 @@ nodes subpaths #select | .github/workflows/cache_write_capable_push.yml:10:21:10:59 | github.event.head_commit.message | .github/workflows/cache_write_capable_push.yml:10:21:10:59 | github.event.head_commit.message | .github/workflows/cache_write_capable_push.yml:10:21:10:59 | github.event.head_commit.message | Unprivileged code injection in $@, which may lead to cache poisoning ($@). | .github/workflows/cache_write_capable_push.yml:10:21:10:59 | github.event.head_commit.message | ${{ github.event.head_commit.message }} | .github/workflows/cache_write_capable_push.yml:2:3:2:6 | push | push | +| .github/workflows/cache_write_capable_reusable_workflow.yml:45:21:45:59 | github.event.head_commit.message | .github/workflows/cache_write_capable_reusable_workflow.yml:45:21:45:59 | github.event.head_commit.message | .github/workflows/cache_write_capable_reusable_workflow.yml:45:21:45:59 | github.event.head_commit.message | Unprivileged code injection in $@, which may lead to cache poisoning ($@). | .github/workflows/cache_write_capable_reusable_workflow.yml:45:21:45:59 | github.event.head_commit.message | ${{ github.event.head_commit.message }} | .github/workflows/cache_write_capable_reusable_workflow_caller.yml:2:3:2:6 | push | push | diff --git a/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaDirectCache.expected b/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaDirectCache.expected index 0491a0de4e8d..ad5e6e972c89 100644 --- a/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaDirectCache.expected +++ b/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaDirectCache.expected @@ -1,4 +1,8 @@ edges +| .github/workflows/cache_write_capable_reusable_workflow.yml:14:9:15:6 | Uses Step | .github/workflows/cache_write_capable_reusable_workflow.yml:15:9:21:6 | Run Step | +| .github/workflows/cache_write_capable_reusable_workflow.yml:15:9:21:6 | Run Step | .github/workflows/cache_write_capable_reusable_workflow.yml:21:9:26:2 | Uses Step | +| .github/workflows/cache_write_capable_reusable_workflow.yml:31:9:32:6 | Uses Step | .github/workflows/cache_write_capable_reusable_workflow.yml:32:9:38:6 | Run Step | +| .github/workflows/cache_write_capable_reusable_workflow.yml:32:9:38:6 | Run Step | .github/workflows/cache_write_capable_reusable_workflow.yml:38:9:40:2 | Run Step | | .github/workflows/cache_write_capable_workflow_dispatch.yml:14:9:15:6 | Uses Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:15:9:21:6 | Run Step | | .github/workflows/cache_write_capable_workflow_dispatch.yml:15:9:21:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:21:9:22:6 | Run Step | | .github/workflows/cache_write_capable_workflow_dispatch.yml:21:9:22:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:22:9:25:33 | Uses Step | @@ -47,4 +51,5 @@ edges | .github/workflows/poisonable_step5.yml:17:9:22:6 | Uses Step | .github/workflows/poisonable_step5.yml:22:9:24:6 | Uses Step | | .github/workflows/poisonable_step5.yml:22:9:24:6 | Uses Step | .github/workflows/poisonable_step5.yml:24:9:28:31 | Uses Step | #select +| .github/workflows/cache_write_capable_reusable_workflow.yml:21:9:26:2 | Uses Step | .github/workflows/cache_write_capable_reusable_workflow.yml:15:9:21:6 | Run Step | .github/workflows/cache_write_capable_reusable_workflow.yml:21:9:26:2 | Uses Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/cache_write_capable_reusable_workflow_caller.yml:4:3:4:19 | workflow_dispatch | workflow_dispatch | | .github/workflows/cache_write_capable_workflow_dispatch.yml:22:9:25:33 | Uses Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:15:9:21:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:22:9:25:33 | Uses Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/cache_write_capable_workflow_dispatch.yml:2:3:2:19 | workflow_dispatch | workflow_dispatch | diff --git a/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaPoisonableStep.expected b/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaPoisonableStep.expected index 0b637891d8e0..4460256416cf 100644 --- a/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaPoisonableStep.expected +++ b/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaPoisonableStep.expected @@ -1,4 +1,8 @@ edges +| .github/workflows/cache_write_capable_reusable_workflow.yml:14:9:15:6 | Uses Step | .github/workflows/cache_write_capable_reusable_workflow.yml:15:9:21:6 | Run Step | +| .github/workflows/cache_write_capable_reusable_workflow.yml:15:9:21:6 | Run Step | .github/workflows/cache_write_capable_reusable_workflow.yml:21:9:26:2 | Uses Step | +| .github/workflows/cache_write_capable_reusable_workflow.yml:31:9:32:6 | Uses Step | .github/workflows/cache_write_capable_reusable_workflow.yml:32:9:38:6 | Run Step | +| .github/workflows/cache_write_capable_reusable_workflow.yml:32:9:38:6 | Run Step | .github/workflows/cache_write_capable_reusable_workflow.yml:38:9:40:2 | Run Step | | .github/workflows/cache_write_capable_workflow_dispatch.yml:14:9:15:6 | Uses Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:15:9:21:6 | Run Step | | .github/workflows/cache_write_capable_workflow_dispatch.yml:15:9:21:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:21:9:22:6 | Run Step | | .github/workflows/cache_write_capable_workflow_dispatch.yml:21:9:22:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:22:9:25:33 | Uses Step | @@ -47,4 +51,5 @@ edges | .github/workflows/poisonable_step5.yml:17:9:22:6 | Uses Step | .github/workflows/poisonable_step5.yml:22:9:24:6 | Uses Step | | .github/workflows/poisonable_step5.yml:22:9:24:6 | Uses Step | .github/workflows/poisonable_step5.yml:24:9:28:31 | Uses Step | #select +| .github/workflows/cache_write_capable_reusable_workflow.yml:38:9:40:2 | Run Step | .github/workflows/cache_write_capable_reusable_workflow.yml:32:9:38:6 | Run Step | .github/workflows/cache_write_capable_reusable_workflow.yml:38:9:40:2 | Run Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/cache_write_capable_reusable_workflow_caller.yml:4:3:4:19 | workflow_dispatch | workflow_dispatch | | .github/workflows/cache_write_capable_workflow_dispatch.yml:21:9:22:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:15:9:21:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:21:9:22:6 | Run Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/cache_write_capable_workflow_dispatch.yml:2:3:2:19 | workflow_dispatch | workflow_dispatch | From 3cd2f914a7400175c3e7c7fd9b5202c9b195f644 Mon Sep 17 00:00:00 2001 From: Asger F Date: Fri, 31 Jul 2026 14:57:56 +0200 Subject: [PATCH 167/188] JS: Support MaD targeting specific files For codebase-specific models it's useful to be able to write models for specific files, without an NPM package boundary around it. But previously it was only possible to use NPM package exports as the starting point of a model. This adds the type `file:` which uses imports of the given file as the starting point, exactly as it if had been importing aname NPM package. --- .../data/internal/ApiGraphModelsSpecific.qll | 49 +++++++++++++++++++ .../frameworks/data/foo/bar/baz.js | 1 + .../frameworks/data/importFileBasedModel.js | 5 ++ .../frameworks/data/test.expected | 1 + .../frameworks/data/test.ext.yml | 1 + 5 files changed, 57 insertions(+) create mode 100644 javascript/ql/test/library-tests/frameworks/data/foo/bar/baz.js create mode 100644 javascript/ql/test/library-tests/frameworks/data/importFileBasedModel.js diff --git a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModelsSpecific.qll b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModelsSpecific.qll index 00929f19d279..837aa6463b35 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModelsSpecific.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModelsSpecific.qll @@ -53,6 +53,13 @@ predicate parseTypeString(string rawType, string package, string qualifiedName) qualifiedName = "" } +/** If `type` has the form `file:` gets the path to the file. */ +bindingset[type] +overlay[caller] +private string getRawFilePathFromTypeName(string type) { + result = type.regexpCapture("file:(.*)", 1) +} + /** * Holds if models describing `package` may be relevant for the analysis of this database. */ @@ -76,6 +83,8 @@ predicate isTypeUsed(string type) { parseTypeString(type, package, _) and isPackageUsed(package) ) + or + exists(getRawFilePathFromTypeName(type)) // No need to prune repository-specific models } /** @@ -126,6 +135,41 @@ private API::Node getGlobalNode(string globalName) { result = any(GlobalApiEntryPoint e | e.getGlobal() = globalName).getANode() } +/** Holds if `type` is used as a type string in a model, and has the form `file:` */ +overlay[local] +private predicate relevantRawFilePath(string type, string filePath) { + isRelevantType(type) and + filePath = getRawFilePathFromTypeName(type) +} + +/** An API graph entry point for package specifiers of form `file:`. */ +overlay[local?] +private class RawFilePathEntryPoint extends API::EntryPoint { + string path; + + RawFilePathEntryPoint() { + relevantRawFilePath(_, path) and + this = "RawFilePathEntryPoint:" + path + } + + override DataFlow::SourceNode getASource() { + exists(JS::Import imprt | + imprt.getImportedFile().getRelativePath() = path and + result = imprt.getImportedModuleNode() + ) + } + + /** Gets the name of the path variable. */ + string getPath() { result = path } +} + +/** + * Gets an API node referring to the given global variable (if relevant). + */ +private API::Node getRawFilePathNode(string rawFilePathNode) { + result = any(RawFilePathEntryPoint e | e.getPath() = rawFilePathNode).getANode() +} + /** Gets a JavaScript-specific interpretation of the `(type, path)` tuple after resolving the first `n` access path tokens. */ bindingset[type, path] API::Node getExtraNodeFromPath(string type, AccessPath path, int n) { @@ -150,6 +194,11 @@ API::Node getExtraNodeFromType(string type) { // Access instance of a type based on type annotations result = API::Internal::getANodeOfTypeRaw(package, qualifiedName) ) + or + exists(string filePath | + relevantRawFilePath(type, filePath) and + result = getRawFilePathNode(filePath) + ) } /** diff --git a/javascript/ql/test/library-tests/frameworks/data/foo/bar/baz.js b/javascript/ql/test/library-tests/frameworks/data/foo/bar/baz.js new file mode 100644 index 000000000000..bb1843d113a5 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/data/foo/bar/baz.js @@ -0,0 +1 @@ +export const foo = 1; diff --git a/javascript/ql/test/library-tests/frameworks/data/importFileBasedModel.js b/javascript/ql/test/library-tests/frameworks/data/importFileBasedModel.js new file mode 100644 index 000000000000..4fcb5c3dc1cf --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/data/importFileBasedModel.js @@ -0,0 +1,5 @@ +import * as bar from './foo/bar/baz'; + +function t1() { + sink(bar.customSource()); // NOT OK +} diff --git a/javascript/ql/test/library-tests/frameworks/data/test.expected b/javascript/ql/test/library-tests/frameworks/data/test.expected index 0bc1b6b6ee07..0f945b6c3515 100644 --- a/javascript/ql/test/library-tests/frameworks/data/test.expected +++ b/javascript/ql/test/library-tests/frameworks/data/test.expected @@ -5,6 +5,7 @@ taintFlow | guardedRouteHandler.js:10:10:10:28 | res.injectedResData | guardedRouteHandler.js:10:10:10:28 | res.injectedResData | | guardedRouteHandler.js:16:10:16:28 | req.injectedReqData | guardedRouteHandler.js:16:10:16:28 | req.injectedReqData | | guardedRouteHandler.js:20:10:20:28 | res.injectedResData | guardedRouteHandler.js:20:10:20:28 | res.injectedResData | +| importFileBasedModel.js:4:10:4:27 | bar.customSource() | importFileBasedModel.js:4:10:4:27 | bar.customSource() | | paramDecorator.ts:6:54:6:54 | x | paramDecorator.ts:7:10:7:10 | x | | test.js:5:30:5:37 | source() | test.js:5:8:5:38 | testlib ... urce()) | | test.js:6:22:6:29 | source() | test.js:6:8:6:30 | preserv ... urce()) | diff --git a/javascript/ql/test/library-tests/frameworks/data/test.ext.yml b/javascript/ql/test/library-tests/frameworks/data/test.ext.yml index 1ac621936a4a..868a8d18998c 100644 --- a/javascript/ql/test/library-tests/frameworks/data/test.ext.yml +++ b/javascript/ql/test/library-tests/frameworks/data/test.ext.yml @@ -15,6 +15,7 @@ extensions: - ['danger-constant', 'Member[danger]', 'test-source'] - ['testlib', 'Member[middleware].ReturnValue.GuardedRouteHandler.Parameter[0].Member[injectedReqData]', 'test-source'] - ['testlib', 'Member[middleware].ReturnValue.GuardedRouteHandler.Parameter[1].Member[injectedResData]', 'test-source'] + - ['file:foo/bar/baz.js', 'Member[customSource].ReturnValue', 'test-source'] - addsTo: pack: codeql/javascript-all From 8f387b741da9ff1d338cde8f61695c3da6a2b839 Mon Sep 17 00:00:00 2001 From: Asger F Date: Fri, 31 Jul 2026 15:02:21 +0200 Subject: [PATCH 168/188] JS: Add documentation --- .../customizing-library-models-for-javascript.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/codeql/codeql-language-guides/customizing-library-models-for-javascript.rst b/docs/codeql/codeql-language-guides/customizing-library-models-for-javascript.rst index 77ea678f5468..7ede0d0aff3a 100644 --- a/docs/codeql/codeql-language-guides/customizing-library-models-for-javascript.rst +++ b/docs/codeql/codeql-language-guides/customizing-library-models-for-javascript.rst @@ -549,6 +549,7 @@ A type can be defined by adding ``typeModel`` tuples for that type. Additionally - The name of an NPM package matches imports of that package. For example, the type ``express`` matches the expression ``require("express")``. If the package name includes dots, it must be surrounded by single quotes, such as in ``'lodash.escape'``. - The type ``global`` identifies the global object, also known as ``window``. In JavaScript, global variables are properties of the global object, so global variables can be identified using this type. (This type also matches imports of the NPM package named ``global``, which is a package that happens to export the global object.) - A qualified type name of form ``.`` identifies expressions of type ```` from ````. For example, ``mysql.Connection`` identifies expression of type ``Connection`` from the ``mysql`` package. Note that this only works if type annotations are present in the codebase, or if sufficient ``typeModel`` tuples have been provided for that type. +- A string of form ``file:`` identifies expressions that are imported from a file at the given path. The path is relative to the root of the codebase, must use forward slashes as path separator, must include the file extension, and is case-sensitive. For example, ``file:src/utils.js`` identifies expressions such as ``require('./utils')`` inside ``src/``, or ``require('../src/utils')`` inside another top-level folder. Access paths ------------ From d0cb4ef80212f6b51a17bd0701f888061221b510 Mon Sep 17 00:00:00 2001 From: Asger F Date: Fri, 31 Jul 2026 15:07:54 +0200 Subject: [PATCH 169/188] JS: Add change note --- .../ql/lib/change-notes/2026-07-31-file-scoped-models.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 javascript/ql/lib/change-notes/2026-07-31-file-scoped-models.md diff --git a/javascript/ql/lib/change-notes/2026-07-31-file-scoped-models.md b/javascript/ql/lib/change-notes/2026-07-31-file-scoped-models.md new file mode 100644 index 000000000000..b3df112a1f1d --- /dev/null +++ b/javascript/ql/lib/change-notes/2026-07-31-file-scoped-models.md @@ -0,0 +1,6 @@ +--- +category: majorAnalysis +--- +* It is now possible for custom models to refer to specific files in the codebase, using a package name of form `file:`. The model should describe the public exports + of that file. This can be used to derive sources and sinks in code that imports the file, but note that sources and sinks will not generally be placed within the file itself. + For example, a source model `['file:lib/service.js', 'Member[getData].ReturnValue', 'remote']` could identify `require('../lib/service').getData()` as a source. From cd7f6b768c08a5be67ce2a3e6d741def117540fc Mon Sep 17 00:00:00 2001 From: JarLob Date: Fri, 31 Jul 2026 16:18:14 +0300 Subject: [PATCH 170/188] Remove unreachable workflow_call cache access handling Reusable workflow jobs inherit their callers' trigger events and do not expose workflow_call through getATriggerEvent(). Remove the branch that assumed otherwise, and add coverage for caller resolution and inherited events. --- .../actions/security/CachePoisoningQuery.qll | 16 +++++----------- .../.github/workflows/caller.yml | 5 +++++ .../.github/workflows/reusable.yml | 7 +++++++ .../reusable-workflow-callers/test.expected | 1 + .../reusable-workflow-callers/test.ql | 9 +++++++++ 5 files changed, 27 insertions(+), 11 deletions(-) create mode 100644 actions/ql/test/library-tests/reusable-workflow-callers/.github/workflows/caller.yml create mode 100644 actions/ql/test/library-tests/reusable-workflow-callers/.github/workflows/reusable.yml create mode 100644 actions/ql/test/library-tests/reusable-workflow-callers/test.expected create mode 100644 actions/ql/test/library-tests/reusable-workflow-callers/test.ql diff --git a/actions/ql/lib/codeql/actions/security/CachePoisoningQuery.qll b/actions/ql/lib/codeql/actions/security/CachePoisoningQuery.qll index 52ceb9a94e0c..41529c489ff0 100644 --- a/actions/ql/lib/codeql/actions/security/CachePoisoningQuery.qll +++ b/actions/ql/lib/codeql/actions/security/CachePoisoningQuery.qll @@ -54,19 +54,13 @@ private predicate eventHasDefaultBranchCacheWriteAccess(Event event) { runsOnDefaultBranch(event) and event.getName() = defaultBranchCacheWriteEvent() } -/** Holds if `job` can write to the cache scope of the default branch for `event`. */ +/** + * Holds if `job` can write to the cache scope of the default branch for `event`. + * Reusable workflow jobs inherit their caller's trigger event. + */ predicate hasDefaultBranchCacheWriteAccess(LocalJob job, Event event) { job.getATriggerEvent() = event and - ( - eventHasDefaultBranchCacheWriteAccess(event) - or - // the workflow caller runs in the context of the default branch - event.getName() = "workflow_call" and - exists(ExternalJob caller | - job.getEnclosingWorkflow().(ReusableWorkflow).getACaller() = caller and - eventHasDefaultBranchCacheWriteAccess(caller.getATriggerEvent()) - ) - ) + eventHasDefaultBranchCacheWriteAccess(event) } abstract class CacheWritingStep extends Step { diff --git a/actions/ql/test/library-tests/reusable-workflow-callers/.github/workflows/caller.yml b/actions/ql/test/library-tests/reusable-workflow-callers/.github/workflows/caller.yml new file mode 100644 index 000000000000..12f3016f5d07 --- /dev/null +++ b/actions/ql/test/library-tests/reusable-workflow-callers/.github/workflows/caller.yml @@ -0,0 +1,5 @@ +on: workflow_dispatch + +jobs: + call-reusable: + uses: ./.github/workflows/reusable.yml \ No newline at end of file diff --git a/actions/ql/test/library-tests/reusable-workflow-callers/.github/workflows/reusable.yml b/actions/ql/test/library-tests/reusable-workflow-callers/.github/workflows/reusable.yml new file mode 100644 index 000000000000..f27aeb584fbd --- /dev/null +++ b/actions/ql/test/library-tests/reusable-workflow-callers/.github/workflows/reusable.yml @@ -0,0 +1,7 @@ +on: workflow_call + +jobs: + build: + runs-on: ubuntu-latest + steps: + - run: echo build \ No newline at end of file diff --git a/actions/ql/test/library-tests/reusable-workflow-callers/test.expected b/actions/ql/test/library-tests/reusable-workflow-callers/test.expected new file mode 100644 index 000000000000..4d2bad7a2bf1 --- /dev/null +++ b/actions/ql/test/library-tests/reusable-workflow-callers/test.expected @@ -0,0 +1 @@ +| .github/workflows/reusable.yml:1:1:7:23 | on: workflow_call | .github/workflows/caller.yml:5:5:5:42 | Job: call-reusable | .github/workflows/reusable.yml:5:5:7:23 | Job: build | workflow_dispatch | diff --git a/actions/ql/test/library-tests/reusable-workflow-callers/test.ql b/actions/ql/test/library-tests/reusable-workflow-callers/test.ql new file mode 100644 index 000000000000..544db1647332 --- /dev/null +++ b/actions/ql/test/library-tests/reusable-workflow-callers/test.ql @@ -0,0 +1,9 @@ +import actions + +from ReusableWorkflow workflow, ExternalJob caller, LocalJob job, Event event +where + workflow.getACaller() = caller and + job.getEnclosingWorkflow() = workflow and + caller.getATriggerEvent() = event and + job.getATriggerEvent() = event +select workflow, caller, job, event.getName() From c40fe85217993a5a0c46316966c2f478ce5900f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20Loba=C4=8Devski?= Date: Sun, 19 Jul 2026 16:54:09 +0000 Subject: [PATCH 171/188] Reworded the misleading 'Unprivileged' --- .../ql/src/Security/CWE-349/CachePoisoningViaCodeInjection.ql | 4 ++-- .../Security/CWE-349/CachePoisoningViaCodeInjection.expected | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/actions/ql/src/Security/CWE-349/CachePoisoningViaCodeInjection.ql b/actions/ql/src/Security/CWE-349/CachePoisoningViaCodeInjection.ql index 2fe792aba1e6..8ff02c5ee288 100644 --- a/actions/ql/src/Security/CWE-349/CachePoisoningViaCodeInjection.ql +++ b/actions/ql/src/Security/CWE-349/CachePoisoningViaCodeInjection.ql @@ -1,5 +1,5 @@ /** - * @name Cache Poisoning via low-privileged code injection + * @name Cache Poisoning via code injection * @description The cache can be poisoned by untrusted code, leading to a cache poisoning attack. * @kind path-problem * @problem.severity error @@ -27,5 +27,5 @@ where check.protects(source.getNode().asExpr(), event, "code-injection") ) select sink.getNode(), source, sink, - "Unprivileged code injection in $@, which may lead to cache poisoning ($@).", sink, + "Code injection in $@ may allow poisoning the default-branch cache (event trigger: $@).", sink, sink.getNode().asExpr().(Expression).getRawExpression(), event, event.getName() diff --git a/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaCodeInjection.expected b/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaCodeInjection.expected index 9cfac091f675..76a95eb204f9 100644 --- a/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaCodeInjection.expected +++ b/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaCodeInjection.expected @@ -7,4 +7,4 @@ nodes | .github/workflows/neg_code_injection1.yml:11:17:11:48 | github.event.comment.body | semmle.label | github.event.comment.body | subpaths #select -| .github/workflows/code_injection1.yml:11:17:11:48 | github.event.comment.body | .github/workflows/code_injection1.yml:11:17:11:48 | github.event.comment.body | .github/workflows/code_injection1.yml:11:17:11:48 | github.event.comment.body | Unprivileged code injection in $@, which may lead to cache poisoning ($@). | .github/workflows/code_injection1.yml:11:17:11:48 | github.event.comment.body | ${{ github.event.comment.body }} | .github/workflows/code_injection1.yml:2:3:2:15 | issue_comment | issue_comment | +| .github/workflows/code_injection1.yml:11:17:11:48 | github.event.comment.body | .github/workflows/code_injection1.yml:11:17:11:48 | github.event.comment.body | .github/workflows/code_injection1.yml:11:17:11:48 | github.event.comment.body | Code injection in $@ may allow poisoning the default-branch cache (event trigger: $@). | .github/workflows/code_injection1.yml:11:17:11:48 | github.event.comment.body | ${{ github.event.comment.body }} | .github/workflows/code_injection1.yml:2:3:2:15 | issue_comment | issue_comment | From caf91c9f2332eaf4bb28828eca6c013d695e74a2 Mon Sep 17 00:00:00 2001 From: JarLob Date: Fri, 31 Jul 2026 23:56:44 +0300 Subject: [PATCH 172/188] Add change note --- .../2026-07-31-cache-poisoning-code-injection-wording.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 actions/ql/src/change-notes/2026-07-31-cache-poisoning-code-injection-wording.md diff --git a/actions/ql/src/change-notes/2026-07-31-cache-poisoning-code-injection-wording.md b/actions/ql/src/change-notes/2026-07-31-cache-poisoning-code-injection-wording.md new file mode 100644 index 000000000000..8e2ade04f8b0 --- /dev/null +++ b/actions/ql/src/change-notes/2026-07-31-cache-poisoning-code-injection-wording.md @@ -0,0 +1,4 @@ +--- +category: queryMetadata +--- +* The name and alert message of the `actions/cache-poisoning/code-injection` query have been reworded for clarity. \ No newline at end of file From cbdc74e2500a1d030e56244e632d971c91eac3c1 Mon Sep 17 00:00:00 2001 From: Keshav Malik Date: Sat, 1 Aug 2026 20:26:29 +0530 Subject: [PATCH 173/188] JS: Track response data through promises --- ...2026-08-01-client-response-promise-data.md | 4 + .../javascript/frameworks/ClientRequests.qll | 12 + .../Xss.expected | 250 ++++++++++++++++++ .../fetch-promise-chain.js | 145 ++++++++++ .../non-fetch-promise-chain.js | 47 ++++ 5 files changed, 458 insertions(+) create mode 100644 javascript/ql/lib/change-notes/2026-08-01-client-response-promise-data.md create mode 100644 javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/fetch-promise-chain.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/non-fetch-promise-chain.js diff --git a/javascript/ql/lib/change-notes/2026-08-01-client-response-promise-data.md b/javascript/ql/lib/change-notes/2026-08-01-client-response-promise-data.md new file mode 100644 index 000000000000..7213d64a830d --- /dev/null +++ b/javascript/ql/lib/change-notes/2026-08-01-client-response-promise-data.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* JavaScript security queries using the `response` threat model now track promise-wrapped client response data into promise fulfillment values. This may improve results for queries such as `js/xss` when response data is consumed through `.then(...)` chains. diff --git a/javascript/ql/lib/semmle/javascript/frameworks/ClientRequests.qll b/javascript/ql/lib/semmle/javascript/frameworks/ClientRequests.qll index 9da93400ef92..fabf0a6d38f5 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/ClientRequests.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/ClientRequests.qll @@ -1016,6 +1016,18 @@ module ClientRequest { override string getSourceType() { result = "HTTP response data" } } + /** + * A taint step from promise-wrapped response data to the value that the promise resolves to. + */ + private class ClientRequestResponsePromiseStep extends TaintTracking::SharedTaintStep { + override predicate promiseStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(ClientRequest r | + r.getAResponseDataNode(_, true).getALocalSource().flowsTo(node1) and + PromiseFlow::loadStep(node1, node2, Promises::valueProp()) + ) + } + } + /** * An additional taint step that captures taint propagation from the receiver of fetch response methods * (such as "json", "text", "blob", and "arrayBuffer") to the call result. diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.expected b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.expected index 99cafddc41d2..8d4eae0a7083 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.expected @@ -1,5 +1,19 @@ #select +| fetch-promise-chain.js:21:47:21:49 | row | fetch-promise-chain.js:7:3:7:12 | fetch(url) | fetch-promise-chain.js:21:47:21:49 | row | Cross-site scripting vulnerability due to $@. | fetch-promise-chain.js:7:3:7:12 | fetch(url) | user-provided value | +| fetch-promise-chain.js:30:33:30:36 | text | fetch-promise-chain.js:27:3:27:23 | fetch(" ... ssage") | fetch-promise-chain.js:30:33:30:36 | text | Cross-site scripting vulnerability due to $@. | fetch-promise-chain.js:27:3:27:23 | fetch(" ... ssage") | user-provided value | +| fetch-promise-chain.js:47:33:47:44 | data.message | fetch-promise-chain.js:43:19:43:39 | fetch(" ... ssage") | fetch-promise-chain.js:47:33:47:44 | data.message | Cross-site scripting vulnerability due to $@. | fetch-promise-chain.js:43:19:43:39 | fetch(" ... ssage") | user-provided value | +| fetch-promise-chain.js:57:33:57:36 | text | fetch-promise-chain.js:53:13:53:33 | fetch(" ... ssage") | fetch-promise-chain.js:57:33:57:36 | text | Cross-site scripting vulnerability due to $@. | fetch-promise-chain.js:53:13:53:33 | fetch(" ... ssage") | user-provided value | +| fetch-promise-chain.js:67:55:67:66 | item.message | fetch-promise-chain.js:62:3:62:23 | fetch(" ... ssage") | fetch-promise-chain.js:67:55:67:66 | item.message | Cross-site scripting vulnerability due to $@. | fetch-promise-chain.js:62:3:62:23 | fetch(" ... ssage") | user-provided value | +| fetch-promise-chain.js:76:33:76:39 | message | fetch-promise-chain.js:73:3:73:23 | fetch(" ... ssage") | fetch-promise-chain.js:76:33:76:39 | message | Cross-site scripting vulnerability due to $@. | fetch-promise-chain.js:73:3:73:23 | fetch(" ... ssage") | user-provided value | +| fetch-promise-chain.js:84:33:84:44 | data.message | fetch-promise-chain.js:81:3:81:23 | fetch(" ... ssage") | fetch-promise-chain.js:84:33:84:44 | data.message | Cross-site scripting vulnerability due to $@. | fetch-promise-chain.js:81:3:81:23 | fetch(" ... ssage") | user-provided value | +| fetch-promise-chain.js:93:31:93:42 | data.message | fetch-promise-chain.js:90:5:90:25 | fetch(" ... ssage") | fetch-promise-chain.js:93:31:93:42 | data.message | Cross-site scripting vulnerability due to $@. | fetch-promise-chain.js:90:5:90:25 | fetch(" ... ssage") | user-provided value | +| fetch-promise-chain.js:102:33:102:47 | payload.message | fetch-promise-chain.js:98:3:98:23 | fetch(" ... ssage") | fetch-promise-chain.js:102:33:102:47 | payload.message | Cross-site scripting vulnerability due to $@. | fetch-promise-chain.js:98:3:98:23 | fetch(" ... ssage") | user-provided value | | interceptors.js:9:56:9:72 | userGeneratedHtml | interceptors.js:7:6:7:13 | response | interceptors.js:9:56:9:72 | userGeneratedHtml | Cross-site scripting vulnerability due to $@. | interceptors.js:7:6:7:13 | response | user-provided value | +| non-fetch-promise-chain.js:5:33:5:36 | body | non-fetch-promise-chain.js:3:3:3:35 | rp("htt ... ssage") | non-fetch-promise-chain.js:5:33:5:36 | body | Cross-site scripting vulnerability due to $@. | non-fetch-promise-chain.js:3:3:3:35 | rp("htt ... ssage") | user-provided value | +| non-fetch-promise-chain.js:13:33:13:44 | data.message | non-fetch-promise-chain.js:11:3:11:56 | rp({ ur ... true }) | non-fetch-promise-chain.js:13:33:13:44 | data.message | Cross-site scripting vulnerability due to $@. | non-fetch-promise-chain.js:11:3:11:56 | rp({ ur ... true }) | user-provided value | +| non-fetch-promise-chain.js:21:31:21:51 | respons ... message | non-fetch-promise-chain.js:19:19:19:58 | axios.g ... ssage") | non-fetch-promise-chain.js:21:31:21:51 | respons ... message | Cross-site scripting vulnerability due to $@. | non-fetch-promise-chain.js:19:19:19:58 | axios.g ... ssage") | user-provided value | +| non-fetch-promise-chain.js:29:33:29:53 | respons ... message | non-fetch-promise-chain.js:27:3:27:46 | needle( ... ssage") | non-fetch-promise-chain.js:29:33:29:53 | respons ... message | Cross-site scripting vulnerability due to $@. | non-fetch-promise-chain.js:27:3:27:46 | needle( ... ssage") | user-provided value | +| non-fetch-promise-chain.js:37:33:37:45 | response.text | non-fetch-promise-chain.js:35:3:35:47 | superag ... ssage") | non-fetch-promise-chain.js:37:33:37:45 | response.text | Cross-site scripting vulnerability due to $@. | non-fetch-promise-chain.js:35:3:35:47 | superag ... ssage") | user-provided value | | test.jsx:27:29:27:32 | data | test.jsx:5:28:5:63 | fetch(" ... ntent") | test.jsx:27:29:27:32 | data | Cross-site scripting vulnerability due to $@. | test.jsx:5:28:5:63 | fetch(" ... ntent") | user-provided value | | test.ts:21:57:21:76 | response.description | test.ts:8:9:8:79 | this.#h ... query') | test.ts:21:57:21:76 | response.description | Cross-site scripting vulnerability due to $@. | test.ts:8:9:8:79 | this.#h ... query') | user-provided value | | test.ts:24:36:24:90 | `

${ ... o}

` | test.ts:8:9:8:79 | this.#h ... query') | test.ts:24:36:24:90 | `

${ ... o}

` | Cross-site scripting vulnerability due to $@. | test.ts:8:9:8:79 | this.#h ... query') | user-provided value | @@ -19,9 +33,121 @@ | testUseQueries2.vue:40:10:40:23 | v-html=data3 | testUseQueries2.vue:12:28:12:41 | fetch("${id}") | testUseQueries2.vue:40:10:40:23 | v-html=data3 | Cross-site scripting vulnerability due to $@. | testUseQueries2.vue:12:28:12:41 | fetch("${id}") | user-provided value | | testUseQueries.vue:25:10:25:23 | v-html=data2 | testUseQueries.vue:11:36:11:49 | fetch("${id}") | testUseQueries.vue:25:10:25:23 | v-html=data2 | Cross-site scripting vulnerability due to $@. | testUseQueries.vue:11:36:11:49 | fetch("${id}") | user-provided value | edges +| fetch-promise-chain.js:7:3:7:12 | fetch(url) | fetch-promise-chain.js:8:11:8:18 | response | provenance | | +| fetch-promise-chain.js:7:3:8:38 | fetch(u ... json()) [PromiseValue] | fetch-promise-chain.js:9:11:9:14 | data | provenance | | +| fetch-promise-chain.js:8:11:8:18 | response | fetch-promise-chain.js:8:23:8:30 | response | provenance | | +| fetch-promise-chain.js:8:23:8:30 | response | fetch-promise-chain.js:8:23:8:37 | response.json() | provenance | | +| fetch-promise-chain.js:8:23:8:37 | response.json() | fetch-promise-chain.js:7:3:8:38 | fetch(u ... json()) [PromiseValue] | provenance | | +| fetch-promise-chain.js:9:11:9:14 | data | fetch-promise-chain.js:13:7:13:10 | data | provenance | | +| fetch-promise-chain.js:13:7:13:10 | data | fetch-promise-chain.js:13:7:13:16 | data.items | provenance | | +| fetch-promise-chain.js:13:7:13:16 | data.items | fetch-promise-chain.js:13:26:13:29 | item | provenance | | +| fetch-promise-chain.js:13:26:13:29 | item | fetch-promise-chain.js:14:55:14:58 | item | provenance | | +| fetch-promise-chain.js:13:26:13:29 | item | fetch-promise-chain.js:16:17:16:20 | item | provenance | | +| fetch-promise-chain.js:13:26:13:29 | item | fetch-promise-chain.js:17:17:17:20 | item | provenance | | +| fetch-promise-chain.js:13:26:13:29 | item | fetch-promise-chain.js:18:17:18:20 | item | provenance | | +| fetch-promise-chain.js:14:15:14:18 | link | fetch-promise-chain.js:19:17:19:20 | link | provenance | | +| fetch-promise-chain.js:14:22:14:88 | `
` | fetch-promise-chain.js:14:15:14:18 | link | provenance | | +| fetch-promise-chain.js:14:55:14:58 | item | fetch-promise-chain.js:14:55:14:68 | item.messageId | provenance | | +| fetch-promise-chain.js:14:55:14:68 | item.messageId | fetch-promise-chain.js:14:22:14:88 | `` | provenance | | +| fetch-promise-chain.js:15:15:15:17 | row | fetch-promise-chain.js:21:47:21:49 | row | provenance | | +| fetch-promise-chain.js:15:21:20:14 | `\\n ... ` | fetch-promise-chain.js:15:15:15:17 | row | provenance | | +| fetch-promise-chain.js:16:17:16:20 | item | fetch-promise-chain.js:16:17:16:32 | item.createdDate | provenance | | +| fetch-promise-chain.js:16:17:16:32 | item.createdDate | fetch-promise-chain.js:15:21:20:14 | `\\n ... ` | provenance | | +| fetch-promise-chain.js:17:17:17:20 | item | fetch-promise-chain.js:17:17:17:30 | item.messageId | provenance | | +| fetch-promise-chain.js:17:17:17:30 | item.messageId | fetch-promise-chain.js:15:21:20:14 | `\\n ... ` | provenance | | +| fetch-promise-chain.js:18:17:18:20 | item | fetch-promise-chain.js:18:17:18:33 | item.target ?? "" | provenance | | +| fetch-promise-chain.js:18:17:18:33 | item.target ?? "" | fetch-promise-chain.js:15:21:20:14 | `\\n ... ` | provenance | | +| fetch-promise-chain.js:19:17:19:20 | link | fetch-promise-chain.js:15:21:20:14 | `\\n ... ` | provenance | | +| fetch-promise-chain.js:27:3:27:23 | fetch(" ... ssage") | fetch-promise-chain.js:28:11:28:18 | response | provenance | | +| fetch-promise-chain.js:27:3:28:38 | fetch(" ... text()) [PromiseValue] | fetch-promise-chain.js:29:11:29:14 | text | provenance | | +| fetch-promise-chain.js:28:11:28:18 | response | fetch-promise-chain.js:28:23:28:30 | response | provenance | | +| fetch-promise-chain.js:28:23:28:30 | response | fetch-promise-chain.js:28:23:28:37 | response.text() | provenance | | +| fetch-promise-chain.js:28:23:28:37 | response.text() | fetch-promise-chain.js:27:3:28:38 | fetch(" ... text()) [PromiseValue] | provenance | | +| fetch-promise-chain.js:29:11:29:14 | text | fetch-promise-chain.js:30:33:30:36 | text | provenance | | +| fetch-promise-chain.js:43:9:43:15 | request | fetch-promise-chain.js:44:3:44:9 | request | provenance | | +| fetch-promise-chain.js:43:19:43:39 | fetch(" ... ssage") | fetch-promise-chain.js:43:9:43:15 | request | provenance | | +| fetch-promise-chain.js:44:3:44:9 | request | fetch-promise-chain.js:45:11:45:18 | response | provenance | | +| fetch-promise-chain.js:44:3:45:38 | request ... json()) [PromiseValue] | fetch-promise-chain.js:46:11:46:14 | data | provenance | | +| fetch-promise-chain.js:45:11:45:18 | response | fetch-promise-chain.js:45:23:45:30 | response | provenance | | +| fetch-promise-chain.js:45:23:45:30 | response | fetch-promise-chain.js:45:23:45:37 | response.json() | provenance | | +| fetch-promise-chain.js:45:23:45:37 | response.json() | fetch-promise-chain.js:44:3:45:38 | request ... json()) [PromiseValue] | provenance | | +| fetch-promise-chain.js:46:11:46:14 | data | fetch-promise-chain.js:47:33:47:36 | data | provenance | | +| fetch-promise-chain.js:47:33:47:36 | data | fetch-promise-chain.js:47:33:47:44 | data.message | provenance | | +| fetch-promise-chain.js:53:3:53:9 | request | fetch-promise-chain.js:54:3:54:9 | request | provenance | | +| fetch-promise-chain.js:53:13:53:33 | fetch(" ... ssage") | fetch-promise-chain.js:53:3:53:9 | request | provenance | | +| fetch-promise-chain.js:54:3:54:9 | request | fetch-promise-chain.js:55:11:55:18 | response | provenance | | +| fetch-promise-chain.js:54:3:55:38 | request ... text()) [PromiseValue] | fetch-promise-chain.js:56:11:56:14 | text | provenance | | +| fetch-promise-chain.js:55:11:55:18 | response | fetch-promise-chain.js:55:23:55:30 | response | provenance | | +| fetch-promise-chain.js:55:23:55:30 | response | fetch-promise-chain.js:55:23:55:37 | response.text() | provenance | | +| fetch-promise-chain.js:55:23:55:37 | response.text() | fetch-promise-chain.js:54:3:55:38 | request ... text()) [PromiseValue] | provenance | | +| fetch-promise-chain.js:56:11:56:14 | text | fetch-promise-chain.js:57:33:57:36 | text | provenance | | +| fetch-promise-chain.js:62:3:62:23 | fetch(" ... ssage") | fetch-promise-chain.js:63:11:63:18 | response | provenance | | +| fetch-promise-chain.js:62:3:63:38 | fetch(" ... json()) [PromiseValue] | fetch-promise-chain.js:62:3:64:29 | fetch(" ... .items) [PromiseValue] | provenance | | +| fetch-promise-chain.js:62:3:63:38 | fetch(" ... json()) [PromiseValue] | fetch-promise-chain.js:64:11:64:14 | data | provenance | | +| fetch-promise-chain.js:62:3:64:29 | fetch(" ... .items) [PromiseValue] | fetch-promise-chain.js:65:11:65:15 | items | provenance | | +| fetch-promise-chain.js:63:11:63:18 | response | fetch-promise-chain.js:63:23:63:30 | response | provenance | | +| fetch-promise-chain.js:63:23:63:30 | response | fetch-promise-chain.js:63:23:63:37 | response.json() | provenance | | +| fetch-promise-chain.js:63:23:63:37 | response.json() | fetch-promise-chain.js:62:3:63:38 | fetch(" ... json()) [PromiseValue] | provenance | | +| fetch-promise-chain.js:64:11:64:14 | data | fetch-promise-chain.js:64:19:64:22 | data | provenance | | +| fetch-promise-chain.js:64:19:64:22 | data | fetch-promise-chain.js:64:19:64:28 | data.items | provenance | | +| fetch-promise-chain.js:65:11:65:15 | items | fetch-promise-chain.js:66:7:66:11 | items | provenance | | +| fetch-promise-chain.js:66:7:66:11 | items | fetch-promise-chain.js:66:21:66:24 | item | provenance | | +| fetch-promise-chain.js:66:21:66:24 | item | fetch-promise-chain.js:67:55:67:58 | item | provenance | | +| fetch-promise-chain.js:67:55:67:58 | item | fetch-promise-chain.js:67:55:67:66 | item.message | provenance | | +| fetch-promise-chain.js:73:3:73:23 | fetch(" ... ssage") | fetch-promise-chain.js:74:11:74:18 | response | provenance | | +| fetch-promise-chain.js:73:3:74:38 | fetch(" ... json()) [PromiseValue] | fetch-promise-chain.js:75:12:75:22 | { message } | provenance | | +| fetch-promise-chain.js:74:11:74:18 | response | fetch-promise-chain.js:74:23:74:30 | response | provenance | | +| fetch-promise-chain.js:74:23:74:30 | response | fetch-promise-chain.js:74:23:74:37 | response.json() | provenance | | +| fetch-promise-chain.js:74:23:74:37 | response.json() | fetch-promise-chain.js:73:3:74:38 | fetch(" ... json()) [PromiseValue] | provenance | | +| fetch-promise-chain.js:75:12:75:22 | { message } | fetch-promise-chain.js:75:14:75:20 | message | provenance | | +| fetch-promise-chain.js:75:14:75:20 | message | fetch-promise-chain.js:76:33:76:39 | message | provenance | | +| fetch-promise-chain.js:81:3:81:23 | fetch(" ... ssage") | fetch-promise-chain.js:82:17:82:24 | response | provenance | | +| fetch-promise-chain.js:81:3:82:50 | fetch(" ... json()) [PromiseValue] | fetch-promise-chain.js:83:11:83:14 | data | provenance | | +| fetch-promise-chain.js:82:17:82:24 | response | fetch-promise-chain.js:82:35:82:42 | response | provenance | | +| fetch-promise-chain.js:82:29:82:49 | await r ... .json() | fetch-promise-chain.js:81:3:82:50 | fetch(" ... json()) [PromiseValue] | provenance | | +| fetch-promise-chain.js:82:35:82:42 | response | fetch-promise-chain.js:82:35:82:49 | response.json() | provenance | | +| fetch-promise-chain.js:82:35:82:49 | response.json() | fetch-promise-chain.js:82:29:82:49 | await r ... .json() | provenance | | +| fetch-promise-chain.js:83:11:83:14 | data | fetch-promise-chain.js:84:33:84:36 | data | provenance | | +| fetch-promise-chain.js:84:33:84:36 | data | fetch-promise-chain.js:84:33:84:44 | data.message | provenance | | +| fetch-promise-chain.js:89:3:92:4 | Promise ... ))\\n ]) [PromiseValue, 0] | fetch-promise-chain.js:92:12:92:17 | [data] [0] | provenance | | +| fetch-promise-chain.js:89:15:92:3 | [\\n f ... ())\\n ] [0, PromiseValue] | fetch-promise-chain.js:89:3:92:4 | Promise ... ))\\n ]) [PromiseValue, 0] | provenance | | +| fetch-promise-chain.js:90:5:90:25 | fetch(" ... ssage") | fetch-promise-chain.js:91:13:91:20 | response | provenance | | +| fetch-promise-chain.js:90:5:91:40 | fetch(" ... json()) [PromiseValue] | fetch-promise-chain.js:89:15:92:3 | [\\n f ... ())\\n ] [0, PromiseValue] | provenance | | +| fetch-promise-chain.js:91:13:91:20 | response | fetch-promise-chain.js:91:25:91:32 | response | provenance | | +| fetch-promise-chain.js:91:25:91:32 | response | fetch-promise-chain.js:91:25:91:39 | response.json() | provenance | | +| fetch-promise-chain.js:91:25:91:39 | response.json() | fetch-promise-chain.js:90:5:91:40 | fetch(" ... json()) [PromiseValue] | provenance | | +| fetch-promise-chain.js:92:12:92:17 | [data] [0] | fetch-promise-chain.js:92:13:92:16 | data | provenance | | +| fetch-promise-chain.js:92:13:92:16 | data | fetch-promise-chain.js:92:13:92:16 | data | provenance | | +| fetch-promise-chain.js:92:13:92:16 | data | fetch-promise-chain.js:93:31:93:34 | data | provenance | | +| fetch-promise-chain.js:93:31:93:34 | data | fetch-promise-chain.js:93:31:93:42 | data.message | provenance | | +| fetch-promise-chain.js:98:3:98:23 | fetch(" ... ssage") | fetch-promise-chain.js:99:11:99:18 | response | provenance | | +| fetch-promise-chain.js:98:3:99:38 | fetch(" ... json()) [PromiseValue] | fetch-promise-chain.js:100:11:100:14 | data | provenance | | +| fetch-promise-chain.js:99:11:99:18 | response | fetch-promise-chain.js:99:23:99:30 | response | provenance | | +| fetch-promise-chain.js:99:23:99:30 | response | fetch-promise-chain.js:99:23:99:37 | response.json() | provenance | | +| fetch-promise-chain.js:99:23:99:37 | response.json() | fetch-promise-chain.js:98:3:99:38 | fetch(" ... json()) [PromiseValue] | provenance | | +| fetch-promise-chain.js:100:11:100:14 | data | fetch-promise-chain.js:101:23:101:26 | data | provenance | | +| fetch-promise-chain.js:101:13:101:19 | payload | fetch-promise-chain.js:102:33:102:39 | payload | provenance | | +| fetch-promise-chain.js:101:23:101:26 | data | fetch-promise-chain.js:101:13:101:19 | payload | provenance | | +| fetch-promise-chain.js:102:33:102:39 | payload | fetch-promise-chain.js:102:33:102:47 | payload.message | provenance | | | interceptors.js:7:6:7:13 | response | interceptors.js:8:35:8:42 | response | provenance | | | interceptors.js:8:15:8:31 | userGeneratedHtml | interceptors.js:9:56:9:72 | userGeneratedHtml | provenance | | | interceptors.js:8:35:8:42 | response | interceptors.js:8:15:8:31 | userGeneratedHtml | provenance | | +| non-fetch-promise-chain.js:3:3:3:35 | rp("htt ... ssage") | non-fetch-promise-chain.js:4:11:4:14 | body | provenance | | +| non-fetch-promise-chain.js:4:11:4:14 | body | non-fetch-promise-chain.js:5:33:5:36 | body | provenance | | +| non-fetch-promise-chain.js:11:3:11:56 | rp({ ur ... true }) | non-fetch-promise-chain.js:12:11:12:14 | data | provenance | | +| non-fetch-promise-chain.js:12:11:12:14 | data | non-fetch-promise-chain.js:13:33:13:36 | data | provenance | | +| non-fetch-promise-chain.js:13:33:13:36 | data | non-fetch-promise-chain.js:13:33:13:44 | data.message | provenance | | +| non-fetch-promise-chain.js:19:9:19:15 | request | non-fetch-promise-chain.js:20:3:20:9 | request | provenance | | +| non-fetch-promise-chain.js:19:19:19:58 | axios.g ... ssage") | non-fetch-promise-chain.js:19:9:19:15 | request | provenance | | +| non-fetch-promise-chain.js:20:3:20:9 | request | non-fetch-promise-chain.js:20:16:20:23 | response | provenance | | +| non-fetch-promise-chain.js:20:16:20:23 | response | non-fetch-promise-chain.js:21:31:21:38 | response | provenance | | +| non-fetch-promise-chain.js:21:31:21:38 | response | non-fetch-promise-chain.js:21:31:21:51 | respons ... message | provenance | | +| non-fetch-promise-chain.js:27:3:27:46 | needle( ... ssage") | non-fetch-promise-chain.js:28:11:28:18 | response | provenance | | +| non-fetch-promise-chain.js:28:11:28:18 | response | non-fetch-promise-chain.js:29:33:29:40 | response | provenance | | +| non-fetch-promise-chain.js:29:33:29:40 | response | non-fetch-promise-chain.js:29:33:29:53 | respons ... message | provenance | | +| non-fetch-promise-chain.js:35:3:35:47 | superag ... ssage") | non-fetch-promise-chain.js:36:11:36:18 | response | provenance | | +| non-fetch-promise-chain.js:36:11:36:18 | response | non-fetch-promise-chain.js:37:33:37:40 | response | provenance | | +| non-fetch-promise-chain.js:37:33:37:40 | response | non-fetch-promise-chain.js:37:33:37:45 | response.text | provenance | | | test.jsx:5:11:5:18 | response | test.jsx:6:24:6:31 | response | provenance | | | test.jsx:5:22:5:63 | await f ... ntent") | test.jsx:5:11:5:18 | response | provenance | | | test.jsx:5:28:5:63 | fetch(" ... ntent") | test.jsx:5:22:5:63 | await f ... ntent") | provenance | | @@ -100,10 +226,133 @@ edges | testUseQueries.vue:12:20:12:34 | response.json() | testUseQueries.vue:18:22:18:36 | results[0].data | provenance | | | testUseQueries.vue:18:22:18:36 | results[0].data | testUseQueries.vue:25:10:25:23 | v-html=data2 | provenance | | nodes +| fetch-promise-chain.js:7:3:7:12 | fetch(url) | semmle.label | fetch(url) | +| fetch-promise-chain.js:7:3:8:38 | fetch(u ... json()) [PromiseValue] | semmle.label | fetch(u ... json()) [PromiseValue] | +| fetch-promise-chain.js:8:11:8:18 | response | semmle.label | response | +| fetch-promise-chain.js:8:23:8:30 | response | semmle.label | response | +| fetch-promise-chain.js:8:23:8:37 | response.json() | semmle.label | response.json() | +| fetch-promise-chain.js:9:11:9:14 | data | semmle.label | data | +| fetch-promise-chain.js:13:7:13:10 | data | semmle.label | data | +| fetch-promise-chain.js:13:7:13:16 | data.items | semmle.label | data.items | +| fetch-promise-chain.js:13:26:13:29 | item | semmle.label | item | +| fetch-promise-chain.js:14:15:14:18 | link | semmle.label | link | +| fetch-promise-chain.js:14:22:14:88 | `` | semmle.label | `` | +| fetch-promise-chain.js:14:55:14:58 | item | semmle.label | item | +| fetch-promise-chain.js:14:55:14:68 | item.messageId | semmle.label | item.messageId | +| fetch-promise-chain.js:15:15:15:17 | row | semmle.label | row | +| fetch-promise-chain.js:15:21:20:14 | `\\n ... ` | semmle.label | `\\n ... ` | +| fetch-promise-chain.js:16:17:16:20 | item | semmle.label | item | +| fetch-promise-chain.js:16:17:16:32 | item.createdDate | semmle.label | item.createdDate | +| fetch-promise-chain.js:17:17:17:20 | item | semmle.label | item | +| fetch-promise-chain.js:17:17:17:30 | item.messageId | semmle.label | item.messageId | +| fetch-promise-chain.js:18:17:18:20 | item | semmle.label | item | +| fetch-promise-chain.js:18:17:18:33 | item.target ?? "" | semmle.label | item.target ?? "" | +| fetch-promise-chain.js:19:17:19:20 | link | semmle.label | link | +| fetch-promise-chain.js:21:47:21:49 | row | semmle.label | row | +| fetch-promise-chain.js:27:3:27:23 | fetch(" ... ssage") | semmle.label | fetch(" ... ssage") | +| fetch-promise-chain.js:27:3:28:38 | fetch(" ... text()) [PromiseValue] | semmle.label | fetch(" ... text()) [PromiseValue] | +| fetch-promise-chain.js:28:11:28:18 | response | semmle.label | response | +| fetch-promise-chain.js:28:23:28:30 | response | semmle.label | response | +| fetch-promise-chain.js:28:23:28:37 | response.text() | semmle.label | response.text() | +| fetch-promise-chain.js:29:11:29:14 | text | semmle.label | text | +| fetch-promise-chain.js:30:33:30:36 | text | semmle.label | text | +| fetch-promise-chain.js:43:9:43:15 | request | semmle.label | request | +| fetch-promise-chain.js:43:19:43:39 | fetch(" ... ssage") | semmle.label | fetch(" ... ssage") | +| fetch-promise-chain.js:44:3:44:9 | request | semmle.label | request | +| fetch-promise-chain.js:44:3:45:38 | request ... json()) [PromiseValue] | semmle.label | request ... json()) [PromiseValue] | +| fetch-promise-chain.js:45:11:45:18 | response | semmle.label | response | +| fetch-promise-chain.js:45:23:45:30 | response | semmle.label | response | +| fetch-promise-chain.js:45:23:45:37 | response.json() | semmle.label | response.json() | +| fetch-promise-chain.js:46:11:46:14 | data | semmle.label | data | +| fetch-promise-chain.js:47:33:47:36 | data | semmle.label | data | +| fetch-promise-chain.js:47:33:47:44 | data.message | semmle.label | data.message | +| fetch-promise-chain.js:53:3:53:9 | request | semmle.label | request | +| fetch-promise-chain.js:53:13:53:33 | fetch(" ... ssage") | semmle.label | fetch(" ... ssage") | +| fetch-promise-chain.js:54:3:54:9 | request | semmle.label | request | +| fetch-promise-chain.js:54:3:55:38 | request ... text()) [PromiseValue] | semmle.label | request ... text()) [PromiseValue] | +| fetch-promise-chain.js:55:11:55:18 | response | semmle.label | response | +| fetch-promise-chain.js:55:23:55:30 | response | semmle.label | response | +| fetch-promise-chain.js:55:23:55:37 | response.text() | semmle.label | response.text() | +| fetch-promise-chain.js:56:11:56:14 | text | semmle.label | text | +| fetch-promise-chain.js:57:33:57:36 | text | semmle.label | text | +| fetch-promise-chain.js:62:3:62:23 | fetch(" ... ssage") | semmle.label | fetch(" ... ssage") | +| fetch-promise-chain.js:62:3:63:38 | fetch(" ... json()) [PromiseValue] | semmle.label | fetch(" ... json()) [PromiseValue] | +| fetch-promise-chain.js:62:3:64:29 | fetch(" ... .items) [PromiseValue] | semmle.label | fetch(" ... .items) [PromiseValue] | +| fetch-promise-chain.js:63:11:63:18 | response | semmle.label | response | +| fetch-promise-chain.js:63:23:63:30 | response | semmle.label | response | +| fetch-promise-chain.js:63:23:63:37 | response.json() | semmle.label | response.json() | +| fetch-promise-chain.js:64:11:64:14 | data | semmle.label | data | +| fetch-promise-chain.js:64:19:64:22 | data | semmle.label | data | +| fetch-promise-chain.js:64:19:64:28 | data.items | semmle.label | data.items | +| fetch-promise-chain.js:65:11:65:15 | items | semmle.label | items | +| fetch-promise-chain.js:66:7:66:11 | items | semmle.label | items | +| fetch-promise-chain.js:66:21:66:24 | item | semmle.label | item | +| fetch-promise-chain.js:67:55:67:58 | item | semmle.label | item | +| fetch-promise-chain.js:67:55:67:66 | item.message | semmle.label | item.message | +| fetch-promise-chain.js:73:3:73:23 | fetch(" ... ssage") | semmle.label | fetch(" ... ssage") | +| fetch-promise-chain.js:73:3:74:38 | fetch(" ... json()) [PromiseValue] | semmle.label | fetch(" ... json()) [PromiseValue] | +| fetch-promise-chain.js:74:11:74:18 | response | semmle.label | response | +| fetch-promise-chain.js:74:23:74:30 | response | semmle.label | response | +| fetch-promise-chain.js:74:23:74:37 | response.json() | semmle.label | response.json() | +| fetch-promise-chain.js:75:12:75:22 | { message } | semmle.label | { message } | +| fetch-promise-chain.js:75:14:75:20 | message | semmle.label | message | +| fetch-promise-chain.js:76:33:76:39 | message | semmle.label | message | +| fetch-promise-chain.js:81:3:81:23 | fetch(" ... ssage") | semmle.label | fetch(" ... ssage") | +| fetch-promise-chain.js:81:3:82:50 | fetch(" ... json()) [PromiseValue] | semmle.label | fetch(" ... json()) [PromiseValue] | +| fetch-promise-chain.js:82:17:82:24 | response | semmle.label | response | +| fetch-promise-chain.js:82:29:82:49 | await r ... .json() | semmle.label | await r ... .json() | +| fetch-promise-chain.js:82:35:82:42 | response | semmle.label | response | +| fetch-promise-chain.js:82:35:82:49 | response.json() | semmle.label | response.json() | +| fetch-promise-chain.js:83:11:83:14 | data | semmle.label | data | +| fetch-promise-chain.js:84:33:84:36 | data | semmle.label | data | +| fetch-promise-chain.js:84:33:84:44 | data.message | semmle.label | data.message | +| fetch-promise-chain.js:89:3:92:4 | Promise ... ))\\n ]) [PromiseValue, 0] | semmle.label | Promise ... ))\\n ]) [PromiseValue, 0] | +| fetch-promise-chain.js:89:15:92:3 | [\\n f ... ())\\n ] [0, PromiseValue] | semmle.label | [\\n f ... ())\\n ] [0, PromiseValue] | +| fetch-promise-chain.js:90:5:90:25 | fetch(" ... ssage") | semmle.label | fetch(" ... ssage") | +| fetch-promise-chain.js:90:5:91:40 | fetch(" ... json()) [PromiseValue] | semmle.label | fetch(" ... json()) [PromiseValue] | +| fetch-promise-chain.js:91:13:91:20 | response | semmle.label | response | +| fetch-promise-chain.js:91:25:91:32 | response | semmle.label | response | +| fetch-promise-chain.js:91:25:91:39 | response.json() | semmle.label | response.json() | +| fetch-promise-chain.js:92:12:92:17 | [data] [0] | semmle.label | [data] [0] | +| fetch-promise-chain.js:92:13:92:16 | data | semmle.label | data | +| fetch-promise-chain.js:92:13:92:16 | data | semmle.label | data | +| fetch-promise-chain.js:93:31:93:34 | data | semmle.label | data | +| fetch-promise-chain.js:93:31:93:42 | data.message | semmle.label | data.message | +| fetch-promise-chain.js:98:3:98:23 | fetch(" ... ssage") | semmle.label | fetch(" ... ssage") | +| fetch-promise-chain.js:98:3:99:38 | fetch(" ... json()) [PromiseValue] | semmle.label | fetch(" ... json()) [PromiseValue] | +| fetch-promise-chain.js:99:11:99:18 | response | semmle.label | response | +| fetch-promise-chain.js:99:23:99:30 | response | semmle.label | response | +| fetch-promise-chain.js:99:23:99:37 | response.json() | semmle.label | response.json() | +| fetch-promise-chain.js:100:11:100:14 | data | semmle.label | data | +| fetch-promise-chain.js:101:13:101:19 | payload | semmle.label | payload | +| fetch-promise-chain.js:101:23:101:26 | data | semmle.label | data | +| fetch-promise-chain.js:102:33:102:39 | payload | semmle.label | payload | +| fetch-promise-chain.js:102:33:102:47 | payload.message | semmle.label | payload.message | | interceptors.js:7:6:7:13 | response | semmle.label | response | | interceptors.js:8:15:8:31 | userGeneratedHtml | semmle.label | userGeneratedHtml | | interceptors.js:8:35:8:42 | response | semmle.label | response | | interceptors.js:9:56:9:72 | userGeneratedHtml | semmle.label | userGeneratedHtml | +| non-fetch-promise-chain.js:3:3:3:35 | rp("htt ... ssage") | semmle.label | rp("htt ... ssage") | +| non-fetch-promise-chain.js:4:11:4:14 | body | semmle.label | body | +| non-fetch-promise-chain.js:5:33:5:36 | body | semmle.label | body | +| non-fetch-promise-chain.js:11:3:11:56 | rp({ ur ... true }) | semmle.label | rp({ ur ... true }) | +| non-fetch-promise-chain.js:12:11:12:14 | data | semmle.label | data | +| non-fetch-promise-chain.js:13:33:13:36 | data | semmle.label | data | +| non-fetch-promise-chain.js:13:33:13:44 | data.message | semmle.label | data.message | +| non-fetch-promise-chain.js:19:9:19:15 | request | semmle.label | request | +| non-fetch-promise-chain.js:19:19:19:58 | axios.g ... ssage") | semmle.label | axios.g ... ssage") | +| non-fetch-promise-chain.js:20:3:20:9 | request | semmle.label | request | +| non-fetch-promise-chain.js:20:16:20:23 | response | semmle.label | response | +| non-fetch-promise-chain.js:21:31:21:38 | response | semmle.label | response | +| non-fetch-promise-chain.js:21:31:21:51 | respons ... message | semmle.label | respons ... message | +| non-fetch-promise-chain.js:27:3:27:46 | needle( ... ssage") | semmle.label | needle( ... ssage") | +| non-fetch-promise-chain.js:28:11:28:18 | response | semmle.label | response | +| non-fetch-promise-chain.js:29:33:29:40 | response | semmle.label | response | +| non-fetch-promise-chain.js:29:33:29:53 | respons ... message | semmle.label | respons ... message | +| non-fetch-promise-chain.js:35:3:35:47 | superag ... ssage") | semmle.label | superag ... ssage") | +| non-fetch-promise-chain.js:36:11:36:18 | response | semmle.label | response | +| non-fetch-promise-chain.js:37:33:37:40 | response | semmle.label | response | +| non-fetch-promise-chain.js:37:33:37:45 | response.text | semmle.label | response.text | | test.jsx:5:11:5:18 | response | semmle.label | response | | test.jsx:5:22:5:63 | await f ... ntent") | semmle.label | await f ... ntent") | | test.jsx:5:28:5:63 | fetch(" ... ntent") | semmle.label | fetch(" ... ntent") | @@ -197,3 +446,4 @@ nodes | testUseQueries.vue:18:22:18:36 | results[0].data | semmle.label | results[0].data | | testUseQueries.vue:25:10:25:23 | v-html=data2 | semmle.label | v-html=data2 | subpaths +| fetch-promise-chain.js:62:3:63:38 | fetch(" ... json()) [PromiseValue] | fetch-promise-chain.js:64:11:64:14 | data | fetch-promise-chain.js:64:19:64:28 | data.items | fetch-promise-chain.js:62:3:64:29 | fetch(" ... .items) [PromiseValue] | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/fetch-promise-chain.js b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/fetch-promise-chain.js new file mode 100644 index 000000000000..ee6f6731f136 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/fetch-promise-chain.js @@ -0,0 +1,145 @@ +function insertMessageRows(pageSize, continuationToken) { + let url = "?handler=LoadMessageLogs&pageSize=" + pageSize; + if (continuationToken) { + url += "&continuationToken=" + encodeURIComponent(continuationToken); + } + + fetch(url) // $ Source[js/xss] + .then(response => response.json()) + .then(data => { + const tbody = document.querySelector("#tblMessageLogs tbody"); + tbody.innerHTML = ""; + + data.items.forEach(item => { + const link = `View message`; + const row = ` + ${item.createdDate} + ${item.messageId} + ${item.target ?? ""} + ${link} + `; + tbody.insertAdjacentHTML("beforeend", row); // $ Alert[js/xss] + }); + }); +} + +function insertPlainTextResponse() { + fetch("/api/message") // $ Source[js/xss] + .then(response => response.text()) + .then(text => { + document.body.innerHTML = text; // $ Alert[js/xss] + }); +} + +function assignTextContent() { + fetch("/api/message") + .then(response => response.json()) + .then(data => { + document.body.textContent = data.message; + }); +} + +function insertAliasedFetchResponse() { + const request = fetch("/api/message"); // $ Source[js/xss] + request + .then(response => response.json()) + .then(data => { + document.body.innerHTML = data.message; // $ Alert[js/xss] + }); +} + +function insertReassignedFetchResponse() { + let request; + request = fetch("/api/message"); // $ Source[js/xss] + request + .then(response => response.text()) + .then(text => { + document.body.innerHTML = text; // $ Alert[js/xss] + }); +} + +function insertMessageAfterMultipleThenHops() { + fetch("/api/message") // $ Source[js/xss] + .then(response => response.json()) + .then(data => data.items) + .then(items => { + items.forEach(item => { + document.body.insertAdjacentHTML("beforeend", item.message); // $ Alert[js/xss] + }); + }); +} + +function insertDestructuredMessage() { + fetch("/api/message") // $ Source[js/xss] + .then(response => response.json()) + .then(({ message }) => { + document.body.innerHTML = message; // $ Alert[js/xss] + }); +} + +function insertMessageFromAsyncThenCallback() { + fetch("/api/message") // $ Source[js/xss] + .then(async response => await response.json()) + .then(data => { + document.body.innerHTML = data.message; // $ Alert[js/xss] + }); +} + +function insertPromiseAllMessage() { + Promise.all([ + fetch("/api/message") // $ Source[js/xss] + .then(response => response.json()) + ]).then(([data]) => { + document.body.innerHTML = data.message; // $ Alert[js/xss] + }); +} + +function insertAliasedDataMessage() { + fetch("/api/message") // $ Source[js/xss] + .then(response => response.json()) + .then(data => { + const payload = data; + document.body.innerHTML = payload.message; // $ Alert[js/xss] + }); +} + +function insertSanitizedHtml() { + fetch("/api/message") + .then(response => response.text()) + .then(text => { + document.body.innerHTML = DOMPurify.sanitize(text); + }); +} + +function assignInputValue() { + fetch("/api/message") + .then(response => response.text()) + .then(text => { + document.querySelector("input").value = text; + }); +} + +function assignSafeAttributes() { + fetch("/api/message") + .then(response => response.text()) + .then(text => { + const element = document.querySelector("div"); + element.setAttribute("title", text); + element.setAttribute("aria-label", text); + }); +} + +function catchDoesNotInventResponseValue() { + fetch("/api/message") + .catch(error => { + document.body.innerHTML = error.message; + }); +} + +function finallyDoesNotInventResponseValue() { + let text = ""; + fetch("/api/message") + .finally(() => { + document.body.innerHTML = text; + }); +} diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/non-fetch-promise-chain.js b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/non-fetch-promise-chain.js new file mode 100644 index 000000000000..2996c9012fa8 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/non-fetch-promise-chain.js @@ -0,0 +1,47 @@ +function insertRequestPromiseBody() { + const rp = require("request-promise-native"); + rp("https://example.com/message") // $ Source[js/xss] + .then(body => { + document.body.innerHTML = body; // $ Alert[js/xss] + }); +} + +function insertRequestPromiseJsonBody() { + const rp = require("request-promise"); + rp({ uri: "https://example.com/message", json: true }) // $ Source[js/xss] + .then(data => { + document.body.innerHTML = data.message; // $ Alert[js/xss] + }); +} + +function insertAxiosResponseData() { + const axios = require("axios"); + const request = axios.get("https://example.com/message"); // $ Source[js/xss] + request.then(response => { + document.body.innerHTML = response.data.message; // $ Alert[js/xss] + }); +} + +function insertNeedleResponseBody() { + const needle = require("needle"); + needle("get", "https://example.com/message") // $ Source[js/xss] + .then(response => { + document.body.innerHTML = response.body.message; // $ Alert[js/xss] + }); +} + +function insertSuperagentResponseText() { + const superagent = require("superagent"); + superagent.get("https://example.com/message") // $ Source[js/xss] + .then(response => { + document.body.innerHTML = response.text; // $ Alert[js/xss] + }); +} + +function assignAxiosResponseToInputValue() { + const axios = require("axios"); + axios.get("https://example.com/message") + .then(response => { + document.querySelector("input").value = response.data.message; + }); +} From 10f3d909ffd042f452fb42b2f169ef54f67f7de8 Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 3 Aug 2026 10:37:20 +0200 Subject: [PATCH 174/188] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../frameworks/data/internal/ApiGraphModelsSpecific.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModelsSpecific.qll b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModelsSpecific.qll index 837aa6463b35..6fc718317a99 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModelsSpecific.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModelsSpecific.qll @@ -164,7 +164,7 @@ private class RawFilePathEntryPoint extends API::EntryPoint { } /** - * Gets an API node referring to the given global variable (if relevant). + * Gets an API node referring to the given file path (if relevant). */ private API::Node getRawFilePathNode(string rawFilePathNode) { result = any(RawFilePathEntryPoint e | e.getPath() = rawFilePathNode).getANode() From 2484a7bed17fd67f7a42ddd7bce0fad729e9392c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 3 Aug 2026 12:58:42 +0000 Subject: [PATCH 175/188] Add qltest for implicit return steps in Ruby dataflow Documents existing behavior for implicit returns (no return keyword) from: - method body with ensure present - rescue clause (with and without ensure) - else clause (with and without ensure) The test shows that only simple body returns currently work; all other cases are marked MISSING to document the known gaps. --- .../implicit-return/implicit-return.expected | 10 +++ .../implicit-return/implicit-return.ql | 12 ++++ .../implicit-return/implicit_return.rb | 68 +++++++++++++++++++ 3 files changed, 90 insertions(+) create mode 100644 ruby/ql/test/library-tests/dataflow/implicit-return/implicit-return.expected create mode 100644 ruby/ql/test/library-tests/dataflow/implicit-return/implicit-return.ql create mode 100644 ruby/ql/test/library-tests/dataflow/implicit-return/implicit_return.rb diff --git a/ruby/ql/test/library-tests/dataflow/implicit-return/implicit-return.expected b/ruby/ql/test/library-tests/dataflow/implicit-return/implicit-return.expected new file mode 100644 index 000000000000..979cc77777b7 --- /dev/null +++ b/ruby/ql/test/library-tests/dataflow/implicit-return/implicit-return.expected @@ -0,0 +1,10 @@ +models +edges +| implicit_return.rb:12:3:12:11 | call to source | implicit_return.rb:15:6:15:11 | call to m_body | provenance | | +nodes +| implicit_return.rb:12:3:12:11 | call to source | semmle.label | call to source | +| implicit_return.rb:15:6:15:11 | call to m_body | semmle.label | call to m_body | +subpaths +testFailures +#select +| implicit_return.rb:15:6:15:11 | call to m_body | implicit_return.rb:12:3:12:11 | call to source | implicit_return.rb:15:6:15:11 | call to m_body | $@ | implicit_return.rb:12:3:12:11 | call to source | call to source | diff --git a/ruby/ql/test/library-tests/dataflow/implicit-return/implicit-return.ql b/ruby/ql/test/library-tests/dataflow/implicit-return/implicit-return.ql new file mode 100644 index 000000000000..fae4b68cda0e --- /dev/null +++ b/ruby/ql/test/library-tests/dataflow/implicit-return/implicit-return.ql @@ -0,0 +1,12 @@ +/** + * @kind path-problem + */ + +import codeql.ruby.AST +import utils.test.InlineFlowTest +import DefaultFlowTest +import ValueFlow::PathGraph + +from ValueFlow::PathNode source, ValueFlow::PathNode sink +where ValueFlow::flowPath(source, sink) +select sink, source, sink, "$@", source, source.toString() diff --git a/ruby/ql/test/library-tests/dataflow/implicit-return/implicit_return.rb b/ruby/ql/test/library-tests/dataflow/implicit-return/implicit_return.rb new file mode 100644 index 000000000000..4cf010ddcf9c --- /dev/null +++ b/ruby/ql/test/library-tests/dataflow/implicit-return/implicit_return.rb @@ -0,0 +1,68 @@ +# Tests for implicit return steps in Ruby data flow. +# +# An implicit return is when no `return` statement is used; instead the +# last evaluated expression is returned. +# +# The following cases test the behaviour when the returned value is +# in the main body, a `rescue` clause, or an `else` clause, +# with and without an `ensure` clause present. + +# Simple implicit return from the method body. +def m_body + source(1) +end + +sink(m_body) # $ hasValueFlow=1 + +# Implicit return from the method body when an `ensure` clause is present. +def m_body_ensure + source(2) +ensure + nil +end + +sink(m_body_ensure) # $ MISSING: hasValueFlow=2 + +# Implicit return from a `rescue` clause. +def m_rescue + raise "error" +rescue + source(3) +end + +sink(m_rescue) # $ MISSING: hasValueFlow=3 + +# Implicit return from a `rescue` clause when an `ensure` clause is present. +def m_rescue_ensure + raise "error" +rescue + source(4) +ensure + nil +end + +sink(m_rescue_ensure) # $ MISSING: hasValueFlow=4 + +# Implicit return from an `else` clause. +def m_else + # nothing raises +rescue + nil +else + source(5) +end + +sink(m_else) # $ MISSING: hasValueFlow=5 + +# Implicit return from an `else` clause when an `ensure` clause is present. +def m_else_ensure + # nothing raises +rescue + nil +else + source(6) +ensure + nil +end + +sink(m_else_ensure) # $ MISSING: hasValueFlow=6 From b4536300ab3ff1524937fdf5bb31d446a2c731ae Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 3 Aug 2026 15:18:59 +0200 Subject: [PATCH 176/188] JS: Fix confusing qldoc --- .../frameworks/data/internal/ApiGraphModelsSpecific.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModelsSpecific.qll b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModelsSpecific.qll index 6fc718317a99..3db8fa1b4364 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModelsSpecific.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModelsSpecific.qll @@ -159,7 +159,7 @@ private class RawFilePathEntryPoint extends API::EntryPoint { ) } - /** Gets the name of the path variable. */ + /** Gets the file path being referenced. */ string getPath() { result = path } } From 7a7dae0a84b47e47819ebb4d0b4c8680cc74c4b3 Mon Sep 17 00:00:00 2001 From: JarLob Date: Mon, 3 Aug 2026 21:56:25 +0300 Subject: [PATCH 177/188] Actions: Remove experimental self-hosted runner query Runner labels cannot reliably distinguish self-hosted runners from managed runners. Deprecate the supporting SelfHostedQuery library module. --- .../query-suite/not_included_in_qls.expected | 1 - .../2026-08-03-deprecate-self-hosted-query.md | 4 + .../actions/security/SelfHostedQuery.qll | 5 + .../CodeExecutionOnSelfHostedRunner.ql | 19 ---- .../CWE-284/.github/workflows/test1.yml | 94 ------------------- .../CWE-284/.github/workflows/test2.yml | 26 ----- .../CWE-284/.github/workflows/test3.yml | 43 --------- .../CodeExecutionOnSelfHostedRunner.expected | 8 -- .../CodeExecutionOnSelfHostedRunner.qlref | 2 - 9 files changed, 9 insertions(+), 193 deletions(-) create mode 100644 actions/ql/lib/change-notes/2026-08-03-deprecate-self-hosted-query.md delete mode 100644 actions/ql/src/experimental/Security/CWE-284/CodeExecutionOnSelfHostedRunner.ql delete mode 100644 actions/ql/test/query-tests/Security/CWE-284/.github/workflows/test1.yml delete mode 100644 actions/ql/test/query-tests/Security/CWE-284/.github/workflows/test2.yml delete mode 100644 actions/ql/test/query-tests/Security/CWE-284/.github/workflows/test3.yml delete mode 100644 actions/ql/test/query-tests/Security/CWE-284/CodeExecutionOnSelfHostedRunner.expected delete mode 100644 actions/ql/test/query-tests/Security/CWE-284/CodeExecutionOnSelfHostedRunner.qlref diff --git a/actions/ql/integration-tests/query-suite/not_included_in_qls.expected b/actions/ql/integration-tests/query-suite/not_included_in_qls.expected index 6ed0a557462b..da088b688131 100644 --- a/actions/ql/integration-tests/query-suite/not_included_in_qls.expected +++ b/actions/ql/integration-tests/query-suite/not_included_in_qls.expected @@ -11,7 +11,6 @@ ql/actions/ql/src/experimental/Security/CWE-078/CommandInjectionMedium.ql ql/actions/ql/src/experimental/Security/CWE-088/ArgumentInjectionCritical.ql ql/actions/ql/src/experimental/Security/CWE-088/ArgumentInjectionMedium.ql ql/actions/ql/src/experimental/Security/CWE-200/SecretExfiltration.ql -ql/actions/ql/src/experimental/Security/CWE-284/CodeExecutionOnSelfHostedRunner.ql ql/actions/ql/src/experimental/Security/CWE-829/ArtifactPoisoningPathTraversal.ql ql/actions/ql/src/experimental/Security/CWE-829/UnversionedImmutableAction.ql ql/actions/ql/src/experimental/Security/CWE-918/RequestForgery.ql diff --git a/actions/ql/lib/change-notes/2026-08-03-deprecate-self-hosted-query.md b/actions/ql/lib/change-notes/2026-08-03-deprecate-self-hosted-query.md new file mode 100644 index 000000000000..932a9e7ca49a --- /dev/null +++ b/actions/ql/lib/change-notes/2026-08-03-deprecate-self-hosted-query.md @@ -0,0 +1,4 @@ +--- +category: deprecated +--- +* The `codeql.actions.security.SelfHostedQuery` module has been deprecated because runner labels do not reliably distinguish self-hosted runners from managed runners. \ No newline at end of file diff --git a/actions/ql/lib/codeql/actions/security/SelfHostedQuery.qll b/actions/ql/lib/codeql/actions/security/SelfHostedQuery.qll index 3a65771c1745..b3f7bdaf24d3 100644 --- a/actions/ql/lib/codeql/actions/security/SelfHostedQuery.qll +++ b/actions/ql/lib/codeql/actions/security/SelfHostedQuery.qll @@ -1,3 +1,8 @@ +/** + * DEPRECATED: Runner labels do not reliably distinguish self-hosted runners from managed runners. + */ +deprecated module; + import actions bindingset[runner] diff --git a/actions/ql/src/experimental/Security/CWE-284/CodeExecutionOnSelfHostedRunner.ql b/actions/ql/src/experimental/Security/CWE-284/CodeExecutionOnSelfHostedRunner.ql deleted file mode 100644 index 9610302d1c2a..000000000000 --- a/actions/ql/src/experimental/Security/CWE-284/CodeExecutionOnSelfHostedRunner.ql +++ /dev/null @@ -1,19 +0,0 @@ -/** - * @name Pull Request code execution on self-hosted runner - * @description Running untrusted code on a public repository's self-hosted runner can lead to the compromise of the runner machine - * @kind problem - * @problem.severity error - * @security-severity 9.0 - * @precision high - * @id actions/pr-on-self-hosted-runner - * @tags actions - * security - * experimental - * external/cwe/cwe-284 - */ - -import codeql.actions.security.SelfHostedQuery - -from Job job -where staticallyIdentifiedSelfHostedRunner(job) or dynamicallyIdentifiedSelfHostedRunner(job) -select job, "Job runs on self-hosted runner" diff --git a/actions/ql/test/query-tests/Security/CWE-284/.github/workflows/test1.yml b/actions/ql/test/query-tests/Security/CWE-284/.github/workflows/test1.yml deleted file mode 100644 index 37eb2bddb58c..000000000000 --- a/actions/ql/test/query-tests/Security/CWE-284/.github/workflows/test1.yml +++ /dev/null @@ -1,94 +0,0 @@ -name: test - -on: - pull_request: - -jobs: - test1: - runs-on: [self-hosted, X64, Linux, 16c32g] - steps: - - run: cmd - test2: - runs-on: - group: my-group - labels: [self-hosted, label-1] - steps: - - run: cmd - test3: - runs-on: - - 'self-hosted' - - 'linux' - - 'x64' - - 'metal' - steps: - - run: echo "foo" - test4: - runs-on: self-hosted-azure - steps: - - run: cmd - test5: - strategy: - fail-fast: false - matrix: - platform: - - name: Linux - os: ubuntu-latest - shell: bash - - name: macOS - os: macos-latest - shell: bash - - name: Windows - os: windows-latest - shell: cmd - node-version: - - 16.14.0 - - 16.x - - 18.0.0 - - 18.x - - 20.x - runs-on: ${{ matrix.platform.os }} - steps: - - run: cmd - test6: - strategy: - matrix: - os: [ubuntu-latest, macos-latest] - runs-on: ${{ matrix.os }} - steps: - - run: cmd - test7: - strategy: - matrix: - os: [self-hosted, ubuntu-latest] - runs-on: ${{ matrix.os }} - steps: - - run: cmd - test8: - strategy: - matrix: - settings: - - host: - - 'self-hosted' - - 'macos' - - 'arm64' - target: 'x86_64-apple-darwin' - runs-on: ${{ matrix.settings.host }} - steps: - - run: cmd - test9: - strategy: - matrix: - os: ${{ github.repository }} - runs-on: ${{ matrix.os }} - steps: - - run: cmd - test10: - strategy: - matrix: - os: ${{ github.repository }} - foo: - - bar: ${{ github.repository }} - baz: "asdf" - runs-on: ${{ matrix.foo.bar }} - steps: - - run: cmd diff --git a/actions/ql/test/query-tests/Security/CWE-284/.github/workflows/test2.yml b/actions/ql/test/query-tests/Security/CWE-284/.github/workflows/test2.yml deleted file mode 100644 index 243bac925994..000000000000 --- a/actions/ql/test/query-tests/Security/CWE-284/.github/workflows/test2.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: test - -on: - push: - -jobs: - test1: - runs-on: [self-hosted, foo] - steps: - - run: cmd - test2: - runs-on: - group: my-group - labels: [self-hosted, foo] - steps: - - run: cmd - test3: - runs-on: - - 'self-hosted' - - 'foo' - steps: - - run: cmd - test4: - runs-on: self-hosted-azure - steps: - - run: cmd diff --git a/actions/ql/test/query-tests/Security/CWE-284/.github/workflows/test3.yml b/actions/ql/test/query-tests/Security/CWE-284/.github/workflows/test3.yml deleted file mode 100644 index b1fe9fa0caa6..000000000000 --- a/actions/ql/test/query-tests/Security/CWE-284/.github/workflows/test3.yml +++ /dev/null @@ -1,43 +0,0 @@ -name: test - -on: - pull_request: - -jobs: - test: - strategy: - fail-fast: false - matrix: - os: - - ubuntu-latest - - ubuntu-24.04 - - ubuntu-24.04-arm - - ubuntu-22.04 - - ubuntu-22.04-arm - - ubuntu-26.04 - - ubuntu-26.04-arm - - ubuntu-slim - - macos-26 - - macos-26-xlarge - - macos-26-intel - - macos-26-large - - macos-latest-large - - macos-15-large - - macos-15 - - macos-15-intel - - macos-latest - - macos-15 - - macos-15-xlarge - - macos-14-large - - macos-14 - - macos-14-xlarge - - windows-2025-vs2026 - - windows-latest - - windows-2025 - - windows-2022 - - windows-11 - - windows-11-arm - - windows-11-vs2026-arm - runs-on: ${{ matrix.os }} - steps: - - run: cmd diff --git a/actions/ql/test/query-tests/Security/CWE-284/CodeExecutionOnSelfHostedRunner.expected b/actions/ql/test/query-tests/Security/CWE-284/CodeExecutionOnSelfHostedRunner.expected deleted file mode 100644 index 306bed9baec1..000000000000 --- a/actions/ql/test/query-tests/Security/CWE-284/CodeExecutionOnSelfHostedRunner.expected +++ /dev/null @@ -1,8 +0,0 @@ -| .github/workflows/test1.yml:8:5:11:2 | Job: test1 | Job runs on self-hosted runner | -| .github/workflows/test1.yml:12:5:17:2 | Job: test2 | Job runs on self-hosted runner | -| .github/workflows/test1.yml:18:5:25:2 | Job: test3 | Job runs on self-hosted runner | -| .github/workflows/test1.yml:26:5:29:2 | Job: test4 | Job runs on self-hosted runner | -| .github/workflows/test1.yml:60:5:66:2 | Job: test7 | Job runs on self-hosted runner | -| .github/workflows/test1.yml:67:5:78:2 | Job: test8 | Job runs on self-hosted runner | -| .github/workflows/test1.yml:79:5:85:2 | Job: test9 | Job runs on self-hosted runner | -| .github/workflows/test1.yml:86:5:94:15 | Job: test10 | Job runs on self-hosted runner | diff --git a/actions/ql/test/query-tests/Security/CWE-284/CodeExecutionOnSelfHostedRunner.qlref b/actions/ql/test/query-tests/Security/CWE-284/CodeExecutionOnSelfHostedRunner.qlref deleted file mode 100644 index dc99068b3035..000000000000 --- a/actions/ql/test/query-tests/Security/CWE-284/CodeExecutionOnSelfHostedRunner.qlref +++ /dev/null @@ -1,2 +0,0 @@ -experimental/Security/CWE-284/CodeExecutionOnSelfHostedRunner.ql - From 92515166fceb89436363e7d75d8b8e40717cf838 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Tue, 4 Aug 2026 08:54:25 +0200 Subject: [PATCH 178/188] Apply batched suggestions from code review Co-authored-by: Anders Schack-Mulligen --- .../dataflow/implicit-return/implicit_return.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ruby/ql/test/library-tests/dataflow/implicit-return/implicit_return.rb b/ruby/ql/test/library-tests/dataflow/implicit-return/implicit_return.rb index 4cf010ddcf9c..2ea215902f02 100644 --- a/ruby/ql/test/library-tests/dataflow/implicit-return/implicit_return.rb +++ b/ruby/ql/test/library-tests/dataflow/implicit-return/implicit_return.rb @@ -18,7 +18,7 @@ def m_body def m_body_ensure source(2) ensure - nil + source(20) end sink(m_body_ensure) # $ MISSING: hasValueFlow=2 @@ -38,14 +38,14 @@ def m_rescue_ensure rescue source(4) ensure - nil + source(40) end sink(m_rescue_ensure) # $ MISSING: hasValueFlow=4 # Implicit return from an `else` clause. def m_else - # nothing raises + source(50) rescue nil else @@ -56,7 +56,7 @@ def m_else # Implicit return from an `else` clause when an `ensure` clause is present. def m_else_ensure - # nothing raises + source(60) rescue nil else From 369cd160ef536da6bb753ff118c7c61976cb5cff Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Tue, 4 Aug 2026 16:18:33 +0200 Subject: [PATCH 179/188] CODEOWNERS: make language coverage team responsible for more Rust and C++ code --- CODEOWNERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CODEOWNERS b/CODEOWNERS index 9cbda8244467..0c09972f903c 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -24,8 +24,14 @@ /rust/ @github/codeql-rust /rust/extractor/ @github/codeql-rust @github/code-scanning-language-coverage /shared/ @github/codeql-shared-libraries-reviewers +/shared/cpp @github/code-scanning-language-coverage +/shared/yeast @github/code-scanning-language-coverage +/shared/yeast-macros @github/code-scanning-language-coverage +/shared/yeast-schema @github/code-scanning-language-coverage /swift/ @github/codeql-swift /swift/extractor/ @github/codeql-swift @github/code-scanning-language-coverage +/unified/extractor @github/code-scanning-language-coverage +/unified/swift-syntax-rs @github/code-scanning-language-coverage /misc/codegen/ @github/codeql-swift /java/kotlin-extractor/ @github/codeql-kotlin @github/code-scanning-language-coverage /java/ql/test-kotlin1/ @github/codeql-kotlin From 9292c219611f60a84d399cca210b068722fae684 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Tue, 4 Aug 2026 16:40:10 +0200 Subject: [PATCH 180/188] CODEOWNERS: Add missing `/` --- CODEOWNERS | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 0c09972f903c..bceaafdbc07c 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -24,14 +24,14 @@ /rust/ @github/codeql-rust /rust/extractor/ @github/codeql-rust @github/code-scanning-language-coverage /shared/ @github/codeql-shared-libraries-reviewers -/shared/cpp @github/code-scanning-language-coverage -/shared/yeast @github/code-scanning-language-coverage -/shared/yeast-macros @github/code-scanning-language-coverage -/shared/yeast-schema @github/code-scanning-language-coverage +/shared/cpp/ @github/code-scanning-language-coverage +/shared/yeast/ @github/code-scanning-language-coverage +/shared/yeast-macros/ @github/code-scanning-language-coverage +/shared/yeast-schema/ @github/code-scanning-language-coverage /swift/ @github/codeql-swift /swift/extractor/ @github/codeql-swift @github/code-scanning-language-coverage -/unified/extractor @github/code-scanning-language-coverage -/unified/swift-syntax-rs @github/code-scanning-language-coverage +/unified/extractor/ @github/code-scanning-language-coverage +/unified/swift-syntax-rs/ @github/code-scanning-language-coverage /misc/codegen/ @github/codeql-swift /java/kotlin-extractor/ @github/codeql-kotlin @github/code-scanning-language-coverage /java/ql/test-kotlin1/ @github/codeql-kotlin From 22c5ab2c265064cbf9b60069908bf8a2a77b5c83 Mon Sep 17 00:00:00 2001 From: JarLob Date: Tue, 4 Aug 2026 23:34:52 +0300 Subject: [PATCH 181/188] Remove SelfHostedQuery completely --- .../2026-08-03-deprecate-self-hosted-query.md | 4 -- ...-08-04-remove-self-hosted-query-library.md | 4 ++ .../actions/security/SelfHostedQuery.qll | 52 ------------------- 3 files changed, 4 insertions(+), 56 deletions(-) delete mode 100644 actions/ql/lib/change-notes/2026-08-03-deprecate-self-hosted-query.md create mode 100644 actions/ql/lib/change-notes/2026-08-04-remove-self-hosted-query-library.md delete mode 100644 actions/ql/lib/codeql/actions/security/SelfHostedQuery.qll diff --git a/actions/ql/lib/change-notes/2026-08-03-deprecate-self-hosted-query.md b/actions/ql/lib/change-notes/2026-08-03-deprecate-self-hosted-query.md deleted file mode 100644 index 932a9e7ca49a..000000000000 --- a/actions/ql/lib/change-notes/2026-08-03-deprecate-self-hosted-query.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: deprecated ---- -* The `codeql.actions.security.SelfHostedQuery` module has been deprecated because runner labels do not reliably distinguish self-hosted runners from managed runners. \ No newline at end of file diff --git a/actions/ql/lib/change-notes/2026-08-04-remove-self-hosted-query-library.md b/actions/ql/lib/change-notes/2026-08-04-remove-self-hosted-query-library.md new file mode 100644 index 000000000000..562b519e001a --- /dev/null +++ b/actions/ql/lib/change-notes/2026-08-04-remove-self-hosted-query-library.md @@ -0,0 +1,4 @@ +--- +category: breaking +--- +* The `codeql.actions.security.SelfHostedQuery` module has been removed because runner labels do not reliably distinguish self-hosted runners from managed runners. diff --git a/actions/ql/lib/codeql/actions/security/SelfHostedQuery.qll b/actions/ql/lib/codeql/actions/security/SelfHostedQuery.qll deleted file mode 100644 index b3f7bdaf24d3..000000000000 --- a/actions/ql/lib/codeql/actions/security/SelfHostedQuery.qll +++ /dev/null @@ -1,52 +0,0 @@ -/** - * DEPRECATED: Runner labels do not reliably distinguish self-hosted runners from managed runners. - */ -deprecated module; - -import actions - -bindingset[runner] -predicate isGithubHostedRunner(string runner) { - // The list of github hosted repos: - // https://github.com/actions/runner-images/blob/main/README.md#available-images - // https://docs.github.com/en/enterprise-cloud@latest/actions/how-tos/write-workflows/choose-where-workflows-run/choose-the-runner-for-a-job#standard-github-hosted-runners-for-public-repositories - runner.toLowerCase().regexpMatch("^ubuntu-([0-9.]+|latest|slim)(-arm)?$") or - runner.toLowerCase().regexpMatch("^macos-([0-9]+|latest)(-x?large|-intel)?$") or - runner.toLowerCase().regexpMatch("^windows-([0-9.]+|latest)(-vs[0-9.]+)?(-arm)?$") -} - -bindingset[runner] -predicate is3rdPartyHostedRunner(string runner) { - runner.toLowerCase().regexpMatch("^(buildjet|warp)-[a-z0-9-]+$") -} - -/** - * This predicate uses data available in the workflow file to identify self-hosted runners. - * It does not know if the repository is public or private. - * It is a best-effort approach to identify self-hosted runners. - */ -predicate staticallyIdentifiedSelfHostedRunner(Job job) { - exists(string label | - job.getATriggerEvent().getName() = - [ - "issue_comment", "pull_request", "pull_request_review", "pull_request_review_comment", - "pull_request_target", "workflow_run" - ] and - label = job.getARunsOnLabel() and - not isGithubHostedRunner(label) and - not is3rdPartyHostedRunner(label) - ) -} - -/** - * This predicate uses data available in the job log files to identify self-hosted runners. - * It is a best-effort approach to identify self-hosted runners. - */ -predicate dynamicallyIdentifiedSelfHostedRunner(Job job) { - exists(string runner_info | - repositoryDataModel("public", _) and - workflowDataModel(job.getEnclosingWorkflow().getLocation().getFile().getRelativePath(), _, - job.getId(), _, _, runner_info) and - runner_info.indexOf("self-hosted:true") > 0 - ) -} From 50555f4c4379aa0b4dca5137b7edd66724a51e07 Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 5 Aug 2026 09:56:39 +0200 Subject: [PATCH 182/188] JS: Update supported TypeScript language version Even though we're not using the new Go-based TypeScript compiler under the hood, we can still handle TypeScript 7.0 codebases, so bumping to that version. --- docs/codeql/reusables/supported-versions-compilers.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/codeql/reusables/supported-versions-compilers.rst b/docs/codeql/reusables/supported-versions-compilers.rst index 69def9ffeb19..881b8aef448a 100644 --- a/docs/codeql/reusables/supported-versions-compilers.rst +++ b/docs/codeql/reusables/supported-versions-compilers.rst @@ -27,7 +27,7 @@ Ruby [10]_,"up to 3.3",Not applicable,"``.rb``, ``.erb``, ``.gemspec``, ``Gemfile``" Rust [11]_,"Rust editions 2021 and 2024","Rust compiler","``.rs``, ``Cargo.toml``" Swift [12]_ [13]_,"Swift 5.4-6.3","Swift compiler","``.swift``" - TypeScript [14]_,"2.6-5.9",Standard TypeScript compiler,"``.ts``, ``.tsx``, ``.mts``, ``.cts``" + TypeScript [14]_,"2.6-7.0",Standard TypeScript compiler,"``.ts``, ``.tsx``, ``.mts``, ``.cts``" .. container:: footnote-group From ab2d6f762ecf26de1b556eb5d836f51a4c2063bc Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Wed, 5 Aug 2026 10:44:30 +0200 Subject: [PATCH 183/188] Ruby: Exclude vendored library parameters from taint sources. --- ruby/ql/lib/codeql/ruby/frameworks/core/Gem.qll | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/core/Gem.qll b/ruby/ql/lib/codeql/ruby/frameworks/core/Gem.qll index f0e5725eef0d..5a7c65f3d88f 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/core/Gem.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/core/Gem.qll @@ -90,6 +90,9 @@ module Gem { result = this.getAPublicModule().getStmt(_).(SingletonClass) } + /** Holds if this gem is vendored in this codebase. */ + predicate isVendored() { File.super.getParentContainer+().getBaseName() = "vendor" } + /** Gets a parameter from an exported method, which is an input to this gem. */ DataFlow::ParameterNode getAnInputParameter() { exists(MethodBase method | @@ -107,6 +110,7 @@ module Gem { DataFlow::ParameterNode getALibraryInput() { exists(GemSpec spec | exists(spec.getName()) and // we only consider `.gemspec` files that have a name + not spec.isVendored() and // if the gem is vendored its parameters are not external inputs result = spec.getAnInputParameter() ) } From 1430dfe4b91ca386063049bd292040a784d3b357 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Wed, 5 Aug 2026 10:58:26 +0200 Subject: [PATCH 184/188] Ruby: Add change note. --- ruby/ql/lib/change-notes/2026-08-05-vendored-lib-taint.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 ruby/ql/lib/change-notes/2026-08-05-vendored-lib-taint.md diff --git a/ruby/ql/lib/change-notes/2026-08-05-vendored-lib-taint.md b/ruby/ql/lib/change-notes/2026-08-05-vendored-lib-taint.md new file mode 100644 index 000000000000..e5eab2447c30 --- /dev/null +++ b/ruby/ql/lib/change-notes/2026-08-05-vendored-lib-taint.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Removed library input to vendored gems from the set of taint sources. This should reduce false positives for `rb/polynomial-redos`, `rb/regex/badly-anchored-regexp`, `rb/unsafe-code-construction`, `rb/html-constructed-from-input`, and `rb/shell-command-constructed-from-input` whenever vendoring is used. From 6bfc70500d527038f35ff96fb7c0bdba96d3f06a Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Wed, 5 Aug 2026 11:31:31 +0200 Subject: [PATCH 185/188] Python: Update doc to refect that we support Python 3.14 --- docs/codeql/reusables/supported-versions-compilers.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/codeql/reusables/supported-versions-compilers.rst b/docs/codeql/reusables/supported-versions-compilers.rst index 881b8aef448a..15b21cc94b04 100644 --- a/docs/codeql/reusables/supported-versions-compilers.rst +++ b/docs/codeql/reusables/supported-versions-compilers.rst @@ -23,7 +23,7 @@ Eclipse compiler for Java (ECJ) [7]_",``.java`` Kotlin,"Kotlin 1.8.0 to 2.4.1\ *x*","kotlinc",``.kt`` JavaScript,ECMAScript 2022 or lower,Not applicable,"``.js``, ``.jsx``, ``.mjs``, ``.es``, ``.es6``, ``.htm``, ``.html``, ``.xhtm``, ``.xhtml``, ``.vue``, ``.hbs``, ``.ejs``, ``.njk``, ``.json``, ``.yaml``, ``.yml``, ``.raml``, ``.xml`` [8]_" - Python [9]_,"2.7, 3.5, 3.6, 3.7, 3.8, 3.9, 3.10, 3.11, 3.12, 3.13",Not applicable,``.py`` + Python [9]_,"2.7, 3.5, 3.6, 3.7, 3.8, 3.9, 3.10, 3.11, 3.12, 3.13, 3.14",Not applicable,``.py`` Ruby [10]_,"up to 3.3",Not applicable,"``.rb``, ``.erb``, ``.gemspec``, ``Gemfile``" Rust [11]_,"Rust editions 2021 and 2024","Rust compiler","``.rs``, ``Cargo.toml``" Swift [12]_ [13]_,"Swift 5.4-6.3","Swift compiler","``.swift``" From fae4a92773122bad91bde11242d67826ad69252b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 6 Aug 2026 10:37:58 +0000 Subject: [PATCH 186/188] Release preparation for version 2.26.3 --- actions/ql/lib/CHANGELOG.md | 10 ++++++++++ .../2026-07-27-merge-group-event-source.md | 4 ---- ...-08-04-remove-self-hosted-query-library.md | 4 ---- actions/ql/lib/change-notes/released/0.5.0.md | 9 +++++++++ actions/ql/lib/codeql-pack.release.yml | 2 +- actions/ql/lib/qlpack.yml | 2 +- actions/ql/src/CHANGELOG.md | 19 +++++++++++++++++++ .../2026-07-18-envvar-injection-precision.md | 4 ---- ...26-07-18-read-only-default-branch-cache.md | 4 ---- .../2026-07-28-checkout-provenance.md | 4 ---- .../2026-07-28-output-clobbering-regex.md | 4 ---- .../2026-07-28-schedule-event-mapping.md | 4 ---- ...26-07-29-output-clobbering-jq-precision.md | 4 ---- .../2026-07-29-output-clobbering-messages.md | 4 ---- ...-cache-poisoning-code-injection-wording.md | 4 ---- .../ql/src/change-notes/released/0.6.33.md | 18 ++++++++++++++++++ actions/ql/src/codeql-pack.release.yml | 2 +- actions/ql/src/qlpack.yml | 2 +- cpp/ql/lib/CHANGELOG.md | 6 ++++++ .../change-notes/2026-07-28-winreg-sources.md | 4 ---- cpp/ql/lib/change-notes/released/12.0.2.md | 5 +++++ cpp/ql/lib/codeql-pack.release.yml | 2 +- cpp/ql/lib/qlpack.yml | 2 +- cpp/ql/src/CHANGELOG.md | 4 ++++ cpp/ql/src/change-notes/released/1.8.1.md | 3 +++ cpp/ql/src/codeql-pack.release.yml | 2 +- cpp/ql/src/qlpack.yml | 2 +- .../ql/campaigns/Solorigate/lib/CHANGELOG.md | 4 ++++ .../lib/change-notes/released/1.7.72.md | 3 +++ .../Solorigate/lib/codeql-pack.release.yml | 2 +- csharp/ql/campaigns/Solorigate/lib/qlpack.yml | 2 +- .../ql/campaigns/Solorigate/src/CHANGELOG.md | 4 ++++ .../src/change-notes/released/1.7.72.md | 3 +++ .../Solorigate/src/codeql-pack.release.yml | 2 +- csharp/ql/campaigns/Solorigate/src/qlpack.yml | 2 +- csharp/ql/lib/CHANGELOG.md | 4 ++++ csharp/ql/lib/change-notes/released/7.1.2.md | 3 +++ csharp/ql/lib/codeql-pack.release.yml | 2 +- csharp/ql/lib/qlpack.yml | 2 +- csharp/ql/src/CHANGELOG.md | 4 ++++ csharp/ql/src/change-notes/released/1.9.1.md | 3 +++ csharp/ql/src/codeql-pack.release.yml | 2 +- csharp/ql/src/qlpack.yml | 2 +- go/ql/consistency-queries/CHANGELOG.md | 4 ++++ .../change-notes/released/1.0.55.md | 3 +++ .../codeql-pack.release.yml | 2 +- go/ql/consistency-queries/qlpack.yml | 2 +- go/ql/lib/CHANGELOG.md | 4 ++++ go/ql/lib/change-notes/released/7.2.3.md | 3 +++ go/ql/lib/codeql-pack.release.yml | 2 +- go/ql/lib/qlpack.yml | 2 +- go/ql/src/CHANGELOG.md | 4 ++++ go/ql/src/change-notes/released/1.6.8.md | 3 +++ go/ql/src/codeql-pack.release.yml | 2 +- go/ql/src/qlpack.yml | 2 +- java/ql/lib/CHANGELOG.md | 4 ++++ java/ql/lib/change-notes/released/9.2.3.md | 3 +++ java/ql/lib/codeql-pack.release.yml | 2 +- java/ql/lib/qlpack.yml | 2 +- java/ql/src/CHANGELOG.md | 4 ++++ java/ql/src/change-notes/released/1.11.8.md | 3 +++ java/ql/src/codeql-pack.release.yml | 2 +- java/ql/src/qlpack.yml | 2 +- javascript/ql/lib/CHANGELOG.md | 15 +++++++++++++++ .../2026-07-07-sails-action2-inputs.md | 4 ---- .../2026-07-16-vue-router-useRoute-query.md | 5 ----- .../2026-07-31-file-scoped-models.md | 6 ------ ...2026-08-01-client-response-promise-data.md | 4 ---- .../ql/lib/change-notes/released/2.9.0.md | 14 ++++++++++++++ javascript/ql/lib/codeql-pack.release.yml | 2 +- javascript/ql/lib/qlpack.yml | 2 +- javascript/ql/src/CHANGELOG.md | 6 ++++++ .../2.4.3.md} | 7 ++++--- javascript/ql/src/codeql-pack.release.yml | 2 +- javascript/ql/src/qlpack.yml | 2 +- misc/suite-helpers/CHANGELOG.md | 4 ++++ .../change-notes/released/1.0.55.md | 3 +++ misc/suite-helpers/codeql-pack.release.yml | 2 +- misc/suite-helpers/qlpack.yml | 2 +- python/ql/lib/CHANGELOG.md | 4 ++++ python/ql/lib/change-notes/released/7.2.3.md | 3 +++ python/ql/lib/codeql-pack.release.yml | 2 +- python/ql/lib/qlpack.yml | 2 +- python/ql/src/CHANGELOG.md | 4 ++++ python/ql/src/change-notes/released/1.8.8.md | 3 +++ python/ql/src/codeql-pack.release.yml | 2 +- python/ql/src/qlpack.yml | 2 +- ruby/ql/lib/CHANGELOG.md | 6 ++++++ .../6.0.3.md} | 7 ++++--- ruby/ql/lib/codeql-pack.release.yml | 2 +- ruby/ql/lib/qlpack.yml | 2 +- ruby/ql/src/CHANGELOG.md | 4 ++++ ruby/ql/src/change-notes/released/1.6.8.md | 3 +++ ruby/ql/src/codeql-pack.release.yml | 2 +- ruby/ql/src/qlpack.yml | 2 +- rust/ql/lib/CHANGELOG.md | 4 ++++ rust/ql/lib/change-notes/released/0.2.19.md | 3 +++ rust/ql/lib/codeql-pack.release.yml | 2 +- rust/ql/lib/qlpack.yml | 2 +- rust/ql/src/CHANGELOG.md | 4 ++++ rust/ql/src/change-notes/released/0.1.40.md | 3 +++ rust/ql/src/codeql-pack.release.yml | 2 +- rust/ql/src/qlpack.yml | 2 +- shared/concepts/CHANGELOG.md | 4 ++++ .../concepts/change-notes/released/0.0.29.md | 3 +++ shared/concepts/codeql-pack.release.yml | 2 +- shared/concepts/qlpack.yml | 2 +- shared/controlflow/CHANGELOG.md | 4 ++++ .../change-notes/released/2.0.39.md | 3 +++ shared/controlflow/codeql-pack.release.yml | 2 +- shared/controlflow/qlpack.yml | 2 +- shared/dataflow/CHANGELOG.md | 4 ++++ .../dataflow/change-notes/released/2.1.11.md | 3 +++ shared/dataflow/codeql-pack.release.yml | 2 +- shared/dataflow/qlpack.yml | 2 +- shared/mad/CHANGELOG.md | 4 ++++ shared/mad/change-notes/released/1.0.55.md | 3 +++ shared/mad/codeql-pack.release.yml | 2 +- shared/mad/qlpack.yml | 2 +- shared/namebinding/CHANGELOG.md | 4 ++++ .../change-notes/released/0.0.4.md | 3 +++ shared/namebinding/codeql-pack.release.yml | 2 +- shared/namebinding/qlpack.yml | 2 +- shared/quantum/CHANGELOG.md | 4 ++++ .../quantum/change-notes/released/0.0.33.md | 3 +++ shared/quantum/codeql-pack.release.yml | 2 +- shared/quantum/qlpack.yml | 2 +- shared/rangeanalysis/CHANGELOG.md | 4 ++++ .../change-notes/released/1.0.55.md | 3 +++ shared/rangeanalysis/codeql-pack.release.yml | 2 +- shared/rangeanalysis/qlpack.yml | 2 +- shared/regex/CHANGELOG.md | 4 ++++ shared/regex/change-notes/released/1.0.55.md | 3 +++ shared/regex/codeql-pack.release.yml | 2 +- shared/regex/qlpack.yml | 2 +- shared/ssa/CHANGELOG.md | 4 ++++ shared/ssa/change-notes/released/2.0.31.md | 3 +++ shared/ssa/codeql-pack.release.yml | 2 +- shared/ssa/qlpack.yml | 2 +- shared/threat-models/CHANGELOG.md | 4 ++++ .../change-notes/released/1.0.55.md | 3 +++ shared/threat-models/codeql-pack.release.yml | 2 +- shared/threat-models/qlpack.yml | 2 +- shared/tutorial/CHANGELOG.md | 4 ++++ .../tutorial/change-notes/released/1.0.55.md | 3 +++ shared/tutorial/codeql-pack.release.yml | 2 +- shared/tutorial/qlpack.yml | 2 +- shared/typeflow/CHANGELOG.md | 4 ++++ .../typeflow/change-notes/released/1.0.55.md | 3 +++ shared/typeflow/codeql-pack.release.yml | 2 +- shared/typeflow/qlpack.yml | 2 +- shared/typeinference/CHANGELOG.md | 4 ++++ .../change-notes/released/0.0.36.md | 3 +++ shared/typeinference/codeql-pack.release.yml | 2 +- shared/typeinference/qlpack.yml | 2 +- shared/typetracking/CHANGELOG.md | 4 ++++ .../change-notes/released/2.0.39.md | 3 +++ shared/typetracking/codeql-pack.release.yml | 2 +- shared/typetracking/qlpack.yml | 2 +- shared/typos/CHANGELOG.md | 4 ++++ shared/typos/change-notes/released/1.0.55.md | 3 +++ shared/typos/codeql-pack.release.yml | 2 +- shared/typos/qlpack.yml | 2 +- shared/util/CHANGELOG.md | 4 ++++ shared/util/change-notes/released/2.0.42.md | 3 +++ shared/util/codeql-pack.release.yml | 2 +- shared/util/qlpack.yml | 2 +- shared/xml/CHANGELOG.md | 4 ++++ shared/xml/change-notes/released/1.0.55.md | 3 +++ shared/xml/codeql-pack.release.yml | 2 +- shared/xml/qlpack.yml | 2 +- shared/yaml/CHANGELOG.md | 4 ++++ shared/yaml/change-notes/released/1.0.55.md | 3 +++ shared/yaml/codeql-pack.release.yml | 2 +- shared/yaml/qlpack.yml | 2 +- swift/ql/lib/CHANGELOG.md | 4 ++++ swift/ql/lib/change-notes/released/6.8.1.md | 3 +++ swift/ql/lib/codeql-pack.release.yml | 2 +- swift/ql/lib/qlpack.yml | 2 +- swift/ql/src/CHANGELOG.md | 4 ++++ swift/ql/src/change-notes/released/1.3.8.md | 3 +++ swift/ql/src/codeql-pack.release.yml | 2 +- swift/ql/src/qlpack.yml | 2 +- 183 files changed, 452 insertions(+), 153 deletions(-) delete mode 100644 actions/ql/lib/change-notes/2026-07-27-merge-group-event-source.md delete mode 100644 actions/ql/lib/change-notes/2026-08-04-remove-self-hosted-query-library.md create mode 100644 actions/ql/lib/change-notes/released/0.5.0.md delete mode 100644 actions/ql/src/change-notes/2026-07-18-envvar-injection-precision.md delete mode 100644 actions/ql/src/change-notes/2026-07-18-read-only-default-branch-cache.md delete mode 100644 actions/ql/src/change-notes/2026-07-28-checkout-provenance.md delete mode 100644 actions/ql/src/change-notes/2026-07-28-output-clobbering-regex.md delete mode 100644 actions/ql/src/change-notes/2026-07-28-schedule-event-mapping.md delete mode 100644 actions/ql/src/change-notes/2026-07-29-output-clobbering-jq-precision.md delete mode 100644 actions/ql/src/change-notes/2026-07-29-output-clobbering-messages.md delete mode 100644 actions/ql/src/change-notes/2026-07-31-cache-poisoning-code-injection-wording.md create mode 100644 actions/ql/src/change-notes/released/0.6.33.md delete mode 100644 cpp/ql/lib/change-notes/2026-07-28-winreg-sources.md create mode 100644 cpp/ql/lib/change-notes/released/12.0.2.md create mode 100644 cpp/ql/src/change-notes/released/1.8.1.md create mode 100644 csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.7.72.md create mode 100644 csharp/ql/campaigns/Solorigate/src/change-notes/released/1.7.72.md create mode 100644 csharp/ql/lib/change-notes/released/7.1.2.md create mode 100644 csharp/ql/src/change-notes/released/1.9.1.md create mode 100644 go/ql/consistency-queries/change-notes/released/1.0.55.md create mode 100644 go/ql/lib/change-notes/released/7.2.3.md create mode 100644 go/ql/src/change-notes/released/1.6.8.md create mode 100644 java/ql/lib/change-notes/released/9.2.3.md create mode 100644 java/ql/src/change-notes/released/1.11.8.md delete mode 100644 javascript/ql/lib/change-notes/2026-07-07-sails-action2-inputs.md delete mode 100644 javascript/ql/lib/change-notes/2026-07-16-vue-router-useRoute-query.md delete mode 100644 javascript/ql/lib/change-notes/2026-07-31-file-scoped-models.md delete mode 100644 javascript/ql/lib/change-notes/2026-08-01-client-response-promise-data.md create mode 100644 javascript/ql/lib/change-notes/released/2.9.0.md rename javascript/ql/src/change-notes/{2026-07-22-fastify-rate-limit.md => released/2.4.3.md} (71%) create mode 100644 misc/suite-helpers/change-notes/released/1.0.55.md create mode 100644 python/ql/lib/change-notes/released/7.2.3.md create mode 100644 python/ql/src/change-notes/released/1.8.8.md rename ruby/ql/lib/change-notes/{2026-08-05-vendored-lib-taint.md => released/6.0.3.md} (87%) create mode 100644 ruby/ql/src/change-notes/released/1.6.8.md create mode 100644 rust/ql/lib/change-notes/released/0.2.19.md create mode 100644 rust/ql/src/change-notes/released/0.1.40.md create mode 100644 shared/concepts/change-notes/released/0.0.29.md create mode 100644 shared/controlflow/change-notes/released/2.0.39.md create mode 100644 shared/dataflow/change-notes/released/2.1.11.md create mode 100644 shared/mad/change-notes/released/1.0.55.md create mode 100644 shared/namebinding/change-notes/released/0.0.4.md create mode 100644 shared/quantum/change-notes/released/0.0.33.md create mode 100644 shared/rangeanalysis/change-notes/released/1.0.55.md create mode 100644 shared/regex/change-notes/released/1.0.55.md create mode 100644 shared/ssa/change-notes/released/2.0.31.md create mode 100644 shared/threat-models/change-notes/released/1.0.55.md create mode 100644 shared/tutorial/change-notes/released/1.0.55.md create mode 100644 shared/typeflow/change-notes/released/1.0.55.md create mode 100644 shared/typeinference/change-notes/released/0.0.36.md create mode 100644 shared/typetracking/change-notes/released/2.0.39.md create mode 100644 shared/typos/change-notes/released/1.0.55.md create mode 100644 shared/util/change-notes/released/2.0.42.md create mode 100644 shared/xml/change-notes/released/1.0.55.md create mode 100644 shared/yaml/change-notes/released/1.0.55.md create mode 100644 swift/ql/lib/change-notes/released/6.8.1.md create mode 100644 swift/ql/src/change-notes/released/1.3.8.md diff --git a/actions/ql/lib/CHANGELOG.md b/actions/ql/lib/CHANGELOG.md index 630b089310b9..ea32d9c07193 100644 --- a/actions/ql/lib/CHANGELOG.md +++ b/actions/ql/lib/CHANGELOG.md @@ -1,3 +1,13 @@ +## 0.5.0 + +### Breaking Changes + +* The `codeql.actions.security.SelfHostedQuery` module has been removed because runner labels do not reliably distinguish self-hosted runners from managed runners. + +### Minor Analysis Improvements + +* GitHub Actions analysis now recognizes untrusted data in `github.event.merge_group` for workflows triggered by the `merge_group` event. + ## 0.4.40 ### Minor Analysis Improvements diff --git a/actions/ql/lib/change-notes/2026-07-27-merge-group-event-source.md b/actions/ql/lib/change-notes/2026-07-27-merge-group-event-source.md deleted file mode 100644 index 41b39b6c452f..000000000000 --- a/actions/ql/lib/change-notes/2026-07-27-merge-group-event-source.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* GitHub Actions analysis now recognizes untrusted data in `github.event.merge_group` for workflows triggered by the `merge_group` event. \ No newline at end of file diff --git a/actions/ql/lib/change-notes/2026-08-04-remove-self-hosted-query-library.md b/actions/ql/lib/change-notes/2026-08-04-remove-self-hosted-query-library.md deleted file mode 100644 index 562b519e001a..000000000000 --- a/actions/ql/lib/change-notes/2026-08-04-remove-self-hosted-query-library.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: breaking ---- -* The `codeql.actions.security.SelfHostedQuery` module has been removed because runner labels do not reliably distinguish self-hosted runners from managed runners. diff --git a/actions/ql/lib/change-notes/released/0.5.0.md b/actions/ql/lib/change-notes/released/0.5.0.md new file mode 100644 index 000000000000..3e89301899bd --- /dev/null +++ b/actions/ql/lib/change-notes/released/0.5.0.md @@ -0,0 +1,9 @@ +## 0.5.0 + +### Breaking Changes + +* The `codeql.actions.security.SelfHostedQuery` module has been removed because runner labels do not reliably distinguish self-hosted runners from managed runners. + +### Minor Analysis Improvements + +* GitHub Actions analysis now recognizes untrusted data in `github.event.merge_group` for workflows triggered by the `merge_group` event. diff --git a/actions/ql/lib/codeql-pack.release.yml b/actions/ql/lib/codeql-pack.release.yml index 8f5be10acbe6..30e271c5361c 100644 --- a/actions/ql/lib/codeql-pack.release.yml +++ b/actions/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.4.40 +lastReleaseVersion: 0.5.0 diff --git a/actions/ql/lib/qlpack.yml b/actions/ql/lib/qlpack.yml index 5111dd27cc89..859c7eb4a6f4 100644 --- a/actions/ql/lib/qlpack.yml +++ b/actions/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/actions-all -version: 0.4.41-dev +version: 0.5.0 library: true warnOnImplicitThis: true dependencies: diff --git a/actions/ql/src/CHANGELOG.md b/actions/ql/src/CHANGELOG.md index bc013b962f80..84f8321799d8 100644 --- a/actions/ql/src/CHANGELOG.md +++ b/actions/ql/src/CHANGELOG.md @@ -1,3 +1,22 @@ +## 0.6.33 + +### Query Metadata Changes + +* The name and alert message of the `actions/cache-poisoning/code-injection` query have been reworded for clarity. + +### Minor Analysis Improvements + +* The `actions/output-clobbering/high` query no longer reports simple `jq` path filters when their output remains JSON-encoded. Raw-output modes, complex filters, and unrecognized options remain reportable. +* GitHub Actions queries now correctly classify the `schedule` event when determining whether a workflow is externally triggerable. +* The `actions/envvar-injection/critical` query now requires the untrusted source and privileged context to originate from the same trigger event. The environment variable injection queries also no longer treat pull request head labels as injection-capable because they cannot contain newlines. +* The `actions/cache-poisoning/code-injection`, `actions/cache-poisoning/direct-cache`, and `actions/cache-poisoning/poisonable-step` queries now account for read-only cache access on low-trust triggers that run in the default branch scope. Results are retained for triggers that GitHub allows to write to that cache scope. + +### Bug Fixes + +* The `actions/output-clobbering/high` query now provides messages tailored to the affected output channel and includes expanded documentation and recommendations. +* The `actions/cache-poisoning/poisonable-step` and `actions/untrusted-checkout/critical` queries now start paths at the expressions that control untrusted checkouts and link their alert messages to those expressions. +* Fixed a performance issue in the `actions/output-clobbering/high` query caused by using unescaped source-code input in a regular expression. + ## 0.6.32 No user-facing changes. diff --git a/actions/ql/src/change-notes/2026-07-18-envvar-injection-precision.md b/actions/ql/src/change-notes/2026-07-18-envvar-injection-precision.md deleted file mode 100644 index c5bc9ba79bf1..000000000000 --- a/actions/ql/src/change-notes/2026-07-18-envvar-injection-precision.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* The `actions/envvar-injection/critical` query now requires the untrusted source and privileged context to originate from the same trigger event. The environment variable injection queries also no longer treat pull request head labels as injection-capable because they cannot contain newlines. diff --git a/actions/ql/src/change-notes/2026-07-18-read-only-default-branch-cache.md b/actions/ql/src/change-notes/2026-07-18-read-only-default-branch-cache.md deleted file mode 100644 index 9952be542003..000000000000 --- a/actions/ql/src/change-notes/2026-07-18-read-only-default-branch-cache.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* The `actions/cache-poisoning/code-injection`, `actions/cache-poisoning/direct-cache`, and `actions/cache-poisoning/poisonable-step` queries now account for read-only cache access on low-trust triggers that run in the default branch scope. Results are retained for triggers that GitHub allows to write to that cache scope. diff --git a/actions/ql/src/change-notes/2026-07-28-checkout-provenance.md b/actions/ql/src/change-notes/2026-07-28-checkout-provenance.md deleted file mode 100644 index 9a1bb29be1d9..000000000000 --- a/actions/ql/src/change-notes/2026-07-28-checkout-provenance.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: fix ---- -* The `actions/cache-poisoning/poisonable-step` and `actions/untrusted-checkout/critical` queries now start paths at the expressions that control untrusted checkouts and link their alert messages to those expressions. diff --git a/actions/ql/src/change-notes/2026-07-28-output-clobbering-regex.md b/actions/ql/src/change-notes/2026-07-28-output-clobbering-regex.md deleted file mode 100644 index d9e84a447c91..000000000000 --- a/actions/ql/src/change-notes/2026-07-28-output-clobbering-regex.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: fix ---- -* Fixed a performance issue in the `actions/output-clobbering/high` query caused by using unescaped source-code input in a regular expression. diff --git a/actions/ql/src/change-notes/2026-07-28-schedule-event-mapping.md b/actions/ql/src/change-notes/2026-07-28-schedule-event-mapping.md deleted file mode 100644 index ff949c266d08..000000000000 --- a/actions/ql/src/change-notes/2026-07-28-schedule-event-mapping.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* GitHub Actions queries now correctly classify the `schedule` event when determining whether a workflow is externally triggerable. diff --git a/actions/ql/src/change-notes/2026-07-29-output-clobbering-jq-precision.md b/actions/ql/src/change-notes/2026-07-29-output-clobbering-jq-precision.md deleted file mode 100644 index 9fba403a5715..000000000000 --- a/actions/ql/src/change-notes/2026-07-29-output-clobbering-jq-precision.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* The `actions/output-clobbering/high` query no longer reports simple `jq` path filters when their output remains JSON-encoded. Raw-output modes, complex filters, and unrecognized options remain reportable. diff --git a/actions/ql/src/change-notes/2026-07-29-output-clobbering-messages.md b/actions/ql/src/change-notes/2026-07-29-output-clobbering-messages.md deleted file mode 100644 index 4abb7a029762..000000000000 --- a/actions/ql/src/change-notes/2026-07-29-output-clobbering-messages.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: fix ---- -* The `actions/output-clobbering/high` query now provides messages tailored to the affected output channel and includes expanded documentation and recommendations. diff --git a/actions/ql/src/change-notes/2026-07-31-cache-poisoning-code-injection-wording.md b/actions/ql/src/change-notes/2026-07-31-cache-poisoning-code-injection-wording.md deleted file mode 100644 index 8e2ade04f8b0..000000000000 --- a/actions/ql/src/change-notes/2026-07-31-cache-poisoning-code-injection-wording.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: queryMetadata ---- -* The name and alert message of the `actions/cache-poisoning/code-injection` query have been reworded for clarity. \ No newline at end of file diff --git a/actions/ql/src/change-notes/released/0.6.33.md b/actions/ql/src/change-notes/released/0.6.33.md new file mode 100644 index 000000000000..86351b4c9158 --- /dev/null +++ b/actions/ql/src/change-notes/released/0.6.33.md @@ -0,0 +1,18 @@ +## 0.6.33 + +### Query Metadata Changes + +* The name and alert message of the `actions/cache-poisoning/code-injection` query have been reworded for clarity. + +### Minor Analysis Improvements + +* The `actions/output-clobbering/high` query no longer reports simple `jq` path filters when their output remains JSON-encoded. Raw-output modes, complex filters, and unrecognized options remain reportable. +* GitHub Actions queries now correctly classify the `schedule` event when determining whether a workflow is externally triggerable. +* The `actions/envvar-injection/critical` query now requires the untrusted source and privileged context to originate from the same trigger event. The environment variable injection queries also no longer treat pull request head labels as injection-capable because they cannot contain newlines. +* The `actions/cache-poisoning/code-injection`, `actions/cache-poisoning/direct-cache`, and `actions/cache-poisoning/poisonable-step` queries now account for read-only cache access on low-trust triggers that run in the default branch scope. Results are retained for triggers that GitHub allows to write to that cache scope. + +### Bug Fixes + +* The `actions/output-clobbering/high` query now provides messages tailored to the affected output channel and includes expanded documentation and recommendations. +* The `actions/cache-poisoning/poisonable-step` and `actions/untrusted-checkout/critical` queries now start paths at the expressions that control untrusted checkouts and link their alert messages to those expressions. +* Fixed a performance issue in the `actions/output-clobbering/high` query caused by using unescaped source-code input in a regular expression. diff --git a/actions/ql/src/codeql-pack.release.yml b/actions/ql/src/codeql-pack.release.yml index 6c5978280b02..ce257a8193e6 100644 --- a/actions/ql/src/codeql-pack.release.yml +++ b/actions/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.6.32 +lastReleaseVersion: 0.6.33 diff --git a/actions/ql/src/qlpack.yml b/actions/ql/src/qlpack.yml index 6d2a221c1b4a..648a6fb436fa 100644 --- a/actions/ql/src/qlpack.yml +++ b/actions/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/actions-queries -version: 0.6.33-dev +version: 0.6.33 library: false warnOnImplicitThis: true groups: [actions, queries] diff --git a/cpp/ql/lib/CHANGELOG.md b/cpp/ql/lib/CHANGELOG.md index f5f7d195fa61..04ad4bba646b 100644 --- a/cpp/ql/lib/CHANGELOG.md +++ b/cpp/ql/lib/CHANGELOG.md @@ -1,3 +1,9 @@ +## 12.0.2 + +### Minor Analysis Improvements + +* Added flow source models for `RegQueryValue` and related functions from the `winreg.h` Windows header. + ## 12.0.1 No user-facing changes. diff --git a/cpp/ql/lib/change-notes/2026-07-28-winreg-sources.md b/cpp/ql/lib/change-notes/2026-07-28-winreg-sources.md deleted file mode 100644 index 9a70926b9984..000000000000 --- a/cpp/ql/lib/change-notes/2026-07-28-winreg-sources.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* Added flow source models for `RegQueryValue` and related functions from the `winreg.h` Windows header. \ No newline at end of file diff --git a/cpp/ql/lib/change-notes/released/12.0.2.md b/cpp/ql/lib/change-notes/released/12.0.2.md new file mode 100644 index 000000000000..cecfb536211f --- /dev/null +++ b/cpp/ql/lib/change-notes/released/12.0.2.md @@ -0,0 +1,5 @@ +## 12.0.2 + +### Minor Analysis Improvements + +* Added flow source models for `RegQueryValue` and related functions from the `winreg.h` Windows header. diff --git a/cpp/ql/lib/codeql-pack.release.yml b/cpp/ql/lib/codeql-pack.release.yml index 95ce69d8d492..500fb3b8051e 100644 --- a/cpp/ql/lib/codeql-pack.release.yml +++ b/cpp/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 12.0.1 +lastReleaseVersion: 12.0.2 diff --git a/cpp/ql/lib/qlpack.yml b/cpp/ql/lib/qlpack.yml index 2932987ec152..fd32327163ba 100644 --- a/cpp/ql/lib/qlpack.yml +++ b/cpp/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cpp-all -version: 12.0.2-dev +version: 12.0.2 groups: cpp dbscheme: semmlecode.cpp.dbscheme extractor: cpp diff --git a/cpp/ql/src/CHANGELOG.md b/cpp/ql/src/CHANGELOG.md index 945a605d7e3d..bc3adffadcdc 100644 --- a/cpp/ql/src/CHANGELOG.md +++ b/cpp/ql/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.8.1 + +No user-facing changes. + ## 1.8.0 ### Query Metadata Changes diff --git a/cpp/ql/src/change-notes/released/1.8.1.md b/cpp/ql/src/change-notes/released/1.8.1.md new file mode 100644 index 000000000000..0b1a7cdad10a --- /dev/null +++ b/cpp/ql/src/change-notes/released/1.8.1.md @@ -0,0 +1,3 @@ +## 1.8.1 + +No user-facing changes. diff --git a/cpp/ql/src/codeql-pack.release.yml b/cpp/ql/src/codeql-pack.release.yml index dc8a37cc443d..28a7c123ae84 100644 --- a/cpp/ql/src/codeql-pack.release.yml +++ b/cpp/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.8.0 +lastReleaseVersion: 1.8.1 diff --git a/cpp/ql/src/qlpack.yml b/cpp/ql/src/qlpack.yml index ad0a0cd8943b..8495d389e7fb 100644 --- a/cpp/ql/src/qlpack.yml +++ b/cpp/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cpp-queries -version: 1.8.1-dev +version: 1.8.1 groups: - cpp - queries diff --git a/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md b/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md index a8774769b98c..f1ee51f9d945 100644 --- a/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md +++ b/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.7.72 + +No user-facing changes. + ## 1.7.71 No user-facing changes. diff --git a/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.7.72.md b/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.7.72.md new file mode 100644 index 000000000000..9ff61fe3c5d3 --- /dev/null +++ b/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.7.72.md @@ -0,0 +1,3 @@ +## 1.7.72 + +No user-facing changes. diff --git a/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml b/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml index 9cb591428908..33d595a3ea10 100644 --- a/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml +++ b/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.7.71 +lastReleaseVersion: 1.7.72 diff --git a/csharp/ql/campaigns/Solorigate/lib/qlpack.yml b/csharp/ql/campaigns/Solorigate/lib/qlpack.yml index 9968c6570e7d..8333936d134a 100644 --- a/csharp/ql/campaigns/Solorigate/lib/qlpack.yml +++ b/csharp/ql/campaigns/Solorigate/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-solorigate-all -version: 1.7.72-dev +version: 1.7.72 groups: - csharp - solorigate diff --git a/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md b/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md index a8774769b98c..f1ee51f9d945 100644 --- a/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md +++ b/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.7.72 + +No user-facing changes. + ## 1.7.71 No user-facing changes. diff --git a/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.7.72.md b/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.7.72.md new file mode 100644 index 000000000000..9ff61fe3c5d3 --- /dev/null +++ b/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.7.72.md @@ -0,0 +1,3 @@ +## 1.7.72 + +No user-facing changes. diff --git a/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml b/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml index 9cb591428908..33d595a3ea10 100644 --- a/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml +++ b/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.7.71 +lastReleaseVersion: 1.7.72 diff --git a/csharp/ql/campaigns/Solorigate/src/qlpack.yml b/csharp/ql/campaigns/Solorigate/src/qlpack.yml index 9ccab68881a5..5379a3416f94 100644 --- a/csharp/ql/campaigns/Solorigate/src/qlpack.yml +++ b/csharp/ql/campaigns/Solorigate/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-solorigate-queries -version: 1.7.72-dev +version: 1.7.72 groups: - csharp - solorigate diff --git a/csharp/ql/lib/CHANGELOG.md b/csharp/ql/lib/CHANGELOG.md index 3ea969a9e9a5..ccfde0f7f8fb 100644 --- a/csharp/ql/lib/CHANGELOG.md +++ b/csharp/ql/lib/CHANGELOG.md @@ -1,3 +1,7 @@ +## 7.1.2 + +No user-facing changes. + ## 7.1.1 No user-facing changes. diff --git a/csharp/ql/lib/change-notes/released/7.1.2.md b/csharp/ql/lib/change-notes/released/7.1.2.md new file mode 100644 index 000000000000..d55cf91e2492 --- /dev/null +++ b/csharp/ql/lib/change-notes/released/7.1.2.md @@ -0,0 +1,3 @@ +## 7.1.2 + +No user-facing changes. diff --git a/csharp/ql/lib/codeql-pack.release.yml b/csharp/ql/lib/codeql-pack.release.yml index 8e970df6cae3..547681cc4408 100644 --- a/csharp/ql/lib/codeql-pack.release.yml +++ b/csharp/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 7.1.1 +lastReleaseVersion: 7.1.2 diff --git a/csharp/ql/lib/qlpack.yml b/csharp/ql/lib/qlpack.yml index 035a38389157..82fec250fc95 100644 --- a/csharp/ql/lib/qlpack.yml +++ b/csharp/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-all -version: 7.1.2-dev +version: 7.1.2 groups: csharp dbscheme: semmlecode.csharp.dbscheme extractor: csharp diff --git a/csharp/ql/src/CHANGELOG.md b/csharp/ql/src/CHANGELOG.md index f3aee337480f..6fab89a5cac1 100644 --- a/csharp/ql/src/CHANGELOG.md +++ b/csharp/ql/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.9.1 + +No user-facing changes. + ## 1.9.0 ### Query Metadata Changes diff --git a/csharp/ql/src/change-notes/released/1.9.1.md b/csharp/ql/src/change-notes/released/1.9.1.md new file mode 100644 index 000000000000..bc5c4bd30411 --- /dev/null +++ b/csharp/ql/src/change-notes/released/1.9.1.md @@ -0,0 +1,3 @@ +## 1.9.1 + +No user-facing changes. diff --git a/csharp/ql/src/codeql-pack.release.yml b/csharp/ql/src/codeql-pack.release.yml index df17dc3a3662..29c886b15136 100644 --- a/csharp/ql/src/codeql-pack.release.yml +++ b/csharp/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.9.0 +lastReleaseVersion: 1.9.1 diff --git a/csharp/ql/src/qlpack.yml b/csharp/ql/src/qlpack.yml index 8d3728935138..647d273d52bc 100644 --- a/csharp/ql/src/qlpack.yml +++ b/csharp/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-queries -version: 1.9.1-dev +version: 1.9.1 groups: - csharp - queries diff --git a/go/ql/consistency-queries/CHANGELOG.md b/go/ql/consistency-queries/CHANGELOG.md index d75ab9a9e2d7..3a3948e7bf27 100644 --- a/go/ql/consistency-queries/CHANGELOG.md +++ b/go/ql/consistency-queries/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.55 + +No user-facing changes. + ## 1.0.54 No user-facing changes. diff --git a/go/ql/consistency-queries/change-notes/released/1.0.55.md b/go/ql/consistency-queries/change-notes/released/1.0.55.md new file mode 100644 index 000000000000..fd53dce64a9f --- /dev/null +++ b/go/ql/consistency-queries/change-notes/released/1.0.55.md @@ -0,0 +1,3 @@ +## 1.0.55 + +No user-facing changes. diff --git a/go/ql/consistency-queries/codeql-pack.release.yml b/go/ql/consistency-queries/codeql-pack.release.yml index c3c3b0f4418a..3c942a6b4ea3 100644 --- a/go/ql/consistency-queries/codeql-pack.release.yml +++ b/go/ql/consistency-queries/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.54 +lastReleaseVersion: 1.0.55 diff --git a/go/ql/consistency-queries/qlpack.yml b/go/ql/consistency-queries/qlpack.yml index e21cc5f01830..3ade0367079d 100644 --- a/go/ql/consistency-queries/qlpack.yml +++ b/go/ql/consistency-queries/qlpack.yml @@ -1,5 +1,5 @@ name: codeql-go-consistency-queries -version: 1.0.55-dev +version: 1.0.55 groups: - go - queries diff --git a/go/ql/lib/CHANGELOG.md b/go/ql/lib/CHANGELOG.md index 4b594f8f7405..14c075851e29 100644 --- a/go/ql/lib/CHANGELOG.md +++ b/go/ql/lib/CHANGELOG.md @@ -1,3 +1,7 @@ +## 7.2.3 + +No user-facing changes. + ## 7.2.2 ### Minor Analysis Improvements diff --git a/go/ql/lib/change-notes/released/7.2.3.md b/go/ql/lib/change-notes/released/7.2.3.md new file mode 100644 index 000000000000..ba04214fb88d --- /dev/null +++ b/go/ql/lib/change-notes/released/7.2.3.md @@ -0,0 +1,3 @@ +## 7.2.3 + +No user-facing changes. diff --git a/go/ql/lib/codeql-pack.release.yml b/go/ql/lib/codeql-pack.release.yml index fa4a7164fb7b..7d0dee6395ee 100644 --- a/go/ql/lib/codeql-pack.release.yml +++ b/go/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 7.2.2 +lastReleaseVersion: 7.2.3 diff --git a/go/ql/lib/qlpack.yml b/go/ql/lib/qlpack.yml index 47c1077e0992..d11fb5937d3b 100644 --- a/go/ql/lib/qlpack.yml +++ b/go/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/go-all -version: 7.2.3-dev +version: 7.2.3 groups: go dbscheme: go.dbscheme extractor: go diff --git a/go/ql/src/CHANGELOG.md b/go/ql/src/CHANGELOG.md index 6d012f9d2a4d..9dfd046bec53 100644 --- a/go/ql/src/CHANGELOG.md +++ b/go/ql/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.6.8 + +No user-facing changes. + ## 1.6.7 No user-facing changes. diff --git a/go/ql/src/change-notes/released/1.6.8.md b/go/ql/src/change-notes/released/1.6.8.md new file mode 100644 index 000000000000..0a5d9b06c55e --- /dev/null +++ b/go/ql/src/change-notes/released/1.6.8.md @@ -0,0 +1,3 @@ +## 1.6.8 + +No user-facing changes. diff --git a/go/ql/src/codeql-pack.release.yml b/go/ql/src/codeql-pack.release.yml index 0b49adeac7da..fbc11aa62b75 100644 --- a/go/ql/src/codeql-pack.release.yml +++ b/go/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.6.7 +lastReleaseVersion: 1.6.8 diff --git a/go/ql/src/qlpack.yml b/go/ql/src/qlpack.yml index 25a573adf8a0..61ae6f2fe439 100644 --- a/go/ql/src/qlpack.yml +++ b/go/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/go-queries -version: 1.6.8-dev +version: 1.6.8 groups: - go - queries diff --git a/java/ql/lib/CHANGELOG.md b/java/ql/lib/CHANGELOG.md index 83910f155a3c..2fd58088dab6 100644 --- a/java/ql/lib/CHANGELOG.md +++ b/java/ql/lib/CHANGELOG.md @@ -1,3 +1,7 @@ +## 9.2.3 + +No user-facing changes. + ## 9.2.2 ### Minor Analysis Improvements diff --git a/java/ql/lib/change-notes/released/9.2.3.md b/java/ql/lib/change-notes/released/9.2.3.md new file mode 100644 index 000000000000..c0cdbd68de76 --- /dev/null +++ b/java/ql/lib/change-notes/released/9.2.3.md @@ -0,0 +1,3 @@ +## 9.2.3 + +No user-facing changes. diff --git a/java/ql/lib/codeql-pack.release.yml b/java/ql/lib/codeql-pack.release.yml index 41cfa549b0a6..39a6208d44d2 100644 --- a/java/ql/lib/codeql-pack.release.yml +++ b/java/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 9.2.2 +lastReleaseVersion: 9.2.3 diff --git a/java/ql/lib/qlpack.yml b/java/ql/lib/qlpack.yml index 782d89ff8172..e8e9de7cd03c 100644 --- a/java/ql/lib/qlpack.yml +++ b/java/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/java-all -version: 9.2.3-dev +version: 9.2.3 groups: java dbscheme: config/semmlecode.dbscheme extractor: java diff --git a/java/ql/src/CHANGELOG.md b/java/ql/src/CHANGELOG.md index 3fd98c386b69..b31db924d53d 100644 --- a/java/ql/src/CHANGELOG.md +++ b/java/ql/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.11.8 + +No user-facing changes. + ## 1.11.7 No user-facing changes. diff --git a/java/ql/src/change-notes/released/1.11.8.md b/java/ql/src/change-notes/released/1.11.8.md new file mode 100644 index 000000000000..0783473b96d3 --- /dev/null +++ b/java/ql/src/change-notes/released/1.11.8.md @@ -0,0 +1,3 @@ +## 1.11.8 + +No user-facing changes. diff --git a/java/ql/src/codeql-pack.release.yml b/java/ql/src/codeql-pack.release.yml index da245378bca5..1235b98cb049 100644 --- a/java/ql/src/codeql-pack.release.yml +++ b/java/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.11.7 +lastReleaseVersion: 1.11.8 diff --git a/java/ql/src/qlpack.yml b/java/ql/src/qlpack.yml index f85ddd4d3f6a..e22f77c81351 100644 --- a/java/ql/src/qlpack.yml +++ b/java/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/java-queries -version: 1.11.8-dev +version: 1.11.8 groups: - java - queries diff --git a/javascript/ql/lib/CHANGELOG.md b/javascript/ql/lib/CHANGELOG.md index c0217aee81e7..0f509e829b05 100644 --- a/javascript/ql/lib/CHANGELOG.md +++ b/javascript/ql/lib/CHANGELOG.md @@ -1,3 +1,18 @@ +## 2.9.0 + +### Major Analysis Improvements + +* It is now possible for custom models to refer to specific files in the codebase, using a package name of form `file:`. The model should describe the public exports + of that file. This can be used to derive sources and sinks in code that imports the file, but note that sources and sinks will not generally be placed within the file itself. + For example, a source model `['file:lib/service.js', 'Member[getData].ReturnValue', 'remote']` could identify `require('../lib/service').getData()` as a source. + +### Minor Analysis Improvements + +* JavaScript security queries using the `response` threat model now track promise-wrapped client response data into promise fulfillment values. This may improve results for queries such as `js/xss` when response data is consumed through `.then(...)` chains. +* The route object returned by Vue Router's `useRoute()` Composition API is now recognized as a client-side remote flow source, covering its `query`, `params`, `path`, `fullPath`, and `hash` members. These members are additionally reported under the corresponding `browser-url-query`, `browser-url-path`, and `browser-url-fragment` threat models. +* Added flow models for Vue's `ref`, `shallowRef`, `toRef`, `reactive`, and `computed` Composition API helpers. +* Added support for treating declared `inputs` properties in Sails Action2 controller files as remote flow sources. This may improve results for security queries such as `js/path-injection`. + ## 2.8.2 No user-facing changes. diff --git a/javascript/ql/lib/change-notes/2026-07-07-sails-action2-inputs.md b/javascript/ql/lib/change-notes/2026-07-07-sails-action2-inputs.md deleted file mode 100644 index 72b5fda6137b..000000000000 --- a/javascript/ql/lib/change-notes/2026-07-07-sails-action2-inputs.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* Added support for treating declared `inputs` properties in Sails Action2 controller files as remote flow sources. This may improve results for security queries such as `js/path-injection`. diff --git a/javascript/ql/lib/change-notes/2026-07-16-vue-router-useRoute-query.md b/javascript/ql/lib/change-notes/2026-07-16-vue-router-useRoute-query.md deleted file mode 100644 index 973af15aae03..000000000000 --- a/javascript/ql/lib/change-notes/2026-07-16-vue-router-useRoute-query.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -category: minorAnalysis ---- -* The route object returned by Vue Router's `useRoute()` Composition API is now recognized as a client-side remote flow source, covering its `query`, `params`, `path`, `fullPath`, and `hash` members. These members are additionally reported under the corresponding `browser-url-query`, `browser-url-path`, and `browser-url-fragment` threat models. -* Added flow models for Vue's `ref`, `shallowRef`, `toRef`, `reactive`, and `computed` Composition API helpers. diff --git a/javascript/ql/lib/change-notes/2026-07-31-file-scoped-models.md b/javascript/ql/lib/change-notes/2026-07-31-file-scoped-models.md deleted file mode 100644 index b3df112a1f1d..000000000000 --- a/javascript/ql/lib/change-notes/2026-07-31-file-scoped-models.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -category: majorAnalysis ---- -* It is now possible for custom models to refer to specific files in the codebase, using a package name of form `file:`. The model should describe the public exports - of that file. This can be used to derive sources and sinks in code that imports the file, but note that sources and sinks will not generally be placed within the file itself. - For example, a source model `['file:lib/service.js', 'Member[getData].ReturnValue', 'remote']` could identify `require('../lib/service').getData()` as a source. diff --git a/javascript/ql/lib/change-notes/2026-08-01-client-response-promise-data.md b/javascript/ql/lib/change-notes/2026-08-01-client-response-promise-data.md deleted file mode 100644 index 7213d64a830d..000000000000 --- a/javascript/ql/lib/change-notes/2026-08-01-client-response-promise-data.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* JavaScript security queries using the `response` threat model now track promise-wrapped client response data into promise fulfillment values. This may improve results for queries such as `js/xss` when response data is consumed through `.then(...)` chains. diff --git a/javascript/ql/lib/change-notes/released/2.9.0.md b/javascript/ql/lib/change-notes/released/2.9.0.md new file mode 100644 index 000000000000..6892fa665580 --- /dev/null +++ b/javascript/ql/lib/change-notes/released/2.9.0.md @@ -0,0 +1,14 @@ +## 2.9.0 + +### Major Analysis Improvements + +* It is now possible for custom models to refer to specific files in the codebase, using a package name of form `file:`. The model should describe the public exports + of that file. This can be used to derive sources and sinks in code that imports the file, but note that sources and sinks will not generally be placed within the file itself. + For example, a source model `['file:lib/service.js', 'Member[getData].ReturnValue', 'remote']` could identify `require('../lib/service').getData()` as a source. + +### Minor Analysis Improvements + +* JavaScript security queries using the `response` threat model now track promise-wrapped client response data into promise fulfillment values. This may improve results for queries such as `js/xss` when response data is consumed through `.then(...)` chains. +* The route object returned by Vue Router's `useRoute()` Composition API is now recognized as a client-side remote flow source, covering its `query`, `params`, `path`, `fullPath`, and `hash` members. These members are additionally reported under the corresponding `browser-url-query`, `browser-url-path`, and `browser-url-fragment` threat models. +* Added flow models for Vue's `ref`, `shallowRef`, `toRef`, `reactive`, and `computed` Composition API helpers. +* Added support for treating declared `inputs` properties in Sails Action2 controller files as remote flow sources. This may improve results for security queries such as `js/path-injection`. diff --git a/javascript/ql/lib/codeql-pack.release.yml b/javascript/ql/lib/codeql-pack.release.yml index 49d300fe06bf..d6329a574932 100644 --- a/javascript/ql/lib/codeql-pack.release.yml +++ b/javascript/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 2.8.2 +lastReleaseVersion: 2.9.0 diff --git a/javascript/ql/lib/qlpack.yml b/javascript/ql/lib/qlpack.yml index 6e10c05aa596..a8caae8cf334 100644 --- a/javascript/ql/lib/qlpack.yml +++ b/javascript/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/javascript-all -version: 2.8.3-dev +version: 2.9.0 groups: javascript dbscheme: semmlecode.javascript.dbscheme extractor: javascript diff --git a/javascript/ql/src/CHANGELOG.md b/javascript/ql/src/CHANGELOG.md index 2e8bcd543c25..87b01cbc4afa 100644 --- a/javascript/ql/src/CHANGELOG.md +++ b/javascript/ql/src/CHANGELOG.md @@ -1,3 +1,9 @@ +## 2.4.3 + +### Minor Analysis Improvements + +* The `js/missing-rate-limiting` query now recognizes the `@fastify/rate-limit` package as a rate limiter. + ## 2.4.2 No user-facing changes. diff --git a/javascript/ql/src/change-notes/2026-07-22-fastify-rate-limit.md b/javascript/ql/src/change-notes/released/2.4.3.md similarity index 71% rename from javascript/ql/src/change-notes/2026-07-22-fastify-rate-limit.md rename to javascript/ql/src/change-notes/released/2.4.3.md index 55e23b9dc111..11f57d32a7a9 100644 --- a/javascript/ql/src/change-notes/2026-07-22-fastify-rate-limit.md +++ b/javascript/ql/src/change-notes/released/2.4.3.md @@ -1,4 +1,5 @@ ---- -category: minorAnalysis ---- +## 2.4.3 + +### Minor Analysis Improvements + * The `js/missing-rate-limiting` query now recognizes the `@fastify/rate-limit` package as a rate limiter. diff --git a/javascript/ql/src/codeql-pack.release.yml b/javascript/ql/src/codeql-pack.release.yml index 660b0f7e51c9..2520785bcc40 100644 --- a/javascript/ql/src/codeql-pack.release.yml +++ b/javascript/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 2.4.2 +lastReleaseVersion: 2.4.3 diff --git a/javascript/ql/src/qlpack.yml b/javascript/ql/src/qlpack.yml index 1c534df4d85b..b21af7515f5b 100644 --- a/javascript/ql/src/qlpack.yml +++ b/javascript/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/javascript-queries -version: 2.4.3-dev +version: 2.4.3 groups: - javascript - queries diff --git a/misc/suite-helpers/CHANGELOG.md b/misc/suite-helpers/CHANGELOG.md index 2e398f4824df..dd22444f54fe 100644 --- a/misc/suite-helpers/CHANGELOG.md +++ b/misc/suite-helpers/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.55 + +No user-facing changes. + ## 1.0.54 No user-facing changes. diff --git a/misc/suite-helpers/change-notes/released/1.0.55.md b/misc/suite-helpers/change-notes/released/1.0.55.md new file mode 100644 index 000000000000..fd53dce64a9f --- /dev/null +++ b/misc/suite-helpers/change-notes/released/1.0.55.md @@ -0,0 +1,3 @@ +## 1.0.55 + +No user-facing changes. diff --git a/misc/suite-helpers/codeql-pack.release.yml b/misc/suite-helpers/codeql-pack.release.yml index c3c3b0f4418a..3c942a6b4ea3 100644 --- a/misc/suite-helpers/codeql-pack.release.yml +++ b/misc/suite-helpers/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.54 +lastReleaseVersion: 1.0.55 diff --git a/misc/suite-helpers/qlpack.yml b/misc/suite-helpers/qlpack.yml index 12203ff110fa..dff0d253cbce 100644 --- a/misc/suite-helpers/qlpack.yml +++ b/misc/suite-helpers/qlpack.yml @@ -1,4 +1,4 @@ name: codeql/suite-helpers -version: 1.0.55-dev +version: 1.0.55 groups: shared warnOnImplicitThis: true diff --git a/python/ql/lib/CHANGELOG.md b/python/ql/lib/CHANGELOG.md index e36b11806aa3..2a6de92ecbce 100644 --- a/python/ql/lib/CHANGELOG.md +++ b/python/ql/lib/CHANGELOG.md @@ -1,3 +1,7 @@ +## 7.2.3 + +No user-facing changes. + ## 7.2.2 No user-facing changes. diff --git a/python/ql/lib/change-notes/released/7.2.3.md b/python/ql/lib/change-notes/released/7.2.3.md new file mode 100644 index 000000000000..ba04214fb88d --- /dev/null +++ b/python/ql/lib/change-notes/released/7.2.3.md @@ -0,0 +1,3 @@ +## 7.2.3 + +No user-facing changes. diff --git a/python/ql/lib/codeql-pack.release.yml b/python/ql/lib/codeql-pack.release.yml index fa4a7164fb7b..7d0dee6395ee 100644 --- a/python/ql/lib/codeql-pack.release.yml +++ b/python/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 7.2.2 +lastReleaseVersion: 7.2.3 diff --git a/python/ql/lib/qlpack.yml b/python/ql/lib/qlpack.yml index 51fbf227e0b9..d8914df8750b 100644 --- a/python/ql/lib/qlpack.yml +++ b/python/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/python-all -version: 7.2.3-dev +version: 7.2.3 groups: python dbscheme: semmlecode.python.dbscheme extractor: python diff --git a/python/ql/src/CHANGELOG.md b/python/ql/src/CHANGELOG.md index 154686ec4aa9..97904c1bd7af 100644 --- a/python/ql/src/CHANGELOG.md +++ b/python/ql/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.8.8 + +No user-facing changes. + ## 1.8.7 No user-facing changes. diff --git a/python/ql/src/change-notes/released/1.8.8.md b/python/ql/src/change-notes/released/1.8.8.md new file mode 100644 index 000000000000..fcbf14e0fd9b --- /dev/null +++ b/python/ql/src/change-notes/released/1.8.8.md @@ -0,0 +1,3 @@ +## 1.8.8 + +No user-facing changes. diff --git a/python/ql/src/codeql-pack.release.yml b/python/ql/src/codeql-pack.release.yml index 353f6d821ebe..d224b6ac3595 100644 --- a/python/ql/src/codeql-pack.release.yml +++ b/python/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.8.7 +lastReleaseVersion: 1.8.8 diff --git a/python/ql/src/qlpack.yml b/python/ql/src/qlpack.yml index 7d54edbaa03f..1aca14fd33ae 100644 --- a/python/ql/src/qlpack.yml +++ b/python/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/python-queries -version: 1.8.8-dev +version: 1.8.8 groups: - python - queries diff --git a/ruby/ql/lib/CHANGELOG.md b/ruby/ql/lib/CHANGELOG.md index d79eaed159e4..146fdb46d43c 100644 --- a/ruby/ql/lib/CHANGELOG.md +++ b/ruby/ql/lib/CHANGELOG.md @@ -1,3 +1,9 @@ +## 6.0.3 + +### Minor Analysis Improvements + +* Removed library input to vendored gems from the set of taint sources. This should reduce false positives for `rb/polynomial-redos`, `rb/regex/badly-anchored-regexp`, `rb/unsafe-code-construction`, `rb/html-constructed-from-input`, and `rb/shell-command-constructed-from-input` whenever vendoring is used. + ## 6.0.2 No user-facing changes. diff --git a/ruby/ql/lib/change-notes/2026-08-05-vendored-lib-taint.md b/ruby/ql/lib/change-notes/released/6.0.3.md similarity index 87% rename from ruby/ql/lib/change-notes/2026-08-05-vendored-lib-taint.md rename to ruby/ql/lib/change-notes/released/6.0.3.md index e5eab2447c30..81e3925ea383 100644 --- a/ruby/ql/lib/change-notes/2026-08-05-vendored-lib-taint.md +++ b/ruby/ql/lib/change-notes/released/6.0.3.md @@ -1,4 +1,5 @@ ---- -category: minorAnalysis ---- +## 6.0.3 + +### Minor Analysis Improvements + * Removed library input to vendored gems from the set of taint sources. This should reduce false positives for `rb/polynomial-redos`, `rb/regex/badly-anchored-regexp`, `rb/unsafe-code-construction`, `rb/html-constructed-from-input`, and `rb/shell-command-constructed-from-input` whenever vendoring is used. diff --git a/ruby/ql/lib/codeql-pack.release.yml b/ruby/ql/lib/codeql-pack.release.yml index 70437ec53b89..304c17ad4092 100644 --- a/ruby/ql/lib/codeql-pack.release.yml +++ b/ruby/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 6.0.2 +lastReleaseVersion: 6.0.3 diff --git a/ruby/ql/lib/qlpack.yml b/ruby/ql/lib/qlpack.yml index 29d38c9a1948..597e6242c9dd 100644 --- a/ruby/ql/lib/qlpack.yml +++ b/ruby/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/ruby-all -version: 6.0.3-dev +version: 6.0.3 groups: ruby extractor: ruby dbscheme: ruby.dbscheme diff --git a/ruby/ql/src/CHANGELOG.md b/ruby/ql/src/CHANGELOG.md index 781cbbe6d9f7..a8502538032b 100644 --- a/ruby/ql/src/CHANGELOG.md +++ b/ruby/ql/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.6.8 + +No user-facing changes. + ## 1.6.7 No user-facing changes. diff --git a/ruby/ql/src/change-notes/released/1.6.8.md b/ruby/ql/src/change-notes/released/1.6.8.md new file mode 100644 index 000000000000..0a5d9b06c55e --- /dev/null +++ b/ruby/ql/src/change-notes/released/1.6.8.md @@ -0,0 +1,3 @@ +## 1.6.8 + +No user-facing changes. diff --git a/ruby/ql/src/codeql-pack.release.yml b/ruby/ql/src/codeql-pack.release.yml index 0b49adeac7da..fbc11aa62b75 100644 --- a/ruby/ql/src/codeql-pack.release.yml +++ b/ruby/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.6.7 +lastReleaseVersion: 1.6.8 diff --git a/ruby/ql/src/qlpack.yml b/ruby/ql/src/qlpack.yml index f73004c8530d..60d063996d4a 100644 --- a/ruby/ql/src/qlpack.yml +++ b/ruby/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/ruby-queries -version: 1.6.8-dev +version: 1.6.8 groups: - ruby - queries diff --git a/rust/ql/lib/CHANGELOG.md b/rust/ql/lib/CHANGELOG.md index c4da1d50e0aa..6e7ca1f1f10a 100644 --- a/rust/ql/lib/CHANGELOG.md +++ b/rust/ql/lib/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.2.19 + +No user-facing changes. + ## 0.2.18 No user-facing changes. diff --git a/rust/ql/lib/change-notes/released/0.2.19.md b/rust/ql/lib/change-notes/released/0.2.19.md new file mode 100644 index 000000000000..40c7c07e47b7 --- /dev/null +++ b/rust/ql/lib/change-notes/released/0.2.19.md @@ -0,0 +1,3 @@ +## 0.2.19 + +No user-facing changes. diff --git a/rust/ql/lib/codeql-pack.release.yml b/rust/ql/lib/codeql-pack.release.yml index 22e36b609026..b37d10786472 100644 --- a/rust/ql/lib/codeql-pack.release.yml +++ b/rust/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.2.18 +lastReleaseVersion: 0.2.19 diff --git a/rust/ql/lib/qlpack.yml b/rust/ql/lib/qlpack.yml index 14e8ab08f4d9..9f013c345d61 100644 --- a/rust/ql/lib/qlpack.yml +++ b/rust/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/rust-all -version: 0.2.19-dev +version: 0.2.19 groups: rust extractor: rust dbscheme: rust.dbscheme diff --git a/rust/ql/src/CHANGELOG.md b/rust/ql/src/CHANGELOG.md index 1732a4853b12..e6a2f67fac00 100644 --- a/rust/ql/src/CHANGELOG.md +++ b/rust/ql/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.1.40 + +No user-facing changes. + ## 0.1.39 No user-facing changes. diff --git a/rust/ql/src/change-notes/released/0.1.40.md b/rust/ql/src/change-notes/released/0.1.40.md new file mode 100644 index 000000000000..f7aacd7a077e --- /dev/null +++ b/rust/ql/src/change-notes/released/0.1.40.md @@ -0,0 +1,3 @@ +## 0.1.40 + +No user-facing changes. diff --git a/rust/ql/src/codeql-pack.release.yml b/rust/ql/src/codeql-pack.release.yml index 2ae59ee1c0ae..676d88550b91 100644 --- a/rust/ql/src/codeql-pack.release.yml +++ b/rust/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.1.39 +lastReleaseVersion: 0.1.40 diff --git a/rust/ql/src/qlpack.yml b/rust/ql/src/qlpack.yml index 74a67365b1da..a4a357bff44f 100644 --- a/rust/ql/src/qlpack.yml +++ b/rust/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/rust-queries -version: 0.1.40-dev +version: 0.1.40 groups: - rust - queries diff --git a/shared/concepts/CHANGELOG.md b/shared/concepts/CHANGELOG.md index 772a7934b5c2..9acabbed4e46 100644 --- a/shared/concepts/CHANGELOG.md +++ b/shared/concepts/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.29 + +No user-facing changes. + ## 0.0.28 No user-facing changes. diff --git a/shared/concepts/change-notes/released/0.0.29.md b/shared/concepts/change-notes/released/0.0.29.md new file mode 100644 index 000000000000..4428927c79d5 --- /dev/null +++ b/shared/concepts/change-notes/released/0.0.29.md @@ -0,0 +1,3 @@ +## 0.0.29 + +No user-facing changes. diff --git a/shared/concepts/codeql-pack.release.yml b/shared/concepts/codeql-pack.release.yml index 3462db7d348f..c81f18131208 100644 --- a/shared/concepts/codeql-pack.release.yml +++ b/shared/concepts/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.0.28 +lastReleaseVersion: 0.0.29 diff --git a/shared/concepts/qlpack.yml b/shared/concepts/qlpack.yml index c5f8b2831ab0..b00bbb9f887b 100644 --- a/shared/concepts/qlpack.yml +++ b/shared/concepts/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/concepts -version: 0.0.29-dev +version: 0.0.29 groups: shared library: true dependencies: diff --git a/shared/controlflow/CHANGELOG.md b/shared/controlflow/CHANGELOG.md index 1cd70884e88b..9abcc742814f 100644 --- a/shared/controlflow/CHANGELOG.md +++ b/shared/controlflow/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.39 + +No user-facing changes. + ## 2.0.38 No user-facing changes. diff --git a/shared/controlflow/change-notes/released/2.0.39.md b/shared/controlflow/change-notes/released/2.0.39.md new file mode 100644 index 000000000000..887d030df420 --- /dev/null +++ b/shared/controlflow/change-notes/released/2.0.39.md @@ -0,0 +1,3 @@ +## 2.0.39 + +No user-facing changes. diff --git a/shared/controlflow/codeql-pack.release.yml b/shared/controlflow/codeql-pack.release.yml index 4ec9eb0980cf..063a268e5f9f 100644 --- a/shared/controlflow/codeql-pack.release.yml +++ b/shared/controlflow/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 2.0.38 +lastReleaseVersion: 2.0.39 diff --git a/shared/controlflow/qlpack.yml b/shared/controlflow/qlpack.yml index e4358bf4e80d..d3cc00f776ed 100644 --- a/shared/controlflow/qlpack.yml +++ b/shared/controlflow/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/controlflow -version: 2.0.39-dev +version: 2.0.39 groups: shared library: true dependencies: diff --git a/shared/dataflow/CHANGELOG.md b/shared/dataflow/CHANGELOG.md index 957500952a2d..8b981f92142e 100644 --- a/shared/dataflow/CHANGELOG.md +++ b/shared/dataflow/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.1.11 + +No user-facing changes. + ## 2.1.10 No user-facing changes. diff --git a/shared/dataflow/change-notes/released/2.1.11.md b/shared/dataflow/change-notes/released/2.1.11.md new file mode 100644 index 000000000000..16b106c2f6c9 --- /dev/null +++ b/shared/dataflow/change-notes/released/2.1.11.md @@ -0,0 +1,3 @@ +## 2.1.11 + +No user-facing changes. diff --git a/shared/dataflow/codeql-pack.release.yml b/shared/dataflow/codeql-pack.release.yml index 66c655c4b892..768e745f3b43 100644 --- a/shared/dataflow/codeql-pack.release.yml +++ b/shared/dataflow/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 2.1.10 +lastReleaseVersion: 2.1.11 diff --git a/shared/dataflow/qlpack.yml b/shared/dataflow/qlpack.yml index a9aa3a70f451..3c53868dc3ce 100644 --- a/shared/dataflow/qlpack.yml +++ b/shared/dataflow/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/dataflow -version: 2.1.11-dev +version: 2.1.11 groups: shared library: true dependencies: diff --git a/shared/mad/CHANGELOG.md b/shared/mad/CHANGELOG.md index b1e3e366b72c..3a981e317c75 100644 --- a/shared/mad/CHANGELOG.md +++ b/shared/mad/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.55 + +No user-facing changes. + ## 1.0.54 No user-facing changes. diff --git a/shared/mad/change-notes/released/1.0.55.md b/shared/mad/change-notes/released/1.0.55.md new file mode 100644 index 000000000000..fd53dce64a9f --- /dev/null +++ b/shared/mad/change-notes/released/1.0.55.md @@ -0,0 +1,3 @@ +## 1.0.55 + +No user-facing changes. diff --git a/shared/mad/codeql-pack.release.yml b/shared/mad/codeql-pack.release.yml index c3c3b0f4418a..3c942a6b4ea3 100644 --- a/shared/mad/codeql-pack.release.yml +++ b/shared/mad/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.54 +lastReleaseVersion: 1.0.55 diff --git a/shared/mad/qlpack.yml b/shared/mad/qlpack.yml index a160bab98f55..72caf44fdad2 100644 --- a/shared/mad/qlpack.yml +++ b/shared/mad/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/mad -version: 1.0.55-dev +version: 1.0.55 groups: shared library: true dependencies: diff --git a/shared/namebinding/CHANGELOG.md b/shared/namebinding/CHANGELOG.md index d7831747b120..4ffbff1e0c4e 100644 --- a/shared/namebinding/CHANGELOG.md +++ b/shared/namebinding/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.4 + +No user-facing changes. + ## 0.0.3 No user-facing changes. diff --git a/shared/namebinding/change-notes/released/0.0.4.md b/shared/namebinding/change-notes/released/0.0.4.md new file mode 100644 index 000000000000..eefe286a4d88 --- /dev/null +++ b/shared/namebinding/change-notes/released/0.0.4.md @@ -0,0 +1,3 @@ +## 0.0.4 + +No user-facing changes. diff --git a/shared/namebinding/codeql-pack.release.yml b/shared/namebinding/codeql-pack.release.yml index a24b693d1e7a..ec411a674bcd 100644 --- a/shared/namebinding/codeql-pack.release.yml +++ b/shared/namebinding/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.0.3 +lastReleaseVersion: 0.0.4 diff --git a/shared/namebinding/qlpack.yml b/shared/namebinding/qlpack.yml index ecb08c95dda6..587b6de4f125 100644 --- a/shared/namebinding/qlpack.yml +++ b/shared/namebinding/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/namebinding -version: 0.0.4-dev +version: 0.0.4 groups: shared library: true dependencies: diff --git a/shared/quantum/CHANGELOG.md b/shared/quantum/CHANGELOG.md index 24dc81f3aa2c..66b8fa3444bb 100644 --- a/shared/quantum/CHANGELOG.md +++ b/shared/quantum/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.33 + +No user-facing changes. + ## 0.0.32 No user-facing changes. diff --git a/shared/quantum/change-notes/released/0.0.33.md b/shared/quantum/change-notes/released/0.0.33.md new file mode 100644 index 000000000000..0b46f1130fac --- /dev/null +++ b/shared/quantum/change-notes/released/0.0.33.md @@ -0,0 +1,3 @@ +## 0.0.33 + +No user-facing changes. diff --git a/shared/quantum/codeql-pack.release.yml b/shared/quantum/codeql-pack.release.yml index 714fcfc18281..dff9e7f6ea97 100644 --- a/shared/quantum/codeql-pack.release.yml +++ b/shared/quantum/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.0.32 +lastReleaseVersion: 0.0.33 diff --git a/shared/quantum/qlpack.yml b/shared/quantum/qlpack.yml index 6a7a0abe44a2..c26d83a0a25f 100644 --- a/shared/quantum/qlpack.yml +++ b/shared/quantum/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/quantum -version: 0.0.33-dev +version: 0.0.33 groups: shared library: true dependencies: diff --git a/shared/rangeanalysis/CHANGELOG.md b/shared/rangeanalysis/CHANGELOG.md index d3f599dc28ff..3a874c765ab7 100644 --- a/shared/rangeanalysis/CHANGELOG.md +++ b/shared/rangeanalysis/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.55 + +No user-facing changes. + ## 1.0.54 No user-facing changes. diff --git a/shared/rangeanalysis/change-notes/released/1.0.55.md b/shared/rangeanalysis/change-notes/released/1.0.55.md new file mode 100644 index 000000000000..fd53dce64a9f --- /dev/null +++ b/shared/rangeanalysis/change-notes/released/1.0.55.md @@ -0,0 +1,3 @@ +## 1.0.55 + +No user-facing changes. diff --git a/shared/rangeanalysis/codeql-pack.release.yml b/shared/rangeanalysis/codeql-pack.release.yml index c3c3b0f4418a..3c942a6b4ea3 100644 --- a/shared/rangeanalysis/codeql-pack.release.yml +++ b/shared/rangeanalysis/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.54 +lastReleaseVersion: 1.0.55 diff --git a/shared/rangeanalysis/qlpack.yml b/shared/rangeanalysis/qlpack.yml index d37c35c424e8..d8b0292bfdae 100644 --- a/shared/rangeanalysis/qlpack.yml +++ b/shared/rangeanalysis/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/rangeanalysis -version: 1.0.55-dev +version: 1.0.55 groups: shared library: true dependencies: diff --git a/shared/regex/CHANGELOG.md b/shared/regex/CHANGELOG.md index 4b02993bb99f..bbfe25191a71 100644 --- a/shared/regex/CHANGELOG.md +++ b/shared/regex/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.55 + +No user-facing changes. + ## 1.0.54 No user-facing changes. diff --git a/shared/regex/change-notes/released/1.0.55.md b/shared/regex/change-notes/released/1.0.55.md new file mode 100644 index 000000000000..fd53dce64a9f --- /dev/null +++ b/shared/regex/change-notes/released/1.0.55.md @@ -0,0 +1,3 @@ +## 1.0.55 + +No user-facing changes. diff --git a/shared/regex/codeql-pack.release.yml b/shared/regex/codeql-pack.release.yml index c3c3b0f4418a..3c942a6b4ea3 100644 --- a/shared/regex/codeql-pack.release.yml +++ b/shared/regex/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.54 +lastReleaseVersion: 1.0.55 diff --git a/shared/regex/qlpack.yml b/shared/regex/qlpack.yml index eb4f9f9bff24..187bb5f5af95 100644 --- a/shared/regex/qlpack.yml +++ b/shared/regex/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/regex -version: 1.0.55-dev +version: 1.0.55 groups: shared library: true dependencies: diff --git a/shared/ssa/CHANGELOG.md b/shared/ssa/CHANGELOG.md index 2bc90a791ab0..b742fb0a2601 100644 --- a/shared/ssa/CHANGELOG.md +++ b/shared/ssa/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.31 + +No user-facing changes. + ## 2.0.30 No user-facing changes. diff --git a/shared/ssa/change-notes/released/2.0.31.md b/shared/ssa/change-notes/released/2.0.31.md new file mode 100644 index 000000000000..b3cd05e3de4d --- /dev/null +++ b/shared/ssa/change-notes/released/2.0.31.md @@ -0,0 +1,3 @@ +## 2.0.31 + +No user-facing changes. diff --git a/shared/ssa/codeql-pack.release.yml b/shared/ssa/codeql-pack.release.yml index 19c804295854..783d47207cda 100644 --- a/shared/ssa/codeql-pack.release.yml +++ b/shared/ssa/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 2.0.30 +lastReleaseVersion: 2.0.31 diff --git a/shared/ssa/qlpack.yml b/shared/ssa/qlpack.yml index 30c04dc81b95..a66e5225abd0 100644 --- a/shared/ssa/qlpack.yml +++ b/shared/ssa/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/ssa -version: 2.0.31-dev +version: 2.0.31 groups: shared library: true dependencies: diff --git a/shared/threat-models/CHANGELOG.md b/shared/threat-models/CHANGELOG.md index d75ab9a9e2d7..3a3948e7bf27 100644 --- a/shared/threat-models/CHANGELOG.md +++ b/shared/threat-models/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.55 + +No user-facing changes. + ## 1.0.54 No user-facing changes. diff --git a/shared/threat-models/change-notes/released/1.0.55.md b/shared/threat-models/change-notes/released/1.0.55.md new file mode 100644 index 000000000000..fd53dce64a9f --- /dev/null +++ b/shared/threat-models/change-notes/released/1.0.55.md @@ -0,0 +1,3 @@ +## 1.0.55 + +No user-facing changes. diff --git a/shared/threat-models/codeql-pack.release.yml b/shared/threat-models/codeql-pack.release.yml index c3c3b0f4418a..3c942a6b4ea3 100644 --- a/shared/threat-models/codeql-pack.release.yml +++ b/shared/threat-models/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.54 +lastReleaseVersion: 1.0.55 diff --git a/shared/threat-models/qlpack.yml b/shared/threat-models/qlpack.yml index 785d18c741c0..93ab66cfc33f 100644 --- a/shared/threat-models/qlpack.yml +++ b/shared/threat-models/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/threat-models -version: 1.0.55-dev +version: 1.0.55 library: true groups: shared dataExtensions: diff --git a/shared/tutorial/CHANGELOG.md b/shared/tutorial/CHANGELOG.md index 34f695126455..267dbfeb562f 100644 --- a/shared/tutorial/CHANGELOG.md +++ b/shared/tutorial/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.55 + +No user-facing changes. + ## 1.0.54 No user-facing changes. diff --git a/shared/tutorial/change-notes/released/1.0.55.md b/shared/tutorial/change-notes/released/1.0.55.md new file mode 100644 index 000000000000..fd53dce64a9f --- /dev/null +++ b/shared/tutorial/change-notes/released/1.0.55.md @@ -0,0 +1,3 @@ +## 1.0.55 + +No user-facing changes. diff --git a/shared/tutorial/codeql-pack.release.yml b/shared/tutorial/codeql-pack.release.yml index c3c3b0f4418a..3c942a6b4ea3 100644 --- a/shared/tutorial/codeql-pack.release.yml +++ b/shared/tutorial/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.54 +lastReleaseVersion: 1.0.55 diff --git a/shared/tutorial/qlpack.yml b/shared/tutorial/qlpack.yml index d8d6ee9cdaa8..0a6f77df0754 100644 --- a/shared/tutorial/qlpack.yml +++ b/shared/tutorial/qlpack.yml @@ -1,7 +1,7 @@ name: codeql/tutorial description: Library for the CodeQL detective tutorials, helping new users learn to write CodeQL queries. -version: 1.0.55-dev +version: 1.0.55 groups: shared library: true warnOnImplicitThis: true diff --git a/shared/typeflow/CHANGELOG.md b/shared/typeflow/CHANGELOG.md index 906d6b96ebea..90dc2603d772 100644 --- a/shared/typeflow/CHANGELOG.md +++ b/shared/typeflow/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.55 + +No user-facing changes. + ## 1.0.54 No user-facing changes. diff --git a/shared/typeflow/change-notes/released/1.0.55.md b/shared/typeflow/change-notes/released/1.0.55.md new file mode 100644 index 000000000000..fd53dce64a9f --- /dev/null +++ b/shared/typeflow/change-notes/released/1.0.55.md @@ -0,0 +1,3 @@ +## 1.0.55 + +No user-facing changes. diff --git a/shared/typeflow/codeql-pack.release.yml b/shared/typeflow/codeql-pack.release.yml index c3c3b0f4418a..3c942a6b4ea3 100644 --- a/shared/typeflow/codeql-pack.release.yml +++ b/shared/typeflow/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.54 +lastReleaseVersion: 1.0.55 diff --git a/shared/typeflow/qlpack.yml b/shared/typeflow/qlpack.yml index e7d3ae0279be..deb074f38410 100644 --- a/shared/typeflow/qlpack.yml +++ b/shared/typeflow/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/typeflow -version: 1.0.55-dev +version: 1.0.55 groups: shared library: true dependencies: diff --git a/shared/typeinference/CHANGELOG.md b/shared/typeinference/CHANGELOG.md index 4916c26d385a..cd72576290a7 100644 --- a/shared/typeinference/CHANGELOG.md +++ b/shared/typeinference/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.36 + +No user-facing changes. + ## 0.0.35 No user-facing changes. diff --git a/shared/typeinference/change-notes/released/0.0.36.md b/shared/typeinference/change-notes/released/0.0.36.md new file mode 100644 index 000000000000..14c56d238da9 --- /dev/null +++ b/shared/typeinference/change-notes/released/0.0.36.md @@ -0,0 +1,3 @@ +## 0.0.36 + +No user-facing changes. diff --git a/shared/typeinference/codeql-pack.release.yml b/shared/typeinference/codeql-pack.release.yml index 143c97892032..b6df3a024ee6 100644 --- a/shared/typeinference/codeql-pack.release.yml +++ b/shared/typeinference/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.0.35 +lastReleaseVersion: 0.0.36 diff --git a/shared/typeinference/qlpack.yml b/shared/typeinference/qlpack.yml index 4d48222f41aa..b2bef17c8c5a 100644 --- a/shared/typeinference/qlpack.yml +++ b/shared/typeinference/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/typeinference -version: 0.0.36-dev +version: 0.0.36 groups: shared library: true dependencies: diff --git a/shared/typetracking/CHANGELOG.md b/shared/typetracking/CHANGELOG.md index a0ddc0dabdb0..8226f0232aff 100644 --- a/shared/typetracking/CHANGELOG.md +++ b/shared/typetracking/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.39 + +No user-facing changes. + ## 2.0.38 No user-facing changes. diff --git a/shared/typetracking/change-notes/released/2.0.39.md b/shared/typetracking/change-notes/released/2.0.39.md new file mode 100644 index 000000000000..887d030df420 --- /dev/null +++ b/shared/typetracking/change-notes/released/2.0.39.md @@ -0,0 +1,3 @@ +## 2.0.39 + +No user-facing changes. diff --git a/shared/typetracking/codeql-pack.release.yml b/shared/typetracking/codeql-pack.release.yml index 4ec9eb0980cf..063a268e5f9f 100644 --- a/shared/typetracking/codeql-pack.release.yml +++ b/shared/typetracking/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 2.0.38 +lastReleaseVersion: 2.0.39 diff --git a/shared/typetracking/qlpack.yml b/shared/typetracking/qlpack.yml index e9fb4f6c0447..b4c98d2ed55b 100644 --- a/shared/typetracking/qlpack.yml +++ b/shared/typetracking/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/typetracking -version: 2.0.39-dev +version: 2.0.39 groups: shared library: true dependencies: diff --git a/shared/typos/CHANGELOG.md b/shared/typos/CHANGELOG.md index 1f1760051700..2cad9992afb8 100644 --- a/shared/typos/CHANGELOG.md +++ b/shared/typos/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.55 + +No user-facing changes. + ## 1.0.54 No user-facing changes. diff --git a/shared/typos/change-notes/released/1.0.55.md b/shared/typos/change-notes/released/1.0.55.md new file mode 100644 index 000000000000..fd53dce64a9f --- /dev/null +++ b/shared/typos/change-notes/released/1.0.55.md @@ -0,0 +1,3 @@ +## 1.0.55 + +No user-facing changes. diff --git a/shared/typos/codeql-pack.release.yml b/shared/typos/codeql-pack.release.yml index c3c3b0f4418a..3c942a6b4ea3 100644 --- a/shared/typos/codeql-pack.release.yml +++ b/shared/typos/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.54 +lastReleaseVersion: 1.0.55 diff --git a/shared/typos/qlpack.yml b/shared/typos/qlpack.yml index 9218a86a215b..7f17b05eb5dc 100644 --- a/shared/typos/qlpack.yml +++ b/shared/typos/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/typos -version: 1.0.55-dev +version: 1.0.55 groups: shared library: true warnOnImplicitThis: true diff --git a/shared/util/CHANGELOG.md b/shared/util/CHANGELOG.md index 587c0a00aa15..55fa9e7730b5 100644 --- a/shared/util/CHANGELOG.md +++ b/shared/util/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.42 + +No user-facing changes. + ## 2.0.41 No user-facing changes. diff --git a/shared/util/change-notes/released/2.0.42.md b/shared/util/change-notes/released/2.0.42.md new file mode 100644 index 000000000000..85ba02702b9f --- /dev/null +++ b/shared/util/change-notes/released/2.0.42.md @@ -0,0 +1,3 @@ +## 2.0.42 + +No user-facing changes. diff --git a/shared/util/codeql-pack.release.yml b/shared/util/codeql-pack.release.yml index dcd61b02de59..000a2d0de2d1 100644 --- a/shared/util/codeql-pack.release.yml +++ b/shared/util/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 2.0.41 +lastReleaseVersion: 2.0.42 diff --git a/shared/util/qlpack.yml b/shared/util/qlpack.yml index 0a58c95a984d..85d435b88027 100644 --- a/shared/util/qlpack.yml +++ b/shared/util/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/util -version: 2.0.42-dev +version: 2.0.42 groups: shared library: true dependencies: null diff --git a/shared/xml/CHANGELOG.md b/shared/xml/CHANGELOG.md index 15640e5c1cbd..0901e77ebb22 100644 --- a/shared/xml/CHANGELOG.md +++ b/shared/xml/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.55 + +No user-facing changes. + ## 1.0.54 No user-facing changes. diff --git a/shared/xml/change-notes/released/1.0.55.md b/shared/xml/change-notes/released/1.0.55.md new file mode 100644 index 000000000000..fd53dce64a9f --- /dev/null +++ b/shared/xml/change-notes/released/1.0.55.md @@ -0,0 +1,3 @@ +## 1.0.55 + +No user-facing changes. diff --git a/shared/xml/codeql-pack.release.yml b/shared/xml/codeql-pack.release.yml index c3c3b0f4418a..3c942a6b4ea3 100644 --- a/shared/xml/codeql-pack.release.yml +++ b/shared/xml/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.54 +lastReleaseVersion: 1.0.55 diff --git a/shared/xml/qlpack.yml b/shared/xml/qlpack.yml index d1c821414117..2e4d61f11abe 100644 --- a/shared/xml/qlpack.yml +++ b/shared/xml/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/xml -version: 1.0.55-dev +version: 1.0.55 groups: shared library: true dependencies: diff --git a/shared/yaml/CHANGELOG.md b/shared/yaml/CHANGELOG.md index e45ca7c51319..9ff01d7f1b17 100644 --- a/shared/yaml/CHANGELOG.md +++ b/shared/yaml/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.55 + +No user-facing changes. + ## 1.0.54 No user-facing changes. diff --git a/shared/yaml/change-notes/released/1.0.55.md b/shared/yaml/change-notes/released/1.0.55.md new file mode 100644 index 000000000000..fd53dce64a9f --- /dev/null +++ b/shared/yaml/change-notes/released/1.0.55.md @@ -0,0 +1,3 @@ +## 1.0.55 + +No user-facing changes. diff --git a/shared/yaml/codeql-pack.release.yml b/shared/yaml/codeql-pack.release.yml index c3c3b0f4418a..3c942a6b4ea3 100644 --- a/shared/yaml/codeql-pack.release.yml +++ b/shared/yaml/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.54 +lastReleaseVersion: 1.0.55 diff --git a/shared/yaml/qlpack.yml b/shared/yaml/qlpack.yml index 272b9f20f8fc..5c5a36fa69f3 100644 --- a/shared/yaml/qlpack.yml +++ b/shared/yaml/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/yaml -version: 1.0.55-dev +version: 1.0.55 groups: shared library: true warnOnImplicitThis: true diff --git a/swift/ql/lib/CHANGELOG.md b/swift/ql/lib/CHANGELOG.md index 168e31e76c18..ffad5ee2398a 100644 --- a/swift/ql/lib/CHANGELOG.md +++ b/swift/ql/lib/CHANGELOG.md @@ -1,3 +1,7 @@ +## 6.8.1 + +No user-facing changes. + ## 6.8.0 ### Major Analysis Improvements diff --git a/swift/ql/lib/change-notes/released/6.8.1.md b/swift/ql/lib/change-notes/released/6.8.1.md new file mode 100644 index 000000000000..eb2ce653fc0f --- /dev/null +++ b/swift/ql/lib/change-notes/released/6.8.1.md @@ -0,0 +1,3 @@ +## 6.8.1 + +No user-facing changes. diff --git a/swift/ql/lib/codeql-pack.release.yml b/swift/ql/lib/codeql-pack.release.yml index 78131e1dceb7..49874c2924ed 100644 --- a/swift/ql/lib/codeql-pack.release.yml +++ b/swift/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 6.8.0 +lastReleaseVersion: 6.8.1 diff --git a/swift/ql/lib/qlpack.yml b/swift/ql/lib/qlpack.yml index 46bbe03047d3..856752875cd8 100644 --- a/swift/ql/lib/qlpack.yml +++ b/swift/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/swift-all -version: 6.8.1-dev +version: 6.8.1 groups: swift extractor: swift dbscheme: swift.dbscheme diff --git a/swift/ql/src/CHANGELOG.md b/swift/ql/src/CHANGELOG.md index 0063b69f12b3..826ee7e9d4e9 100644 --- a/swift/ql/src/CHANGELOG.md +++ b/swift/ql/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.3.8 + +No user-facing changes. + ## 1.3.7 No user-facing changes. diff --git a/swift/ql/src/change-notes/released/1.3.8.md b/swift/ql/src/change-notes/released/1.3.8.md new file mode 100644 index 000000000000..c7f5b27e47ec --- /dev/null +++ b/swift/ql/src/change-notes/released/1.3.8.md @@ -0,0 +1,3 @@ +## 1.3.8 + +No user-facing changes. diff --git a/swift/ql/src/codeql-pack.release.yml b/swift/ql/src/codeql-pack.release.yml index 2f4b67be43f7..898725a6deb4 100644 --- a/swift/ql/src/codeql-pack.release.yml +++ b/swift/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.3.7 +lastReleaseVersion: 1.3.8 diff --git a/swift/ql/src/qlpack.yml b/swift/ql/src/qlpack.yml index a738635a8d07..91be0e594012 100644 --- a/swift/ql/src/qlpack.yml +++ b/swift/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/swift-queries -version: 1.3.8-dev +version: 1.3.8 groups: - swift - queries From 1740d1700ff557f92b31295ad325ffa916b3fea2 Mon Sep 17 00:00:00 2001 From: Henry Mercer Date: Thu, 6 Aug 2026 11:48:00 +0100 Subject: [PATCH 187/188] JS: Fix minor wording issues in changelog --- javascript/ql/lib/CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/lib/CHANGELOG.md b/javascript/ql/lib/CHANGELOG.md index 0f509e829b05..6ac06fe87b99 100644 --- a/javascript/ql/lib/CHANGELOG.md +++ b/javascript/ql/lib/CHANGELOG.md @@ -2,14 +2,14 @@ ### Major Analysis Improvements -* It is now possible for custom models to refer to specific files in the codebase, using a package name of form `file:`. The model should describe the public exports +* It is now possible for custom models to refer to specific files in the codebase, using a package name of the form `file:`. The model should describe the public exports of that file. This can be used to derive sources and sinks in code that imports the file, but note that sources and sinks will not generally be placed within the file itself. For example, a source model `['file:lib/service.js', 'Member[getData].ReturnValue', 'remote']` could identify `require('../lib/service').getData()` as a source. ### Minor Analysis Improvements * JavaScript security queries using the `response` threat model now track promise-wrapped client response data into promise fulfillment values. This may improve results for queries such as `js/xss` when response data is consumed through `.then(...)` chains. -* The route object returned by Vue Router's `useRoute()` Composition API is now recognized as a client-side remote flow source, covering its `query`, `params`, `path`, `fullPath`, and `hash` members. These members are additionally reported under the corresponding `browser-url-query`, `browser-url-path`, and `browser-url-fragment` threat models. +* The route object returned by Vue Router's `useRoute()` Composition API is now recognized as a client-side remote flow source, covering its `query`, `params`, `path`, `fullPath`, and `hash` members. These members are additionally reported under the `browser-url-query`, `browser-url-path`, and `browser-url-fragment` threat models. * Added flow models for Vue's `ref`, `shallowRef`, `toRef`, `reactive`, and `computed` Composition API helpers. * Added support for treating declared `inputs` properties in Sails Action2 controller files as remote flow sources. This may improve results for security queries such as `js/path-injection`. From 8887b2ec68c37b68956feba65e1b2402b4afb3df Mon Sep 17 00:00:00 2001 From: Henry Mercer Date: Thu, 6 Aug 2026 11:53:51 +0100 Subject: [PATCH 188/188] Ruby: Tweak changelog note for readability --- ruby/ql/lib/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby/ql/lib/CHANGELOG.md b/ruby/ql/lib/CHANGELOG.md index 146fdb46d43c..55c64cb527cb 100644 --- a/ruby/ql/lib/CHANGELOG.md +++ b/ruby/ql/lib/CHANGELOG.md @@ -2,7 +2,7 @@ ### Minor Analysis Improvements -* Removed library input to vendored gems from the set of taint sources. This should reduce false positives for `rb/polynomial-redos`, `rb/regex/badly-anchored-regexp`, `rb/unsafe-code-construction`, `rb/html-constructed-from-input`, and `rb/shell-command-constructed-from-input` whenever vendoring is used. +* Parameters of methods exported by vendored gems are no longer treated as flow sources, since such methods are only called from within the codebase. This should reduce false positives for `rb/polynomial-redos`, `rb/regex/badly-anchored-regexp`, `rb/unsafe-code-construction`, `rb/html-constructed-from-input`, and `rb/shell-command-constructed-from-input` in codebases that vendor their dependencies. ## 6.0.2