From c8736e8a3da54a65adaf8e837e18b025c65da608 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Mon, 4 Nov 2024 08:45:54 +0100 Subject: [PATCH] Rust: Auto-generate `CfgNodes.qll` --- misc/codegen/codegen.py | 2 + misc/codegen/generators/qlgen.py | 24 + misc/codegen/lib/ql.py | 17 + misc/codegen/lib/schema.py | 1 + misc/codegen/lib/schemadefs.py | 3 +- misc/codegen/loaders/schemaloader.py | 1 + misc/codegen/templates/ql_cfg_nodes.mustache | 199 + rust/codegen.conf | 1 + rust/ql/.generated.list | 1 + rust/ql/.gitattributes | 1 + .../lib/codeql/rust/controlflow/CfgNodes.qll | 6 +- .../controlflow/internal/CfgConsistency.qll | 23 + .../rust/controlflow/internal/CfgNodes.qll | 116 + .../internal/generated/CfgNodes.qll | 3657 +++++++++++++++++ .../rust/elements/internal/AstNodeImpl.qll | 33 + .../lib/codeql/rust/internal/CachedStages.qll | 3 + .../diagnostics/CfgConsistencyCounts.expected | 1 + rust/schema/annotations.py | 106 +- 18 files changed, 4139 insertions(+), 56 deletions(-) create mode 100644 misc/codegen/templates/ql_cfg_nodes.mustache create mode 100644 rust/ql/lib/codeql/rust/controlflow/internal/CfgNodes.qll create mode 100644 rust/ql/lib/codeql/rust/controlflow/internal/generated/CfgNodes.qll diff --git a/misc/codegen/codegen.py b/misc/codegen/codegen.py index acc8e59bba5..ce991b6f0d4 100755 --- a/misc/codegen/codegen.py +++ b/misc/codegen/codegen.py @@ -64,6 +64,8 @@ def _parse_args() -> argparse.Namespace: help="registry file containing information about checked-in generated code. A .gitattributes" "file is generated besides it to mark those files with linguist-generated=true. Must" "be in a directory containing all generated code."), + p.add_argument("--ql-cfg-output", + help="output directory for QL CFG layer (optional)."), ] p.add_argument("--script-name", help="script name to put in header comments of generated files. By default, the path of this " diff --git a/misc/codegen/generators/qlgen.py b/misc/codegen/generators/qlgen.py index c5e7153489b..f1a68f6bc01 100755 --- a/misc/codegen/generators/qlgen.py +++ b/misc/codegen/generators/qlgen.py @@ -160,6 +160,8 @@ def get_ql_class(cls: schema.Class, lookup: typing.Dict[str, schema.Class]) -> q prop = get_ql_property(cls, p, lookup, prev_child) if prop.is_child: prev_child = prop.singular + if prop.type in lookup and lookup[prop.type].cfg: + prop.cfg = True properties.append(prop) return ql.Class( name=cls.name, @@ -171,6 +173,16 @@ def get_ql_class(cls: schema.Class, lookup: typing.Dict[str, schema.Class]) -> q doc=cls.doc, hideable="ql_hideable" in cls.pragmas, internal="ql_internal" in cls.pragmas, + cfg=cls.cfg, + ) + + +def get_ql_cfg_class(cls: schema.Class, lookup: typing.Dict[str, ql.Class]) -> ql.CfgClass: + return ql.CfgClass( + name=cls.name, + bases=[base for base in cls.bases if lookup[base.base].cfg], + properties=cls.properties, + doc=cls.doc ) @@ -361,6 +373,7 @@ def generate(opts, renderer): input = opts.schema out = opts.ql_output stub_out = opts.ql_stub_output + cfg_out = opts.ql_cfg_output test_out = opts.ql_test_output missing_test_source_filename = "MISSING_SOURCE.txt" include_file = stub_out.with_suffix(".qll") @@ -385,6 +398,7 @@ def generate(opts, renderer): imports = {} imports_impl = {} classes_used_by = {} + cfg_classes = [] generated_import_prefix = get_import(out, opts.root_dir) registry = opts.generated_registry or pathlib.Path( os.path.commonpath((out, stub_out, test_out)), ".generated.list") @@ -402,6 +416,8 @@ def generate(opts, renderer): imports[c.name] = path path_impl = get_import(stub_out / c.dir / "internal" / c.name, opts.root_dir) imports_impl[c.name + "Impl"] = path_impl + "Impl" + if c.cfg: + cfg_classes.append(get_ql_cfg_class(c, classes)) for c in classes.values(): qll = out / c.path.with_suffix(".qll") @@ -411,6 +427,14 @@ def generate(opts, renderer): c.import_prefix = generated_import_prefix renderer.render(c, qll) + if cfg_out: + cfg_classes_val = ql.CfgClasses( + include_file_import=get_import(include_file, opts.root_dir), + classes=cfg_classes + ) + cfg_qll = cfg_out / "CfgNodes.qll" + renderer.render(cfg_classes_val, cfg_qll) + for c in data.classes.values(): path = _get_path(c) path_impl = _get_path_impl(c) diff --git a/misc/codegen/lib/ql.py b/misc/codegen/lib/ql.py index 1920a813e20..1182c7f5dc1 100644 --- a/misc/codegen/lib/ql.py +++ b/misc/codegen/lib/ql.py @@ -45,6 +45,7 @@ class Property: synth: bool = False type_is_hideable: bool = False internal: bool = False + cfg: bool = False def __post_init__(self): if self.tableparams: @@ -110,6 +111,7 @@ class Class: internal: bool = False doc: List[str] = field(default_factory=list) hideable: bool = False + cfg: bool = False def __post_init__(self): def get_bases(bases): return [Base(str(b), str(prev)) for b, prev in zip(bases, itertools.chain([""], bases))] @@ -333,3 +335,18 @@ class Synth: cls: "Synth.FinalClass" import_prefix: str + + +@dataclass +class CfgClass: + name: str + bases: List[Base] = field(default_factory=list) + properties: List[Property] = field(default_factory=list) + doc: List[str] = field(default_factory=list) + + +@dataclass +class CfgClasses: + template: ClassVar = 'ql_cfg_nodes' + include_file_import: Optional[str] = None + classes: List[CfgClass] = field(default_factory=list) diff --git a/misc/codegen/lib/schema.py b/misc/codegen/lib/schema.py index c5c3dc810b6..23f1aea2ba4 100644 --- a/misc/codegen/lib/schema.py +++ b/misc/codegen/lib/schema.py @@ -94,6 +94,7 @@ class Class: properties: List[Property] = field(default_factory=list) pragmas: List[str] | Dict[str, object] = field(default_factory=dict) doc: List[str] = field(default_factory=list) + cfg: bool = False def __post_init__(self): if not isinstance(self.pragmas, dict): diff --git a/misc/codegen/lib/schemadefs.py b/misc/codegen/lib/schemadefs.py index 997b85b4ca6..32d3a6b85ae 100644 --- a/misc/codegen/lib/schemadefs.py +++ b/misc/codegen/lib/schemadefs.py @@ -279,7 +279,7 @@ _ = _PropertyAnnotation() drop = object() -def annotate(annotated_cls: type, add_bases: _Iterable[type] | None = None, replace_bases: _Dict[type, type] | None = None) -> _Callable[[type], _PropertyAnnotation]: +def annotate(annotated_cls: type, add_bases: _Iterable[type] | None = None, replace_bases: _Dict[type, type] | None = None, cfg: bool = False) -> _Callable[[type], _PropertyAnnotation]: """ Add or modify schema annotations after a class has been defined previously. @@ -298,6 +298,7 @@ def annotate(annotated_cls: type, add_bases: _Iterable[type] | None = None, repl annotated_cls.__bases__ = tuple(replace_bases.get(b, b) for b in annotated_cls.__bases__) if add_bases: annotated_cls.__bases__ += tuple(add_bases) + annotated_cls.__cfg__ = cfg for a in dir(cls): if a.startswith(_schema.inheritable_pragma_prefix): setattr(annotated_cls, a, getattr(cls, a)) diff --git a/misc/codegen/loaders/schemaloader.py b/misc/codegen/loaders/schemaloader.py index 069e3b65474..dd1edee1de0 100644 --- a/misc/codegen/loaders/schemaloader.py +++ b/misc/codegen/loaders/schemaloader.py @@ -53,6 +53,7 @@ def _get_class(cls: type) -> schema.Class: bases=[b.__name__ for b in cls.__bases__ if b is not object], derived=derived, pragmas=pragmas, + cfg=cls.__cfg__ if hasattr(cls, "__cfg__") else False, # in the following we don't use `getattr` to avoid inheriting properties=[ a | _PropertyNamer(n) diff --git a/misc/codegen/templates/ql_cfg_nodes.mustache b/misc/codegen/templates/ql_cfg_nodes.mustache new file mode 100644 index 00000000000..fd969b1c59b --- /dev/null +++ b/misc/codegen/templates/ql_cfg_nodes.mustache @@ -0,0 +1,199 @@ +// generated by {{generator}}, do not edit +/** + * This module provides generated wrappers around the `CfgNode` type. + * + * INTERNAL: Do not import directly. + */ + +private import codeql.util.Location +private import codeql.util.Unit +private import {{include_file_import}} + +/** Provides the input to `MakeCfgNodes` */ +signature module InputSig { + class CfgNode { + AstNode getAstNode(); + + string toString(); + + Loc getLocation(); + } + + AstNode getDesugared(AstNode n); +} + +/** + * Given a `CfgNode` implementation, provides the module `Nodes` that + * contains wrappers around `CfgNode` for relevant classes. + */ +module MakeCfgNodes Input> { + private import Input + + final private class AstNodeFinal = AstNode; + + final private class CfgNodeFinal = CfgNode; + + /** + * INTERNAL: Do not expose. + */ + abstract class ParentAstNode extends AstNodeFinal { + /** + * Holds if `child` is a (possibly nested) child of this AST node + * for which we would like to find a matching CFG child. + */ + abstract predicate relevantChild(AstNode child); + } + + /** + * INTERNAL: Do not expose. + */ + abstract class ChildMapping extends Unit { + /** + * Holds if `child` is a (possibly nested) child of AST node `parent` + * for which we would like to find a matching CFG child. + */ + final predicate relevantChild(AstNode parent, AstNode child) { + parent.(ParentAstNode).relevantChild(child) + } + + /** + * Holds if there is a control-flow path from `cfn` to `cfnChild`, where `cfn` + * is a control-flow node for this AST node, and `cfnChild` is a control-flow + * node for `child`. + * + * This predicate should be implemented at the place where `MakeCfgNodes` is + * invoked. Ideally, `MakeCfgNodes` should be a higher-order parameterized + * module, but since that is currently not supported, we achieve the "callback" + * effect using this `abstract` class instead. + */ + cached + abstract predicate hasCfgChild(AstNode parent, AstNode child, CfgNode cfn, CfgNode cfnChild); + } + + /** Provides sub classes of `CfgNode`. */ + module Nodes { + {{#classes}} + private final class Parent{{name}} extends ParentAstNode, {{name}} { + override predicate relevantChild(AstNode child) { + none() + {{#properties}} + {{#cfg}} + or + child = this.{{getter}}({{#is_indexed}}_{{/is_indexed}}) + {{/cfg}} + {{/properties}} + } + } + + /** + {{#doc}} + * {{.}} + {{/doc}} + */ + final class {{name}}CfgNode extends CfgNodeFinal{{#bases}}, {{.}}CfgNode{{/bases}} { + private {{name}} node; + + {{name}}CfgNode() { + node = this.getAstNode() + } + + /** Gets the underlying `{{name}}`. */ + {{name}} get{{name}}() { result = node } + + {{#properties}} + /** + * {{>ql_property_doc}} * + {{#description}} + * {{.}} + {{/description}} + {{#internal}} + * INTERNAL: Do not use. + {{/internal}} + */ + {{type}}{{#cfg}}CfgNode{{/cfg}} {{getter}}({{#is_indexed}}int index{{/is_indexed}}) { + {{#cfg}} + any(ChildMapping mapping).hasCfgChild(node, node.{{getter}}({{#is_indexed}}index{{/is_indexed}}), this, result) + {{/cfg}} + {{^cfg}} + {{^is_predicate}}result = {{/is_predicate}}node.{{getter}}({{#is_indexed}}index{{/is_indexed}}) + {{/cfg}} + } + + {{#is_optional}} + /** + * Holds if `{{getter}}({{#is_repeated}}index{{/is_repeated}})` exists. + {{#internal}} + * INTERNAL: Do not use. + {{/internal}} + */ + predicate has{{singular}}({{#is_repeated}}int index{{/is_repeated}}) { + exists(this.{{getter}}({{#is_repeated}}index{{/is_repeated}})) + } + {{/is_optional}} + {{#is_indexed}} + + /** + * Gets any of the {{doc_plural}}. + {{#internal}} + * INTERNAL: Do not use. + {{/internal}} + */ + {{type}}{{#cfg}}CfgNode{{/cfg}} {{indefinite_getter}}() { + result = this.{{getter}}(_) + } + {{^is_optional}} + + /** + * Gets the number of {{doc_plural}}. + {{#internal}} + * INTERNAL: Do not use. + {{/internal}} + */ + int getNumberOf{{plural}}() { + result = count(int i | exists(this.{{getter}}(i))) + } + {{/is_optional}} + {{/is_indexed}} + {{#is_unordered}} + /** + * Gets the number of {{doc_plural}}. + {{#internal}} + * INTERNAL: Do not use. + {{/internal}} + */ + int getNumberOf{{plural}}() { + result = count(this.{{getter}}()) + } + {{/is_unordered}} + {{/properties}} + } + {{/classes}} + } + + module Consistency { + private predicate hasCfgNode(AstNode astNode) { + astNode = any(CfgNode cfgNode).getAstNode() + } + + query predicate missingCfgChild(CfgNode parent, string pred, int i, AstNode child) { + none() + {{#classes}} + {{#properties}} + {{#cfg}} + or + pred = "{{getter}}" and + parent = any(Nodes::{{name}}CfgNode cfgNode, {{name}} astNode | + astNode = cfgNode.get{{name}}() and + child = getDesugared(astNode.{{getter}}({{#is_indexed}}i{{/is_indexed}})) + {{^is_indexed}}and i = -1{{/is_indexed}} and + hasCfgNode(child) and + not child = cfgNode.{{getter}}({{#is_indexed}}i{{/is_indexed}}).getAstNode() + | + cfgNode + ) + {{/cfg}} + {{/properties}} + {{/classes}} + } + } +} \ No newline at end of file diff --git a/rust/codegen.conf b/rust/codegen.conf index 29b6edc8985..d40fada446b 100644 --- a/rust/codegen.conf +++ b/rust/codegen.conf @@ -4,6 +4,7 @@ --dbscheme=ql/lib/rust.dbscheme --ql-output=ql/lib/codeql/rust/elements/internal/generated --ql-stub-output=ql/lib/codeql/rust/elements +--ql-cfg-output=ql/lib/codeql/rust/controlflow/internal/generated --ql-test-output=ql/test/extractor-tests/generated --rust-output=extractor/src/generated --script-name=codegen diff --git a/rust/ql/.generated.list b/rust/ql/.generated.list index ca25e0533fc..11980eb55df 100644 --- a/rust/ql/.generated.list +++ b/rust/ql/.generated.list @@ -1,3 +1,4 @@ +lib/codeql/rust/controlflow/internal/generated/CfgNodes.qll 55c20303ad50f17ddea728eb840304e0a634821adb7b13471a9ce55b71ed3886 13509512ffb59a9634ed2dc3c4969af26d5ba2d1502d98dc0c107a99392ce892 lib/codeql/rust/elements/Abi.qll 4c973d28b6d628f5959d1f1cc793704572fd0acaae9a97dfce82ff9d73f73476 250f68350180af080f904cd34cb2af481c5c688dc93edf7365fd0ae99855e893 lib/codeql/rust/elements/ArgList.qll 661f5100f5d3ef8351452d9058b663a2a5c720eea8cf11bedd628969741486a2 28e424aac01a90fb58cd6f9f83c7e4cf379eea39e636bc0ba07efc818be71c71 lib/codeql/rust/elements/ArrayExpr.qll a3e6e122632f4011644ec31b37f88b32fe3f2b7e388e7e878a6883309937049f 12ccb5873d95c433da5606fd371d182ef2f71b78d0c53c2d6dec10fa45852bdc diff --git a/rust/ql/.gitattributes b/rust/ql/.gitattributes index a532f142ec9..68b893ba9c7 100644 --- a/rust/ql/.gitattributes +++ b/rust/ql/.gitattributes @@ -1,5 +1,6 @@ /.generated.list linguist-generated /.gitattributes linguist-generated +/lib/codeql/rust/controlflow/internal/generated/CfgNodes.qll linguist-generated /lib/codeql/rust/elements/Abi.qll linguist-generated /lib/codeql/rust/elements/ArgList.qll linguist-generated /lib/codeql/rust/elements/ArrayExpr.qll linguist-generated diff --git a/rust/ql/lib/codeql/rust/controlflow/CfgNodes.qll b/rust/ql/lib/codeql/rust/controlflow/CfgNodes.qll index 4a51506dbc0..1a7c7e212b9 100644 --- a/rust/ql/lib/codeql/rust/controlflow/CfgNodes.qll +++ b/rust/ql/lib/codeql/rust/controlflow/CfgNodes.qll @@ -5,7 +5,9 @@ private import rust private import ControlFlowGraph -private import internal.ControlFlowGraphImpl +private import internal.ControlFlowGraphImpl as CfgImpl +private import internal.CfgNodes +import Nodes /** A CFG node that corresponds to an element in the AST. */ class AstCfgNode extends CfgNode { @@ -57,4 +59,4 @@ class MethodCallExprCfgNode extends ExprCfgNode { MethodCallExpr getMethodCallExpr() { result = node } } -final class ExitCfgNode = ExitNode; +final class ExitCfgNode = CfgImpl::ExitNode; diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/CfgConsistency.qll b/rust/ql/lib/codeql/rust/controlflow/internal/CfgConsistency.qll index 2722661494d..0f178726ad8 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/CfgConsistency.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/CfgConsistency.qll @@ -8,6 +8,8 @@ import Consistency private import codeql.rust.controlflow.ControlFlowGraph private import codeql.rust.controlflow.internal.ControlFlowGraphImpl as CfgImpl private import codeql.rust.controlflow.internal.Completion +private import codeql.rust.controlflow.internal.CfgNodes::Consistency as CfgNodes +private import codeql.rust.Diagnostics private predicate nonPostOrderExpr(Expr e) { not e instanceof LetExpr and @@ -54,6 +56,24 @@ query predicate deadEnd(CfgImpl::Node node) { not letElsePanic(node.getAstNode()) } +pragma[nomagic] +private predicate successfullyExtractedFile(File f) { + not exists(ExtractionWarning ee | ee.getLocation().getFile() = f) +} + +query predicate missingCfgChild(CfgNode parent, string pred, int i, AstNode child) { + CfgNodes::missingCfgChild(parent, pred, i, child) and + successfullyExtractedFile(child.getLocation().getFile()) and + not exists(AstNode last, CfgImpl::Completion c | CfgImpl::last(child, last, c) | + // In for example `if (a && true) ...` there is no RHS CFG node going into the + // `[false] a && true` operation + strictcount(ConditionalSuccessor cs | exists(last.getACfgNode().getASuccessor(cs)) | cs) = 1 + or + // In for example `x && return`, there is no RHS CFG node going into the `&&` operation + not c instanceof CfgImpl::NormalCompletion + ) +} + /** * Gets counts of control flow graph inconsistencies of each type. */ @@ -99,4 +119,7 @@ int getCfgInconsistencyCounts(string type) { or type = "Non-PostOrderTree Expr node" and result = count(Expr e | nonPostOrderExpr(e) | e) + or + type = "Missing CFG child" and + result = count(CfgNode parent, string pred, int child | missingCfgChild(parent, pred, child, _)) } diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/CfgNodes.qll b/rust/ql/lib/codeql/rust/controlflow/internal/CfgNodes.qll new file mode 100644 index 00000000000..3f5b3c0e483 --- /dev/null +++ b/rust/ql/lib/codeql/rust/controlflow/internal/CfgNodes.qll @@ -0,0 +1,116 @@ +private import rust +private import codeql.rust.controlflow.internal.generated.CfgNodes +private import codeql.rust.controlflow.internal.ControlFlowGraphImpl as CfgImpl +private import codeql.rust.controlflow.ControlFlowGraph +private import codeql.rust.controlflow.BasicBlocks +private import codeql.rust.controlflow.CfgNodes +private import codeql.rust.internal.CachedStages + +private predicate isPostOrder(AstNode n) { + n instanceof Expr and + not n instanceof LetExpr + or + n instanceof OrPat + or + n instanceof IdentPat + or + n instanceof LiteralPat + or + n instanceof Param +} + +private module CfgNodesInput implements InputSig { + private import codeql.rust.controlflow.ControlFlowGraph as Cfg + + class CfgNode = AstCfgNode; + + private AstNode desugar(AstNode n) { + result = n.(ParenPat).getPat() + or + result = n.(ParenExpr).getExpr() + } + + AstNode getDesugared(AstNode n) { + result = getDesugared(desugar(n)) + or + not exists(desugar(n)) and + result = n + } +} + +import MakeCfgNodes + +private class ChildMappingImpl extends ChildMapping { + /** Gets a CFG node for `child`, where `child` is a relevant child node of `parent`. */ + private CfgNode getRelevantChildCfgNode(AstNode parent, AstNode child) { + this.relevantChild(parent, child) and + result = CfgNodesInput::getDesugared(child).getACfgNode() + } + + pragma[nomagic] + private BasicBlock getARelevantBasicBlock(AstNode parent) { + result.getANode().getAstNode() = parent or + result.getANode() = this.getRelevantChildCfgNode(parent, _) + } + + /** + * Holds if CFG node `cfnChild` can reach basic block `bb`, without going + * through an intermediate block that contains a CFG node for `parent` or + * any other relevant child of `parent`. + */ + pragma[nomagic] + predicate childNodeReachesBasicBlock( + AstNode parent, AstNode child, CfgNode cfnChild, BasicBlock bb + ) { + exists(BasicBlock bb0 | + cfnChild = this.getRelevantChildCfgNode(parent, child) and + bb0.getANode() = cfnChild + | + bb = bb0 + or + not bb0.getANode().getAstNode() = parent and + if isPostOrder(parent) then bb = bb0.getASuccessor() else bb = bb0.getAPredecessor() + ) + or + exists(BasicBlock mid | + this.childNodeReachesBasicBlock(parent, child, cfnChild, mid) and + not mid = this.getARelevantBasicBlock(parent) and + if isPostOrder(parent) then bb = mid.getASuccessor() else bb = mid.getAPredecessor() + ) + } + + /** + * Holds if CFG node `cfnChild` can reach CFG node `cfnParent`, without going + * through an intermediate block that contains a CFG node for `parent`. + */ + pragma[nomagic] + predicate childNodeReachesParentNode( + AstNode parent, CfgNode cfnParent, AstNode child, CfgNode cfnChild + ) { + // `cfnChild` can reach `cfnParent` directly + exists(BasicBlock bb | + this.childNodeReachesBasicBlock(parent, child, cfnChild, bb) and + cfnParent.getAstNode() = parent + | + cfnParent = bb.getANode() + or + if isPostOrder(parent) + then cfnParent = bb.getASuccessor().getANode() + else cfnParent = bb.getAPredecessor().getANode() + ) + or + // `cfnChild` can reach `cfnParent` by going via another relevant child + exists(CfgNode cfnOtherChild | + this.childNodeReachesParentNode(parent, cfnParent, _, cfnOtherChild) and + exists(BasicBlock bb | + this.childNodeReachesBasicBlock(parent, child, cfnChild, bb) and + bb.getANode() = cfnOtherChild + ) + ) + } + + override predicate hasCfgChild(AstNode parent, AstNode child, AstCfgNode cfn, AstCfgNode cfnChild) { + Stages::CfgStage::ref() and + this.childNodeReachesParentNode(parent, cfn, child, cfnChild) + } +} diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/generated/CfgNodes.qll b/rust/ql/lib/codeql/rust/controlflow/internal/generated/CfgNodes.qll new file mode 100644 index 00000000000..1cd67ef2cd1 --- /dev/null +++ b/rust/ql/lib/codeql/rust/controlflow/internal/generated/CfgNodes.qll @@ -0,0 +1,3657 @@ +// generated by codegen, do not edit +/** + * This module provides generated wrappers around the `CfgNode` type. + * + * INTERNAL: Do not import directly. + */ + +private import codeql.util.Location +private import codeql.util.Unit +private import codeql.rust.elements + +/** Provides the input to `MakeCfgNodes` */ +signature module InputSig { + class CfgNode { + AstNode getAstNode(); + + string toString(); + + Loc getLocation(); + } + + AstNode getDesugared(AstNode n); +} + +/** + * Given a `CfgNode` implementation, provides the module `Nodes` that + * contains wrappers around `CfgNode` for relevant classes. + */ +module MakeCfgNodes Input> { + private import Input + + final private class AstNodeFinal = AstNode; + + final private class CfgNodeFinal = CfgNode; + + /** + * INTERNAL: Do not expose. + */ + abstract class ParentAstNode extends AstNodeFinal { + /** + * Holds if `child` is a (possibly nested) child of this AST node + * for which we would like to find a matching CFG child. + */ + abstract predicate relevantChild(AstNode child); + } + + /** + * INTERNAL: Do not expose. + */ + abstract class ChildMapping extends Unit { + /** + * Holds if `child` is a (possibly nested) child of AST node `parent` + * for which we would like to find a matching CFG child. + */ + final predicate relevantChild(AstNode parent, AstNode child) { + parent.(ParentAstNode).relevantChild(child) + } + + /** + * Holds if there is a control-flow path from `cfn` to `cfnChild`, where `cfn` + * is a control-flow node for this AST node, and `cfnChild` is a control-flow + * node for `child`. + * + * This predicate should be implemented at the place where `MakeCfgNodes` is + * invoked. Ideally, `MakeCfgNodes` should be a higher-order parameterized + * module, but since that is currently not supported, we achieve the "callback" + * effect using this `abstract` class instead. + */ + cached + abstract predicate hasCfgChild(AstNode parent, AstNode child, CfgNode cfn, CfgNode cfnChild); + } + + /** Provides sub classes of `CfgNode`. */ + module Nodes { + final private class ParentArrayExpr extends ParentAstNode, ArrayExpr { + override predicate relevantChild(AstNode child) { + none() + or + child = this.getExpr(_) + } + } + + /** + * An array expression. For example: + * ```rust + * [1, 2, 3]; + * [1; 10]; + * ``` + */ + final class ArrayExprCfgNode extends CfgNodeFinal, ExprCfgNode { + private ArrayExpr node; + + ArrayExprCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `ArrayExpr`. */ + ArrayExpr getArrayExpr() { result = node } + + /** + * Gets the `index`th attr of this array expression (0-based). + */ + Attr getAttr(int index) { result = node.getAttr(index) } + + /** + * Gets any of the attrs of this array expression. + */ + Attr getAnAttr() { result = this.getAttr(_) } + + /** + * Gets the number of attrs of this array expression. + */ + int getNumberOfAttrs() { result = count(int i | exists(this.getAttr(i))) } + + /** + * Gets the `index`th expression of this array expression (0-based). + */ + ExprCfgNode getExpr(int index) { + any(ChildMapping mapping).hasCfgChild(node, node.getExpr(index), this, result) + } + + /** + * Gets any of the expressions of this array expression. + */ + ExprCfgNode getAnExpr() { result = this.getExpr(_) } + + /** + * Gets the number of expressions of this array expression. + */ + int getNumberOfExprs() { result = count(int i | exists(this.getExpr(i))) } + } + + final private class ParentAsmExpr extends ParentAstNode, AsmExpr { + override predicate relevantChild(AstNode child) { + none() + or + child = this.getExpr() + } + } + + /** + * An inline assembly expression. For example: + * ```rust + * unsafe { + * builtin # asm(_); + * } + * ``` + */ + final class AsmExprCfgNode extends CfgNodeFinal, ExprCfgNode { + private AsmExpr node; + + AsmExprCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `AsmExpr`. */ + AsmExpr getAsmExpr() { result = node } + + /** + * Gets the `index`th attr of this asm expression (0-based). + */ + Attr getAttr(int index) { result = node.getAttr(index) } + + /** + * Gets any of the attrs of this asm expression. + */ + Attr getAnAttr() { result = this.getAttr(_) } + + /** + * Gets the number of attrs of this asm expression. + */ + int getNumberOfAttrs() { result = count(int i | exists(this.getAttr(i))) } + + /** + * Gets the expression of this asm expression, if it exists. + */ + ExprCfgNode getExpr() { + any(ChildMapping mapping).hasCfgChild(node, node.getExpr(), this, result) + } + + /** + * Holds if `getExpr()` exists. + */ + predicate hasExpr() { exists(this.getExpr()) } + } + + final private class ParentAwaitExpr extends ParentAstNode, AwaitExpr { + override predicate relevantChild(AstNode child) { + none() + or + child = this.getExpr() + } + } + + /** + * An `await` expression. For example: + * ```rust + * async { + * let x = foo().await; + * x + * } + * ``` + */ + final class AwaitExprCfgNode extends CfgNodeFinal, ExprCfgNode { + private AwaitExpr node; + + AwaitExprCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `AwaitExpr`. */ + AwaitExpr getAwaitExpr() { result = node } + + /** + * Gets the `index`th attr of this await expression (0-based). + */ + Attr getAttr(int index) { result = node.getAttr(index) } + + /** + * Gets any of the attrs of this await expression. + */ + Attr getAnAttr() { result = this.getAttr(_) } + + /** + * Gets the number of attrs of this await expression. + */ + int getNumberOfAttrs() { result = count(int i | exists(this.getAttr(i))) } + + /** + * Gets the expression of this await expression, if it exists. + */ + ExprCfgNode getExpr() { + any(ChildMapping mapping).hasCfgChild(node, node.getExpr(), this, result) + } + + /** + * Holds if `getExpr()` exists. + */ + predicate hasExpr() { exists(this.getExpr()) } + } + + final private class ParentBecomeExpr extends ParentAstNode, BecomeExpr { + override predicate relevantChild(AstNode child) { + none() + or + child = this.getExpr() + } + } + + /** + * A `become` expression. For example: + * ```rust + * fn fact_a(n: i32, a: i32) -> i32 { + * if n == 0 { + * a + * } else { + * become fact_a(n - 1, n * a) + * } + * } + * ``` + */ + final class BecomeExprCfgNode extends CfgNodeFinal, ExprCfgNode { + private BecomeExpr node; + + BecomeExprCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `BecomeExpr`. */ + BecomeExpr getBecomeExpr() { result = node } + + /** + * Gets the `index`th attr of this become expression (0-based). + */ + Attr getAttr(int index) { result = node.getAttr(index) } + + /** + * Gets any of the attrs of this become expression. + */ + Attr getAnAttr() { result = this.getAttr(_) } + + /** + * Gets the number of attrs of this become expression. + */ + int getNumberOfAttrs() { result = count(int i | exists(this.getAttr(i))) } + + /** + * Gets the expression of this become expression, if it exists. + */ + ExprCfgNode getExpr() { + any(ChildMapping mapping).hasCfgChild(node, node.getExpr(), this, result) + } + + /** + * Holds if `getExpr()` exists. + */ + predicate hasExpr() { exists(this.getExpr()) } + } + + final private class ParentBinaryExpr extends ParentAstNode, BinaryExpr { + override predicate relevantChild(AstNode child) { + none() + or + child = this.getLhs() + or + child = this.getRhs() + } + } + + /** + * A binary operation expression. For example: + * ```rust + * x + y; + * x && y; + * x <= y; + * x = y; + * x += y; + * ``` + */ + final class BinaryExprCfgNode extends CfgNodeFinal, ExprCfgNode { + private BinaryExpr node; + + BinaryExprCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `BinaryExpr`. */ + BinaryExpr getBinaryExpr() { result = node } + + /** + * Gets the `index`th attr of this binary expression (0-based). + */ + Attr getAttr(int index) { result = node.getAttr(index) } + + /** + * Gets any of the attrs of this binary expression. + */ + Attr getAnAttr() { result = this.getAttr(_) } + + /** + * Gets the number of attrs of this binary expression. + */ + int getNumberOfAttrs() { result = count(int i | exists(this.getAttr(i))) } + + /** + * Gets the lhs of this binary expression, if it exists. + */ + ExprCfgNode getLhs() { + any(ChildMapping mapping).hasCfgChild(node, node.getLhs(), this, result) + } + + /** + * Holds if `getLhs()` exists. + */ + predicate hasLhs() { exists(this.getLhs()) } + + /** + * Gets the operator name of this binary expression, if it exists. + */ + string getOperatorName() { result = node.getOperatorName() } + + /** + * Holds if `getOperatorName()` exists. + */ + predicate hasOperatorName() { exists(this.getOperatorName()) } + + /** + * Gets the rhs of this binary expression, if it exists. + */ + ExprCfgNode getRhs() { + any(ChildMapping mapping).hasCfgChild(node, node.getRhs(), this, result) + } + + /** + * Holds if `getRhs()` exists. + */ + predicate hasRhs() { exists(this.getRhs()) } + } + + final private class ParentBlockExpr extends ParentAstNode, BlockExpr { + override predicate relevantChild(AstNode child) { none() } + } + + /** + * A block expression. For example: + * ```rust + * { + * let x = 42; + * } + * ``` + * ```rust + * 'label: { + * let x = 42; + * x + * } + * ``` + */ + final class BlockExprCfgNode extends CfgNodeFinal, ExprCfgNode { + private BlockExpr node; + + BlockExprCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `BlockExpr`. */ + BlockExpr getBlockExpr() { result = node } + + /** + * Gets the `index`th attr of this block expression (0-based). + */ + Attr getAttr(int index) { result = node.getAttr(index) } + + /** + * Gets any of the attrs of this block expression. + */ + Attr getAnAttr() { result = this.getAttr(_) } + + /** + * Gets the number of attrs of this block expression. + */ + int getNumberOfAttrs() { result = count(int i | exists(this.getAttr(i))) } + + /** + * Holds if this block expression is async. + */ + predicate isAsync() { node.isAsync() } + + /** + * Holds if this block expression is const. + */ + predicate isConst() { node.isConst() } + + /** + * Holds if this block expression is gen. + */ + predicate isGen() { node.isGen() } + + /** + * Holds if this block expression is move. + */ + predicate isMove() { node.isMove() } + + /** + * Holds if this block expression is try. + */ + predicate isTry() { node.isTry() } + + /** + * Holds if this block expression is unsafe. + */ + predicate isUnsafe() { node.isUnsafe() } + + /** + * Gets the label of this block expression, if it exists. + */ + Label getLabel() { result = node.getLabel() } + + /** + * Holds if `getLabel()` exists. + */ + predicate hasLabel() { exists(this.getLabel()) } + + /** + * Gets the statement list of this block expression, if it exists. + */ + StmtList getStmtList() { result = node.getStmtList() } + + /** + * Holds if `getStmtList()` exists. + */ + predicate hasStmtList() { exists(this.getStmtList()) } + } + + final private class ParentBoxPat extends ParentAstNode, BoxPat { + override predicate relevantChild(AstNode child) { + none() + or + child = this.getPat() + } + } + + /** + * A box pattern. For example: + * ```rust + * match x { + * box Option::Some(y) => y, + * box Option::None => 0, + * }; + * ``` + */ + final class BoxPatCfgNode extends CfgNodeFinal, PatCfgNode { + private BoxPat node; + + BoxPatCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `BoxPat`. */ + BoxPat getBoxPat() { result = node } + + /** + * Gets the pat of this box pat, if it exists. + */ + PatCfgNode getPat() { + any(ChildMapping mapping).hasCfgChild(node, node.getPat(), this, result) + } + + /** + * Holds if `getPat()` exists. + */ + predicate hasPat() { exists(this.getPat()) } + } + + final private class ParentBreakExpr extends ParentAstNode, BreakExpr { + override predicate relevantChild(AstNode child) { + none() + or + child = this.getExpr() + } + } + + /** + * A break expression. For example: + * ```rust + * loop { + * if not_ready() { + * break; + * } + * } + * ``` + * ```rust + * let x = 'label: loop { + * if done() { + * break 'label 42; + * } + * }; + * ``` + * ```rust + * let x = 'label: { + * if exit() { + * break 'label 42; + * } + * 0; + * }; + * ``` + */ + final class BreakExprCfgNode extends CfgNodeFinal, ExprCfgNode { + private BreakExpr node; + + BreakExprCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `BreakExpr`. */ + BreakExpr getBreakExpr() { result = node } + + /** + * Gets the `index`th attr of this break expression (0-based). + */ + Attr getAttr(int index) { result = node.getAttr(index) } + + /** + * Gets any of the attrs of this break expression. + */ + Attr getAnAttr() { result = this.getAttr(_) } + + /** + * Gets the number of attrs of this break expression. + */ + int getNumberOfAttrs() { result = count(int i | exists(this.getAttr(i))) } + + /** + * Gets the expression of this break expression, if it exists. + */ + ExprCfgNode getExpr() { + any(ChildMapping mapping).hasCfgChild(node, node.getExpr(), this, result) + } + + /** + * Holds if `getExpr()` exists. + */ + predicate hasExpr() { exists(this.getExpr()) } + + /** + * Gets the lifetime of this break expression, if it exists. + */ + Lifetime getLifetime() { result = node.getLifetime() } + + /** + * Holds if `getLifetime()` exists. + */ + predicate hasLifetime() { exists(this.getLifetime()) } + } + + final private class ParentCallExpr extends ParentAstNode, CallExpr { + override predicate relevantChild(AstNode child) { + none() + or + child = this.getExpr() + } + } + + /** + * A function call expression. For example: + * ```rust + * foo(42); + * foo::(42); + * foo[0](42); + * foo(1) = 4; + * ``` + */ + final class CallExprCfgNode extends CfgNodeFinal, CallExprBaseCfgNode { + private CallExpr node; + + CallExprCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `CallExpr`. */ + CallExpr getCallExpr() { result = node } + + /** + * Gets the expression of this call expression, if it exists. + */ + ExprCfgNode getExpr() { + any(ChildMapping mapping).hasCfgChild(node, node.getExpr(), this, result) + } + + /** + * Holds if `getExpr()` exists. + */ + predicate hasExpr() { exists(this.getExpr()) } + } + + final private class ParentCallExprBase extends ParentAstNode, CallExprBase { + override predicate relevantChild(AstNode child) { none() } + } + + /** + * A function or method call expression. See `CallExpr` and `MethodCallExpr` for further details. + */ + final class CallExprBaseCfgNode extends CfgNodeFinal, ExprCfgNode { + private CallExprBase node; + + CallExprBaseCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `CallExprBase`. */ + CallExprBase getCallExprBase() { result = node } + + /** + * Gets the argument list of this call expression base, if it exists. + */ + ArgList getArgList() { result = node.getArgList() } + + /** + * Holds if `getArgList()` exists. + */ + predicate hasArgList() { exists(this.getArgList()) } + + /** + * Gets the `index`th attr of this call expression base (0-based). + */ + Attr getAttr(int index) { result = node.getAttr(index) } + + /** + * Gets any of the attrs of this call expression base. + */ + Attr getAnAttr() { result = this.getAttr(_) } + + /** + * Gets the number of attrs of this call expression base. + */ + int getNumberOfAttrs() { result = count(int i | exists(this.getAttr(i))) } + } + + final private class ParentConstBlockPat extends ParentAstNode, ConstBlockPat { + override predicate relevantChild(AstNode child) { + none() + or + child = this.getBlockExpr() + } + } + + /** + * A const block pattern. For example: + * ```rust + * match x { + * const { 1 + 2 + 3 } => "ok", + * _ => "fail", + * }; + * ``` + */ + final class ConstBlockPatCfgNode extends CfgNodeFinal, PatCfgNode { + private ConstBlockPat node; + + ConstBlockPatCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `ConstBlockPat`. */ + ConstBlockPat getConstBlockPat() { result = node } + + /** + * Gets the block expression of this const block pat, if it exists. + */ + BlockExprCfgNode getBlockExpr() { + any(ChildMapping mapping).hasCfgChild(node, node.getBlockExpr(), this, result) + } + + /** + * Holds if `getBlockExpr()` exists. + */ + predicate hasBlockExpr() { exists(this.getBlockExpr()) } + + /** + * Holds if this const block pat is const. + */ + predicate isConst() { node.isConst() } + } + + final private class ParentContinueExpr extends ParentAstNode, ContinueExpr { + override predicate relevantChild(AstNode child) { none() } + } + + /** + * A continue expression. For example: + * ```rust + * loop { + * if not_ready() { + * continue; + * } + * } + * ``` + * ```rust + * 'label: loop { + * if not_ready() { + * continue 'label; + * } + * } + * ``` + */ + final class ContinueExprCfgNode extends CfgNodeFinal, ExprCfgNode { + private ContinueExpr node; + + ContinueExprCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `ContinueExpr`. */ + ContinueExpr getContinueExpr() { result = node } + + /** + * Gets the `index`th attr of this continue expression (0-based). + */ + Attr getAttr(int index) { result = node.getAttr(index) } + + /** + * Gets any of the attrs of this continue expression. + */ + Attr getAnAttr() { result = this.getAttr(_) } + + /** + * Gets the number of attrs of this continue expression. + */ + int getNumberOfAttrs() { result = count(int i | exists(this.getAttr(i))) } + + /** + * Gets the lifetime of this continue expression, if it exists. + */ + Lifetime getLifetime() { result = node.getLifetime() } + + /** + * Holds if `getLifetime()` exists. + */ + predicate hasLifetime() { exists(this.getLifetime()) } + } + + final private class ParentExpr extends ParentAstNode, Expr { + override predicate relevantChild(AstNode child) { none() } + } + + /** + * The base class for expressions. + */ + final class ExprCfgNode extends CfgNodeFinal { + private Expr node; + + ExprCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `Expr`. */ + Expr getExpr() { result = node } + } + + final private class ParentFieldExpr extends ParentAstNode, FieldExpr { + override predicate relevantChild(AstNode child) { + none() + or + child = this.getExpr() + } + } + + /** + * A field access expression. For example: + * ```rust + * x.foo + * ``` + */ + final class FieldExprCfgNode extends CfgNodeFinal, ExprCfgNode { + private FieldExpr node; + + FieldExprCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `FieldExpr`. */ + FieldExpr getFieldExpr() { result = node } + + /** + * Gets the `index`th attr of this field expression (0-based). + */ + Attr getAttr(int index) { result = node.getAttr(index) } + + /** + * Gets any of the attrs of this field expression. + */ + Attr getAnAttr() { result = this.getAttr(_) } + + /** + * Gets the number of attrs of this field expression. + */ + int getNumberOfAttrs() { result = count(int i | exists(this.getAttr(i))) } + + /** + * Gets the expression of this field expression, if it exists. + */ + ExprCfgNode getExpr() { + any(ChildMapping mapping).hasCfgChild(node, node.getExpr(), this, result) + } + + /** + * Holds if `getExpr()` exists. + */ + predicate hasExpr() { exists(this.getExpr()) } + + /** + * Gets the name reference of this field expression, if it exists. + */ + NameRef getNameRef() { result = node.getNameRef() } + + /** + * Holds if `getNameRef()` exists. + */ + predicate hasNameRef() { exists(this.getNameRef()) } + } + + final private class ParentForExpr extends ParentAstNode, ForExpr { + override predicate relevantChild(AstNode child) { + none() + or + child = this.getIterable() + or + child = this.getLoopBody() + or + child = this.getPat() + } + } + + /** + * A ForExpr. For example: + * ```rust + * todo!() + * ``` + */ + final class ForExprCfgNode extends CfgNodeFinal, ExprCfgNode { + private ForExpr node; + + ForExprCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `ForExpr`. */ + ForExpr getForExpr() { result = node } + + /** + * Gets the `index`th attr of this for expression (0-based). + */ + Attr getAttr(int index) { result = node.getAttr(index) } + + /** + * Gets any of the attrs of this for expression. + */ + Attr getAnAttr() { result = this.getAttr(_) } + + /** + * Gets the number of attrs of this for expression. + */ + int getNumberOfAttrs() { result = count(int i | exists(this.getAttr(i))) } + + /** + * Gets the iterable of this for expression, if it exists. + */ + ExprCfgNode getIterable() { + any(ChildMapping mapping).hasCfgChild(node, node.getIterable(), this, result) + } + + /** + * Holds if `getIterable()` exists. + */ + predicate hasIterable() { exists(this.getIterable()) } + + /** + * Gets the label of this for expression, if it exists. + */ + Label getLabel() { result = node.getLabel() } + + /** + * Holds if `getLabel()` exists. + */ + predicate hasLabel() { exists(this.getLabel()) } + + /** + * Gets the loop body of this for expression, if it exists. + */ + BlockExprCfgNode getLoopBody() { + any(ChildMapping mapping).hasCfgChild(node, node.getLoopBody(), this, result) + } + + /** + * Holds if `getLoopBody()` exists. + */ + predicate hasLoopBody() { exists(this.getLoopBody()) } + + /** + * Gets the pat of this for expression, if it exists. + */ + PatCfgNode getPat() { + any(ChildMapping mapping).hasCfgChild(node, node.getPat(), this, result) + } + + /** + * Holds if `getPat()` exists. + */ + predicate hasPat() { exists(this.getPat()) } + } + + final private class ParentFormatArgsExpr extends ParentAstNode, FormatArgsExpr { + override predicate relevantChild(AstNode child) { + none() + or + child = this.getTemplate() + } + } + + /** + * A FormatArgsExpr. For example: + * ```rust + * todo!() + * ``` + */ + final class FormatArgsExprCfgNode extends CfgNodeFinal, ExprCfgNode { + private FormatArgsExpr node; + + FormatArgsExprCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `FormatArgsExpr`. */ + FormatArgsExpr getFormatArgsExpr() { result = node } + + /** + * Gets the `index`th argument of this format arguments expression (0-based). + */ + FormatArgsArg getArg(int index) { result = node.getArg(index) } + + /** + * Gets any of the arguments of this format arguments expression. + */ + FormatArgsArg getAnArg() { result = this.getArg(_) } + + /** + * Gets the number of arguments of this format arguments expression. + */ + int getNumberOfArgs() { result = count(int i | exists(this.getArg(i))) } + + /** + * Gets the `index`th attr of this format arguments expression (0-based). + */ + Attr getAttr(int index) { result = node.getAttr(index) } + + /** + * Gets any of the attrs of this format arguments expression. + */ + Attr getAnAttr() { result = this.getAttr(_) } + + /** + * Gets the number of attrs of this format arguments expression. + */ + int getNumberOfAttrs() { result = count(int i | exists(this.getAttr(i))) } + + /** + * Gets the template of this format arguments expression, if it exists. + */ + ExprCfgNode getTemplate() { + any(ChildMapping mapping).hasCfgChild(node, node.getTemplate(), this, result) + } + + /** + * Holds if `getTemplate()` exists. + */ + predicate hasTemplate() { exists(this.getTemplate()) } + } + + final private class ParentFormatTemplateVariableAccess extends ParentAstNode, + FormatTemplateVariableAccess + { + override predicate relevantChild(AstNode child) { none() } + } + + /** + */ + final class FormatTemplateVariableAccessCfgNode extends CfgNodeFinal, PathExprBaseCfgNode { + private FormatTemplateVariableAccess node; + + FormatTemplateVariableAccessCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `FormatTemplateVariableAccess`. */ + FormatTemplateVariableAccess getFormatTemplateVariableAccess() { result = node } + } + + final private class ParentIdentPat extends ParentAstNode, IdentPat { + override predicate relevantChild(AstNode child) { + none() + or + child = this.getPat() + } + } + + /** + * A binding pattern. For example: + * ```rust + * match x { + * Option::Some(y) => y, + * Option::None => 0, + * }; + * ``` + * ```rust + * match x { + * y@Option::Some(_) => y, + * Option::None => 0, + * }; + * ``` + */ + final class IdentPatCfgNode extends CfgNodeFinal, PatCfgNode { + private IdentPat node; + + IdentPatCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `IdentPat`. */ + IdentPat getIdentPat() { result = node } + + /** + * Gets the `index`th attr of this ident pat (0-based). + */ + Attr getAttr(int index) { result = node.getAttr(index) } + + /** + * Gets any of the attrs of this ident pat. + */ + Attr getAnAttr() { result = this.getAttr(_) } + + /** + * Gets the number of attrs of this ident pat. + */ + int getNumberOfAttrs() { result = count(int i | exists(this.getAttr(i))) } + + /** + * Holds if this ident pat is mut. + */ + predicate isMut() { node.isMut() } + + /** + * Holds if this ident pat is reference. + */ + predicate isRef() { node.isRef() } + + /** + * Gets the name of this ident pat, if it exists. + */ + Name getName() { result = node.getName() } + + /** + * Holds if `getName()` exists. + */ + predicate hasName() { exists(this.getName()) } + + /** + * Gets the pat of this ident pat, if it exists. + */ + PatCfgNode getPat() { + any(ChildMapping mapping).hasCfgChild(node, node.getPat(), this, result) + } + + /** + * Holds if `getPat()` exists. + */ + predicate hasPat() { exists(this.getPat()) } + } + + final private class ParentIfExpr extends ParentAstNode, IfExpr { + override predicate relevantChild(AstNode child) { + none() + or + child = this.getCondition() + or + child = this.getElse() + or + child = this.getThen() + } + } + + /** + * An `if` expression. For example: + * ```rust + * if x == 42 { + * println!("that's the answer"); + * } + * ``` + * ```rust + * let y = if x > 0 { + * 1 + * } else { + * 0 + * }; + * ``` + */ + final class IfExprCfgNode extends CfgNodeFinal, ExprCfgNode { + private IfExpr node; + + IfExprCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `IfExpr`. */ + IfExpr getIfExpr() { result = node } + + /** + * Gets the `index`th attr of this if expression (0-based). + */ + Attr getAttr(int index) { result = node.getAttr(index) } + + /** + * Gets any of the attrs of this if expression. + */ + Attr getAnAttr() { result = this.getAttr(_) } + + /** + * Gets the number of attrs of this if expression. + */ + int getNumberOfAttrs() { result = count(int i | exists(this.getAttr(i))) } + + /** + * Gets the condition of this if expression, if it exists. + */ + ExprCfgNode getCondition() { + any(ChildMapping mapping).hasCfgChild(node, node.getCondition(), this, result) + } + + /** + * Holds if `getCondition()` exists. + */ + predicate hasCondition() { exists(this.getCondition()) } + + /** + * Gets the else of this if expression, if it exists. + */ + ExprCfgNode getElse() { + any(ChildMapping mapping).hasCfgChild(node, node.getElse(), this, result) + } + + /** + * Holds if `getElse()` exists. + */ + predicate hasElse() { exists(this.getElse()) } + + /** + * Gets the then of this if expression, if it exists. + */ + BlockExprCfgNode getThen() { + any(ChildMapping mapping).hasCfgChild(node, node.getThen(), this, result) + } + + /** + * Holds if `getThen()` exists. + */ + predicate hasThen() { exists(this.getThen()) } + } + + final private class ParentIndexExpr extends ParentAstNode, IndexExpr { + override predicate relevantChild(AstNode child) { + none() + or + child = this.getBase() + or + child = this.getIndex() + } + } + + /** + * An index expression. For example: + * ```rust + * list[42]; + * list[42] = 1; + * ``` + */ + final class IndexExprCfgNode extends CfgNodeFinal, ExprCfgNode { + private IndexExpr node; + + IndexExprCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `IndexExpr`. */ + IndexExpr getIndexExpr() { result = node } + + /** + * Gets the `index`th attr of this index expression (0-based). + */ + Attr getAttr(int index) { result = node.getAttr(index) } + + /** + * Gets any of the attrs of this index expression. + */ + Attr getAnAttr() { result = this.getAttr(_) } + + /** + * Gets the number of attrs of this index expression. + */ + int getNumberOfAttrs() { result = count(int i | exists(this.getAttr(i))) } + + /** + * Gets the base of this index expression, if it exists. + */ + ExprCfgNode getBase() { + any(ChildMapping mapping).hasCfgChild(node, node.getBase(), this, result) + } + + /** + * Holds if `getBase()` exists. + */ + predicate hasBase() { exists(this.getBase()) } + + /** + * Gets the index of this index expression, if it exists. + */ + ExprCfgNode getIndex() { + any(ChildMapping mapping).hasCfgChild(node, node.getIndex(), this, result) + } + + /** + * Holds if `getIndex()` exists. + */ + predicate hasIndex() { exists(this.getIndex()) } + } + + final private class ParentLetExpr extends ParentAstNode, LetExpr { + override predicate relevantChild(AstNode child) { + none() + or + child = this.getExpr() + or + child = this.getPat() + } + } + + /** + * A `let` expression. For example: + * ```rust + * if let Some(x) = maybe_some { + * println!("{}", x); + * } + * ``` + */ + final class LetExprCfgNode extends CfgNodeFinal, ExprCfgNode { + private LetExpr node; + + LetExprCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `LetExpr`. */ + LetExpr getLetExpr() { result = node } + + /** + * Gets the `index`th attr of this let expression (0-based). + */ + Attr getAttr(int index) { result = node.getAttr(index) } + + /** + * Gets any of the attrs of this let expression. + */ + Attr getAnAttr() { result = this.getAttr(_) } + + /** + * Gets the number of attrs of this let expression. + */ + int getNumberOfAttrs() { result = count(int i | exists(this.getAttr(i))) } + + /** + * Gets the expression of this let expression, if it exists. + */ + ExprCfgNode getExpr() { + any(ChildMapping mapping).hasCfgChild(node, node.getExpr(), this, result) + } + + /** + * Holds if `getExpr()` exists. + */ + predicate hasExpr() { exists(this.getExpr()) } + + /** + * Gets the pat of this let expression, if it exists. + */ + PatCfgNode getPat() { + any(ChildMapping mapping).hasCfgChild(node, node.getPat(), this, result) + } + + /** + * Holds if `getPat()` exists. + */ + predicate hasPat() { exists(this.getPat()) } + } + + final private class ParentLetStmt extends ParentAstNode, LetStmt { + override predicate relevantChild(AstNode child) { + none() + or + child = this.getInitializer() + or + child = this.getPat() + } + } + + /** + * A let statement. For example: + * ```rust + * let x = 42; + * let x: i32 = 42; + * let x: i32; + * let x; + * let (x, y) = (1, 2); + * let Some(x) = std::env::var("FOO") else { + * return; + * }; + * ``` + */ + final class LetStmtCfgNode extends CfgNodeFinal { + private LetStmt node; + + LetStmtCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `LetStmt`. */ + LetStmt getLetStmt() { result = node } + + /** + * Gets the `index`th attr of this let statement (0-based). + */ + Attr getAttr(int index) { result = node.getAttr(index) } + + /** + * Gets any of the attrs of this let statement. + */ + Attr getAnAttr() { result = this.getAttr(_) } + + /** + * Gets the number of attrs of this let statement. + */ + int getNumberOfAttrs() { result = count(int i | exists(this.getAttr(i))) } + + /** + * Gets the initializer of this let statement, if it exists. + */ + ExprCfgNode getInitializer() { + any(ChildMapping mapping).hasCfgChild(node, node.getInitializer(), this, result) + } + + /** + * Holds if `getInitializer()` exists. + */ + predicate hasInitializer() { exists(this.getInitializer()) } + + /** + * Gets the let else of this let statement, if it exists. + */ + LetElse getLetElse() { result = node.getLetElse() } + + /** + * Holds if `getLetElse()` exists. + */ + predicate hasLetElse() { exists(this.getLetElse()) } + + /** + * Gets the pat of this let statement, if it exists. + */ + PatCfgNode getPat() { + any(ChildMapping mapping).hasCfgChild(node, node.getPat(), this, result) + } + + /** + * Holds if `getPat()` exists. + */ + predicate hasPat() { exists(this.getPat()) } + + /** + * Gets the ty of this let statement, if it exists. + */ + TypeRef getTy() { result = node.getTy() } + + /** + * Holds if `getTy()` exists. + */ + predicate hasTy() { exists(this.getTy()) } + } + + final private class ParentLiteralExpr extends ParentAstNode, LiteralExpr { + override predicate relevantChild(AstNode child) { none() } + } + + /** + * A literal expression. For example: + * ```rust + * 42; + * 42.0; + * "Hello, world!"; + * b"Hello, world!"; + * 'x'; + * b'x'; + * r"Hello, world!"; + * true; + * ``` + */ + final class LiteralExprCfgNode extends CfgNodeFinal, ExprCfgNode { + private LiteralExpr node; + + LiteralExprCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `LiteralExpr`. */ + LiteralExpr getLiteralExpr() { result = node } + + /** + * Gets the `index`th attr of this literal expression (0-based). + */ + Attr getAttr(int index) { result = node.getAttr(index) } + + /** + * Gets any of the attrs of this literal expression. + */ + Attr getAnAttr() { result = this.getAttr(_) } + + /** + * Gets the number of attrs of this literal expression. + */ + int getNumberOfAttrs() { result = count(int i | exists(this.getAttr(i))) } + + /** + * Gets the text value of this literal expression, if it exists. + */ + string getTextValue() { result = node.getTextValue() } + + /** + * Holds if `getTextValue()` exists. + */ + predicate hasTextValue() { exists(this.getTextValue()) } + } + + final private class ParentLiteralPat extends ParentAstNode, LiteralPat { + override predicate relevantChild(AstNode child) { + none() + or + child = this.getLiteral() + } + } + + /** + * A literal pattern. For example: + * ```rust + * match x { + * 42 => "ok", + * _ => "fail", + * } + * ``` + */ + final class LiteralPatCfgNode extends CfgNodeFinal, PatCfgNode { + private LiteralPat node; + + LiteralPatCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `LiteralPat`. */ + LiteralPat getLiteralPat() { result = node } + + /** + * Gets the literal of this literal pat, if it exists. + */ + LiteralExprCfgNode getLiteral() { + any(ChildMapping mapping).hasCfgChild(node, node.getLiteral(), this, result) + } + + /** + * Holds if `getLiteral()` exists. + */ + predicate hasLiteral() { exists(this.getLiteral()) } + } + + final private class ParentLoopExpr extends ParentAstNode, LoopExpr { + override predicate relevantChild(AstNode child) { + none() + or + child = this.getLoopBody() + } + } + + /** + * A loop expression. For example: + * ```rust + * loop { + * println!("Hello, world (again)!"); + * }; + * ``` + * ```rust + * 'label: loop { + * println!("Hello, world (once)!"); + * break 'label; + * }; + * ``` + * ```rust + * let mut x = 0; + * loop { + * if x < 10 { + * x += 1; + * } else { + * break; + * } + * }; + * ``` + */ + final class LoopExprCfgNode extends CfgNodeFinal, ExprCfgNode { + private LoopExpr node; + + LoopExprCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `LoopExpr`. */ + LoopExpr getLoopExpr() { result = node } + + /** + * Gets the `index`th attr of this loop expression (0-based). + */ + Attr getAttr(int index) { result = node.getAttr(index) } + + /** + * Gets any of the attrs of this loop expression. + */ + Attr getAnAttr() { result = this.getAttr(_) } + + /** + * Gets the number of attrs of this loop expression. + */ + int getNumberOfAttrs() { result = count(int i | exists(this.getAttr(i))) } + + /** + * Gets the label of this loop expression, if it exists. + */ + Label getLabel() { result = node.getLabel() } + + /** + * Holds if `getLabel()` exists. + */ + predicate hasLabel() { exists(this.getLabel()) } + + /** + * Gets the loop body of this loop expression, if it exists. + */ + BlockExprCfgNode getLoopBody() { + any(ChildMapping mapping).hasCfgChild(node, node.getLoopBody(), this, result) + } + + /** + * Holds if `getLoopBody()` exists. + */ + predicate hasLoopBody() { exists(this.getLoopBody()) } + } + + final private class ParentMacroCall extends ParentAstNode, MacroCall { + override predicate relevantChild(AstNode child) { none() } + } + + /** + * A MacroCall. For example: + * ```rust + * todo!() + * ``` + */ + final class MacroCallCfgNode extends CfgNodeFinal { + private MacroCall node; + + MacroCallCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `MacroCall`. */ + MacroCall getMacroCall() { result = node } + + /** + * Gets the `index`th attr of this macro call (0-based). + */ + Attr getAttr(int index) { result = node.getAttr(index) } + + /** + * Gets any of the attrs of this macro call. + */ + Attr getAnAttr() { result = this.getAttr(_) } + + /** + * Gets the number of attrs of this macro call. + */ + int getNumberOfAttrs() { result = count(int i | exists(this.getAttr(i))) } + + /** + * Gets the path of this macro call, if it exists. + */ + Path getPath() { result = node.getPath() } + + /** + * Holds if `getPath()` exists. + */ + predicate hasPath() { exists(this.getPath()) } + + /** + * Gets the token tree of this macro call, if it exists. + */ + TokenTree getTokenTree() { result = node.getTokenTree() } + + /** + * Holds if `getTokenTree()` exists. + */ + predicate hasTokenTree() { exists(this.getTokenTree()) } + + /** + * Gets the expanded of this macro call, if it exists. + */ + AstNode getExpanded() { result = node.getExpanded() } + + /** + * Holds if `getExpanded()` exists. + */ + predicate hasExpanded() { exists(this.getExpanded()) } + } + + final private class ParentMacroExpr extends ParentAstNode, MacroExpr { + override predicate relevantChild(AstNode child) { + none() + or + child = this.getMacroCall() + } + } + + /** + * A MacroExpr. For example: + * ```rust + * todo!() + * ``` + */ + final class MacroExprCfgNode extends CfgNodeFinal, ExprCfgNode { + private MacroExpr node; + + MacroExprCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `MacroExpr`. */ + MacroExpr getMacroExpr() { result = node } + + /** + * Gets the macro call of this macro expression, if it exists. + */ + MacroCallCfgNode getMacroCall() { + any(ChildMapping mapping).hasCfgChild(node, node.getMacroCall(), this, result) + } + + /** + * Holds if `getMacroCall()` exists. + */ + predicate hasMacroCall() { exists(this.getMacroCall()) } + } + + final private class ParentMacroPat extends ParentAstNode, MacroPat { + override predicate relevantChild(AstNode child) { + none() + or + child = this.getMacroCall() + } + } + + /** + * A MacroPat. For example: + * ```rust + * todo!() + * ``` + */ + final class MacroPatCfgNode extends CfgNodeFinal, PatCfgNode { + private MacroPat node; + + MacroPatCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `MacroPat`. */ + MacroPat getMacroPat() { result = node } + + /** + * Gets the macro call of this macro pat, if it exists. + */ + MacroCallCfgNode getMacroCall() { + any(ChildMapping mapping).hasCfgChild(node, node.getMacroCall(), this, result) + } + + /** + * Holds if `getMacroCall()` exists. + */ + predicate hasMacroCall() { exists(this.getMacroCall()) } + } + + final private class ParentMatchExpr extends ParentAstNode, MatchExpr { + override predicate relevantChild(AstNode child) { + none() + or + child = this.getExpr() + } + } + + /** + * A match expression. For example: + * ```rust + * match x { + * Option::Some(y) => y, + * Option::None => 0, + * } + * ``` + * ```rust + * match x { + * Some(y) if y != 0 => 1 / y, + * _ => 0, + * } + * ``` + */ + final class MatchExprCfgNode extends CfgNodeFinal, ExprCfgNode { + private MatchExpr node; + + MatchExprCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `MatchExpr`. */ + MatchExpr getMatchExpr() { result = node } + + /** + * Gets the `index`th attr of this match expression (0-based). + */ + Attr getAttr(int index) { result = node.getAttr(index) } + + /** + * Gets any of the attrs of this match expression. + */ + Attr getAnAttr() { result = this.getAttr(_) } + + /** + * Gets the number of attrs of this match expression. + */ + int getNumberOfAttrs() { result = count(int i | exists(this.getAttr(i))) } + + /** + * Gets the expression of this match expression, if it exists. + */ + ExprCfgNode getExpr() { + any(ChildMapping mapping).hasCfgChild(node, node.getExpr(), this, result) + } + + /** + * Holds if `getExpr()` exists. + */ + predicate hasExpr() { exists(this.getExpr()) } + + /** + * Gets the match arm list of this match expression, if it exists. + */ + MatchArmList getMatchArmList() { result = node.getMatchArmList() } + + /** + * Holds if `getMatchArmList()` exists. + */ + predicate hasMatchArmList() { exists(this.getMatchArmList()) } + } + + final private class ParentMethodCallExpr extends ParentAstNode, MethodCallExpr { + override predicate relevantChild(AstNode child) { + none() + or + child = this.getReceiver() + } + } + + /** + * A method call expression. For example: + * ```rust + * x.foo(42); + * x.foo::(42); + * ``` + */ + final class MethodCallExprCfgNode extends CfgNodeFinal, CallExprBaseCfgNode { + private MethodCallExpr node; + + MethodCallExprCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `MethodCallExpr`. */ + MethodCallExpr getMethodCallExpr() { result = node } + + /** + * Gets the generic argument list of this method call expression, if it exists. + */ + GenericArgList getGenericArgList() { result = node.getGenericArgList() } + + /** + * Holds if `getGenericArgList()` exists. + */ + predicate hasGenericArgList() { exists(this.getGenericArgList()) } + + /** + * Gets the name reference of this method call expression, if it exists. + */ + NameRef getNameRef() { result = node.getNameRef() } + + /** + * Holds if `getNameRef()` exists. + */ + predicate hasNameRef() { exists(this.getNameRef()) } + + /** + * Gets the receiver of this method call expression, if it exists. + */ + ExprCfgNode getReceiver() { + any(ChildMapping mapping).hasCfgChild(node, node.getReceiver(), this, result) + } + + /** + * Holds if `getReceiver()` exists. + */ + predicate hasReceiver() { exists(this.getReceiver()) } + } + + final private class ParentOffsetOfExpr extends ParentAstNode, OffsetOfExpr { + override predicate relevantChild(AstNode child) { none() } + } + + /** + * An `offset_of` expression. For example: + * ```rust + * builtin # offset_of(Struct, field); + * ``` + */ + final class OffsetOfExprCfgNode extends CfgNodeFinal, ExprCfgNode { + private OffsetOfExpr node; + + OffsetOfExprCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `OffsetOfExpr`. */ + OffsetOfExpr getOffsetOfExpr() { result = node } + + /** + * Gets the `index`th attr of this offset of expression (0-based). + */ + Attr getAttr(int index) { result = node.getAttr(index) } + + /** + * Gets any of the attrs of this offset of expression. + */ + Attr getAnAttr() { result = this.getAttr(_) } + + /** + * Gets the number of attrs of this offset of expression. + */ + int getNumberOfAttrs() { result = count(int i | exists(this.getAttr(i))) } + + /** + * Gets the `index`th field of this offset of expression (0-based). + */ + NameRef getField(int index) { result = node.getField(index) } + + /** + * Gets any of the fields of this offset of expression. + */ + NameRef getAField() { result = this.getField(_) } + + /** + * Gets the number of fields of this offset of expression. + */ + int getNumberOfFields() { result = count(int i | exists(this.getField(i))) } + + /** + * Gets the ty of this offset of expression, if it exists. + */ + TypeRef getTy() { result = node.getTy() } + + /** + * Holds if `getTy()` exists. + */ + predicate hasTy() { exists(this.getTy()) } + } + + final private class ParentOrPat extends ParentAstNode, OrPat { + override predicate relevantChild(AstNode child) { + none() + or + child = this.getPat(_) + } + } + + /** + * An or pattern. For example: + * ```rust + * match x { + * Option::Some(y) | Option::None => 0, + * } + * ``` + */ + final class OrPatCfgNode extends CfgNodeFinal, PatCfgNode { + private OrPat node; + + OrPatCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `OrPat`. */ + OrPat getOrPat() { result = node } + + /** + * Gets the `index`th pat of this or pat (0-based). + */ + PatCfgNode getPat(int index) { + any(ChildMapping mapping).hasCfgChild(node, node.getPat(index), this, result) + } + + /** + * Gets any of the pats of this or pat. + */ + PatCfgNode getAPat() { result = this.getPat(_) } + + /** + * Gets the number of pats of this or pat. + */ + int getNumberOfPats() { result = count(int i | exists(this.getPat(i))) } + } + + final private class ParentParam extends ParentAstNode, Param { + override predicate relevantChild(AstNode child) { + none() + or + child = this.getPat() + } + } + + /** + * A Param. For example: + * ```rust + * todo!() + * ``` + */ + final class ParamCfgNode extends CfgNodeFinal { + private Param node; + + ParamCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `Param`. */ + Param getParam() { result = node } + + /** + * Gets the `index`th attr of this parameter (0-based). + */ + Attr getAttr(int index) { result = node.getAttr(index) } + + /** + * Gets any of the attrs of this parameter. + */ + Attr getAnAttr() { result = this.getAttr(_) } + + /** + * Gets the number of attrs of this parameter. + */ + int getNumberOfAttrs() { result = count(int i | exists(this.getAttr(i))) } + + /** + * Gets the pat of this parameter, if it exists. + */ + PatCfgNode getPat() { + any(ChildMapping mapping).hasCfgChild(node, node.getPat(), this, result) + } + + /** + * Holds if `getPat()` exists. + */ + predicate hasPat() { exists(this.getPat()) } + + /** + * Gets the ty of this parameter, if it exists. + */ + TypeRef getTy() { result = node.getTy() } + + /** + * Holds if `getTy()` exists. + */ + predicate hasTy() { exists(this.getTy()) } + } + + final private class ParentPat extends ParentAstNode, Pat { + override predicate relevantChild(AstNode child) { none() } + } + + /** + * The base class for patterns. + */ + final class PatCfgNode extends CfgNodeFinal { + private Pat node; + + PatCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `Pat`. */ + Pat getPat() { result = node } + } + + final private class ParentPathExpr extends ParentAstNode, PathExpr { + override predicate relevantChild(AstNode child) { none() } + } + + /** + * A path expression. For example: + * ```rust + * let x = variable; + * let x = foo::bar; + * let y = ::foo; + * let z = ::foo; + * ``` + */ + final class PathExprCfgNode extends CfgNodeFinal, PathExprBaseCfgNode { + private PathExpr node; + + PathExprCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `PathExpr`. */ + PathExpr getPathExpr() { result = node } + + /** + * Gets the `index`th attr of this path expression (0-based). + */ + Attr getAttr(int index) { result = node.getAttr(index) } + + /** + * Gets any of the attrs of this path expression. + */ + Attr getAnAttr() { result = this.getAttr(_) } + + /** + * Gets the number of attrs of this path expression. + */ + int getNumberOfAttrs() { result = count(int i | exists(this.getAttr(i))) } + + /** + * Gets the path of this path expression, if it exists. + */ + Path getPath() { result = node.getPath() } + + /** + * Holds if `getPath()` exists. + */ + predicate hasPath() { exists(this.getPath()) } + } + + final private class ParentPathExprBase extends ParentAstNode, PathExprBase { + override predicate relevantChild(AstNode child) { none() } + } + + /** + * A path expression or a variable access in a formatting template. See `PathExpr` and `FormatTemplateVariableAccess` for further details. + */ + final class PathExprBaseCfgNode extends CfgNodeFinal, ExprCfgNode { + private PathExprBase node; + + PathExprBaseCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `PathExprBase`. */ + PathExprBase getPathExprBase() { result = node } + } + + final private class ParentPathPat extends ParentAstNode, PathPat { + override predicate relevantChild(AstNode child) { none() } + } + + /** + * A path pattern. For example: + * ```rust + * match x { + * Foo::Bar => "ok", + * _ => "fail", + * } + * ``` + */ + final class PathPatCfgNode extends CfgNodeFinal, PatCfgNode { + private PathPat node; + + PathPatCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `PathPat`. */ + PathPat getPathPat() { result = node } + + /** + * Gets the path of this path pat, if it exists. + */ + Path getPath() { result = node.getPath() } + + /** + * Holds if `getPath()` exists. + */ + predicate hasPath() { exists(this.getPath()) } + } + + final private class ParentPrefixExpr extends ParentAstNode, PrefixExpr { + override predicate relevantChild(AstNode child) { + none() + or + child = this.getExpr() + } + } + + /** + * A unary operation expression. For example: + * ```rust + * let x = -42; + * let y = !true; + * let z = *ptr; + * ``` + */ + final class PrefixExprCfgNode extends CfgNodeFinal, ExprCfgNode { + private PrefixExpr node; + + PrefixExprCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `PrefixExpr`. */ + PrefixExpr getPrefixExpr() { result = node } + + /** + * Gets the `index`th attr of this prefix expression (0-based). + */ + Attr getAttr(int index) { result = node.getAttr(index) } + + /** + * Gets any of the attrs of this prefix expression. + */ + Attr getAnAttr() { result = this.getAttr(_) } + + /** + * Gets the number of attrs of this prefix expression. + */ + int getNumberOfAttrs() { result = count(int i | exists(this.getAttr(i))) } + + /** + * Gets the expression of this prefix expression, if it exists. + */ + ExprCfgNode getExpr() { + any(ChildMapping mapping).hasCfgChild(node, node.getExpr(), this, result) + } + + /** + * Holds if `getExpr()` exists. + */ + predicate hasExpr() { exists(this.getExpr()) } + + /** + * Gets the operator name of this prefix expression, if it exists. + */ + string getOperatorName() { result = node.getOperatorName() } + + /** + * Holds if `getOperatorName()` exists. + */ + predicate hasOperatorName() { exists(this.getOperatorName()) } + } + + final private class ParentRangeExpr extends ParentAstNode, RangeExpr { + override predicate relevantChild(AstNode child) { + none() + or + child = this.getEnd() + or + child = this.getStart() + } + } + + /** + * A range expression. For example: + * ```rust + * let x = 1..=10; + * let x = 1..10; + * let x = 10..; + * let x = ..10; + * let x = ..=10; + * let x = ..; + * ``` + */ + final class RangeExprCfgNode extends CfgNodeFinal, ExprCfgNode { + private RangeExpr node; + + RangeExprCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `RangeExpr`. */ + RangeExpr getRangeExpr() { result = node } + + /** + * Gets the `index`th attr of this range expression (0-based). + */ + Attr getAttr(int index) { result = node.getAttr(index) } + + /** + * Gets any of the attrs of this range expression. + */ + Attr getAnAttr() { result = this.getAttr(_) } + + /** + * Gets the number of attrs of this range expression. + */ + int getNumberOfAttrs() { result = count(int i | exists(this.getAttr(i))) } + + /** + * Gets the end of this range expression, if it exists. + */ + ExprCfgNode getEnd() { + any(ChildMapping mapping).hasCfgChild(node, node.getEnd(), this, result) + } + + /** + * Holds if `getEnd()` exists. + */ + predicate hasEnd() { exists(this.getEnd()) } + + /** + * Gets the operator name of this range expression, if it exists. + */ + string getOperatorName() { result = node.getOperatorName() } + + /** + * Holds if `getOperatorName()` exists. + */ + predicate hasOperatorName() { exists(this.getOperatorName()) } + + /** + * Gets the start of this range expression, if it exists. + */ + ExprCfgNode getStart() { + any(ChildMapping mapping).hasCfgChild(node, node.getStart(), this, result) + } + + /** + * Holds if `getStart()` exists. + */ + predicate hasStart() { exists(this.getStart()) } + } + + final private class ParentRangePat extends ParentAstNode, RangePat { + override predicate relevantChild(AstNode child) { + none() + or + child = this.getEnd() + or + child = this.getStart() + } + } + + /** + * A range pattern. For example: + * ```rust + * match x { + * ..15 => "too cold", + * 16..=25 => "just right", + * 26.. => "too hot", + * } + * ``` + */ + final class RangePatCfgNode extends CfgNodeFinal, PatCfgNode { + private RangePat node; + + RangePatCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `RangePat`. */ + RangePat getRangePat() { result = node } + + /** + * Gets the end of this range pat, if it exists. + */ + PatCfgNode getEnd() { + any(ChildMapping mapping).hasCfgChild(node, node.getEnd(), this, result) + } + + /** + * Holds if `getEnd()` exists. + */ + predicate hasEnd() { exists(this.getEnd()) } + + /** + * Gets the operator name of this range pat, if it exists. + */ + string getOperatorName() { result = node.getOperatorName() } + + /** + * Holds if `getOperatorName()` exists. + */ + predicate hasOperatorName() { exists(this.getOperatorName()) } + + /** + * Gets the start of this range pat, if it exists. + */ + PatCfgNode getStart() { + any(ChildMapping mapping).hasCfgChild(node, node.getStart(), this, result) + } + + /** + * Holds if `getStart()` exists. + */ + predicate hasStart() { exists(this.getStart()) } + } + + final private class ParentRecordExpr extends ParentAstNode, RecordExpr { + override predicate relevantChild(AstNode child) { none() } + } + + /** + * A record expression. For example: + * ```rust + * let first = Foo { a: 1, b: 2 }; + * let second = Foo { a: 2, ..first }; + * Foo { a: 1, b: 2 }[2] = 10; + * Foo { .. } = second; + * ``` + */ + final class RecordExprCfgNode extends CfgNodeFinal, ExprCfgNode { + private RecordExpr node; + + RecordExprCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `RecordExpr`. */ + RecordExpr getRecordExpr() { result = node } + + /** + * Gets the path of this record expression, if it exists. + */ + Path getPath() { result = node.getPath() } + + /** + * Holds if `getPath()` exists. + */ + predicate hasPath() { exists(this.getPath()) } + + /** + * Gets the record expression field list of this record expression, if it exists. + */ + RecordExprFieldList getRecordExprFieldList() { result = node.getRecordExprFieldList() } + + /** + * Holds if `getRecordExprFieldList()` exists. + */ + predicate hasRecordExprFieldList() { exists(this.getRecordExprFieldList()) } + } + + final private class ParentRecordPat extends ParentAstNode, RecordPat { + override predicate relevantChild(AstNode child) { none() } + } + + /** + * A record pattern. For example: + * ```rust + * match x { + * Foo { a: 1, b: 2 } => "ok", + * Foo { .. } => "fail", + * } + * ``` + */ + final class RecordPatCfgNode extends CfgNodeFinal, PatCfgNode { + private RecordPat node; + + RecordPatCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `RecordPat`. */ + RecordPat getRecordPat() { result = node } + + /** + * Gets the path of this record pat, if it exists. + */ + Path getPath() { result = node.getPath() } + + /** + * Holds if `getPath()` exists. + */ + predicate hasPath() { exists(this.getPath()) } + + /** + * Gets the record pat field list of this record pat, if it exists. + */ + RecordPatFieldList getRecordPatFieldList() { result = node.getRecordPatFieldList() } + + /** + * Holds if `getRecordPatFieldList()` exists. + */ + predicate hasRecordPatFieldList() { exists(this.getRecordPatFieldList()) } + } + + final private class ParentRefExpr extends ParentAstNode, RefExpr { + override predicate relevantChild(AstNode child) { + none() + or + child = this.getExpr() + } + } + + /** + * A reference expression. For example: + * ```rust + * let ref_const = &foo; + * let ref_mut = &mut foo; + * let raw_const: &mut i32 = &raw const foo; + * let raw_mut: &mut i32 = &raw mut foo; + * ``` + */ + final class RefExprCfgNode extends CfgNodeFinal, ExprCfgNode { + private RefExpr node; + + RefExprCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `RefExpr`. */ + RefExpr getRefExpr() { result = node } + + /** + * Gets the `index`th attr of this reference expression (0-based). + */ + Attr getAttr(int index) { result = node.getAttr(index) } + + /** + * Gets any of the attrs of this reference expression. + */ + Attr getAnAttr() { result = this.getAttr(_) } + + /** + * Gets the number of attrs of this reference expression. + */ + int getNumberOfAttrs() { result = count(int i | exists(this.getAttr(i))) } + + /** + * Gets the expression of this reference expression, if it exists. + */ + ExprCfgNode getExpr() { + any(ChildMapping mapping).hasCfgChild(node, node.getExpr(), this, result) + } + + /** + * Holds if `getExpr()` exists. + */ + predicate hasExpr() { exists(this.getExpr()) } + + /** + * Holds if this reference expression is const. + */ + predicate isConst() { node.isConst() } + + /** + * Holds if this reference expression is mut. + */ + predicate isMut() { node.isMut() } + + /** + * Holds if this reference expression is raw. + */ + predicate isRaw() { node.isRaw() } + } + + final private class ParentRefPat extends ParentAstNode, RefPat { + override predicate relevantChild(AstNode child) { + none() + or + child = this.getPat() + } + } + + /** + * A reference pattern. For example: + * ```rust + * match x { + * &mut Option::Some(y) => y, + * &Option::None => 0, + * }; + * ``` + */ + final class RefPatCfgNode extends CfgNodeFinal, PatCfgNode { + private RefPat node; + + RefPatCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `RefPat`. */ + RefPat getRefPat() { result = node } + + /** + * Holds if this reference pat is mut. + */ + predicate isMut() { node.isMut() } + + /** + * Gets the pat of this reference pat, if it exists. + */ + PatCfgNode getPat() { + any(ChildMapping mapping).hasCfgChild(node, node.getPat(), this, result) + } + + /** + * Holds if `getPat()` exists. + */ + predicate hasPat() { exists(this.getPat()) } + } + + final private class ParentRestPat extends ParentAstNode, RestPat { + override predicate relevantChild(AstNode child) { none() } + } + + /** + * A RestPat. For example: + * ```rust + * todo!() + * ``` + */ + final class RestPatCfgNode extends CfgNodeFinal, PatCfgNode { + private RestPat node; + + RestPatCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `RestPat`. */ + RestPat getRestPat() { result = node } + + /** + * Gets the `index`th attr of this rest pat (0-based). + */ + Attr getAttr(int index) { result = node.getAttr(index) } + + /** + * Gets any of the attrs of this rest pat. + */ + Attr getAnAttr() { result = this.getAttr(_) } + + /** + * Gets the number of attrs of this rest pat. + */ + int getNumberOfAttrs() { result = count(int i | exists(this.getAttr(i))) } + } + + final private class ParentReturnExpr extends ParentAstNode, ReturnExpr { + override predicate relevantChild(AstNode child) { + none() + or + child = this.getExpr() + } + } + + /** + * A return expression. For example: + * ```rust + * fn some_value() -> i32 { + * return 42; + * } + * ``` + * ```rust + * fn no_value() -> () { + * return; + * } + * ``` + */ + final class ReturnExprCfgNode extends CfgNodeFinal, ExprCfgNode { + private ReturnExpr node; + + ReturnExprCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `ReturnExpr`. */ + ReturnExpr getReturnExpr() { result = node } + + /** + * Gets the `index`th attr of this return expression (0-based). + */ + Attr getAttr(int index) { result = node.getAttr(index) } + + /** + * Gets any of the attrs of this return expression. + */ + Attr getAnAttr() { result = this.getAttr(_) } + + /** + * Gets the number of attrs of this return expression. + */ + int getNumberOfAttrs() { result = count(int i | exists(this.getAttr(i))) } + + /** + * Gets the expression of this return expression, if it exists. + */ + ExprCfgNode getExpr() { + any(ChildMapping mapping).hasCfgChild(node, node.getExpr(), this, result) + } + + /** + * Holds if `getExpr()` exists. + */ + predicate hasExpr() { exists(this.getExpr()) } + } + + final private class ParentSlicePat extends ParentAstNode, SlicePat { + override predicate relevantChild(AstNode child) { + none() + or + child = this.getPat(_) + } + } + + /** + * A slice pattern. For example: + * ```rust + * match x { + * [1, 2, 3, 4, 5] => "ok", + * [1, 2, ..] => "fail", + * [x, y, .., z, 7] => "fail", + * } + * ``` + */ + final class SlicePatCfgNode extends CfgNodeFinal, PatCfgNode { + private SlicePat node; + + SlicePatCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `SlicePat`. */ + SlicePat getSlicePat() { result = node } + + /** + * Gets the `index`th pat of this slice pat (0-based). + */ + PatCfgNode getPat(int index) { + any(ChildMapping mapping).hasCfgChild(node, node.getPat(index), this, result) + } + + /** + * Gets any of the pats of this slice pat. + */ + PatCfgNode getAPat() { result = this.getPat(_) } + + /** + * Gets the number of pats of this slice pat. + */ + int getNumberOfPats() { result = count(int i | exists(this.getPat(i))) } + } + + final private class ParentTryExpr extends ParentAstNode, TryExpr { + override predicate relevantChild(AstNode child) { + none() + or + child = this.getExpr() + } + } + + /** + * A TryExpr. For example: + * ```rust + * todo!() + * ``` + */ + final class TryExprCfgNode extends CfgNodeFinal, ExprCfgNode { + private TryExpr node; + + TryExprCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `TryExpr`. */ + TryExpr getTryExpr() { result = node } + + /** + * Gets the `index`th attr of this try expression (0-based). + */ + Attr getAttr(int index) { result = node.getAttr(index) } + + /** + * Gets any of the attrs of this try expression. + */ + Attr getAnAttr() { result = this.getAttr(_) } + + /** + * Gets the number of attrs of this try expression. + */ + int getNumberOfAttrs() { result = count(int i | exists(this.getAttr(i))) } + + /** + * Gets the expression of this try expression, if it exists. + */ + ExprCfgNode getExpr() { + any(ChildMapping mapping).hasCfgChild(node, node.getExpr(), this, result) + } + + /** + * Holds if `getExpr()` exists. + */ + predicate hasExpr() { exists(this.getExpr()) } + } + + final private class ParentTupleExpr extends ParentAstNode, TupleExpr { + override predicate relevantChild(AstNode child) { + none() + or + child = this.getField(_) + } + } + + /** + * A tuple expression. For example: + * ```rust + * (1, "one"); + * (2, "two")[0] = 3; + * ``` + */ + final class TupleExprCfgNode extends CfgNodeFinal, ExprCfgNode { + private TupleExpr node; + + TupleExprCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `TupleExpr`. */ + TupleExpr getTupleExpr() { result = node } + + /** + * Gets the `index`th attr of this tuple expression (0-based). + */ + Attr getAttr(int index) { result = node.getAttr(index) } + + /** + * Gets any of the attrs of this tuple expression. + */ + Attr getAnAttr() { result = this.getAttr(_) } + + /** + * Gets the number of attrs of this tuple expression. + */ + int getNumberOfAttrs() { result = count(int i | exists(this.getAttr(i))) } + + /** + * Gets the `index`th field of this tuple expression (0-based). + */ + ExprCfgNode getField(int index) { + any(ChildMapping mapping).hasCfgChild(node, node.getField(index), this, result) + } + + /** + * Gets any of the fields of this tuple expression. + */ + ExprCfgNode getAField() { result = this.getField(_) } + + /** + * Gets the number of fields of this tuple expression. + */ + int getNumberOfFields() { result = count(int i | exists(this.getField(i))) } + } + + final private class ParentTuplePat extends ParentAstNode, TuplePat { + override predicate relevantChild(AstNode child) { + none() + or + child = this.getField(_) + } + } + + /** + * A tuple pattern. For example: + * ```rust + * let (x, y) = (1, 2); + * let (a, b, .., z) = (1, 2, 3, 4, 5); + * ``` + */ + final class TuplePatCfgNode extends CfgNodeFinal, PatCfgNode { + private TuplePat node; + + TuplePatCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `TuplePat`. */ + TuplePat getTuplePat() { result = node } + + /** + * Gets the `index`th field of this tuple pat (0-based). + */ + PatCfgNode getField(int index) { + any(ChildMapping mapping).hasCfgChild(node, node.getField(index), this, result) + } + + /** + * Gets any of the fields of this tuple pat. + */ + PatCfgNode getAField() { result = this.getField(_) } + + /** + * Gets the number of fields of this tuple pat. + */ + int getNumberOfFields() { result = count(int i | exists(this.getField(i))) } + } + + final private class ParentTupleStructPat extends ParentAstNode, TupleStructPat { + override predicate relevantChild(AstNode child) { + none() + or + child = this.getField(_) + } + } + + /** + * A tuple struct pattern. For example: + * ```rust + * match x { + * Tuple("a", 1, 2, 3) => "great", + * Tuple(.., 3) => "fine", + * Tuple(..) => "fail", + * }; + * ``` + */ + final class TupleStructPatCfgNode extends CfgNodeFinal, PatCfgNode { + private TupleStructPat node; + + TupleStructPatCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `TupleStructPat`. */ + TupleStructPat getTupleStructPat() { result = node } + + /** + * Gets the `index`th field of this tuple struct pat (0-based). + */ + PatCfgNode getField(int index) { + any(ChildMapping mapping).hasCfgChild(node, node.getField(index), this, result) + } + + /** + * Gets any of the fields of this tuple struct pat. + */ + PatCfgNode getAField() { result = this.getField(_) } + + /** + * Gets the number of fields of this tuple struct pat. + */ + int getNumberOfFields() { result = count(int i | exists(this.getField(i))) } + + /** + * Gets the path of this tuple struct pat, if it exists. + */ + Path getPath() { result = node.getPath() } + + /** + * Holds if `getPath()` exists. + */ + predicate hasPath() { exists(this.getPath()) } + } + + final private class ParentUnderscoreExpr extends ParentAstNode, UnderscoreExpr { + override predicate relevantChild(AstNode child) { none() } + } + + /** + * An underscore expression. For example: + * ```rust + * _ = 42; + * ``` + */ + final class UnderscoreExprCfgNode extends CfgNodeFinal, ExprCfgNode { + private UnderscoreExpr node; + + UnderscoreExprCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `UnderscoreExpr`. */ + UnderscoreExpr getUnderscoreExpr() { result = node } + + /** + * Gets the `index`th attr of this underscore expression (0-based). + */ + Attr getAttr(int index) { result = node.getAttr(index) } + + /** + * Gets any of the attrs of this underscore expression. + */ + Attr getAnAttr() { result = this.getAttr(_) } + + /** + * Gets the number of attrs of this underscore expression. + */ + int getNumberOfAttrs() { result = count(int i | exists(this.getAttr(i))) } + } + + final private class ParentWhileExpr extends ParentAstNode, WhileExpr { + override predicate relevantChild(AstNode child) { + none() + or + child = this.getCondition() + or + child = this.getLoopBody() + } + } + + /** + * A WhileExpr. For example: + * ```rust + * todo!() + * ``` + */ + final class WhileExprCfgNode extends CfgNodeFinal, ExprCfgNode { + private WhileExpr node; + + WhileExprCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `WhileExpr`. */ + WhileExpr getWhileExpr() { result = node } + + /** + * Gets the `index`th attr of this while expression (0-based). + */ + Attr getAttr(int index) { result = node.getAttr(index) } + + /** + * Gets any of the attrs of this while expression. + */ + Attr getAnAttr() { result = this.getAttr(_) } + + /** + * Gets the number of attrs of this while expression. + */ + int getNumberOfAttrs() { result = count(int i | exists(this.getAttr(i))) } + + /** + * Gets the condition of this while expression, if it exists. + */ + ExprCfgNode getCondition() { + any(ChildMapping mapping).hasCfgChild(node, node.getCondition(), this, result) + } + + /** + * Holds if `getCondition()` exists. + */ + predicate hasCondition() { exists(this.getCondition()) } + + /** + * Gets the label of this while expression, if it exists. + */ + Label getLabel() { result = node.getLabel() } + + /** + * Holds if `getLabel()` exists. + */ + predicate hasLabel() { exists(this.getLabel()) } + + /** + * Gets the loop body of this while expression, if it exists. + */ + BlockExprCfgNode getLoopBody() { + any(ChildMapping mapping).hasCfgChild(node, node.getLoopBody(), this, result) + } + + /** + * Holds if `getLoopBody()` exists. + */ + predicate hasLoopBody() { exists(this.getLoopBody()) } + } + + final private class ParentWildcardPat extends ParentAstNode, WildcardPat { + override predicate relevantChild(AstNode child) { none() } + } + + /** + * A wildcard pattern. For example: + * ```rust + * let _ = 42; + * ``` + */ + final class WildcardPatCfgNode extends CfgNodeFinal, PatCfgNode { + private WildcardPat node; + + WildcardPatCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `WildcardPat`. */ + WildcardPat getWildcardPat() { result = node } + } + + final private class ParentYeetExpr extends ParentAstNode, YeetExpr { + override predicate relevantChild(AstNode child) { + none() + or + child = this.getExpr() + } + } + + /** + * A `yeet` expression. For example: + * ```rust + * if x < size { + * do yeet "index out of bounds"; + * } + * ``` + */ + final class YeetExprCfgNode extends CfgNodeFinal, ExprCfgNode { + private YeetExpr node; + + YeetExprCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `YeetExpr`. */ + YeetExpr getYeetExpr() { result = node } + + /** + * Gets the `index`th attr of this yeet expression (0-based). + */ + Attr getAttr(int index) { result = node.getAttr(index) } + + /** + * Gets any of the attrs of this yeet expression. + */ + Attr getAnAttr() { result = this.getAttr(_) } + + /** + * Gets the number of attrs of this yeet expression. + */ + int getNumberOfAttrs() { result = count(int i | exists(this.getAttr(i))) } + + /** + * Gets the expression of this yeet expression, if it exists. + */ + ExprCfgNode getExpr() { + any(ChildMapping mapping).hasCfgChild(node, node.getExpr(), this, result) + } + + /** + * Holds if `getExpr()` exists. + */ + predicate hasExpr() { exists(this.getExpr()) } + } + + final private class ParentYieldExpr extends ParentAstNode, YieldExpr { + override predicate relevantChild(AstNode child) { + none() + or + child = this.getExpr() + } + } + + /** + * A `yield` expression. For example: + * ```rust + * let one = #[coroutine] + * || { + * yield 1; + * }; + * ``` + */ + final class YieldExprCfgNode extends CfgNodeFinal, ExprCfgNode { + private YieldExpr node; + + YieldExprCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `YieldExpr`. */ + YieldExpr getYieldExpr() { result = node } + + /** + * Gets the `index`th attr of this yield expression (0-based). + */ + Attr getAttr(int index) { result = node.getAttr(index) } + + /** + * Gets any of the attrs of this yield expression. + */ + Attr getAnAttr() { result = this.getAttr(_) } + + /** + * Gets the number of attrs of this yield expression. + */ + int getNumberOfAttrs() { result = count(int i | exists(this.getAttr(i))) } + + /** + * Gets the expression of this yield expression, if it exists. + */ + ExprCfgNode getExpr() { + any(ChildMapping mapping).hasCfgChild(node, node.getExpr(), this, result) + } + + /** + * Holds if `getExpr()` exists. + */ + predicate hasExpr() { exists(this.getExpr()) } + } + } + + module Consistency { + private predicate hasCfgNode(AstNode astNode) { astNode = any(CfgNode cfgNode).getAstNode() } + + query predicate missingCfgChild(CfgNode parent, string pred, int i, AstNode child) { + none() + or + pred = "getExpr" and + parent = + any(Nodes::ArrayExprCfgNode cfgNode, ArrayExpr astNode | + astNode = cfgNode.getArrayExpr() and + child = getDesugared(astNode.getExpr(i)) and + hasCfgNode(child) and + not child = cfgNode.getExpr(i).getAstNode() + | + cfgNode + ) + or + pred = "getExpr" and + parent = + any(Nodes::AsmExprCfgNode cfgNode, AsmExpr astNode | + astNode = cfgNode.getAsmExpr() and + child = getDesugared(astNode.getExpr()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getExpr().getAstNode() + | + cfgNode + ) + or + pred = "getExpr" and + parent = + any(Nodes::AwaitExprCfgNode cfgNode, AwaitExpr astNode | + astNode = cfgNode.getAwaitExpr() and + child = getDesugared(astNode.getExpr()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getExpr().getAstNode() + | + cfgNode + ) + or + pred = "getExpr" and + parent = + any(Nodes::BecomeExprCfgNode cfgNode, BecomeExpr astNode | + astNode = cfgNode.getBecomeExpr() and + child = getDesugared(astNode.getExpr()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getExpr().getAstNode() + | + cfgNode + ) + or + pred = "getLhs" and + parent = + any(Nodes::BinaryExprCfgNode cfgNode, BinaryExpr astNode | + astNode = cfgNode.getBinaryExpr() and + child = getDesugared(astNode.getLhs()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getLhs().getAstNode() + | + cfgNode + ) + or + pred = "getRhs" and + parent = + any(Nodes::BinaryExprCfgNode cfgNode, BinaryExpr astNode | + astNode = cfgNode.getBinaryExpr() and + child = getDesugared(astNode.getRhs()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getRhs().getAstNode() + | + cfgNode + ) + or + pred = "getPat" and + parent = + any(Nodes::BoxPatCfgNode cfgNode, BoxPat astNode | + astNode = cfgNode.getBoxPat() and + child = getDesugared(astNode.getPat()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getPat().getAstNode() + | + cfgNode + ) + or + pred = "getExpr" and + parent = + any(Nodes::BreakExprCfgNode cfgNode, BreakExpr astNode | + astNode = cfgNode.getBreakExpr() and + child = getDesugared(astNode.getExpr()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getExpr().getAstNode() + | + cfgNode + ) + or + pred = "getExpr" and + parent = + any(Nodes::CallExprCfgNode cfgNode, CallExpr astNode | + astNode = cfgNode.getCallExpr() and + child = getDesugared(astNode.getExpr()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getExpr().getAstNode() + | + cfgNode + ) + or + pred = "getBlockExpr" and + parent = + any(Nodes::ConstBlockPatCfgNode cfgNode, ConstBlockPat astNode | + astNode = cfgNode.getConstBlockPat() and + child = getDesugared(astNode.getBlockExpr()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getBlockExpr().getAstNode() + | + cfgNode + ) + or + pred = "getExpr" and + parent = + any(Nodes::FieldExprCfgNode cfgNode, FieldExpr astNode | + astNode = cfgNode.getFieldExpr() and + child = getDesugared(astNode.getExpr()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getExpr().getAstNode() + | + cfgNode + ) + or + pred = "getIterable" and + parent = + any(Nodes::ForExprCfgNode cfgNode, ForExpr astNode | + astNode = cfgNode.getForExpr() and + child = getDesugared(astNode.getIterable()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getIterable().getAstNode() + | + cfgNode + ) + or + pred = "getLoopBody" and + parent = + any(Nodes::ForExprCfgNode cfgNode, ForExpr astNode | + astNode = cfgNode.getForExpr() and + child = getDesugared(astNode.getLoopBody()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getLoopBody().getAstNode() + | + cfgNode + ) + or + pred = "getPat" and + parent = + any(Nodes::ForExprCfgNode cfgNode, ForExpr astNode | + astNode = cfgNode.getForExpr() and + child = getDesugared(astNode.getPat()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getPat().getAstNode() + | + cfgNode + ) + or + pred = "getTemplate" and + parent = + any(Nodes::FormatArgsExprCfgNode cfgNode, FormatArgsExpr astNode | + astNode = cfgNode.getFormatArgsExpr() and + child = getDesugared(astNode.getTemplate()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getTemplate().getAstNode() + | + cfgNode + ) + or + pred = "getPat" and + parent = + any(Nodes::IdentPatCfgNode cfgNode, IdentPat astNode | + astNode = cfgNode.getIdentPat() and + child = getDesugared(astNode.getPat()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getPat().getAstNode() + | + cfgNode + ) + or + pred = "getCondition" and + parent = + any(Nodes::IfExprCfgNode cfgNode, IfExpr astNode | + astNode = cfgNode.getIfExpr() and + child = getDesugared(astNode.getCondition()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getCondition().getAstNode() + | + cfgNode + ) + or + pred = "getElse" and + parent = + any(Nodes::IfExprCfgNode cfgNode, IfExpr astNode | + astNode = cfgNode.getIfExpr() and + child = getDesugared(astNode.getElse()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getElse().getAstNode() + | + cfgNode + ) + or + pred = "getThen" and + parent = + any(Nodes::IfExprCfgNode cfgNode, IfExpr astNode | + astNode = cfgNode.getIfExpr() and + child = getDesugared(astNode.getThen()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getThen().getAstNode() + | + cfgNode + ) + or + pred = "getBase" and + parent = + any(Nodes::IndexExprCfgNode cfgNode, IndexExpr astNode | + astNode = cfgNode.getIndexExpr() and + child = getDesugared(astNode.getBase()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getBase().getAstNode() + | + cfgNode + ) + or + pred = "getIndex" and + parent = + any(Nodes::IndexExprCfgNode cfgNode, IndexExpr astNode | + astNode = cfgNode.getIndexExpr() and + child = getDesugared(astNode.getIndex()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getIndex().getAstNode() + | + cfgNode + ) + or + pred = "getExpr" and + parent = + any(Nodes::LetExprCfgNode cfgNode, LetExpr astNode | + astNode = cfgNode.getLetExpr() and + child = getDesugared(astNode.getExpr()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getExpr().getAstNode() + | + cfgNode + ) + or + pred = "getPat" and + parent = + any(Nodes::LetExprCfgNode cfgNode, LetExpr astNode | + astNode = cfgNode.getLetExpr() and + child = getDesugared(astNode.getPat()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getPat().getAstNode() + | + cfgNode + ) + or + pred = "getInitializer" and + parent = + any(Nodes::LetStmtCfgNode cfgNode, LetStmt astNode | + astNode = cfgNode.getLetStmt() and + child = getDesugared(astNode.getInitializer()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getInitializer().getAstNode() + | + cfgNode + ) + or + pred = "getPat" and + parent = + any(Nodes::LetStmtCfgNode cfgNode, LetStmt astNode | + astNode = cfgNode.getLetStmt() and + child = getDesugared(astNode.getPat()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getPat().getAstNode() + | + cfgNode + ) + or + pred = "getLiteral" and + parent = + any(Nodes::LiteralPatCfgNode cfgNode, LiteralPat astNode | + astNode = cfgNode.getLiteralPat() and + child = getDesugared(astNode.getLiteral()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getLiteral().getAstNode() + | + cfgNode + ) + or + pred = "getLoopBody" and + parent = + any(Nodes::LoopExprCfgNode cfgNode, LoopExpr astNode | + astNode = cfgNode.getLoopExpr() and + child = getDesugared(astNode.getLoopBody()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getLoopBody().getAstNode() + | + cfgNode + ) + or + pred = "getMacroCall" and + parent = + any(Nodes::MacroExprCfgNode cfgNode, MacroExpr astNode | + astNode = cfgNode.getMacroExpr() and + child = getDesugared(astNode.getMacroCall()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getMacroCall().getAstNode() + | + cfgNode + ) + or + pred = "getMacroCall" and + parent = + any(Nodes::MacroPatCfgNode cfgNode, MacroPat astNode | + astNode = cfgNode.getMacroPat() and + child = getDesugared(astNode.getMacroCall()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getMacroCall().getAstNode() + | + cfgNode + ) + or + pred = "getExpr" and + parent = + any(Nodes::MatchExprCfgNode cfgNode, MatchExpr astNode | + astNode = cfgNode.getMatchExpr() and + child = getDesugared(astNode.getExpr()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getExpr().getAstNode() + | + cfgNode + ) + or + pred = "getReceiver" and + parent = + any(Nodes::MethodCallExprCfgNode cfgNode, MethodCallExpr astNode | + astNode = cfgNode.getMethodCallExpr() and + child = getDesugared(astNode.getReceiver()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getReceiver().getAstNode() + | + cfgNode + ) + or + pred = "getPat" and + parent = + any(Nodes::OrPatCfgNode cfgNode, OrPat astNode | + astNode = cfgNode.getOrPat() and + child = getDesugared(astNode.getPat(i)) and + hasCfgNode(child) and + not child = cfgNode.getPat(i).getAstNode() + | + cfgNode + ) + or + pred = "getPat" and + parent = + any(Nodes::ParamCfgNode cfgNode, Param astNode | + astNode = cfgNode.getParam() and + child = getDesugared(astNode.getPat()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getPat().getAstNode() + | + cfgNode + ) + or + pred = "getExpr" and + parent = + any(Nodes::PrefixExprCfgNode cfgNode, PrefixExpr astNode | + astNode = cfgNode.getPrefixExpr() and + child = getDesugared(astNode.getExpr()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getExpr().getAstNode() + | + cfgNode + ) + or + pred = "getEnd" and + parent = + any(Nodes::RangeExprCfgNode cfgNode, RangeExpr astNode | + astNode = cfgNode.getRangeExpr() and + child = getDesugared(astNode.getEnd()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getEnd().getAstNode() + | + cfgNode + ) + or + pred = "getStart" and + parent = + any(Nodes::RangeExprCfgNode cfgNode, RangeExpr astNode | + astNode = cfgNode.getRangeExpr() and + child = getDesugared(astNode.getStart()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getStart().getAstNode() + | + cfgNode + ) + or + pred = "getEnd" and + parent = + any(Nodes::RangePatCfgNode cfgNode, RangePat astNode | + astNode = cfgNode.getRangePat() and + child = getDesugared(astNode.getEnd()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getEnd().getAstNode() + | + cfgNode + ) + or + pred = "getStart" and + parent = + any(Nodes::RangePatCfgNode cfgNode, RangePat astNode | + astNode = cfgNode.getRangePat() and + child = getDesugared(astNode.getStart()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getStart().getAstNode() + | + cfgNode + ) + or + pred = "getExpr" and + parent = + any(Nodes::RefExprCfgNode cfgNode, RefExpr astNode | + astNode = cfgNode.getRefExpr() and + child = getDesugared(astNode.getExpr()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getExpr().getAstNode() + | + cfgNode + ) + or + pred = "getPat" and + parent = + any(Nodes::RefPatCfgNode cfgNode, RefPat astNode | + astNode = cfgNode.getRefPat() and + child = getDesugared(astNode.getPat()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getPat().getAstNode() + | + cfgNode + ) + or + pred = "getExpr" and + parent = + any(Nodes::ReturnExprCfgNode cfgNode, ReturnExpr astNode | + astNode = cfgNode.getReturnExpr() and + child = getDesugared(astNode.getExpr()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getExpr().getAstNode() + | + cfgNode + ) + or + pred = "getPat" and + parent = + any(Nodes::SlicePatCfgNode cfgNode, SlicePat astNode | + astNode = cfgNode.getSlicePat() and + child = getDesugared(astNode.getPat(i)) and + hasCfgNode(child) and + not child = cfgNode.getPat(i).getAstNode() + | + cfgNode + ) + or + pred = "getExpr" and + parent = + any(Nodes::TryExprCfgNode cfgNode, TryExpr astNode | + astNode = cfgNode.getTryExpr() and + child = getDesugared(astNode.getExpr()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getExpr().getAstNode() + | + cfgNode + ) + or + pred = "getField" and + parent = + any(Nodes::TupleExprCfgNode cfgNode, TupleExpr astNode | + astNode = cfgNode.getTupleExpr() and + child = getDesugared(astNode.getField(i)) and + hasCfgNode(child) and + not child = cfgNode.getField(i).getAstNode() + | + cfgNode + ) + or + pred = "getField" and + parent = + any(Nodes::TuplePatCfgNode cfgNode, TuplePat astNode | + astNode = cfgNode.getTuplePat() and + child = getDesugared(astNode.getField(i)) and + hasCfgNode(child) and + not child = cfgNode.getField(i).getAstNode() + | + cfgNode + ) + or + pred = "getField" and + parent = + any(Nodes::TupleStructPatCfgNode cfgNode, TupleStructPat astNode | + astNode = cfgNode.getTupleStructPat() and + child = getDesugared(astNode.getField(i)) and + hasCfgNode(child) and + not child = cfgNode.getField(i).getAstNode() + | + cfgNode + ) + or + pred = "getCondition" and + parent = + any(Nodes::WhileExprCfgNode cfgNode, WhileExpr astNode | + astNode = cfgNode.getWhileExpr() and + child = getDesugared(astNode.getCondition()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getCondition().getAstNode() + | + cfgNode + ) + or + pred = "getLoopBody" and + parent = + any(Nodes::WhileExprCfgNode cfgNode, WhileExpr astNode | + astNode = cfgNode.getWhileExpr() and + child = getDesugared(astNode.getLoopBody()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getLoopBody().getAstNode() + | + cfgNode + ) + or + pred = "getExpr" and + parent = + any(Nodes::YeetExprCfgNode cfgNode, YeetExpr astNode | + astNode = cfgNode.getYeetExpr() and + child = getDesugared(astNode.getExpr()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getExpr().getAstNode() + | + cfgNode + ) + or + pred = "getExpr" and + parent = + any(Nodes::YieldExprCfgNode cfgNode, YieldExpr astNode | + astNode = cfgNode.getYieldExpr() and + child = getDesugared(astNode.getExpr()) and + i = -1 and + hasCfgNode(child) and + not child = cfgNode.getExpr().getAstNode() + | + cfgNode + ) + } + } +} diff --git a/rust/ql/lib/codeql/rust/elements/internal/AstNodeImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/AstNodeImpl.qll index f2784d058ae..cbe9653e493 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/AstNodeImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/AstNodeImpl.qll @@ -14,6 +14,7 @@ private import codeql.rust.controlflow.ControlFlowGraph module Impl { private import rust private import codeql.rust.elements.internal.generated.ParentChild + private import codeql.rust.controlflow.ControlFlowGraph /** * Gets the immediate parent of a non-`AstNode` element `e`. @@ -62,5 +63,37 @@ module Impl { or this.getParentNode().isInMacroExpansion() } + + /** + * Gets a control-flow node for this AST node, if any. + * + * Note that because of _control-flow splitting_, one `AstNode` node may correspond + * to multiple `CfgNode`s. Example: + * + * ```rust + * if a && b { + * // ... + * } + * ``` + * + * The CFG for the condition above looks like + * + * ```mermaid + * flowchart TD + * 1["a"] + * 2["b"] + * 3["[false] a && b"] + * 4["[true] a && b"] + * + * 1 -- false --> 3 + * 1 -- true --> 2 + * 2 -- false --> 3 + * 2 -- true --> 4 + * ``` + * + * That is, the AST node for `a && b` corresponds to _two_ CFG nodes (it is + * split into two). + */ + CfgNode getACfgNode() { this = result.getAstNode() } } } diff --git a/rust/ql/lib/codeql/rust/internal/CachedStages.qll b/rust/ql/lib/codeql/rust/internal/CachedStages.qll index 162853846f2..3defe0b8168 100644 --- a/rust/ql/lib/codeql/rust/internal/CachedStages.qll +++ b/rust/ql/lib/codeql/rust/internal/CachedStages.qll @@ -71,6 +71,7 @@ module Stages { private import codeql.rust.controlflow.internal.Splitting private import codeql.rust.controlflow.internal.SuccessorType private import codeql.rust.controlflow.internal.ControlFlowGraphImpl + private import codeql.rust.controlflow.CfgNodes /** * Always holds. @@ -93,6 +94,8 @@ module Stages { exists(TNormalSuccessor()) or exists(AstCfgNode n) + or + exists(CallExprCfgNode n | exists(n.getExpr())) } } } diff --git a/rust/ql/test/query-tests/diagnostics/CfgConsistencyCounts.expected b/rust/ql/test/query-tests/diagnostics/CfgConsistencyCounts.expected index 7df2863da9e..7056936908c 100644 --- a/rust/ql/test/query-tests/diagnostics/CfgConsistencyCounts.expected +++ b/rust/ql/test/query-tests/diagnostics/CfgConsistencyCounts.expected @@ -1,5 +1,6 @@ | CFG scope lacks initial AST node | 0 | | Dead end | 0 | +| Missing CFG child | 0 | | Multiple successors of the same type | 0 | | Multiple toStrings | 0 | | Non-PostOrderTree Expr node | 0 | diff --git a/rust/schema/annotations.py b/rust/schema/annotations.py index d8e9835b16a..e84648ca662 100644 --- a/rust/schema/annotations.py +++ b/rust/schema/annotations.py @@ -18,14 +18,14 @@ class _: """ -@annotate(Expr) +@annotate(Expr, cfg = True) class _: """ The base class for expressions. """ -@annotate(Pat) +@annotate(Pat, cfg = True) class _: """ The base class for patterns. @@ -106,7 +106,7 @@ class PathExprBase(Expr): """ -@annotate(PathExpr, replace_bases={Expr: PathExprBase}) +@annotate(PathExpr, replace_bases={Expr: PathExprBase}, cfg = True) class _: """ A path expression. For example: @@ -119,7 +119,7 @@ class _: """ -@annotate(IfExpr) +@annotate(IfExpr, cfg = True) class _: """ An `if` expression. For example: @@ -138,7 +138,7 @@ class _: """ -@annotate(LetExpr) +@annotate(LetExpr, cfg = True) @rust.doc_test_signature("(maybe_some: Option) -> ()") class _: """ @@ -151,7 +151,7 @@ class _: """ -@annotate(BlockExpr) +@annotate(BlockExpr, cfg = True) class _: """ A block expression. For example: @@ -169,7 +169,7 @@ class _: """ -@annotate(LoopExpr) +@annotate(LoopExpr, cfg = True) class _: """ A loop expression. For example: @@ -205,7 +205,7 @@ class CallExprBase(Expr): attrs: list["Attr"] | child -@annotate(CallExpr, replace_bases={Expr: CallExprBase}) +@annotate(CallExpr, replace_bases={Expr: CallExprBase}, cfg = True) class _: """ A function call expression. For example: @@ -220,7 +220,7 @@ class _: attrs: drop -@annotate(MethodCallExpr, replace_bases={Expr: CallExprBase}, add_bases=(Resolvable,)) +@annotate(MethodCallExpr, replace_bases={Expr: CallExprBase}, add_bases=(Resolvable,), cfg = True) class _: """ A method call expression. For example: @@ -253,7 +253,7 @@ class _: """ -@annotate(MatchExpr) +@annotate(MatchExpr, cfg = True) @rust.doc_test_signature("(x: i32) -> i32") class _: """ @@ -273,7 +273,7 @@ class _: """ -@annotate(ContinueExpr) +@annotate(ContinueExpr, cfg = True) class _: """ A continue expression. For example: @@ -294,7 +294,7 @@ class _: """ -@annotate(BreakExpr) +@annotate(BreakExpr, cfg = True) class _: """ A break expression. For example: @@ -323,7 +323,7 @@ class _: """ -@annotate(ReturnExpr) +@annotate(ReturnExpr, cfg = True) @rust.doc_test_signature(None) class _: """ @@ -341,7 +341,7 @@ class _: """ -@annotate(BecomeExpr) +@annotate(BecomeExpr, cfg = True) @rust.doc_test_signature(None) class _: """ @@ -358,7 +358,7 @@ class _: """ -@annotate(YieldExpr) +@annotate(YieldExpr, cfg = True) class _: """ A `yield` expression. For example: @@ -371,7 +371,7 @@ class _: """ -@annotate(YeetExpr) +@annotate(YeetExpr, cfg = True) class _: """ A `yeet` expression. For example: @@ -393,7 +393,7 @@ class _: """ -@annotate(RecordExpr) +@annotate(RecordExpr, cfg = True) class _: """ A record expression. For example: @@ -406,7 +406,7 @@ class _: """ -@annotate(FieldExpr) +@annotate(FieldExpr, cfg = True) class _: """ A field access expression. For example: @@ -416,7 +416,7 @@ class _: """ -@annotate(AwaitExpr) +@annotate(AwaitExpr, cfg = True) class _: """ An `await` expression. For example: @@ -439,7 +439,7 @@ class _: """ -@annotate(RefExpr) +@annotate(RefExpr, cfg = True) class _: """ A reference expression. For example: @@ -452,7 +452,7 @@ class _: """ -@annotate(PrefixExpr) +@annotate(PrefixExpr, cfg = True) class _: """ A unary operation expression. For example: @@ -464,7 +464,7 @@ class _: """ -@annotate(BinaryExpr) +@annotate(BinaryExpr, cfg = True) class _: """ A binary operation expression. For example: @@ -478,7 +478,7 @@ class _: """ -@annotate(RangeExpr) +@annotate(RangeExpr, cfg = True) class _: """ A range expression. For example: @@ -493,7 +493,7 @@ class _: """ -@annotate(IndexExpr) +@annotate(IndexExpr, cfg = True) class _: """ An index expression. For example: @@ -520,7 +520,7 @@ class _: """ -@annotate(TupleExpr) +@annotate(TupleExpr, cfg = True) class _: """ A tuple expression. For example: @@ -531,7 +531,7 @@ class _: """ -@annotate(ArrayExpr) +@annotate(ArrayExpr, cfg = True) class _: """ An array expression. For example: @@ -542,7 +542,7 @@ class _: """ -@annotate(LiteralExpr) +@annotate(LiteralExpr, cfg = True) class _: """ A literal expression. For example: @@ -559,7 +559,7 @@ class _: """ -@annotate(UnderscoreExpr) +@annotate(UnderscoreExpr, cfg = True) class _: """ An underscore expression. For example: @@ -569,7 +569,7 @@ class _: """ -@annotate(OffsetOfExpr) +@annotate(OffsetOfExpr, cfg = True) class _: """ An `offset_of` expression. For example: @@ -579,7 +579,7 @@ class _: """ -@annotate(AsmExpr) +@annotate(AsmExpr, cfg = True) class _: """ An inline assembly expression. For example: @@ -591,7 +591,7 @@ class _: """ -@annotate(LetStmt) +@annotate(LetStmt, cfg = True) class _: """ A let statement. For example: @@ -620,7 +620,7 @@ class _: """ -@annotate(WildcardPat) +@annotate(WildcardPat, cfg = True) class _: """ A wildcard pattern. For example: @@ -630,7 +630,7 @@ class _: """ -@annotate(TuplePat) +@annotate(TuplePat, cfg = True) class _: """ A tuple pattern. For example: @@ -641,7 +641,7 @@ class _: """ -@annotate(OrPat) +@annotate(OrPat, cfg = True) class _: """ An or pattern. For example: @@ -663,7 +663,7 @@ class _: """ -@annotate(RecordPat) +@annotate(RecordPat, cfg = True) class _: """ A record pattern. For example: @@ -676,7 +676,7 @@ class _: """ -@annotate(RangePat) +@annotate(RangePat, cfg = True) class _: """ A range pattern. For example: @@ -690,7 +690,7 @@ class _: """ -@annotate(SlicePat) +@annotate(SlicePat, cfg = True) class _: """ A slice pattern. For example: @@ -704,7 +704,7 @@ class _: """ -@annotate(PathPat) +@annotate(PathPat, cfg = True) class _: """ A path pattern. For example: @@ -717,7 +717,7 @@ class _: """ -@annotate(LiteralPat) +@annotate(LiteralPat, cfg = True) class _: """ A literal pattern. For example: @@ -730,7 +730,7 @@ class _: """ -@annotate(IdentPat) +@annotate(IdentPat, cfg = True) class _: """ A binding pattern. For example: @@ -749,7 +749,7 @@ class _: """ -@annotate(TupleStructPat) +@annotate(TupleStructPat, cfg = True) class _: """ A tuple struct pattern. For example: @@ -763,7 +763,7 @@ class _: """ -@annotate(RefPat) +@annotate(RefPat, cfg = True) class _: """ A reference pattern. For example: @@ -776,7 +776,7 @@ class _: """ -@annotate(BoxPat) +@annotate(BoxPat, cfg = True) class _: """ A box pattern. For example: @@ -789,7 +789,7 @@ class _: """ -@annotate(ConstBlockPat) +@annotate(ConstBlockPat, cfg = True) class _: """ A const block pattern. For example: @@ -990,7 +990,7 @@ class _: """ -@annotate(ForExpr) +@annotate(ForExpr, cfg = True) class _: """ A ForExpr. For example: @@ -1020,7 +1020,7 @@ class _: """ -@annotate(FormatArgsExpr) +@annotate(FormatArgsExpr, cfg = True) class _: """ A FormatArgsExpr. For example: @@ -1150,7 +1150,7 @@ class _: """ -@annotate(MacroCall) +@annotate(MacroCall, cfg = True) class _: """ A MacroCall. For example: @@ -1171,7 +1171,7 @@ class _: """ -@annotate(MacroExpr) +@annotate(MacroExpr, cfg = True) class _: """ A MacroExpr. For example: @@ -1194,7 +1194,7 @@ class _: """ -@annotate(MacroPat) +@annotate(MacroPat, cfg = True) class _: """ A MacroPat. For example: @@ -1297,7 +1297,7 @@ class _: """ -@annotate(Param) +@annotate(Param, cfg = True) class _: """ A Param. For example: @@ -1437,7 +1437,7 @@ class _: """ -@annotate(RestPat) +@annotate(RestPat, cfg = True) class _: """ A RestPat. For example: @@ -1564,7 +1564,7 @@ class _: """ -@annotate(TryExpr) +@annotate(TryExpr, cfg = True) class _: """ A TryExpr. For example: @@ -1744,7 +1744,7 @@ class _: """ -@annotate(WhileExpr) +@annotate(WhileExpr, cfg = True) class _: """ A WhileExpr. For example: