diff --git a/misc/codegen/codegen.py b/misc/codegen/codegen.py index acc8e59bba5f..ae3a67d3fba6 100755 --- a/misc/codegen/codegen.py +++ b/misc/codegen/codegen.py @@ -54,6 +54,8 @@ def _parse_args() -> argparse.Namespace: "generated qll file importing every class file"), p.add_argument("--ql-test-output", help="output directory for QL generated extractor test files"), + p.add_argument("--ql-cfg-output", + help="output directory for QL CFG layer (optional)."), p.add_argument("--cpp-output", help="output directory for generated C++ files, required if trap or cpp is provided to " "--generate"), diff --git a/misc/codegen/generators/qlgen.py b/misc/codegen/generators/qlgen.py index c5e7153489b6..f1a68f6bc014 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 1920a813e20d..1182c7f5dc16 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 ConstructorStub: 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 c5c3dc810b68..23f1aea2ba42 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 997b85b4ca6a..32d3a6b85aed 100644 --- a/misc/codegen/lib/schemadefs.py +++ b/misc/codegen/lib/schemadefs.py @@ -279,7 +279,7 @@ def __or__(self, other: _schema.PropertyModifier): 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 decorator(cls: type) -> _PropertyAnnotation: 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 069e3b654740..dd1edee1de09 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 000000000000..a2edf4410be0 --- /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 29b6edc89853..d40fada446bb 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 ca25e0533fc8..e3fe15f3e5bf 100644 --- a/rust/ql/.generated.list +++ b/rust/ql/.generated.list @@ -1,3 +1,4 @@ +lib/codeql/rust/controlflow/internal/generated/CfgNodes.qll e7bcae1016e1853d46d9c91dc5f9b81e81d207fdf91fdaa6eadb3bf185879674 541d386db1f0b662d0cbe1aface1bc6e4b1bc484d1230b95523f35ca63c08875 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 a532f142ec98..68b893ba9c78 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 4a51506dbc0a..b60a6b857b2e 100644 --- a/rust/ql/lib/codeql/rust/controlflow/CfgNodes.qll +++ b/rust/ql/lib/codeql/rust/controlflow/CfgNodes.qll @@ -5,56 +5,189 @@ 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 { - AstNode node; +class AstCfgNode = CfgImpl::AstCfgNode; - AstCfgNode() { node = this.getAstNode() } +class ExitCfgNode = CfgImpl::ExitNode; - /** Gets the underlying ast node. */ - AstNode getAstNode() { result = node } -} +/** + * An assignment expression, for example + * + * ```rust + * x = y; + * ``` + */ +final class AssignmentExprCfgNode extends BinaryExprCfgNode { + AssignmentExpr a; -/** A CFG node that corresponds to a parameter in the AST. */ -class ParamCfgNode extends AstCfgNode { - override Param node; + AssignmentExprCfgNode() { a = this.getBinaryExpr() } - /** Gets the underlying parameter. */ - Param getParam() { result = node } + /** Gets the underlying `AssignmentExpr`. */ + AssignmentExpr getAssignmentExpr() { result = a } } -/** A CFG node that corresponds to a parameter in the AST. */ -class PatCfgNode extends AstCfgNode { - override Pat node; +/** + * 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 Nodes::MatchExprCfgNode { + private MatchExpr node; - /** Gets the underlying pattern. */ - Pat getPat() { result = node } -} + MatchExprCfgNode() { node = this.getMatchExpr() } + + /** + * Gets the pattern of the `i`th match arm, if it exists. + */ + PatCfgNode getArmPat(int i) { + any(ChildMapping mapping).hasCfgChild(node, node.getArm(i).getPat(), this, result) + } -/** A CFG node that corresponds to an expression in the AST. */ -class ExprCfgNode extends AstCfgNode { - override Expr node; + /** + * Gets the guard of the `i`th match arm, if it exists. + */ + ExprCfgNode getArmGuard(int i) { + any(ChildMapping mapping) + .hasCfgChild(node, node.getArm(i).getGuard().getCondition(), this, result) + } - /** Gets the underlying expression. */ - Expr getExpr() { result = node } + /** + * Gets the expression of the `i`th match arm, if it exists. + */ + ExprCfgNode getArmExpr(int i) { + any(ChildMapping mapping).hasCfgChild(node, node.getArm(i).getExpr(), this, result) + } } -/** A CFG node that corresponds to a call in the AST. */ -class CallExprCfgNode extends ExprCfgNode { - override CallExpr node; +/** + * A block expression. For example: + * ```rust + * { + * let x = 42; + * } + * ``` + * ```rust + * 'label: { + * let x = 42; + * x + * } + * ``` + */ +final class BlockExprCfgNode extends Nodes::BlockExprCfgNode { + private BlockExprChildMapping node; - /** Gets the underlying `CallExpr`. */ - CallExpr getCallExpr() { result = node } + BlockExprCfgNode() { node = this.getAstNode() } + + /** + * Gets the tail expression of this block, if it exists. + */ + ExprCfgNode getTailExpr() { + any(ChildMapping mapping).hasCfgChild(node, node.getStmtList().getTailExpr(), this, result) + } +} + +/** + * 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 Nodes::BreakExprCfgNode { + /** + * Gets the target of this `break` expression. + * + * The target is either a `LoopExpr`, a `ForExpr`, a `WhileExpr`, or a + * `BlockExpr`. + */ + ExprCfgNode getTarget() { + any(ChildMapping mapping) + .hasCfgChild(this.getBreakExpr().getTarget(), this.getBreakExpr(), result, this) + } } -/** A CFG node that corresponds to a call in the AST. */ -class MethodCallExprCfgNode extends ExprCfgNode { - override MethodCallExpr node; +/** + * A function or method call expression. See `CallExpr` and `MethodCallExpr` for further details. + */ +final class CallExprBaseCfgNode extends Nodes::CallExprBaseCfgNode { + private CallExprBaseChildMapping node; - /** Gets the underlying `MethodCallExpr`. */ - MethodCallExpr getMethodCallExpr() { result = node } + CallExprBaseCfgNode() { node = this.getAstNode() } + + /** Gets the `i`th argument of this call. */ + ExprCfgNode getArgument(int i) { + any(ChildMapping mapping).hasCfgChild(node, node.getArgList().getArg(i), this, result) + } } -final class ExitCfgNode = ExitNode; +/** + * A method call expression. For example: + * ```rust + * x.foo(42); + * x.foo::(42); + * ``` + */ +final class MethodCallExprCfgNode extends CallExprBaseCfgNode, Nodes::MethodCallExprCfgNode { } + +/** + * A function call expression. For example: + * ```rust + * foo(42); + * foo::(42); + * foo[0](42); + * foo(1) = 4; + * ``` + */ +final class CallExprCfgNode extends CallExprBaseCfgNode, Nodes::CallExprCfgNode { } + +/** + * 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 Nodes::RecordExprCfgNode { + private RecordExprChildMapping node; + + RecordExprCfgNode() { node = this.getRecordExpr() } + + /** Gets the `i`th record expression. */ + ExprCfgNode getExpr(int i) { + any(ChildMapping mapping) + .hasCfgChild(node, node.getRecordExprFieldList().getField(i).getExpr(), this, result) + } +} diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/CfgConsistency.qll b/rust/ql/lib/codeql/rust/controlflow/internal/CfgConsistency.qll index 2722661494d6..62ac5822dbbc 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,25 @@ 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 edge from the CFG node + // for `true` into the `[false] a && true` node. + strictcount(ConditionalSuccessor cs | exists(last.getACfgNode().getASuccessor(cs)) | cs) = 1 + or + // In for example `x && return`, there is no edge from the node for + // `return` into the `&&` node. + not c instanceof CfgImpl::NormalCompletion + ) +} + /** * Gets counts of control flow graph inconsistencies of each type. */ @@ -99,4 +120,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 000000000000..fc0df95f24a2 --- /dev/null +++ b/rust/ql/lib/codeql/rust/controlflow/internal/CfgNodes.qll @@ -0,0 +1,148 @@ +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 + +class MatchExprChildMapping extends ParentAstNode, MatchExpr { + override predicate relevantChild(AstNode child) { + child = this.getAnArm().getPat() + or + child = this.getAnArm().getGuard().getCondition() + or + child = this.getAnArm().getExpr() + } +} + +class BlockExprChildMapping extends ParentAstNode, BlockExpr { + override predicate relevantChild(AstNode child) { child = this.getStmtList().getTailExpr() } +} + +class BreakExprTargetChildMapping extends ParentAstNode, Expr { + override predicate relevantChild(AstNode child) { child.(BreakExpr).getTarget() = this } +} + +class CallExprBaseChildMapping extends ParentAstNode, CallExprBase { + override predicate relevantChild(AstNode child) { child = this.getArgList().getAnArg() } +} + +class RecordExprChildMapping extends ParentAstNode, RecordExpr { + override predicate relevantChild(AstNode child) { + child = this.getRecordExprFieldList().getAField().getExpr() + } +} + +class FormatArgsExprChildMapping extends ParentAstNode, CfgImpl::ExprTrees::FormatArgsExprTree { + override predicate relevantChild(AstNode child) { child = this.getChildNode(_) } +} + +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/ControlFlowGraphImpl.qll b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll index 938b933cba05..df43d450a505 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll @@ -19,7 +19,7 @@ private module CfgInput implements InputSig { predicate completionIsValidFor = C::completionIsValidFor/2; - /** An AST node with an associated control-flow graph. */ + /** An AST node with an associated control flow graph. */ class CfgScope = Scope::CfgScope; CfgScope getCfgScope(AstNode n) { diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/Scope.qll b/rust/ql/lib/codeql/rust/controlflow/internal/Scope.qll index 7b3367690ec6..cf779ed152f4 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/Scope.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/Scope.qll @@ -4,7 +4,7 @@ private import ControlFlowGraphImpl private import codeql.rust.elements.internal.generated.ParentChild /** - * A control-flow graph (CFG) scope. + * A control flow graph (CFG) scope. */ abstract private class CfgScopeImpl extends AstNode { /** Holds if `first` is executed first when entering `scope`. */ 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 000000000000..b42a00bf551f --- /dev/null +++ b/rust/ql/lib/codeql/rust/controlflow/internal/generated/CfgNodes.qll @@ -0,0 +1,3726 @@ +// 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 ParentSelfParam extends ParentAstNode, SelfParam { + override predicate relevantChild(AstNode child) { none() } + } + + /** + * A SelfParam. For example: + * ```rust + * todo!() + * ``` + */ + final class SelfParamCfgNode extends CfgNodeFinal { + private SelfParam node; + + SelfParamCfgNode() { node = this.getAstNode() } + + /** Gets the underlying `SelfParam`. */ + SelfParam getSelfParam() { result = node } + + /** + * Gets the `index`th attr of this self parameter (0-based). + */ + Attr getAttr(int index) { result = node.getAttr(index) } + + /** + * Gets any of the attrs of this self parameter. + */ + Attr getAnAttr() { result = this.getAttr(_) } + + /** + * Gets the number of attrs of this self parameter. + */ + int getNumberOfAttrs() { result = count(int i | exists(this.getAttr(i))) } + + /** + * Holds if this self parameter is mut. + */ + predicate isMut() { node.isMut() } + + /** + * Gets the lifetime of this self parameter, if it exists. + */ + Lifetime getLifetime() { result = node.getLifetime() } + + /** + * Holds if `getLifetime()` exists. + */ + predicate hasLifetime() { exists(this.getLifetime()) } + + /** + * Gets the name of this self parameter, if it exists. + */ + Name getName() { result = node.getName() } + + /** + * Holds if `getName()` exists. + */ + predicate hasName() { exists(this.getName()) } + + /** + * Gets the ty of this self parameter, if it exists. + */ + TypeRef getTy() { result = node.getTy() } + + /** + * Holds if `getTy()` exists. + */ + predicate hasTy() { exists(this.getTy()) } + } + + 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/dataflow/Ssa.qll b/rust/ql/lib/codeql/rust/dataflow/Ssa.qll index ff1aae058aaa..5b452a329fa9 100644 --- a/rust/ql/lib/codeql/rust/dataflow/Ssa.qll +++ b/rust/ql/lib/codeql/rust/dataflow/Ssa.qll @@ -9,6 +9,7 @@ module Ssa { private import rust private import codeql.rust.controlflow.BasicBlocks private import codeql.rust.controlflow.ControlFlowGraph + private import codeql.rust.controlflow.CfgNodes private import codeql.rust.controlflow.internal.ControlFlowGraphImpl as CfgImpl private import internal.SsaImpl as SsaImpl @@ -26,7 +27,7 @@ module Ssa { } /** - * Gets a control-flow node that reads the value of this SSA definition. + * Gets a control flow node that reads the value of this SSA definition. * * Example: * @@ -53,7 +54,7 @@ module Ssa { final CfgNode getARead() { result = SsaImpl::getARead(this) } /** - * Gets a first control-flow node that reads the value of this SSA definition. + * Gets a first control flow node that reads the value of this SSA definition. * That is, a read that can be reached from this definition without passing * through other reads. * @@ -82,7 +83,7 @@ module Ssa { final CfgNode getAFirstRead() { SsaImpl::firstRead(this, result) } /** - * Gets a last control-flow node that reads the value of this SSA definition. + * Gets a last control flow node that reads the value of this SSA definition. * That is, a read that can reach the end of the enclosing CFG scope, or another * SSA definition for the source variable, without passing through any other read. * @@ -221,11 +222,11 @@ module Ssa { * end * ``` */ - predicate assigns(CfgNode value) { - exists(AssignmentExpr ae, BasicBlock bb, int i | + predicate assigns(ExprCfgNode value) { + exists(AssignmentExprCfgNode ae, BasicBlock bb, int i | this.definesAt(_, bb, i) and - ae.getLhs() = bb.getNode(i).getAstNode() and - value.getAstNode() = ae.getRhs() + ae.getLhs() = bb.getNode(i) and + value = ae.getRhs() ) } diff --git a/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll b/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll index c31ef9e81072..210f12825cf2 100644 --- a/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll +++ b/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll @@ -48,7 +48,7 @@ final class DataFlowCall extends TDataFlowCall { MethodCallExprCfgNode asMethodCallExprCfgNode() { this = TMethodCall(result) } - ExprCfgNode asExprCfgNode() { + CallExprBaseCfgNode asExprCfgNode() { result = this.asCallExprCfgNode() or result = this.asMethodCallExprCfgNode() } @@ -76,7 +76,7 @@ module Node { /** * Gets the expression that corresponds to this node, if any. */ - Expr asExpr() { none() } + ExprCfgNode asExpr() { none() } /** Gets the enclosing callable. */ DataFlowCallable getEnclosingCallable() { result = TCfgScope(this.getCfgScope()) } @@ -115,20 +115,20 @@ module Node { abstract class AstCfgFlowNode extends Node { AstCfgNode n; - override CfgNode getCfgNode() { result = n } + final override CfgNode getCfgNode() { result = n } - override CfgScope getCfgScope() { result = n.getAstNode().getEnclosingCfgScope() } + final override CfgScope getCfgScope() { result = n.getAstNode().getEnclosingCfgScope() } - override Location getLocation() { result = n.getAstNode().getLocation() } + final override Location getLocation() { result = n.getAstNode().getLocation() } - override string toString() { result = n.getAstNode().toString() } + final override string toString() { result = n.getAstNode().toString() } } /** * A node in the data flow graph that corresponds to an expression in the * AST. * - * Note that because of control-flow splitting, one `Expr` may correspond + * Note that because of control flow splitting, one `Expr` may correspond * to multiple `ExprNode`s, just like it may correspond to multiple * `ControlFlow::Node`s. */ @@ -137,7 +137,7 @@ module Node { ExprNode() { this = TExprNode(n) } - override Expr asExpr() { result = n.getExpr() } + override ExprCfgNode asExpr() { result = n } } final class PatNode extends AstCfgFlowNode, TPatNode { @@ -158,8 +158,8 @@ module Node { ParameterNode() { this = TParameterNode(n) } - /** Gets the parameter in the AST that this node corresponds to. */ - Param getParameter() { result = n.getParam() } + /** Gets the parameter in the CFG that this node corresponds to. */ + ParamCfgNode getParameter() { result = n } } final class ArgumentNode = NaNode; @@ -197,7 +197,7 @@ module Node { } final private class ExprOutNode extends ExprNode, OutNode { - ExprOutNode() { this.asExpr() instanceof CallExpr } + ExprOutNode() { this.asExpr() instanceof CallExprCfgNode } /** Gets the underlying call CFG node that includes this out node. */ override DataFlowCall getCall() { result.asExprCfgNode() = this.getCfgNode() } @@ -228,13 +228,13 @@ final class Node = Node::Node; module SsaFlow { private module Impl = SsaImpl::DataFlowIntegration; - private Node::ParameterNode toParameterNode(Param p) { result.getParameter() = p } + private Node::ParameterNode toParameterNode(ParamCfgNode p) { result.getParameter() = p } /** Converts a control flow node into an SSA control flow node. */ Impl::Node asNode(Node n) { n = TSsaNode(result) or - result.(Impl::ExprNode).getExpr() = n.(Node::ExprNode).getCfgNode() + result.(Impl::ExprNode).getExpr() = n.asExpr() or n = toParameterNode(result.(Impl::ParameterNode).getParameter()) } @@ -248,29 +248,18 @@ module SsaFlow { } } -/** - * Holds for expressions `e` that evaluate to the value of any last (in - * evaluation order) subexpressions within it. E.g., expressions that propagate - * a values from a subexpression. - * - * For instance, the predicate holds for if expressions as `if b { e1 } else { - * e2 }` evalates to the value of one of the subexpressions `e1` or `e2`. - */ -private predicate propagatesValue(Expr e) { - e instanceof IfExpr or - e instanceof LoopExpr or - e instanceof ReturnExpr or - e instanceof BreakExpr or - e.(BlockExpr).getStmtList().hasTailExpr() or - e instanceof MatchExpr -} - /** * Gets a node that may execute last in `n`, and which, when it executes last, * will be the value of `n`. */ -private ExprCfgNode getALastEvalNode(ExprCfgNode n) { - propagatesValue(n.getExpr()) and result.getASuccessor() = n +private ExprCfgNode getALastEvalNode(ExprCfgNode e) { + e = any(IfExprCfgNode n | result = [n.getThen(), n.getElse()]) or + result = e.(LoopExprCfgNode).getLoopBody() or + result = e.(ReturnExprCfgNode).getExpr() or + result = e.(BreakExprCfgNode).getExpr() or + result = e.(BlockExprCfgNode).getTailExpr() or + result = e.(MatchExprCfgNode).getArmExpr(_) or + result.(BreakExprCfgNode).getTarget() = e } module LocalFlow { @@ -278,9 +267,9 @@ module LocalFlow { predicate localFlowStepCommon(Node nodeFrom, Node nodeTo) { nodeFrom.getCfgNode() = getALastEvalNode(nodeTo.getCfgNode()) or - exists(LetStmt s | - nodeFrom.getCfgNode().getAstNode() = s.getInitializer() and - nodeTo.getCfgNode().getAstNode() = s.getPat() + exists(LetStmtCfgNode s | + nodeFrom.getCfgNode() = s.getInitializer() and + nodeTo.getCfgNode() = s.getPat() ) or // An edge from a pattern/expression to its corresponding SSA definition. @@ -288,6 +277,11 @@ module LocalFlow { nodeTo.(Node::SsaNode).getDefinitionExt().(Ssa::WriteDefinition).getControlFlowNode() or SsaFlow::localFlowStep(_, nodeFrom, nodeTo, _) + or + exists(AssignmentExprCfgNode a | + a.getRhs() = nodeFrom.getCfgNode() and + a.getLhs() = nodeTo.getCfgNode() + ) } } @@ -329,7 +323,7 @@ module RustDataFlow implements InputSig { class DataFlowExpr = ExprCfgNode; /** Gets the node corresponding to `e`. */ - Node exprNode(DataFlowExpr e) { result.getCfgNode() = e } + Node exprNode(DataFlowExpr e) { result.asExpr() = e } final class DataFlowCall = DataFlowCallAlias; diff --git a/rust/ql/lib/codeql/rust/dataflow/internal/SsaImpl.qll b/rust/ql/lib/codeql/rust/dataflow/internal/SsaImpl.qll index d5263fca8106..6e9032f1dc4c 100644 --- a/rust/ql/lib/codeql/rust/dataflow/internal/SsaImpl.qll +++ b/rust/ql/lib/codeql/rust/dataflow/internal/SsaImpl.qll @@ -474,14 +474,14 @@ private module DataFlowIntegrationInput implements Impl::DataFlowIntegrationInpu /** Holds if SSA definition `def` assigns `value` to the underlying variable. */ predicate ssaDefAssigns(WriteDefinition def, Expr value) { - exists(BasicBlock bb, int i | def.definesAt(_, bb, i) and value = bb.getNode(i)) + none() // handled in `DataFlowImpl.qll` instead } - class Parameter = Param; + class Parameter = CfgNodes::ParamCfgNode; /** Holds if SSA definition `def` initializes parameter `p` at function entry. */ predicate ssaDefInitializesParam(WriteDefinition def, Parameter p) { - exists(BasicBlock bb, int i | bb.getNode(i).getAstNode() = p and def.definesAt(_, bb, i)) + none() // handled in `DataFlowImpl.qll` instead } class Guard extends CfgNodes::AstCfgNode { diff --git a/rust/ql/lib/codeql/rust/elements/internal/AstNodeImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/AstNodeImpl.qll index f2784d058ae7..c33b1f3dd6eb 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 162853846f2d..3defe0b8168d 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/library-tests/controlflow/Cfg.expected b/rust/ql/test/library-tests/controlflow/Cfg.expected index 8fd71a451b86..93022fe371d4 100644 --- a/rust/ql/test/library-tests/controlflow/Cfg.expected +++ b/rust/ql/test/library-tests/controlflow/Cfg.expected @@ -608,476 +608,492 @@ edges | test.rs:278:9:278:19 | ... && ... | test.rs:277:33:279:5 | BlockExpr | | | test.rs:278:9:278:20 | ExprStmt | test.rs:278:9:278:9 | a | | | test.rs:278:14:278:19 | ReturnExpr | test.rs:277:5:279:5 | exit test_and_return (normal) | return | -| test.rs:285:5:287:5 | enter test_question_mark_operator_1 | test.rs:285:38:285:38 | s | | -| test.rs:285:5:287:5 | exit test_question_mark_operator_1 (normal) | test.rs:285:5:287:5 | exit test_question_mark_operator_1 | | -| test.rs:285:38:285:38 | s | test.rs:285:38:285:44 | Param | match | -| test.rs:285:38:285:44 | Param | test.rs:286:9:286:10 | Ok | | -| test.rs:285:87:287:5 | BlockExpr | test.rs:285:5:287:5 | exit test_question_mark_operator_1 (normal) | | -| test.rs:286:9:286:10 | Ok | test.rs:286:12:286:12 | s | | -| test.rs:286:9:286:33 | CallExpr | test.rs:285:87:287:5 | BlockExpr | | -| test.rs:286:12:286:12 | s | test.rs:286:12:286:27 | ... .parse(...) | | -| test.rs:286:12:286:27 | ... .parse(...) | test.rs:286:12:286:28 | TryExpr | | -| test.rs:286:12:286:28 | TryExpr | test.rs:285:5:287:5 | exit test_question_mark_operator_1 (normal) | return | -| test.rs:286:12:286:28 | TryExpr | test.rs:286:32:286:32 | 4 | match | -| test.rs:286:12:286:32 | ... + ... | test.rs:286:9:286:33 | CallExpr | | -| test.rs:286:32:286:32 | 4 | test.rs:286:12:286:32 | ... + ... | | -| test.rs:289:5:294:5 | enter test_question_mark_operator_2 | test.rs:289:38:289:38 | b | | -| test.rs:289:5:294:5 | exit test_question_mark_operator_2 (normal) | test.rs:289:5:294:5 | exit test_question_mark_operator_2 | | -| test.rs:289:38:289:38 | b | test.rs:289:38:289:52 | Param | match | -| test.rs:289:38:289:52 | Param | test.rs:290:15:290:15 | b | | -| test.rs:289:71:294:5 | BlockExpr | test.rs:289:5:294:5 | exit test_question_mark_operator_2 (normal) | | -| test.rs:290:9:293:9 | MatchExpr | test.rs:289:71:294:5 | BlockExpr | | -| test.rs:290:15:290:15 | b | test.rs:290:15:290:16 | TryExpr | | -| test.rs:290:15:290:16 | TryExpr | test.rs:289:5:294:5 | exit test_question_mark_operator_2 (normal) | return | -| test.rs:290:15:290:16 | TryExpr | test.rs:291:13:291:16 | true | match | -| test.rs:291:13:291:16 | LiteralPat | test.rs:291:21:291:24 | Some | match | -| test.rs:291:13:291:16 | LiteralPat | test.rs:292:13:292:17 | false | no-match | -| test.rs:291:13:291:16 | true | test.rs:291:13:291:16 | LiteralPat | | -| test.rs:291:21:291:24 | Some | test.rs:291:26:291:30 | false | | -| test.rs:291:21:291:31 | CallExpr | test.rs:290:9:293:9 | MatchExpr | | -| test.rs:291:26:291:30 | false | test.rs:291:21:291:31 | CallExpr | | -| test.rs:292:13:292:17 | LiteralPat | test.rs:292:22:292:25 | Some | match | -| test.rs:292:13:292:17 | false | test.rs:292:13:292:17 | LiteralPat | | -| test.rs:292:22:292:25 | Some | test.rs:292:27:292:30 | true | | -| test.rs:292:22:292:31 | CallExpr | test.rs:290:9:293:9 | MatchExpr | | -| test.rs:292:27:292:30 | true | test.rs:292:22:292:31 | CallExpr | | -| test.rs:300:5:306:5 | enter test_match | test.rs:300:19:300:29 | maybe_digit | | -| test.rs:300:5:306:5 | exit test_match (normal) | test.rs:300:5:306:5 | exit test_match | | -| test.rs:300:19:300:29 | maybe_digit | test.rs:300:19:300:42 | Param | match | -| test.rs:300:19:300:42 | Param | test.rs:301:15:301:25 | maybe_digit | | -| test.rs:300:52:306:5 | BlockExpr | test.rs:300:5:306:5 | exit test_match (normal) | | -| test.rs:301:9:305:9 | MatchExpr | test.rs:300:52:306:5 | BlockExpr | | -| test.rs:301:15:301:25 | maybe_digit | test.rs:302:13:302:27 | TupleStructPat | | -| test.rs:302:13:302:27 | TupleStructPat | test.rs:302:26:302:26 | x | match | -| test.rs:302:13:302:27 | TupleStructPat | test.rs:303:13:303:27 | TupleStructPat | no-match | -| test.rs:302:26:302:26 | x | test.rs:302:32:302:32 | x | match | -| test.rs:302:32:302:32 | x | test.rs:302:36:302:37 | 10 | | -| test.rs:302:32:302:37 | ... < ... | test.rs:302:42:302:42 | x | true | -| test.rs:302:32:302:37 | ... < ... | test.rs:303:13:303:27 | TupleStructPat | false | -| test.rs:302:36:302:37 | 10 | test.rs:302:32:302:37 | ... < ... | | -| test.rs:302:42:302:42 | x | test.rs:302:46:302:46 | 5 | | -| test.rs:302:42:302:46 | ... + ... | test.rs:301:9:305:9 | MatchExpr | | -| test.rs:302:46:302:46 | 5 | test.rs:302:42:302:46 | ... + ... | | -| test.rs:303:13:303:27 | TupleStructPat | test.rs:303:26:303:26 | x | match | -| test.rs:303:13:303:27 | TupleStructPat | test.rs:304:13:304:24 | PathPat | no-match | -| test.rs:303:26:303:26 | x | test.rs:303:32:303:32 | x | match | -| test.rs:303:32:303:32 | x | test.rs:301:9:305:9 | MatchExpr | | -| test.rs:304:13:304:24 | PathPat | test.rs:304:29:304:29 | 5 | match | -| test.rs:304:29:304:29 | 5 | test.rs:301:9:305:9 | MatchExpr | | -| test.rs:308:5:317:5 | enter test_match_with_return_in_scrutinee | test.rs:308:44:308:54 | maybe_digit | | -| test.rs:308:5:317:5 | exit test_match_with_return_in_scrutinee (normal) | test.rs:308:5:317:5 | exit test_match_with_return_in_scrutinee | | -| test.rs:308:44:308:54 | maybe_digit | test.rs:308:44:308:67 | Param | match | -| test.rs:308:44:308:67 | Param | test.rs:309:19:309:29 | maybe_digit | | -| test.rs:308:77:317:5 | BlockExpr | test.rs:308:5:317:5 | exit test_match_with_return_in_scrutinee (normal) | | -| test.rs:309:9:316:9 | MatchExpr | test.rs:308:77:317:5 | BlockExpr | | -| test.rs:309:16:313:9 | IfExpr | test.rs:314:13:314:27 | TupleStructPat | | -| test.rs:309:19:309:29 | maybe_digit | test.rs:309:34:309:37 | Some | | -| test.rs:309:19:309:40 | ... == ... | test.rs:310:13:310:21 | ExprStmt | true | -| test.rs:309:19:309:40 | ... == ... | test.rs:312:13:312:23 | maybe_digit | false | -| test.rs:309:34:309:37 | Some | test.rs:309:39:309:39 | 3 | | -| test.rs:309:34:309:40 | CallExpr | test.rs:309:19:309:40 | ... == ... | | -| test.rs:309:39:309:39 | 3 | test.rs:309:34:309:40 | CallExpr | | -| test.rs:310:13:310:20 | ReturnExpr | test.rs:308:5:317:5 | exit test_match_with_return_in_scrutinee (normal) | return | -| test.rs:310:13:310:21 | ExprStmt | test.rs:310:20:310:20 | 3 | | -| test.rs:310:20:310:20 | 3 | test.rs:310:13:310:20 | ReturnExpr | | -| test.rs:311:16:313:9 | BlockExpr | test.rs:309:16:313:9 | IfExpr | | -| test.rs:312:13:312:23 | maybe_digit | test.rs:311:16:313:9 | BlockExpr | | -| test.rs:314:13:314:27 | TupleStructPat | test.rs:314:26:314:26 | x | match | -| test.rs:314:13:314:27 | TupleStructPat | test.rs:315:13:315:24 | PathPat | no-match | -| test.rs:314:26:314:26 | x | test.rs:314:32:314:32 | x | match | -| test.rs:314:32:314:32 | x | test.rs:314:36:314:36 | 5 | | -| test.rs:314:32:314:36 | ... + ... | test.rs:309:9:316:9 | MatchExpr | | -| test.rs:314:36:314:36 | 5 | test.rs:314:32:314:36 | ... + ... | | -| test.rs:315:13:315:24 | PathPat | test.rs:315:29:315:29 | 5 | match | -| test.rs:315:29:315:29 | 5 | test.rs:309:9:316:9 | MatchExpr | | -| test.rs:319:5:324:5 | enter test_match_and | test.rs:319:23:319:26 | cond | | -| test.rs:319:5:324:5 | exit test_match_and (normal) | test.rs:319:5:324:5 | exit test_match_and | | -| test.rs:319:23:319:26 | cond | test.rs:319:23:319:32 | Param | match | -| test.rs:319:23:319:32 | Param | test.rs:319:35:319:35 | r | | -| test.rs:319:35:319:35 | r | test.rs:319:35:319:49 | Param | match | -| test.rs:319:35:319:49 | Param | test.rs:320:16:320:16 | r | | -| test.rs:319:60:324:5 | BlockExpr | test.rs:319:5:324:5 | exit test_match_and (normal) | | -| test.rs:320:9:323:18 | ... && ... | test.rs:319:60:324:5 | BlockExpr | | -| test.rs:320:10:323:9 | [boolean(false)] MatchExpr | test.rs:320:9:323:18 | ... && ... | false | -| test.rs:320:10:323:9 | [boolean(true)] MatchExpr | test.rs:323:15:323:18 | cond | true | -| test.rs:320:16:320:16 | r | test.rs:321:13:321:19 | TupleStructPat | | -| test.rs:321:13:321:19 | TupleStructPat | test.rs:321:18:321:18 | a | match | -| test.rs:321:13:321:19 | TupleStructPat | test.rs:322:13:322:13 | WildcardPat | no-match | -| test.rs:321:18:321:18 | a | test.rs:321:24:321:24 | a | match | -| test.rs:321:24:321:24 | a | test.rs:320:10:323:9 | [boolean(false)] MatchExpr | false | -| test.rs:321:24:321:24 | a | test.rs:320:10:323:9 | [boolean(true)] MatchExpr | true | -| test.rs:322:13:322:13 | WildcardPat | test.rs:322:18:322:22 | false | match | -| test.rs:322:18:322:22 | false | test.rs:320:10:323:9 | [boolean(false)] MatchExpr | false | -| test.rs:323:15:323:18 | cond | test.rs:320:9:323:18 | ... && ... | | -| test.rs:326:5:331:5 | enter test_match_with_no_arms | test.rs:326:35:326:35 | r | | -| test.rs:326:5:331:5 | exit test_match_with_no_arms (normal) | test.rs:326:5:331:5 | exit test_match_with_no_arms | | -| test.rs:326:35:326:35 | r | test.rs:326:35:326:58 | Param | match | -| test.rs:326:35:326:58 | Param | test.rs:327:15:327:15 | r | | -| test.rs:326:66:331:5 | BlockExpr | test.rs:326:5:331:5 | exit test_match_with_no_arms (normal) | | -| test.rs:327:9:330:9 | MatchExpr | test.rs:326:66:331:5 | BlockExpr | | -| test.rs:327:15:327:15 | r | test.rs:328:13:328:21 | TupleStructPat | | -| test.rs:328:13:328:21 | TupleStructPat | test.rs:328:16:328:20 | value | match | -| test.rs:328:13:328:21 | TupleStructPat | test.rs:329:13:329:22 | TupleStructPat | no-match | -| test.rs:328:16:328:20 | value | test.rs:328:26:328:30 | value | match | -| test.rs:328:26:328:30 | value | test.rs:327:9:330:9 | MatchExpr | | -| test.rs:329:13:329:22 | TupleStructPat | test.rs:329:17:329:21 | never | match | -| test.rs:329:17:329:21 | never | test.rs:329:33:329:37 | never | match | -| test.rs:329:27:329:40 | MatchExpr | test.rs:327:9:330:9 | MatchExpr | | -| test.rs:329:33:329:37 | never | test.rs:329:27:329:40 | MatchExpr | | -| test.rs:336:5:339:5 | enter test_let_match | test.rs:336:23:336:23 | a | | -| test.rs:336:5:339:5 | exit test_let_match (normal) | test.rs:336:5:339:5 | exit test_let_match | | -| test.rs:336:23:336:23 | a | test.rs:336:23:336:36 | Param | match | -| test.rs:336:23:336:36 | Param | test.rs:337:9:337:57 | LetStmt | | -| test.rs:336:46:339:5 | BlockExpr | test.rs:336:5:339:5 | exit test_let_match (normal) | | -| test.rs:337:9:337:57 | LetStmt | test.rs:337:23:337:23 | a | | -| test.rs:337:13:337:19 | TupleStructPat | test.rs:337:18:337:18 | n | match | -| test.rs:337:13:337:19 | TupleStructPat | test.rs:337:39:337:53 | MacroStmts | no-match | -| test.rs:337:18:337:18 | n | test.rs:338:9:338:9 | n | match | -| test.rs:337:23:337:23 | a | test.rs:337:13:337:19 | TupleStructPat | | -| test.rs:337:32:337:54 | $crate::panicking::panic_fmt | test.rs:337:39:337:53 | "Expected some" | | -| test.rs:337:32:337:54 | MacroExpr | test.rs:337:30:337:56 | BlockExpr | | -| test.rs:337:39:337:53 | "Expected some" | test.rs:337:39:337:53 | FormatArgsExpr | | -| test.rs:337:39:337:53 | BlockExpr | test.rs:337:39:337:53 | MacroExpr | | -| test.rs:337:39:337:53 | CallExpr | test.rs:337:39:337:53 | BlockExpr | | -| test.rs:337:39:337:53 | ExprStmt | test.rs:337:32:337:54 | $crate::panicking::panic_fmt | | -| test.rs:337:39:337:53 | FormatArgsExpr | test.rs:337:39:337:53 | MacroExpr | | -| test.rs:337:39:337:53 | MacroExpr | test.rs:337:32:337:54 | MacroExpr | | -| test.rs:337:39:337:53 | MacroExpr | test.rs:337:39:337:53 | CallExpr | | -| test.rs:337:39:337:53 | MacroStmts | test.rs:337:39:337:53 | ExprStmt | | -| test.rs:337:39:337:53 | MacroStmts | test.rs:337:39:337:53 | MacroStmts | | -| test.rs:338:9:338:9 | n | test.rs:336:46:339:5 | BlockExpr | | -| test.rs:341:5:347:5 | enter test_let_with_return | test.rs:341:29:341:29 | m | | -| test.rs:341:5:347:5 | exit test_let_with_return (normal) | test.rs:341:5:347:5 | exit test_let_with_return | | -| test.rs:341:29:341:29 | m | test.rs:341:29:341:42 | Param | match | -| test.rs:341:29:341:42 | Param | test.rs:342:9:345:10 | LetStmt | | -| test.rs:341:53:347:5 | BlockExpr | test.rs:341:5:347:5 | exit test_let_with_return (normal) | | -| test.rs:342:9:345:10 | LetStmt | test.rs:342:25:342:25 | m | | -| test.rs:342:13:342:15 | ret | test.rs:346:9:346:12 | true | match | -| test.rs:342:19:345:9 | MatchExpr | test.rs:342:13:342:15 | ret | | -| test.rs:342:25:342:25 | m | test.rs:343:13:343:21 | TupleStructPat | | -| test.rs:343:13:343:21 | TupleStructPat | test.rs:343:18:343:20 | ret | match | -| test.rs:343:13:343:21 | TupleStructPat | test.rs:344:13:344:16 | None | no-match | -| test.rs:343:18:343:20 | ret | test.rs:343:26:343:28 | ret | match | -| test.rs:343:26:343:28 | ret | test.rs:342:19:345:9 | MatchExpr | | -| test.rs:344:13:344:16 | None | test.rs:344:28:344:32 | false | match | -| test.rs:344:21:344:32 | ReturnExpr | test.rs:341:5:347:5 | exit test_let_with_return (normal) | return | -| test.rs:344:28:344:32 | false | test.rs:344:21:344:32 | ReturnExpr | | -| test.rs:346:9:346:12 | true | test.rs:341:53:347:5 | BlockExpr | | -| test.rs:352:5:355:5 | enter empty_tuple_pattern | test.rs:352:28:352:31 | unit | | -| test.rs:352:5:355:5 | exit empty_tuple_pattern (normal) | test.rs:352:5:355:5 | exit empty_tuple_pattern | | -| test.rs:352:28:352:31 | unit | test.rs:352:28:352:35 | Param | match | -| test.rs:352:28:352:35 | Param | test.rs:353:9:353:22 | LetStmt | | -| test.rs:353:9:353:22 | LetStmt | test.rs:353:18:353:21 | unit | | -| test.rs:353:13:353:14 | TuplePat | test.rs:354:9:354:15 | ExprStmt | match | -| test.rs:353:18:353:21 | unit | test.rs:353:13:353:14 | TuplePat | | -| test.rs:354:9:354:14 | ReturnExpr | test.rs:352:5:355:5 | exit empty_tuple_pattern (normal) | return | -| test.rs:354:9:354:15 | ExprStmt | test.rs:354:9:354:14 | ReturnExpr | | -| test.rs:359:5:363:5 | enter empty_struct_pattern | test.rs:359:29:359:30 | st | | -| test.rs:359:5:363:5 | exit empty_struct_pattern (normal) | test.rs:359:5:363:5 | exit empty_struct_pattern | | -| test.rs:359:29:359:30 | st | test.rs:359:29:359:40 | Param | match | -| test.rs:359:29:359:40 | Param | test.rs:360:15:360:16 | st | | -| test.rs:359:50:363:5 | BlockExpr | test.rs:359:5:363:5 | exit empty_struct_pattern (normal) | | -| test.rs:360:9:362:9 | MatchExpr | test.rs:359:50:363:5 | BlockExpr | | -| test.rs:360:15:360:16 | st | test.rs:361:13:361:27 | RecordPat | | -| test.rs:361:13:361:27 | RecordPat | test.rs:361:24:361:25 | RestPat | match | -| test.rs:361:24:361:25 | RestPat | test.rs:361:32:361:32 | 1 | match | -| test.rs:361:32:361:32 | 1 | test.rs:360:9:362:9 | MatchExpr | | -| test.rs:365:5:372:5 | enter range_pattern | test.rs:366:15:366:16 | 42 | | -| test.rs:365:5:372:5 | exit range_pattern (normal) | test.rs:365:5:372:5 | exit range_pattern | | -| test.rs:365:31:372:5 | BlockExpr | test.rs:365:5:372:5 | exit range_pattern (normal) | | -| test.rs:366:9:371:9 | MatchExpr | test.rs:365:31:372:5 | BlockExpr | | -| test.rs:366:15:366:16 | 42 | test.rs:367:13:367:15 | RangePat | | -| test.rs:367:13:367:15 | RangePat | test.rs:367:15:367:15 | 0 | match | -| test.rs:367:13:367:15 | RangePat | test.rs:368:13:368:16 | RangePat | no-match | -| test.rs:367:15:367:15 | 0 | test.rs:367:15:367:15 | LiteralPat | | -| test.rs:367:15:367:15 | LiteralPat | test.rs:367:20:367:20 | 1 | match | -| test.rs:367:15:367:15 | LiteralPat | test.rs:368:13:368:16 | RangePat | no-match | -| test.rs:367:20:367:20 | 1 | test.rs:366:9:371:9 | MatchExpr | | -| test.rs:368:13:368:13 | 1 | test.rs:368:13:368:13 | LiteralPat | | -| test.rs:368:13:368:13 | LiteralPat | test.rs:368:16:368:16 | 2 | match | -| test.rs:368:13:368:13 | LiteralPat | test.rs:369:13:369:15 | RangePat | no-match | -| test.rs:368:13:368:16 | RangePat | test.rs:368:13:368:13 | 1 | match | -| test.rs:368:13:368:16 | RangePat | test.rs:369:13:369:15 | RangePat | no-match | -| test.rs:368:16:368:16 | 2 | test.rs:368:16:368:16 | LiteralPat | | -| test.rs:368:16:368:16 | LiteralPat | test.rs:368:21:368:21 | 2 | match | -| test.rs:368:16:368:16 | LiteralPat | test.rs:369:13:369:15 | RangePat | no-match | -| test.rs:368:21:368:21 | 2 | test.rs:366:9:371:9 | MatchExpr | | -| test.rs:369:13:369:13 | 5 | test.rs:369:13:369:13 | LiteralPat | | -| test.rs:369:13:369:13 | LiteralPat | test.rs:369:20:369:20 | 3 | match | -| test.rs:369:13:369:13 | LiteralPat | test.rs:370:13:370:13 | WildcardPat | no-match | -| test.rs:369:13:369:15 | RangePat | test.rs:369:13:369:13 | 5 | match | -| test.rs:369:13:369:15 | RangePat | test.rs:370:13:370:13 | WildcardPat | no-match | -| test.rs:369:20:369:20 | 3 | test.rs:366:9:371:9 | MatchExpr | | -| test.rs:370:13:370:13 | WildcardPat | test.rs:370:18:370:18 | 4 | match | -| test.rs:370:18:370:18 | 4 | test.rs:366:9:371:9 | MatchExpr | | -| test.rs:376:5:381:5 | enter test_infinite_loop | test.rs:377:9:379:9 | ExprStmt | | -| test.rs:377:9:379:9 | ExprStmt | test.rs:378:13:378:14 | TupleExpr | | -| test.rs:377:14:379:9 | BlockExpr | test.rs:378:13:378:14 | TupleExpr | | -| test.rs:378:13:378:14 | TupleExpr | test.rs:377:14:379:9 | BlockExpr | | -| test.rs:385:5:387:5 | enter say_hello | test.rs:386:9:386:34 | ExprStmt | | -| test.rs:385:5:387:5 | exit say_hello (normal) | test.rs:385:5:387:5 | exit say_hello | | -| test.rs:385:26:387:5 | BlockExpr | test.rs:385:5:387:5 | exit say_hello (normal) | | -| test.rs:386:9:386:33 | $crate::io::_print | test.rs:386:18:386:32 | "hello, world!\\n" | | -| test.rs:386:9:386:33 | MacroExpr | test.rs:385:26:387:5 | BlockExpr | | -| test.rs:386:9:386:34 | ExprStmt | test.rs:386:18:386:32 | MacroStmts | | -| test.rs:386:18:386:32 | "hello, world!\\n" | test.rs:386:18:386:32 | FormatArgsExpr | | -| test.rs:386:18:386:32 | BlockExpr | test.rs:386:9:386:33 | MacroExpr | | -| test.rs:386:18:386:32 | CallExpr | test.rs:386:18:386:32 | BlockExpr | | -| test.rs:386:18:386:32 | ExprStmt | test.rs:386:9:386:33 | $crate::io::_print | | -| test.rs:386:18:386:32 | FormatArgsExpr | test.rs:386:18:386:32 | MacroExpr | | -| test.rs:386:18:386:32 | MacroExpr | test.rs:386:18:386:32 | CallExpr | | -| test.rs:386:18:386:32 | MacroStmts | test.rs:386:18:386:32 | ExprStmt | | -| test.rs:389:5:408:5 | enter async_block | test.rs:389:26:389:26 | b | | -| test.rs:389:5:408:5 | exit async_block (normal) | test.rs:389:5:408:5 | exit async_block | | -| test.rs:389:26:389:26 | b | test.rs:389:26:389:32 | Param | match | -| test.rs:389:26:389:32 | Param | test.rs:390:9:392:10 | LetStmt | | -| test.rs:389:35:408:5 | BlockExpr | test.rs:389:5:408:5 | exit async_block (normal) | | -| test.rs:390:9:392:10 | LetStmt | test.rs:390:26:392:9 | BlockExpr | | -| test.rs:390:13:390:22 | say_godbye | test.rs:393:9:395:10 | LetStmt | match | -| test.rs:390:26:392:9 | BlockExpr | test.rs:390:13:390:22 | say_godbye | | -| test.rs:390:26:392:9 | enter BlockExpr | test.rs:391:13:391:42 | ExprStmt | | -| test.rs:390:26:392:9 | exit BlockExpr (normal) | test.rs:390:26:392:9 | exit BlockExpr | | -| test.rs:391:13:391:41 | $crate::io::_print | test.rs:391:22:391:40 | "godbye, everyone!\\n" | | -| test.rs:391:13:391:41 | MacroExpr | test.rs:390:26:392:9 | exit BlockExpr (normal) | | -| test.rs:391:13:391:42 | ExprStmt | test.rs:391:22:391:40 | MacroStmts | | -| test.rs:391:22:391:40 | "godbye, everyone!\\n" | test.rs:391:22:391:40 | FormatArgsExpr | | -| test.rs:391:22:391:40 | BlockExpr | test.rs:391:13:391:41 | MacroExpr | | -| test.rs:391:22:391:40 | CallExpr | test.rs:391:22:391:40 | BlockExpr | | -| test.rs:391:22:391:40 | ExprStmt | test.rs:391:13:391:41 | $crate::io::_print | | -| test.rs:391:22:391:40 | FormatArgsExpr | test.rs:391:22:391:40 | MacroExpr | | -| test.rs:391:22:391:40 | MacroExpr | test.rs:391:22:391:40 | CallExpr | | -| test.rs:391:22:391:40 | MacroStmts | test.rs:391:22:391:40 | ExprStmt | | -| test.rs:393:9:395:10 | LetStmt | test.rs:393:31:395:9 | BlockExpr | | -| test.rs:393:13:393:27 | say_how_are_you | test.rs:396:9:396:28 | LetStmt | match | -| test.rs:393:31:395:9 | BlockExpr | test.rs:393:13:393:27 | say_how_are_you | | -| test.rs:393:31:395:9 | enter BlockExpr | test.rs:394:13:394:37 | ExprStmt | | -| test.rs:393:31:395:9 | exit BlockExpr (normal) | test.rs:393:31:395:9 | exit BlockExpr | | -| test.rs:394:13:394:36 | $crate::io::_print | test.rs:394:22:394:35 | "how are you?\\n" | | -| test.rs:394:13:394:36 | MacroExpr | test.rs:393:31:395:9 | exit BlockExpr (normal) | | -| test.rs:394:13:394:37 | ExprStmt | test.rs:394:22:394:35 | MacroStmts | | -| test.rs:394:22:394:35 | "how are you?\\n" | test.rs:394:22:394:35 | FormatArgsExpr | | -| test.rs:394:22:394:35 | BlockExpr | test.rs:394:13:394:36 | MacroExpr | | -| test.rs:394:22:394:35 | CallExpr | test.rs:394:22:394:35 | BlockExpr | | -| test.rs:394:22:394:35 | ExprStmt | test.rs:394:13:394:36 | $crate::io::_print | | -| test.rs:394:22:394:35 | FormatArgsExpr | test.rs:394:22:394:35 | MacroExpr | | -| test.rs:394:22:394:35 | MacroExpr | test.rs:394:22:394:35 | CallExpr | | -| test.rs:394:22:394:35 | MacroStmts | test.rs:394:22:394:35 | ExprStmt | | -| test.rs:396:9:396:28 | LetStmt | test.rs:396:20:396:27 | BlockExpr | | -| test.rs:396:13:396:16 | noop | test.rs:397:9:397:26 | ExprStmt | match | -| test.rs:396:20:396:27 | BlockExpr | test.rs:396:13:396:16 | noop | | -| test.rs:397:9:397:17 | say_hello | test.rs:397:9:397:19 | CallExpr | | -| test.rs:397:9:397:19 | CallExpr | test.rs:397:9:397:25 | AwaitExpr | | -| test.rs:397:9:397:25 | AwaitExpr | test.rs:398:9:398:30 | ExprStmt | | -| test.rs:397:9:397:26 | ExprStmt | test.rs:397:9:397:17 | say_hello | | -| test.rs:398:9:398:23 | say_how_are_you | test.rs:398:9:398:29 | AwaitExpr | | -| test.rs:398:9:398:29 | AwaitExpr | test.rs:399:9:399:25 | ExprStmt | | -| test.rs:398:9:398:30 | ExprStmt | test.rs:398:9:398:23 | say_how_are_you | | -| test.rs:399:9:399:18 | say_godbye | test.rs:399:9:399:24 | AwaitExpr | | -| test.rs:399:9:399:24 | AwaitExpr | test.rs:400:9:400:19 | ExprStmt | | -| test.rs:399:9:399:25 | ExprStmt | test.rs:399:9:399:18 | say_godbye | | -| test.rs:400:9:400:12 | noop | test.rs:400:9:400:18 | AwaitExpr | | -| test.rs:400:9:400:18 | AwaitExpr | test.rs:402:9:407:10 | LetStmt | | -| test.rs:400:9:400:19 | ExprStmt | test.rs:400:9:400:12 | noop | | -| test.rs:402:9:407:10 | LetStmt | test.rs:402:22:407:9 | ClosureExpr | | -| test.rs:402:13:402:18 | lambda | test.rs:389:35:408:5 | BlockExpr | match | -| test.rs:402:22:407:9 | ClosureExpr | test.rs:402:13:402:18 | lambda | | -| test.rs:402:22:407:9 | enter ClosureExpr | test.rs:402:23:402:25 | foo | | -| test.rs:402:22:407:9 | exit ClosureExpr (normal) | test.rs:402:22:407:9 | exit ClosureExpr | | -| test.rs:402:23:402:25 | Param | test.rs:402:28:407:9 | BlockExpr | | -| test.rs:402:23:402:25 | foo | test.rs:402:23:402:25 | Param | match | -| test.rs:402:28:407:9 | BlockExpr | test.rs:402:22:407:9 | exit ClosureExpr (normal) | | -| test.rs:402:28:407:9 | enter BlockExpr | test.rs:403:13:405:14 | ExprStmt | | -| test.rs:402:28:407:9 | exit BlockExpr (normal) | test.rs:402:28:407:9 | exit BlockExpr | | -| test.rs:403:13:405:13 | IfExpr | test.rs:406:13:406:15 | foo | | -| test.rs:403:13:405:14 | ExprStmt | test.rs:403:16:403:16 | b | | -| test.rs:403:16:403:16 | b | test.rs:403:13:405:13 | IfExpr | false | -| test.rs:403:16:403:16 | b | test.rs:404:17:404:41 | ExprStmt | true | -| test.rs:404:17:404:40 | ReturnExpr | test.rs:402:28:407:9 | exit BlockExpr (normal) | return | -| test.rs:404:17:404:41 | ExprStmt | test.rs:404:24:404:34 | async_block | | -| test.rs:404:24:404:34 | async_block | test.rs:404:36:404:39 | true | | -| test.rs:404:24:404:40 | CallExpr | test.rs:404:17:404:40 | ReturnExpr | | -| test.rs:404:36:404:39 | true | test.rs:404:24:404:40 | CallExpr | | -| test.rs:406:13:406:15 | foo | test.rs:402:28:407:9 | exit BlockExpr (normal) | | -| test.rs:414:5:416:5 | enter add_two | test.rs:414:22:414:22 | n | | -| test.rs:414:5:416:5 | exit add_two (normal) | test.rs:414:5:416:5 | exit add_two | | -| test.rs:414:22:414:22 | n | test.rs:414:22:414:27 | Param | match | -| test.rs:414:22:414:27 | Param | test.rs:415:9:415:9 | n | | -| test.rs:414:37:416:5 | BlockExpr | test.rs:414:5:416:5 | exit add_two (normal) | | -| test.rs:415:9:415:9 | n | test.rs:415:13:415:13 | 2 | | -| test.rs:415:9:415:13 | ... + ... | test.rs:414:37:416:5 | BlockExpr | | -| test.rs:415:13:415:13 | 2 | test.rs:415:9:415:13 | ... + ... | | -| test.rs:420:5:428:5 | enter const_block_assert | test.rs:423:9:425:9 | ExprStmt | | -| test.rs:420:5:428:5 | exit const_block_assert (normal) | test.rs:420:5:428:5 | exit const_block_assert | | -| test.rs:420:41:428:5 | BlockExpr | test.rs:420:5:428:5 | exit const_block_assert (normal) | | -| test.rs:423:9:425:9 | BlockExpr | test.rs:427:9:427:10 | 42 | | -| test.rs:423:9:425:9 | ExprStmt | test.rs:424:13:424:50 | ExprStmt | | -| test.rs:424:13:424:49 | $crate::panicking::panic_explicit | test.rs:424:13:424:49 | CallExpr | | -| test.rs:424:13:424:49 | BlockExpr | test.rs:424:13:424:49 | MacroExpr | | -| test.rs:424:13:424:49 | BlockExpr | test.rs:424:13:424:49 | exit panic_cold_explicit (normal) | | -| test.rs:424:13:424:49 | BlockExpr | test.rs:424:21:424:48 | IfExpr | | -| test.rs:424:13:424:49 | CallExpr | test.rs:424:13:424:49 | BlockExpr | | -| test.rs:424:13:424:49 | CallExpr | test.rs:424:13:424:49 | BlockExpr | | -| test.rs:424:13:424:49 | ExprStmt | test.rs:424:13:424:49 | MacroStmts | | -| test.rs:424:13:424:49 | ExprStmt | test.rs:424:13:424:49 | panic_cold_explicit | | -| test.rs:424:13:424:49 | MacroExpr | test.rs:423:9:425:9 | BlockExpr | | -| test.rs:424:13:424:49 | MacroExpr | test.rs:424:13:424:49 | BlockExpr | | -| test.rs:424:13:424:49 | MacroStmts | test.rs:424:13:424:49 | panic_cold_explicit | | -| test.rs:424:13:424:49 | enter panic_cold_explicit | test.rs:424:13:424:49 | $crate::panicking::panic_explicit | | -| test.rs:424:13:424:49 | exit panic_cold_explicit (normal) | test.rs:424:13:424:49 | exit panic_cold_explicit | | -| test.rs:424:13:424:49 | panic_cold_explicit | test.rs:424:13:424:49 | CallExpr | | -| test.rs:424:13:424:49 | panic_cold_explicit | test.rs:424:13:424:49 | ExprStmt | | -| test.rs:424:13:424:50 | ExprStmt | test.rs:424:21:424:48 | MacroStmts | | -| test.rs:424:21:424:42 | std::mem::size_of::<...> | test.rs:424:21:424:44 | CallExpr | | -| test.rs:424:21:424:44 | CallExpr | test.rs:424:48:424:48 | 0 | | -| test.rs:424:21:424:48 | ... > ... | test.rs:424:21:424:48 | [boolean(false)] ! ... | true | -| test.rs:424:21:424:48 | ... > ... | test.rs:424:21:424:48 | [boolean(true)] ! ... | false | -| test.rs:424:21:424:48 | BlockExpr | test.rs:424:13:424:49 | MacroExpr | | -| test.rs:424:21:424:48 | IfExpr | test.rs:424:21:424:48 | BlockExpr | | -| test.rs:424:21:424:48 | MacroStmts | test.rs:424:21:424:42 | std::mem::size_of::<...> | | -| test.rs:424:21:424:48 | [boolean(false)] ! ... | test.rs:424:21:424:48 | IfExpr | false | -| test.rs:424:21:424:48 | [boolean(true)] ! ... | test.rs:424:13:424:49 | ExprStmt | true | -| test.rs:424:48:424:48 | 0 | test.rs:424:21:424:48 | ... > ... | | -| test.rs:427:9:427:10 | 42 | test.rs:420:41:428:5 | BlockExpr | | -| test.rs:430:5:439:5 | enter const_block_panic | test.rs:431:9:431:30 | Const | | -| test.rs:430:5:439:5 | exit const_block_panic (normal) | test.rs:430:5:439:5 | exit const_block_panic | | -| test.rs:430:35:439:5 | BlockExpr | test.rs:430:5:439:5 | exit const_block_panic (normal) | | -| test.rs:431:9:431:30 | Const | test.rs:432:9:437:9 | ExprStmt | | -| test.rs:432:9:437:9 | ExprStmt | test.rs:432:12:432:16 | false | | -| test.rs:432:9:437:9 | IfExpr | test.rs:438:9:438:9 | N | | -| test.rs:432:12:432:16 | false | test.rs:432:9:437:9 | IfExpr | false | -| test.rs:435:17:435:24 | $crate::panicking::panic_explicit | test.rs:435:17:435:24 | CallExpr | | -| test.rs:435:17:435:24 | BlockExpr | test.rs:435:17:435:24 | exit panic_cold_explicit (normal) | | -| test.rs:435:17:435:24 | CallExpr | test.rs:435:17:435:24 | BlockExpr | | -| test.rs:435:17:435:24 | enter panic_cold_explicit | test.rs:435:17:435:24 | $crate::panicking::panic_explicit | | -| test.rs:435:17:435:24 | exit panic_cold_explicit (normal) | test.rs:435:17:435:24 | exit panic_cold_explicit | | -| test.rs:438:9:438:9 | N | test.rs:430:35:439:5 | BlockExpr | | -| test.rs:442:1:447:1 | enter dead_code | test.rs:443:5:445:5 | ExprStmt | | -| test.rs:442:1:447:1 | exit dead_code (normal) | test.rs:442:1:447:1 | exit dead_code | | -| test.rs:443:5:445:5 | ExprStmt | test.rs:443:9:443:12 | true | | -| test.rs:443:9:443:12 | true | test.rs:444:9:444:17 | ExprStmt | true | -| test.rs:444:9:444:16 | ReturnExpr | test.rs:442:1:447:1 | exit dead_code (normal) | return | -| test.rs:444:9:444:17 | ExprStmt | test.rs:444:16:444:16 | 0 | | -| test.rs:444:16:444:16 | 0 | test.rs:444:9:444:16 | ReturnExpr | | -| test.rs:449:1:449:16 | enter do_thing | test.rs:449:15:449:16 | BlockExpr | | -| test.rs:449:1:449:16 | exit do_thing (normal) | test.rs:449:1:449:16 | exit do_thing | | -| test.rs:449:15:449:16 | BlockExpr | test.rs:449:1:449:16 | exit do_thing (normal) | | -| test.rs:451:1:453:1 | enter condition_not_met | test.rs:452:5:452:9 | false | | -| test.rs:451:1:453:1 | exit condition_not_met (normal) | test.rs:451:1:453:1 | exit condition_not_met | | -| test.rs:451:32:453:1 | BlockExpr | test.rs:451:1:453:1 | exit condition_not_met (normal) | | -| test.rs:452:5:452:9 | false | test.rs:451:32:453:1 | BlockExpr | | -| test.rs:455:1:455:21 | enter do_next_thing | test.rs:455:20:455:21 | BlockExpr | | -| test.rs:455:1:455:21 | exit do_next_thing (normal) | test.rs:455:1:455:21 | exit do_next_thing | | -| test.rs:455:20:455:21 | BlockExpr | test.rs:455:1:455:21 | exit do_next_thing (normal) | | -| test.rs:457:1:457:21 | enter do_last_thing | test.rs:457:20:457:21 | BlockExpr | | -| test.rs:457:1:457:21 | exit do_last_thing (normal) | test.rs:457:1:457:21 | exit do_last_thing | | -| test.rs:457:20:457:21 | BlockExpr | test.rs:457:1:457:21 | exit do_last_thing (normal) | | -| test.rs:459:1:473:1 | enter labelled_block1 | test.rs:460:5:471:6 | LetStmt | | -| test.rs:459:1:473:1 | exit labelled_block1 (normal) | test.rs:459:1:473:1 | exit labelled_block1 | | -| test.rs:459:29:473:1 | BlockExpr | test.rs:459:1:473:1 | exit labelled_block1 (normal) | | -| test.rs:460:5:471:6 | LetStmt | test.rs:461:9:461:19 | ExprStmt | | -| test.rs:460:9:460:14 | result | test.rs:472:5:472:10 | result | match | -| test.rs:460:18:471:5 | BlockExpr | test.rs:460:9:460:14 | result | | -| test.rs:461:9:461:16 | do_thing | test.rs:461:9:461:18 | CallExpr | | -| test.rs:461:9:461:18 | CallExpr | test.rs:462:9:464:9 | ExprStmt | | -| test.rs:461:9:461:19 | ExprStmt | test.rs:461:9:461:16 | do_thing | | -| test.rs:462:9:464:9 | ExprStmt | test.rs:462:12:462:28 | condition_not_met | | -| test.rs:462:9:464:9 | IfExpr | test.rs:465:9:465:24 | ExprStmt | | -| test.rs:462:12:462:28 | condition_not_met | test.rs:462:12:462:30 | CallExpr | | -| test.rs:462:12:462:30 | CallExpr | test.rs:462:9:464:9 | IfExpr | false | -| test.rs:462:12:462:30 | CallExpr | test.rs:463:13:463:27 | ExprStmt | true | -| test.rs:463:13:463:26 | BreakExpr | test.rs:460:18:471:5 | BlockExpr | break | -| test.rs:463:13:463:27 | ExprStmt | test.rs:463:26:463:26 | 1 | | -| test.rs:463:26:463:26 | 1 | test.rs:463:13:463:26 | BreakExpr | | -| test.rs:465:9:465:21 | do_next_thing | test.rs:465:9:465:23 | CallExpr | | -| test.rs:465:9:465:23 | CallExpr | test.rs:466:9:468:9 | ExprStmt | | -| test.rs:465:9:465:24 | ExprStmt | test.rs:465:9:465:21 | do_next_thing | | -| test.rs:466:9:468:9 | ExprStmt | test.rs:466:12:466:28 | condition_not_met | | -| test.rs:466:9:468:9 | IfExpr | test.rs:469:9:469:24 | ExprStmt | | -| test.rs:466:12:466:28 | condition_not_met | test.rs:466:12:466:30 | CallExpr | | -| test.rs:466:12:466:30 | CallExpr | test.rs:466:9:468:9 | IfExpr | false | -| test.rs:466:12:466:30 | CallExpr | test.rs:467:13:467:27 | ExprStmt | true | -| test.rs:467:13:467:26 | BreakExpr | test.rs:460:18:471:5 | BlockExpr | break | -| test.rs:467:13:467:27 | ExprStmt | test.rs:467:26:467:26 | 2 | | -| test.rs:467:26:467:26 | 2 | test.rs:467:13:467:26 | BreakExpr | | -| test.rs:469:9:469:21 | do_last_thing | test.rs:469:9:469:23 | CallExpr | | -| test.rs:469:9:469:23 | CallExpr | test.rs:470:9:470:9 | 3 | | -| test.rs:469:9:469:24 | ExprStmt | test.rs:469:9:469:21 | do_last_thing | | -| test.rs:470:9:470:9 | 3 | test.rs:460:18:471:5 | BlockExpr | | -| test.rs:472:5:472:10 | result | test.rs:459:29:473:1 | BlockExpr | | -| test.rs:475:1:483:1 | enter labelled_block2 | test.rs:476:5:482:6 | LetStmt | | -| test.rs:475:1:483:1 | exit labelled_block2 (normal) | test.rs:475:1:483:1 | exit labelled_block2 | | -| test.rs:475:22:483:1 | BlockExpr | test.rs:475:1:483:1 | exit labelled_block2 (normal) | | -| test.rs:476:5:482:6 | LetStmt | test.rs:477:9:477:34 | LetStmt | | -| test.rs:476:9:476:14 | result | test.rs:475:22:483:1 | BlockExpr | match | -| test.rs:476:18:482:5 | BlockExpr | test.rs:476:9:476:14 | result | | -| test.rs:477:9:477:34 | LetStmt | test.rs:477:30:477:33 | None | | -| test.rs:477:13:477:13 | x | test.rs:478:9:480:10 | LetStmt | match | -| test.rs:477:30:477:33 | None | test.rs:477:13:477:13 | x | | -| test.rs:478:9:480:10 | LetStmt | test.rs:478:23:478:23 | x | | -| test.rs:478:13:478:19 | TupleStructPat | test.rs:478:18:478:18 | y | match | -| test.rs:478:13:478:19 | TupleStructPat | test.rs:479:13:479:27 | ExprStmt | no-match | -| test.rs:478:18:478:18 | y | test.rs:481:9:481:9 | 0 | match | -| test.rs:478:23:478:23 | x | test.rs:478:13:478:19 | TupleStructPat | | -| test.rs:479:13:479:26 | BreakExpr | test.rs:476:18:482:5 | BlockExpr | break | -| test.rs:479:13:479:27 | ExprStmt | test.rs:479:26:479:26 | 1 | | -| test.rs:479:26:479:26 | 1 | test.rs:479:13:479:26 | BreakExpr | | -| test.rs:481:9:481:9 | 0 | test.rs:476:18:482:5 | BlockExpr | | -| test.rs:485:1:491:1 | enter test_nested_function2 | test.rs:486:5:486:18 | LetStmt | | -| test.rs:485:1:491:1 | exit test_nested_function2 (normal) | test.rs:485:1:491:1 | exit test_nested_function2 | | -| test.rs:485:28:491:1 | BlockExpr | test.rs:485:1:491:1 | exit test_nested_function2 (normal) | | -| test.rs:486:5:486:18 | LetStmt | test.rs:486:17:486:17 | 0 | | -| test.rs:486:9:486:13 | x | test.rs:487:5:489:5 | nested | match | -| test.rs:486:17:486:17 | 0 | test.rs:486:9:486:13 | x | | -| test.rs:487:5:489:5 | enter nested | test.rs:487:15:487:15 | x | | -| test.rs:487:5:489:5 | exit nested (normal) | test.rs:487:5:489:5 | exit nested | | -| test.rs:487:5:489:5 | nested | test.rs:490:5:490:19 | ExprStmt | | -| test.rs:487:15:487:15 | x | test.rs:487:15:487:25 | Param | match | -| test.rs:487:15:487:25 | Param | test.rs:488:9:488:16 | ExprStmt | | -| test.rs:487:28:489:5 | BlockExpr | test.rs:487:5:489:5 | exit nested (normal) | | -| test.rs:488:9:488:10 | * ... | test.rs:488:15:488:15 | 1 | | -| test.rs:488:9:488:15 | ... += ... | test.rs:487:28:489:5 | BlockExpr | | -| test.rs:488:9:488:16 | ExprStmt | test.rs:488:10:488:10 | x | | -| test.rs:488:10:488:10 | x | test.rs:488:9:488:10 | * ... | | -| test.rs:488:15:488:15 | 1 | test.rs:488:9:488:15 | ... += ... | | -| test.rs:490:5:490:10 | nested | test.rs:490:17:490:17 | x | | -| test.rs:490:5:490:18 | CallExpr | test.rs:485:28:491:1 | BlockExpr | | -| test.rs:490:5:490:19 | ExprStmt | test.rs:490:5:490:10 | nested | | -| test.rs:490:12:490:17 | RefExpr | test.rs:490:5:490:18 | CallExpr | | -| test.rs:490:17:490:17 | x | test.rs:490:12:490:17 | RefExpr | | -| test.rs:502:5:504:5 | enter new | test.rs:502:12:502:12 | a | | -| test.rs:502:5:504:5 | exit new (normal) | test.rs:502:5:504:5 | exit new | | -| test.rs:502:12:502:12 | a | test.rs:502:12:502:17 | Param | match | -| test.rs:502:12:502:17 | Param | test.rs:503:23:503:23 | a | | -| test.rs:502:28:504:5 | BlockExpr | test.rs:502:5:504:5 | exit new (normal) | | -| test.rs:503:9:503:25 | RecordExpr | test.rs:502:28:504:5 | BlockExpr | | -| test.rs:503:23:503:23 | a | test.rs:503:9:503:25 | RecordExpr | | -| test.rs:506:5:508:5 | enter negated | test.rs:506:16:506:19 | self | | -| test.rs:506:5:508:5 | exit negated (normal) | test.rs:506:5:508:5 | exit negated | | -| test.rs:506:16:506:19 | SelfParam | test.rs:507:23:507:26 | self | | -| test.rs:506:16:506:19 | self | test.rs:506:16:506:19 | SelfParam | | -| test.rs:506:30:508:5 | BlockExpr | test.rs:506:5:508:5 | exit negated (normal) | | -| test.rs:507:9:507:30 | RecordExpr | test.rs:506:30:508:5 | BlockExpr | | -| test.rs:507:23:507:26 | self | test.rs:507:23:507:28 | FieldExpr | | -| test.rs:507:23:507:28 | FieldExpr | test.rs:507:9:507:30 | RecordExpr | | -| test.rs:510:5:512:5 | enter multifly_add | test.rs:510:26:510:29 | self | | -| test.rs:510:5:512:5 | exit multifly_add (normal) | test.rs:510:5:512:5 | exit multifly_add | | -| test.rs:510:21:510:29 | SelfParam | test.rs:510:32:510:32 | a | | -| test.rs:510:26:510:29 | self | test.rs:510:21:510:29 | SelfParam | | -| test.rs:510:32:510:32 | a | test.rs:510:32:510:37 | Param | match | -| test.rs:510:32:510:37 | Param | test.rs:510:40:510:40 | b | | -| test.rs:510:40:510:40 | b | test.rs:510:40:510:45 | Param | match | -| test.rs:510:40:510:45 | Param | test.rs:511:9:511:34 | ExprStmt | | -| test.rs:510:48:512:5 | BlockExpr | test.rs:510:5:512:5 | exit multifly_add (normal) | | -| test.rs:511:9:511:12 | self | test.rs:511:9:511:14 | FieldExpr | | -| test.rs:511:9:511:14 | FieldExpr | test.rs:511:19:511:22 | self | | -| test.rs:511:9:511:33 | ... = ... | test.rs:510:48:512:5 | BlockExpr | | -| test.rs:511:9:511:34 | ExprStmt | test.rs:511:9:511:12 | self | | -| test.rs:511:18:511:33 | ... + ... | test.rs:511:9:511:33 | ... = ... | | -| test.rs:511:19:511:22 | self | test.rs:511:19:511:24 | FieldExpr | | -| test.rs:511:19:511:24 | FieldExpr | test.rs:511:28:511:28 | a | | -| test.rs:511:19:511:28 | ... * ... | test.rs:511:33:511:33 | b | | -| test.rs:511:28:511:28 | a | test.rs:511:19:511:28 | ... * ... | | -| test.rs:511:33:511:33 | b | test.rs:511:18:511:33 | ... + ... | | +| test.rs:281:5:286:5 | enter test_and_true | test.rs:281:22:281:22 | a | | +| test.rs:281:5:286:5 | exit test_and_true (normal) | test.rs:281:5:286:5 | exit test_and_true | | +| test.rs:281:22:281:22 | a | test.rs:281:22:281:28 | Param | match | +| test.rs:281:22:281:28 | Param | test.rs:282:9:284:9 | ExprStmt | | +| test.rs:281:38:286:5 | BlockExpr | test.rs:281:5:286:5 | exit test_and_true (normal) | | +| test.rs:282:9:284:9 | ExprStmt | test.rs:282:13:282:13 | a | | +| test.rs:282:9:284:9 | IfExpr | test.rs:285:9:285:9 | 0 | | +| test.rs:282:13:282:13 | a | test.rs:282:13:282:21 | [boolean(false)] ... && ... | false | +| test.rs:282:13:282:13 | a | test.rs:282:18:282:21 | true | true | +| test.rs:282:13:282:21 | [boolean(false)] ... && ... | test.rs:282:9:284:9 | IfExpr | false | +| test.rs:282:13:282:21 | [boolean(true)] ... && ... | test.rs:283:13:283:21 | ExprStmt | true | +| test.rs:282:18:282:21 | true | test.rs:282:13:282:21 | [boolean(true)] ... && ... | true | +| test.rs:283:13:283:20 | ReturnExpr | test.rs:281:5:286:5 | exit test_and_true (normal) | return | +| test.rs:283:13:283:21 | ExprStmt | test.rs:283:20:283:20 | 1 | | +| test.rs:283:20:283:20 | 1 | test.rs:283:13:283:20 | ReturnExpr | | +| test.rs:285:9:285:9 | 0 | test.rs:281:38:286:5 | BlockExpr | | +| test.rs:292:5:294:5 | enter test_question_mark_operator_1 | test.rs:292:38:292:38 | s | | +| test.rs:292:5:294:5 | exit test_question_mark_operator_1 (normal) | test.rs:292:5:294:5 | exit test_question_mark_operator_1 | | +| test.rs:292:38:292:38 | s | test.rs:292:38:292:44 | Param | match | +| test.rs:292:38:292:44 | Param | test.rs:293:9:293:10 | Ok | | +| test.rs:292:87:294:5 | BlockExpr | test.rs:292:5:294:5 | exit test_question_mark_operator_1 (normal) | | +| test.rs:293:9:293:10 | Ok | test.rs:293:12:293:12 | s | | +| test.rs:293:9:293:33 | CallExpr | test.rs:292:87:294:5 | BlockExpr | | +| test.rs:293:12:293:12 | s | test.rs:293:12:293:27 | ... .parse(...) | | +| test.rs:293:12:293:27 | ... .parse(...) | test.rs:293:12:293:28 | TryExpr | | +| test.rs:293:12:293:28 | TryExpr | test.rs:292:5:294:5 | exit test_question_mark_operator_1 (normal) | return | +| test.rs:293:12:293:28 | TryExpr | test.rs:293:32:293:32 | 4 | match | +| test.rs:293:12:293:32 | ... + ... | test.rs:293:9:293:33 | CallExpr | | +| test.rs:293:32:293:32 | 4 | test.rs:293:12:293:32 | ... + ... | | +| test.rs:296:5:301:5 | enter test_question_mark_operator_2 | test.rs:296:38:296:38 | b | | +| test.rs:296:5:301:5 | exit test_question_mark_operator_2 (normal) | test.rs:296:5:301:5 | exit test_question_mark_operator_2 | | +| test.rs:296:38:296:38 | b | test.rs:296:38:296:52 | Param | match | +| test.rs:296:38:296:52 | Param | test.rs:297:15:297:15 | b | | +| test.rs:296:71:301:5 | BlockExpr | test.rs:296:5:301:5 | exit test_question_mark_operator_2 (normal) | | +| test.rs:297:9:300:9 | MatchExpr | test.rs:296:71:301:5 | BlockExpr | | +| test.rs:297:15:297:15 | b | test.rs:297:15:297:16 | TryExpr | | +| test.rs:297:15:297:16 | TryExpr | test.rs:296:5:301:5 | exit test_question_mark_operator_2 (normal) | return | +| test.rs:297:15:297:16 | TryExpr | test.rs:298:13:298:16 | true | match | +| test.rs:298:13:298:16 | LiteralPat | test.rs:298:21:298:24 | Some | match | +| test.rs:298:13:298:16 | LiteralPat | test.rs:299:13:299:17 | false | no-match | +| test.rs:298:13:298:16 | true | test.rs:298:13:298:16 | LiteralPat | | +| test.rs:298:21:298:24 | Some | test.rs:298:26:298:30 | false | | +| test.rs:298:21:298:31 | CallExpr | test.rs:297:9:300:9 | MatchExpr | | +| test.rs:298:26:298:30 | false | test.rs:298:21:298:31 | CallExpr | | +| test.rs:299:13:299:17 | LiteralPat | test.rs:299:22:299:25 | Some | match | +| test.rs:299:13:299:17 | false | test.rs:299:13:299:17 | LiteralPat | | +| test.rs:299:22:299:25 | Some | test.rs:299:27:299:30 | true | | +| test.rs:299:22:299:31 | CallExpr | test.rs:297:9:300:9 | MatchExpr | | +| test.rs:299:27:299:30 | true | test.rs:299:22:299:31 | CallExpr | | +| test.rs:307:5:313:5 | enter test_match | test.rs:307:19:307:29 | maybe_digit | | +| test.rs:307:5:313:5 | exit test_match (normal) | test.rs:307:5:313:5 | exit test_match | | +| test.rs:307:19:307:29 | maybe_digit | test.rs:307:19:307:42 | Param | match | +| test.rs:307:19:307:42 | Param | test.rs:308:15:308:25 | maybe_digit | | +| test.rs:307:52:313:5 | BlockExpr | test.rs:307:5:313:5 | exit test_match (normal) | | +| test.rs:308:9:312:9 | MatchExpr | test.rs:307:52:313:5 | BlockExpr | | +| test.rs:308:15:308:25 | maybe_digit | test.rs:309:13:309:27 | TupleStructPat | | +| test.rs:309:13:309:27 | TupleStructPat | test.rs:309:26:309:26 | x | match | +| test.rs:309:13:309:27 | TupleStructPat | test.rs:310:13:310:27 | TupleStructPat | no-match | +| test.rs:309:26:309:26 | x | test.rs:309:32:309:32 | x | match | +| test.rs:309:32:309:32 | x | test.rs:309:36:309:37 | 10 | | +| test.rs:309:32:309:37 | ... < ... | test.rs:309:42:309:42 | x | true | +| test.rs:309:32:309:37 | ... < ... | test.rs:310:13:310:27 | TupleStructPat | false | +| test.rs:309:36:309:37 | 10 | test.rs:309:32:309:37 | ... < ... | | +| test.rs:309:42:309:42 | x | test.rs:309:46:309:46 | 5 | | +| test.rs:309:42:309:46 | ... + ... | test.rs:308:9:312:9 | MatchExpr | | +| test.rs:309:46:309:46 | 5 | test.rs:309:42:309:46 | ... + ... | | +| test.rs:310:13:310:27 | TupleStructPat | test.rs:310:26:310:26 | x | match | +| test.rs:310:13:310:27 | TupleStructPat | test.rs:311:13:311:24 | PathPat | no-match | +| test.rs:310:26:310:26 | x | test.rs:310:32:310:32 | x | match | +| test.rs:310:32:310:32 | x | test.rs:308:9:312:9 | MatchExpr | | +| test.rs:311:13:311:24 | PathPat | test.rs:311:29:311:29 | 5 | match | +| test.rs:311:29:311:29 | 5 | test.rs:308:9:312:9 | MatchExpr | | +| test.rs:315:5:324:5 | enter test_match_with_return_in_scrutinee | test.rs:315:44:315:54 | maybe_digit | | +| test.rs:315:5:324:5 | exit test_match_with_return_in_scrutinee (normal) | test.rs:315:5:324:5 | exit test_match_with_return_in_scrutinee | | +| test.rs:315:44:315:54 | maybe_digit | test.rs:315:44:315:67 | Param | match | +| test.rs:315:44:315:67 | Param | test.rs:316:19:316:29 | maybe_digit | | +| test.rs:315:77:324:5 | BlockExpr | test.rs:315:5:324:5 | exit test_match_with_return_in_scrutinee (normal) | | +| test.rs:316:9:323:9 | MatchExpr | test.rs:315:77:324:5 | BlockExpr | | +| test.rs:316:16:320:9 | IfExpr | test.rs:321:13:321:27 | TupleStructPat | | +| test.rs:316:19:316:29 | maybe_digit | test.rs:316:34:316:37 | Some | | +| test.rs:316:19:316:40 | ... == ... | test.rs:317:13:317:21 | ExprStmt | true | +| test.rs:316:19:316:40 | ... == ... | test.rs:319:13:319:23 | maybe_digit | false | +| test.rs:316:34:316:37 | Some | test.rs:316:39:316:39 | 3 | | +| test.rs:316:34:316:40 | CallExpr | test.rs:316:19:316:40 | ... == ... | | +| test.rs:316:39:316:39 | 3 | test.rs:316:34:316:40 | CallExpr | | +| test.rs:317:13:317:20 | ReturnExpr | test.rs:315:5:324:5 | exit test_match_with_return_in_scrutinee (normal) | return | +| test.rs:317:13:317:21 | ExprStmt | test.rs:317:20:317:20 | 3 | | +| test.rs:317:20:317:20 | 3 | test.rs:317:13:317:20 | ReturnExpr | | +| test.rs:318:16:320:9 | BlockExpr | test.rs:316:16:320:9 | IfExpr | | +| test.rs:319:13:319:23 | maybe_digit | test.rs:318:16:320:9 | BlockExpr | | +| test.rs:321:13:321:27 | TupleStructPat | test.rs:321:26:321:26 | x | match | +| test.rs:321:13:321:27 | TupleStructPat | test.rs:322:13:322:24 | PathPat | no-match | +| test.rs:321:26:321:26 | x | test.rs:321:32:321:32 | x | match | +| test.rs:321:32:321:32 | x | test.rs:321:36:321:36 | 5 | | +| test.rs:321:32:321:36 | ... + ... | test.rs:316:9:323:9 | MatchExpr | | +| test.rs:321:36:321:36 | 5 | test.rs:321:32:321:36 | ... + ... | | +| test.rs:322:13:322:24 | PathPat | test.rs:322:29:322:29 | 5 | match | +| test.rs:322:29:322:29 | 5 | test.rs:316:9:323:9 | MatchExpr | | +| test.rs:326:5:331:5 | enter test_match_and | test.rs:326:23:326:26 | cond | | +| test.rs:326:5:331:5 | exit test_match_and (normal) | test.rs:326:5:331:5 | exit test_match_and | | +| test.rs:326:23:326:26 | cond | test.rs:326:23:326:32 | Param | match | +| test.rs:326:23:326:32 | Param | test.rs:326:35:326:35 | r | | +| test.rs:326:35:326:35 | r | test.rs:326:35:326:49 | Param | match | +| test.rs:326:35:326:49 | Param | test.rs:327:16:327:16 | r | | +| test.rs:326:60:331:5 | BlockExpr | test.rs:326:5:331:5 | exit test_match_and (normal) | | +| test.rs:327:9:330:18 | ... && ... | test.rs:326:60:331:5 | BlockExpr | | +| test.rs:327:10:330:9 | [boolean(false)] MatchExpr | test.rs:327:9:330:18 | ... && ... | false | +| test.rs:327:10:330:9 | [boolean(true)] MatchExpr | test.rs:330:15:330:18 | cond | true | +| test.rs:327:16:327:16 | r | test.rs:328:13:328:19 | TupleStructPat | | +| test.rs:328:13:328:19 | TupleStructPat | test.rs:328:18:328:18 | a | match | +| test.rs:328:13:328:19 | TupleStructPat | test.rs:329:13:329:13 | WildcardPat | no-match | +| test.rs:328:18:328:18 | a | test.rs:328:24:328:24 | a | match | +| test.rs:328:24:328:24 | a | test.rs:327:10:330:9 | [boolean(false)] MatchExpr | false | +| test.rs:328:24:328:24 | a | test.rs:327:10:330:9 | [boolean(true)] MatchExpr | true | +| test.rs:329:13:329:13 | WildcardPat | test.rs:329:18:329:22 | false | match | +| test.rs:329:18:329:22 | false | test.rs:327:10:330:9 | [boolean(false)] MatchExpr | false | +| test.rs:330:15:330:18 | cond | test.rs:327:9:330:18 | ... && ... | | +| test.rs:333:5:338:5 | enter test_match_with_no_arms | test.rs:333:35:333:35 | r | | +| test.rs:333:5:338:5 | exit test_match_with_no_arms (normal) | test.rs:333:5:338:5 | exit test_match_with_no_arms | | +| test.rs:333:35:333:35 | r | test.rs:333:35:333:58 | Param | match | +| test.rs:333:35:333:58 | Param | test.rs:334:15:334:15 | r | | +| test.rs:333:66:338:5 | BlockExpr | test.rs:333:5:338:5 | exit test_match_with_no_arms (normal) | | +| test.rs:334:9:337:9 | MatchExpr | test.rs:333:66:338:5 | BlockExpr | | +| test.rs:334:15:334:15 | r | test.rs:335:13:335:21 | TupleStructPat | | +| test.rs:335:13:335:21 | TupleStructPat | test.rs:335:16:335:20 | value | match | +| test.rs:335:13:335:21 | TupleStructPat | test.rs:336:13:336:22 | TupleStructPat | no-match | +| test.rs:335:16:335:20 | value | test.rs:335:26:335:30 | value | match | +| test.rs:335:26:335:30 | value | test.rs:334:9:337:9 | MatchExpr | | +| test.rs:336:13:336:22 | TupleStructPat | test.rs:336:17:336:21 | never | match | +| test.rs:336:17:336:21 | never | test.rs:336:33:336:37 | never | match | +| test.rs:336:27:336:40 | MatchExpr | test.rs:334:9:337:9 | MatchExpr | | +| test.rs:336:33:336:37 | never | test.rs:336:27:336:40 | MatchExpr | | +| test.rs:343:5:346:5 | enter test_let_match | test.rs:343:23:343:23 | a | | +| test.rs:343:5:346:5 | exit test_let_match (normal) | test.rs:343:5:346:5 | exit test_let_match | | +| test.rs:343:23:343:23 | a | test.rs:343:23:343:36 | Param | match | +| test.rs:343:23:343:36 | Param | test.rs:344:9:344:57 | LetStmt | | +| test.rs:343:46:346:5 | BlockExpr | test.rs:343:5:346:5 | exit test_let_match (normal) | | +| test.rs:344:9:344:57 | LetStmt | test.rs:344:23:344:23 | a | | +| test.rs:344:13:344:19 | TupleStructPat | test.rs:344:18:344:18 | n | match | +| test.rs:344:13:344:19 | TupleStructPat | test.rs:344:39:344:53 | MacroStmts | no-match | +| test.rs:344:18:344:18 | n | test.rs:345:9:345:9 | n | match | +| test.rs:344:23:344:23 | a | test.rs:344:13:344:19 | TupleStructPat | | +| test.rs:344:32:344:54 | $crate::panicking::panic_fmt | test.rs:344:39:344:53 | "Expected some" | | +| test.rs:344:32:344:54 | MacroExpr | test.rs:344:30:344:56 | BlockExpr | | +| test.rs:344:39:344:53 | "Expected some" | test.rs:344:39:344:53 | FormatArgsExpr | | +| test.rs:344:39:344:53 | BlockExpr | test.rs:344:39:344:53 | MacroExpr | | +| test.rs:344:39:344:53 | CallExpr | test.rs:344:39:344:53 | BlockExpr | | +| test.rs:344:39:344:53 | ExprStmt | test.rs:344:32:344:54 | $crate::panicking::panic_fmt | | +| test.rs:344:39:344:53 | FormatArgsExpr | test.rs:344:39:344:53 | MacroExpr | | +| test.rs:344:39:344:53 | MacroExpr | test.rs:344:32:344:54 | MacroExpr | | +| test.rs:344:39:344:53 | MacroExpr | test.rs:344:39:344:53 | CallExpr | | +| test.rs:344:39:344:53 | MacroStmts | test.rs:344:39:344:53 | ExprStmt | | +| test.rs:344:39:344:53 | MacroStmts | test.rs:344:39:344:53 | MacroStmts | | +| test.rs:345:9:345:9 | n | test.rs:343:46:346:5 | BlockExpr | | +| test.rs:348:5:354:5 | enter test_let_with_return | test.rs:348:29:348:29 | m | | +| test.rs:348:5:354:5 | exit test_let_with_return (normal) | test.rs:348:5:354:5 | exit test_let_with_return | | +| test.rs:348:29:348:29 | m | test.rs:348:29:348:42 | Param | match | +| test.rs:348:29:348:42 | Param | test.rs:349:9:352:10 | LetStmt | | +| test.rs:348:53:354:5 | BlockExpr | test.rs:348:5:354:5 | exit test_let_with_return (normal) | | +| test.rs:349:9:352:10 | LetStmt | test.rs:349:25:349:25 | m | | +| test.rs:349:13:349:15 | ret | test.rs:353:9:353:12 | true | match | +| test.rs:349:19:352:9 | MatchExpr | test.rs:349:13:349:15 | ret | | +| test.rs:349:25:349:25 | m | test.rs:350:13:350:21 | TupleStructPat | | +| test.rs:350:13:350:21 | TupleStructPat | test.rs:350:18:350:20 | ret | match | +| test.rs:350:13:350:21 | TupleStructPat | test.rs:351:13:351:16 | None | no-match | +| test.rs:350:18:350:20 | ret | test.rs:350:26:350:28 | ret | match | +| test.rs:350:26:350:28 | ret | test.rs:349:19:352:9 | MatchExpr | | +| test.rs:351:13:351:16 | None | test.rs:351:28:351:32 | false | match | +| test.rs:351:21:351:32 | ReturnExpr | test.rs:348:5:354:5 | exit test_let_with_return (normal) | return | +| test.rs:351:28:351:32 | false | test.rs:351:21:351:32 | ReturnExpr | | +| test.rs:353:9:353:12 | true | test.rs:348:53:354:5 | BlockExpr | | +| test.rs:359:5:362:5 | enter empty_tuple_pattern | test.rs:359:28:359:31 | unit | | +| test.rs:359:5:362:5 | exit empty_tuple_pattern (normal) | test.rs:359:5:362:5 | exit empty_tuple_pattern | | +| test.rs:359:28:359:31 | unit | test.rs:359:28:359:35 | Param | match | +| test.rs:359:28:359:35 | Param | test.rs:360:9:360:22 | LetStmt | | +| test.rs:360:9:360:22 | LetStmt | test.rs:360:18:360:21 | unit | | +| test.rs:360:13:360:14 | TuplePat | test.rs:361:9:361:15 | ExprStmt | match | +| test.rs:360:18:360:21 | unit | test.rs:360:13:360:14 | TuplePat | | +| test.rs:361:9:361:14 | ReturnExpr | test.rs:359:5:362:5 | exit empty_tuple_pattern (normal) | return | +| test.rs:361:9:361:15 | ExprStmt | test.rs:361:9:361:14 | ReturnExpr | | +| test.rs:366:5:370:5 | enter empty_struct_pattern | test.rs:366:29:366:30 | st | | +| test.rs:366:5:370:5 | exit empty_struct_pattern (normal) | test.rs:366:5:370:5 | exit empty_struct_pattern | | +| test.rs:366:29:366:30 | st | test.rs:366:29:366:40 | Param | match | +| test.rs:366:29:366:40 | Param | test.rs:367:15:367:16 | st | | +| test.rs:366:50:370:5 | BlockExpr | test.rs:366:5:370:5 | exit empty_struct_pattern (normal) | | +| test.rs:367:9:369:9 | MatchExpr | test.rs:366:50:370:5 | BlockExpr | | +| test.rs:367:15:367:16 | st | test.rs:368:13:368:27 | RecordPat | | +| test.rs:368:13:368:27 | RecordPat | test.rs:368:24:368:25 | RestPat | match | +| test.rs:368:24:368:25 | RestPat | test.rs:368:32:368:32 | 1 | match | +| test.rs:368:32:368:32 | 1 | test.rs:367:9:369:9 | MatchExpr | | +| test.rs:372:5:379:5 | enter range_pattern | test.rs:373:15:373:16 | 42 | | +| test.rs:372:5:379:5 | exit range_pattern (normal) | test.rs:372:5:379:5 | exit range_pattern | | +| test.rs:372:31:379:5 | BlockExpr | test.rs:372:5:379:5 | exit range_pattern (normal) | | +| test.rs:373:9:378:9 | MatchExpr | test.rs:372:31:379:5 | BlockExpr | | +| test.rs:373:15:373:16 | 42 | test.rs:374:13:374:15 | RangePat | | +| test.rs:374:13:374:15 | RangePat | test.rs:374:15:374:15 | 0 | match | +| test.rs:374:13:374:15 | RangePat | test.rs:375:13:375:16 | RangePat | no-match | +| test.rs:374:15:374:15 | 0 | test.rs:374:15:374:15 | LiteralPat | | +| test.rs:374:15:374:15 | LiteralPat | test.rs:374:20:374:20 | 1 | match | +| test.rs:374:15:374:15 | LiteralPat | test.rs:375:13:375:16 | RangePat | no-match | +| test.rs:374:20:374:20 | 1 | test.rs:373:9:378:9 | MatchExpr | | +| test.rs:375:13:375:13 | 1 | test.rs:375:13:375:13 | LiteralPat | | +| test.rs:375:13:375:13 | LiteralPat | test.rs:375:16:375:16 | 2 | match | +| test.rs:375:13:375:13 | LiteralPat | test.rs:376:13:376:15 | RangePat | no-match | +| test.rs:375:13:375:16 | RangePat | test.rs:375:13:375:13 | 1 | match | +| test.rs:375:13:375:16 | RangePat | test.rs:376:13:376:15 | RangePat | no-match | +| test.rs:375:16:375:16 | 2 | test.rs:375:16:375:16 | LiteralPat | | +| test.rs:375:16:375:16 | LiteralPat | test.rs:375:21:375:21 | 2 | match | +| test.rs:375:16:375:16 | LiteralPat | test.rs:376:13:376:15 | RangePat | no-match | +| test.rs:375:21:375:21 | 2 | test.rs:373:9:378:9 | MatchExpr | | +| test.rs:376:13:376:13 | 5 | test.rs:376:13:376:13 | LiteralPat | | +| test.rs:376:13:376:13 | LiteralPat | test.rs:376:20:376:20 | 3 | match | +| test.rs:376:13:376:13 | LiteralPat | test.rs:377:13:377:13 | WildcardPat | no-match | +| test.rs:376:13:376:15 | RangePat | test.rs:376:13:376:13 | 5 | match | +| test.rs:376:13:376:15 | RangePat | test.rs:377:13:377:13 | WildcardPat | no-match | +| test.rs:376:20:376:20 | 3 | test.rs:373:9:378:9 | MatchExpr | | +| test.rs:377:13:377:13 | WildcardPat | test.rs:377:18:377:18 | 4 | match | +| test.rs:377:18:377:18 | 4 | test.rs:373:9:378:9 | MatchExpr | | +| test.rs:383:5:388:5 | enter test_infinite_loop | test.rs:384:9:386:9 | ExprStmt | | +| test.rs:384:9:386:9 | ExprStmt | test.rs:385:13:385:14 | TupleExpr | | +| test.rs:384:14:386:9 | BlockExpr | test.rs:385:13:385:14 | TupleExpr | | +| test.rs:385:13:385:14 | TupleExpr | test.rs:384:14:386:9 | BlockExpr | | +| test.rs:392:5:394:5 | enter say_hello | test.rs:393:9:393:34 | ExprStmt | | +| test.rs:392:5:394:5 | exit say_hello (normal) | test.rs:392:5:394:5 | exit say_hello | | +| test.rs:392:26:394:5 | BlockExpr | test.rs:392:5:394:5 | exit say_hello (normal) | | +| test.rs:393:9:393:33 | $crate::io::_print | test.rs:393:18:393:32 | "hello, world!\\n" | | +| test.rs:393:9:393:33 | MacroExpr | test.rs:392:26:394:5 | BlockExpr | | +| test.rs:393:9:393:34 | ExprStmt | test.rs:393:18:393:32 | MacroStmts | | +| test.rs:393:18:393:32 | "hello, world!\\n" | test.rs:393:18:393:32 | FormatArgsExpr | | +| test.rs:393:18:393:32 | BlockExpr | test.rs:393:9:393:33 | MacroExpr | | +| test.rs:393:18:393:32 | CallExpr | test.rs:393:18:393:32 | BlockExpr | | +| test.rs:393:18:393:32 | ExprStmt | test.rs:393:9:393:33 | $crate::io::_print | | +| test.rs:393:18:393:32 | FormatArgsExpr | test.rs:393:18:393:32 | MacroExpr | | +| test.rs:393:18:393:32 | MacroExpr | test.rs:393:18:393:32 | CallExpr | | +| test.rs:393:18:393:32 | MacroStmts | test.rs:393:18:393:32 | ExprStmt | | +| test.rs:396:5:415:5 | enter async_block | test.rs:396:26:396:26 | b | | +| test.rs:396:5:415:5 | exit async_block (normal) | test.rs:396:5:415:5 | exit async_block | | +| test.rs:396:26:396:26 | b | test.rs:396:26:396:32 | Param | match | +| test.rs:396:26:396:32 | Param | test.rs:397:9:399:10 | LetStmt | | +| test.rs:396:35:415:5 | BlockExpr | test.rs:396:5:415:5 | exit async_block (normal) | | +| test.rs:397:9:399:10 | LetStmt | test.rs:397:26:399:9 | BlockExpr | | +| test.rs:397:13:397:22 | say_godbye | test.rs:400:9:402:10 | LetStmt | match | +| test.rs:397:26:399:9 | BlockExpr | test.rs:397:13:397:22 | say_godbye | | +| test.rs:397:26:399:9 | enter BlockExpr | test.rs:398:13:398:42 | ExprStmt | | +| test.rs:397:26:399:9 | exit BlockExpr (normal) | test.rs:397:26:399:9 | exit BlockExpr | | +| test.rs:398:13:398:41 | $crate::io::_print | test.rs:398:22:398:40 | "godbye, everyone!\\n" | | +| test.rs:398:13:398:41 | MacroExpr | test.rs:397:26:399:9 | exit BlockExpr (normal) | | +| test.rs:398:13:398:42 | ExprStmt | test.rs:398:22:398:40 | MacroStmts | | +| test.rs:398:22:398:40 | "godbye, everyone!\\n" | test.rs:398:22:398:40 | FormatArgsExpr | | +| test.rs:398:22:398:40 | BlockExpr | test.rs:398:13:398:41 | MacroExpr | | +| test.rs:398:22:398:40 | CallExpr | test.rs:398:22:398:40 | BlockExpr | | +| test.rs:398:22:398:40 | ExprStmt | test.rs:398:13:398:41 | $crate::io::_print | | +| test.rs:398:22:398:40 | FormatArgsExpr | test.rs:398:22:398:40 | MacroExpr | | +| test.rs:398:22:398:40 | MacroExpr | test.rs:398:22:398:40 | CallExpr | | +| test.rs:398:22:398:40 | MacroStmts | test.rs:398:22:398:40 | ExprStmt | | +| test.rs:400:9:402:10 | LetStmt | test.rs:400:31:402:9 | BlockExpr | | +| test.rs:400:13:400:27 | say_how_are_you | test.rs:403:9:403:28 | LetStmt | match | +| test.rs:400:31:402:9 | BlockExpr | test.rs:400:13:400:27 | say_how_are_you | | +| test.rs:400:31:402:9 | enter BlockExpr | test.rs:401:13:401:37 | ExprStmt | | +| test.rs:400:31:402:9 | exit BlockExpr (normal) | test.rs:400:31:402:9 | exit BlockExpr | | +| test.rs:401:13:401:36 | $crate::io::_print | test.rs:401:22:401:35 | "how are you?\\n" | | +| test.rs:401:13:401:36 | MacroExpr | test.rs:400:31:402:9 | exit BlockExpr (normal) | | +| test.rs:401:13:401:37 | ExprStmt | test.rs:401:22:401:35 | MacroStmts | | +| test.rs:401:22:401:35 | "how are you?\\n" | test.rs:401:22:401:35 | FormatArgsExpr | | +| test.rs:401:22:401:35 | BlockExpr | test.rs:401:13:401:36 | MacroExpr | | +| test.rs:401:22:401:35 | CallExpr | test.rs:401:22:401:35 | BlockExpr | | +| test.rs:401:22:401:35 | ExprStmt | test.rs:401:13:401:36 | $crate::io::_print | | +| test.rs:401:22:401:35 | FormatArgsExpr | test.rs:401:22:401:35 | MacroExpr | | +| test.rs:401:22:401:35 | MacroExpr | test.rs:401:22:401:35 | CallExpr | | +| test.rs:401:22:401:35 | MacroStmts | test.rs:401:22:401:35 | ExprStmt | | +| test.rs:403:9:403:28 | LetStmt | test.rs:403:20:403:27 | BlockExpr | | +| test.rs:403:13:403:16 | noop | test.rs:404:9:404:26 | ExprStmt | match | +| test.rs:403:20:403:27 | BlockExpr | test.rs:403:13:403:16 | noop | | +| test.rs:404:9:404:17 | say_hello | test.rs:404:9:404:19 | CallExpr | | +| test.rs:404:9:404:19 | CallExpr | test.rs:404:9:404:25 | AwaitExpr | | +| test.rs:404:9:404:25 | AwaitExpr | test.rs:405:9:405:30 | ExprStmt | | +| test.rs:404:9:404:26 | ExprStmt | test.rs:404:9:404:17 | say_hello | | +| test.rs:405:9:405:23 | say_how_are_you | test.rs:405:9:405:29 | AwaitExpr | | +| test.rs:405:9:405:29 | AwaitExpr | test.rs:406:9:406:25 | ExprStmt | | +| test.rs:405:9:405:30 | ExprStmt | test.rs:405:9:405:23 | say_how_are_you | | +| test.rs:406:9:406:18 | say_godbye | test.rs:406:9:406:24 | AwaitExpr | | +| test.rs:406:9:406:24 | AwaitExpr | test.rs:407:9:407:19 | ExprStmt | | +| test.rs:406:9:406:25 | ExprStmt | test.rs:406:9:406:18 | say_godbye | | +| test.rs:407:9:407:12 | noop | test.rs:407:9:407:18 | AwaitExpr | | +| test.rs:407:9:407:18 | AwaitExpr | test.rs:409:9:414:10 | LetStmt | | +| test.rs:407:9:407:19 | ExprStmt | test.rs:407:9:407:12 | noop | | +| test.rs:409:9:414:10 | LetStmt | test.rs:409:22:414:9 | ClosureExpr | | +| test.rs:409:13:409:18 | lambda | test.rs:396:35:415:5 | BlockExpr | match | +| test.rs:409:22:414:9 | ClosureExpr | test.rs:409:13:409:18 | lambda | | +| test.rs:409:22:414:9 | enter ClosureExpr | test.rs:409:23:409:25 | foo | | +| test.rs:409:22:414:9 | exit ClosureExpr (normal) | test.rs:409:22:414:9 | exit ClosureExpr | | +| test.rs:409:23:409:25 | Param | test.rs:409:28:414:9 | BlockExpr | | +| test.rs:409:23:409:25 | foo | test.rs:409:23:409:25 | Param | match | +| test.rs:409:28:414:9 | BlockExpr | test.rs:409:22:414:9 | exit ClosureExpr (normal) | | +| test.rs:409:28:414:9 | enter BlockExpr | test.rs:410:13:412:14 | ExprStmt | | +| test.rs:409:28:414:9 | exit BlockExpr (normal) | test.rs:409:28:414:9 | exit BlockExpr | | +| test.rs:410:13:412:13 | IfExpr | test.rs:413:13:413:15 | foo | | +| test.rs:410:13:412:14 | ExprStmt | test.rs:410:16:410:16 | b | | +| test.rs:410:16:410:16 | b | test.rs:410:13:412:13 | IfExpr | false | +| test.rs:410:16:410:16 | b | test.rs:411:17:411:41 | ExprStmt | true | +| test.rs:411:17:411:40 | ReturnExpr | test.rs:409:28:414:9 | exit BlockExpr (normal) | return | +| test.rs:411:17:411:41 | ExprStmt | test.rs:411:24:411:34 | async_block | | +| test.rs:411:24:411:34 | async_block | test.rs:411:36:411:39 | true | | +| test.rs:411:24:411:40 | CallExpr | test.rs:411:17:411:40 | ReturnExpr | | +| test.rs:411:36:411:39 | true | test.rs:411:24:411:40 | CallExpr | | +| test.rs:413:13:413:15 | foo | test.rs:409:28:414:9 | exit BlockExpr (normal) | | +| test.rs:421:5:423:5 | enter add_two | test.rs:421:22:421:22 | n | | +| test.rs:421:5:423:5 | exit add_two (normal) | test.rs:421:5:423:5 | exit add_two | | +| test.rs:421:22:421:22 | n | test.rs:421:22:421:27 | Param | match | +| test.rs:421:22:421:27 | Param | test.rs:422:9:422:9 | n | | +| test.rs:421:37:423:5 | BlockExpr | test.rs:421:5:423:5 | exit add_two (normal) | | +| test.rs:422:9:422:9 | n | test.rs:422:13:422:13 | 2 | | +| test.rs:422:9:422:13 | ... + ... | test.rs:421:37:423:5 | BlockExpr | | +| test.rs:422:13:422:13 | 2 | test.rs:422:9:422:13 | ... + ... | | +| test.rs:427:5:435:5 | enter const_block_assert | test.rs:430:9:432:9 | ExprStmt | | +| test.rs:427:5:435:5 | exit const_block_assert (normal) | test.rs:427:5:435:5 | exit const_block_assert | | +| test.rs:427:41:435:5 | BlockExpr | test.rs:427:5:435:5 | exit const_block_assert (normal) | | +| test.rs:430:9:432:9 | BlockExpr | test.rs:434:9:434:10 | 42 | | +| test.rs:430:9:432:9 | ExprStmt | test.rs:431:13:431:50 | ExprStmt | | +| test.rs:431:13:431:49 | $crate::panicking::panic_explicit | test.rs:431:13:431:49 | CallExpr | | +| test.rs:431:13:431:49 | BlockExpr | test.rs:431:13:431:49 | MacroExpr | | +| test.rs:431:13:431:49 | BlockExpr | test.rs:431:13:431:49 | exit panic_cold_explicit (normal) | | +| test.rs:431:13:431:49 | BlockExpr | test.rs:431:21:431:48 | IfExpr | | +| test.rs:431:13:431:49 | CallExpr | test.rs:431:13:431:49 | BlockExpr | | +| test.rs:431:13:431:49 | CallExpr | test.rs:431:13:431:49 | BlockExpr | | +| test.rs:431:13:431:49 | ExprStmt | test.rs:431:13:431:49 | MacroStmts | | +| test.rs:431:13:431:49 | ExprStmt | test.rs:431:13:431:49 | panic_cold_explicit | | +| test.rs:431:13:431:49 | MacroExpr | test.rs:430:9:432:9 | BlockExpr | | +| test.rs:431:13:431:49 | MacroExpr | test.rs:431:13:431:49 | BlockExpr | | +| test.rs:431:13:431:49 | MacroStmts | test.rs:431:13:431:49 | panic_cold_explicit | | +| test.rs:431:13:431:49 | enter panic_cold_explicit | test.rs:431:13:431:49 | $crate::panicking::panic_explicit | | +| test.rs:431:13:431:49 | exit panic_cold_explicit (normal) | test.rs:431:13:431:49 | exit panic_cold_explicit | | +| test.rs:431:13:431:49 | panic_cold_explicit | test.rs:431:13:431:49 | CallExpr | | +| test.rs:431:13:431:49 | panic_cold_explicit | test.rs:431:13:431:49 | ExprStmt | | +| test.rs:431:13:431:50 | ExprStmt | test.rs:431:21:431:48 | MacroStmts | | +| test.rs:431:21:431:42 | std::mem::size_of::<...> | test.rs:431:21:431:44 | CallExpr | | +| test.rs:431:21:431:44 | CallExpr | test.rs:431:48:431:48 | 0 | | +| test.rs:431:21:431:48 | ... > ... | test.rs:431:21:431:48 | [boolean(false)] ! ... | true | +| test.rs:431:21:431:48 | ... > ... | test.rs:431:21:431:48 | [boolean(true)] ! ... | false | +| test.rs:431:21:431:48 | BlockExpr | test.rs:431:13:431:49 | MacroExpr | | +| test.rs:431:21:431:48 | IfExpr | test.rs:431:21:431:48 | BlockExpr | | +| test.rs:431:21:431:48 | MacroStmts | test.rs:431:21:431:42 | std::mem::size_of::<...> | | +| test.rs:431:21:431:48 | [boolean(false)] ! ... | test.rs:431:21:431:48 | IfExpr | false | +| test.rs:431:21:431:48 | [boolean(true)] ! ... | test.rs:431:13:431:49 | ExprStmt | true | +| test.rs:431:48:431:48 | 0 | test.rs:431:21:431:48 | ... > ... | | +| test.rs:434:9:434:10 | 42 | test.rs:427:41:435:5 | BlockExpr | | +| test.rs:437:5:446:5 | enter const_block_panic | test.rs:438:9:438:30 | Const | | +| test.rs:437:5:446:5 | exit const_block_panic (normal) | test.rs:437:5:446:5 | exit const_block_panic | | +| test.rs:437:35:446:5 | BlockExpr | test.rs:437:5:446:5 | exit const_block_panic (normal) | | +| test.rs:438:9:438:30 | Const | test.rs:439:9:444:9 | ExprStmt | | +| test.rs:439:9:444:9 | ExprStmt | test.rs:439:12:439:16 | false | | +| test.rs:439:9:444:9 | IfExpr | test.rs:445:9:445:9 | N | | +| test.rs:439:12:439:16 | false | test.rs:439:9:444:9 | IfExpr | false | +| test.rs:442:17:442:24 | $crate::panicking::panic_explicit | test.rs:442:17:442:24 | CallExpr | | +| test.rs:442:17:442:24 | BlockExpr | test.rs:442:17:442:24 | exit panic_cold_explicit (normal) | | +| test.rs:442:17:442:24 | CallExpr | test.rs:442:17:442:24 | BlockExpr | | +| test.rs:442:17:442:24 | enter panic_cold_explicit | test.rs:442:17:442:24 | $crate::panicking::panic_explicit | | +| test.rs:442:17:442:24 | exit panic_cold_explicit (normal) | test.rs:442:17:442:24 | exit panic_cold_explicit | | +| test.rs:445:9:445:9 | N | test.rs:437:35:446:5 | BlockExpr | | +| test.rs:449:1:454:1 | enter dead_code | test.rs:450:5:452:5 | ExprStmt | | +| test.rs:449:1:454:1 | exit dead_code (normal) | test.rs:449:1:454:1 | exit dead_code | | +| test.rs:450:5:452:5 | ExprStmt | test.rs:450:9:450:12 | true | | +| test.rs:450:9:450:12 | true | test.rs:451:9:451:17 | ExprStmt | true | +| test.rs:451:9:451:16 | ReturnExpr | test.rs:449:1:454:1 | exit dead_code (normal) | return | +| test.rs:451:9:451:17 | ExprStmt | test.rs:451:16:451:16 | 0 | | +| test.rs:451:16:451:16 | 0 | test.rs:451:9:451:16 | ReturnExpr | | +| test.rs:456:1:456:16 | enter do_thing | test.rs:456:15:456:16 | BlockExpr | | +| test.rs:456:1:456:16 | exit do_thing (normal) | test.rs:456:1:456:16 | exit do_thing | | +| test.rs:456:15:456:16 | BlockExpr | test.rs:456:1:456:16 | exit do_thing (normal) | | +| test.rs:458:1:460:1 | enter condition_not_met | test.rs:459:5:459:9 | false | | +| test.rs:458:1:460:1 | exit condition_not_met (normal) | test.rs:458:1:460:1 | exit condition_not_met | | +| test.rs:458:32:460:1 | BlockExpr | test.rs:458:1:460:1 | exit condition_not_met (normal) | | +| test.rs:459:5:459:9 | false | test.rs:458:32:460:1 | BlockExpr | | +| test.rs:462:1:462:21 | enter do_next_thing | test.rs:462:20:462:21 | BlockExpr | | +| test.rs:462:1:462:21 | exit do_next_thing (normal) | test.rs:462:1:462:21 | exit do_next_thing | | +| test.rs:462:20:462:21 | BlockExpr | test.rs:462:1:462:21 | exit do_next_thing (normal) | | +| test.rs:464:1:464:21 | enter do_last_thing | test.rs:464:20:464:21 | BlockExpr | | +| test.rs:464:1:464:21 | exit do_last_thing (normal) | test.rs:464:1:464:21 | exit do_last_thing | | +| test.rs:464:20:464:21 | BlockExpr | test.rs:464:1:464:21 | exit do_last_thing (normal) | | +| test.rs:466:1:480:1 | enter labelled_block1 | test.rs:467:5:478:6 | LetStmt | | +| test.rs:466:1:480:1 | exit labelled_block1 (normal) | test.rs:466:1:480:1 | exit labelled_block1 | | +| test.rs:466:29:480:1 | BlockExpr | test.rs:466:1:480:1 | exit labelled_block1 (normal) | | +| test.rs:467:5:478:6 | LetStmt | test.rs:468:9:468:19 | ExprStmt | | +| test.rs:467:9:467:14 | result | test.rs:479:5:479:10 | result | match | +| test.rs:467:18:478:5 | BlockExpr | test.rs:467:9:467:14 | result | | +| test.rs:468:9:468:16 | do_thing | test.rs:468:9:468:18 | CallExpr | | +| test.rs:468:9:468:18 | CallExpr | test.rs:469:9:471:9 | ExprStmt | | +| test.rs:468:9:468:19 | ExprStmt | test.rs:468:9:468:16 | do_thing | | +| test.rs:469:9:471:9 | ExprStmt | test.rs:469:12:469:28 | condition_not_met | | +| test.rs:469:9:471:9 | IfExpr | test.rs:472:9:472:24 | ExprStmt | | +| test.rs:469:12:469:28 | condition_not_met | test.rs:469:12:469:30 | CallExpr | | +| test.rs:469:12:469:30 | CallExpr | test.rs:469:9:471:9 | IfExpr | false | +| test.rs:469:12:469:30 | CallExpr | test.rs:470:13:470:27 | ExprStmt | true | +| test.rs:470:13:470:26 | BreakExpr | test.rs:467:18:478:5 | BlockExpr | break | +| test.rs:470:13:470:27 | ExprStmt | test.rs:470:26:470:26 | 1 | | +| test.rs:470:26:470:26 | 1 | test.rs:470:13:470:26 | BreakExpr | | +| test.rs:472:9:472:21 | do_next_thing | test.rs:472:9:472:23 | CallExpr | | +| test.rs:472:9:472:23 | CallExpr | test.rs:473:9:475:9 | ExprStmt | | +| test.rs:472:9:472:24 | ExprStmt | test.rs:472:9:472:21 | do_next_thing | | +| test.rs:473:9:475:9 | ExprStmt | test.rs:473:12:473:28 | condition_not_met | | +| test.rs:473:9:475:9 | IfExpr | test.rs:476:9:476:24 | ExprStmt | | +| test.rs:473:12:473:28 | condition_not_met | test.rs:473:12:473:30 | CallExpr | | +| test.rs:473:12:473:30 | CallExpr | test.rs:473:9:475:9 | IfExpr | false | +| test.rs:473:12:473:30 | CallExpr | test.rs:474:13:474:27 | ExprStmt | true | +| test.rs:474:13:474:26 | BreakExpr | test.rs:467:18:478:5 | BlockExpr | break | +| test.rs:474:13:474:27 | ExprStmt | test.rs:474:26:474:26 | 2 | | +| test.rs:474:26:474:26 | 2 | test.rs:474:13:474:26 | BreakExpr | | +| test.rs:476:9:476:21 | do_last_thing | test.rs:476:9:476:23 | CallExpr | | +| test.rs:476:9:476:23 | CallExpr | test.rs:477:9:477:9 | 3 | | +| test.rs:476:9:476:24 | ExprStmt | test.rs:476:9:476:21 | do_last_thing | | +| test.rs:477:9:477:9 | 3 | test.rs:467:18:478:5 | BlockExpr | | +| test.rs:479:5:479:10 | result | test.rs:466:29:480:1 | BlockExpr | | +| test.rs:482:1:490:1 | enter labelled_block2 | test.rs:483:5:489:6 | LetStmt | | +| test.rs:482:1:490:1 | exit labelled_block2 (normal) | test.rs:482:1:490:1 | exit labelled_block2 | | +| test.rs:482:22:490:1 | BlockExpr | test.rs:482:1:490:1 | exit labelled_block2 (normal) | | +| test.rs:483:5:489:6 | LetStmt | test.rs:484:9:484:34 | LetStmt | | +| test.rs:483:9:483:14 | result | test.rs:482:22:490:1 | BlockExpr | match | +| test.rs:483:18:489:5 | BlockExpr | test.rs:483:9:483:14 | result | | +| test.rs:484:9:484:34 | LetStmt | test.rs:484:30:484:33 | None | | +| test.rs:484:13:484:13 | x | test.rs:485:9:487:10 | LetStmt | match | +| test.rs:484:30:484:33 | None | test.rs:484:13:484:13 | x | | +| test.rs:485:9:487:10 | LetStmt | test.rs:485:23:485:23 | x | | +| test.rs:485:13:485:19 | TupleStructPat | test.rs:485:18:485:18 | y | match | +| test.rs:485:13:485:19 | TupleStructPat | test.rs:486:13:486:27 | ExprStmt | no-match | +| test.rs:485:18:485:18 | y | test.rs:488:9:488:9 | 0 | match | +| test.rs:485:23:485:23 | x | test.rs:485:13:485:19 | TupleStructPat | | +| test.rs:486:13:486:26 | BreakExpr | test.rs:483:18:489:5 | BlockExpr | break | +| test.rs:486:13:486:27 | ExprStmt | test.rs:486:26:486:26 | 1 | | +| test.rs:486:26:486:26 | 1 | test.rs:486:13:486:26 | BreakExpr | | +| test.rs:488:9:488:9 | 0 | test.rs:483:18:489:5 | BlockExpr | | +| test.rs:492:1:498:1 | enter test_nested_function2 | test.rs:493:5:493:18 | LetStmt | | +| test.rs:492:1:498:1 | exit test_nested_function2 (normal) | test.rs:492:1:498:1 | exit test_nested_function2 | | +| test.rs:492:28:498:1 | BlockExpr | test.rs:492:1:498:1 | exit test_nested_function2 (normal) | | +| test.rs:493:5:493:18 | LetStmt | test.rs:493:17:493:17 | 0 | | +| test.rs:493:9:493:13 | x | test.rs:494:5:496:5 | nested | match | +| test.rs:493:17:493:17 | 0 | test.rs:493:9:493:13 | x | | +| test.rs:494:5:496:5 | enter nested | test.rs:494:15:494:15 | x | | +| test.rs:494:5:496:5 | exit nested (normal) | test.rs:494:5:496:5 | exit nested | | +| test.rs:494:5:496:5 | nested | test.rs:497:5:497:19 | ExprStmt | | +| test.rs:494:15:494:15 | x | test.rs:494:15:494:25 | Param | match | +| test.rs:494:15:494:25 | Param | test.rs:495:9:495:16 | ExprStmt | | +| test.rs:494:28:496:5 | BlockExpr | test.rs:494:5:496:5 | exit nested (normal) | | +| test.rs:495:9:495:10 | * ... | test.rs:495:15:495:15 | 1 | | +| test.rs:495:9:495:15 | ... += ... | test.rs:494:28:496:5 | BlockExpr | | +| test.rs:495:9:495:16 | ExprStmt | test.rs:495:10:495:10 | x | | +| test.rs:495:10:495:10 | x | test.rs:495:9:495:10 | * ... | | +| test.rs:495:15:495:15 | 1 | test.rs:495:9:495:15 | ... += ... | | +| test.rs:497:5:497:10 | nested | test.rs:497:17:497:17 | x | | +| test.rs:497:5:497:18 | CallExpr | test.rs:492:28:498:1 | BlockExpr | | +| test.rs:497:5:497:19 | ExprStmt | test.rs:497:5:497:10 | nested | | +| test.rs:497:12:497:17 | RefExpr | test.rs:497:5:497:18 | CallExpr | | +| test.rs:497:17:497:17 | x | test.rs:497:12:497:17 | RefExpr | | +| test.rs:509:5:511:5 | enter new | test.rs:509:12:509:12 | a | | +| test.rs:509:5:511:5 | exit new (normal) | test.rs:509:5:511:5 | exit new | | +| test.rs:509:12:509:12 | a | test.rs:509:12:509:17 | Param | match | +| test.rs:509:12:509:17 | Param | test.rs:510:23:510:23 | a | | +| test.rs:509:28:511:5 | BlockExpr | test.rs:509:5:511:5 | exit new (normal) | | +| test.rs:510:9:510:25 | RecordExpr | test.rs:509:28:511:5 | BlockExpr | | +| test.rs:510:23:510:23 | a | test.rs:510:9:510:25 | RecordExpr | | +| test.rs:513:5:515:5 | enter negated | test.rs:513:16:513:19 | self | | +| test.rs:513:5:515:5 | exit negated (normal) | test.rs:513:5:515:5 | exit negated | | +| test.rs:513:16:513:19 | SelfParam | test.rs:514:23:514:26 | self | | +| test.rs:513:16:513:19 | self | test.rs:513:16:513:19 | SelfParam | | +| test.rs:513:30:515:5 | BlockExpr | test.rs:513:5:515:5 | exit negated (normal) | | +| test.rs:514:9:514:30 | RecordExpr | test.rs:513:30:515:5 | BlockExpr | | +| test.rs:514:23:514:26 | self | test.rs:514:23:514:28 | FieldExpr | | +| test.rs:514:23:514:28 | FieldExpr | test.rs:514:9:514:30 | RecordExpr | | +| test.rs:517:5:519:5 | enter multifly_add | test.rs:517:26:517:29 | self | | +| test.rs:517:5:519:5 | exit multifly_add (normal) | test.rs:517:5:519:5 | exit multifly_add | | +| test.rs:517:21:517:29 | SelfParam | test.rs:517:32:517:32 | a | | +| test.rs:517:26:517:29 | self | test.rs:517:21:517:29 | SelfParam | | +| test.rs:517:32:517:32 | a | test.rs:517:32:517:37 | Param | match | +| test.rs:517:32:517:37 | Param | test.rs:517:40:517:40 | b | | +| test.rs:517:40:517:40 | b | test.rs:517:40:517:45 | Param | match | +| test.rs:517:40:517:45 | Param | test.rs:518:9:518:34 | ExprStmt | | +| test.rs:517:48:519:5 | BlockExpr | test.rs:517:5:519:5 | exit multifly_add (normal) | | +| test.rs:518:9:518:12 | self | test.rs:518:9:518:14 | FieldExpr | | +| test.rs:518:9:518:14 | FieldExpr | test.rs:518:19:518:22 | self | | +| test.rs:518:9:518:33 | ... = ... | test.rs:517:48:519:5 | BlockExpr | | +| test.rs:518:9:518:34 | ExprStmt | test.rs:518:9:518:12 | self | | +| test.rs:518:18:518:33 | ... + ... | test.rs:518:9:518:33 | ... = ... | | +| test.rs:518:19:518:22 | self | test.rs:518:19:518:24 | FieldExpr | | +| test.rs:518:19:518:24 | FieldExpr | test.rs:518:28:518:28 | a | | +| test.rs:518:19:518:28 | ... * ... | test.rs:518:33:518:33 | b | | +| test.rs:518:28:518:28 | a | test.rs:518:19:518:28 | ... * ... | | +| test.rs:518:33:518:33 | b | test.rs:518:18:518:33 | ... + ... | | breakTarget | test.rs:34:17:34:21 | BreakExpr | test.rs:28:9:40:9 | LoopExpr | | test.rs:48:21:48:25 | BreakExpr | test.rs:46:13:53:13 | LoopExpr | @@ -1090,9 +1106,9 @@ breakTarget | test.rs:197:17:197:28 | BreakExpr | test.rs:195:13:200:9 | LoopExpr | | test.rs:210:17:210:35 | BreakExpr | test.rs:208:13:213:9 | LoopExpr | | test.rs:222:13:222:30 | BreakExpr | test.rs:221:13:223:9 | BlockExpr | -| test.rs:463:13:463:26 | BreakExpr | test.rs:460:18:471:5 | BlockExpr | -| test.rs:467:13:467:26 | BreakExpr | test.rs:460:18:471:5 | BlockExpr | -| test.rs:479:13:479:26 | BreakExpr | test.rs:476:18:482:5 | BlockExpr | +| test.rs:470:13:470:26 | BreakExpr | test.rs:467:18:478:5 | BlockExpr | +| test.rs:474:13:474:26 | BreakExpr | test.rs:467:18:478:5 | BlockExpr | +| test.rs:486:13:486:26 | BreakExpr | test.rs:483:18:489:5 | BlockExpr | continueTarget | test.rs:37:17:37:24 | ContinueExpr | test.rs:28:9:40:9 | LoopExpr | | test.rs:63:21:63:28 | ContinueExpr | test.rs:61:13:68:13 | LoopExpr | diff --git a/rust/ql/test/library-tests/controlflow/test.rs b/rust/ql/test/library-tests/controlflow/test.rs index 42094c5432e5..42285f42b719 100644 --- a/rust/ql/test/library-tests/controlflow/test.rs +++ b/rust/ql/test/library-tests/controlflow/test.rs @@ -277,6 +277,13 @@ mod logical_operators { fn test_and_return(a: bool) { a && return; } + + fn test_and_true(a: bool) -> i64 { + if (a && true) { + return 1; + } + 0 + } } mod question_mark_operator { diff --git a/rust/ql/test/library-tests/dataflow/local/DataFlowStep.expected b/rust/ql/test/library-tests/dataflow/local/DataFlowStep.expected index 8cc12598f62b..1ccc9c219c32 100644 --- a/rust/ql/test/library-tests/dataflow/local/DataFlowStep.expected +++ b/rust/ql/test/library-tests/dataflow/local/DataFlowStep.expected @@ -46,6 +46,7 @@ | main.rs:51:17:51:17 | 1 | main.rs:51:9:51:13 | i | | main.rs:53:5:53:5 | [SSA] i | main.rs:54:10:54:10 | i | | main.rs:53:5:53:5 | i | main.rs:53:5:53:5 | [SSA] i | +| main.rs:53:9:53:17 | CallExpr | main.rs:53:5:53:5 | i | | main.rs:61:9:61:9 | [SSA] i | main.rs:62:11:62:11 | i | | main.rs:61:9:61:9 | i | main.rs:61:9:61:9 | [SSA] i | | main.rs:61:13:61:31 | CallExpr | main.rs:61:9:61:9 | i | @@ -83,3 +84,27 @@ | main.rs:111:14:111:14 | n | main.rs:111:14:111:14 | [SSA] n | | main.rs:111:20:111:26 | CallExpr | main.rs:110:5:113:5 | MatchExpr | | main.rs:112:17:112:23 | CallExpr | main.rs:110:5:113:5 | MatchExpr | +| main.rs:117:9:117:9 | [SSA] a | main.rs:118:5:118:5 | a | +| main.rs:117:9:117:9 | a | main.rs:117:9:117:9 | [SSA] a | +| main.rs:117:13:117:17 | BlockExpr | main.rs:117:9:117:9 | a | +| main.rs:117:15:117:15 | 0 | main.rs:117:13:117:17 | BlockExpr | +| main.rs:118:5:118:5 | a | main.rs:116:31:119:1 | BlockExpr | +| main.rs:121:22:121:22 | [SSA] b | main.rs:123:12:123:12 | b | +| main.rs:121:22:121:22 | b | main.rs:121:22:121:22 | [SSA] b | +| main.rs:122:9:122:9 | [SSA] a | main.rs:128:5:128:5 | a | +| main.rs:122:9:122:9 | a | main.rs:122:9:122:9 | [SSA] a | +| main.rs:122:13:127:5 | BlockExpr | main.rs:122:9:122:9 | a | +| main.rs:124:13:124:26 | BreakExpr | main.rs:122:13:127:5 | BlockExpr | +| main.rs:124:26:124:26 | 1 | main.rs:124:13:124:26 | BreakExpr | +| main.rs:126:9:126:9 | 2 | main.rs:122:13:127:5 | BlockExpr | +| main.rs:128:5:128:5 | a | main.rs:121:38:129:1 | BlockExpr | +| main.rs:131:22:131:22 | [SSA] b | main.rs:133:12:133:12 | b | +| main.rs:131:22:131:22 | b | main.rs:131:22:131:22 | [SSA] b | +| main.rs:132:9:132:9 | [SSA] a | main.rs:138:5:138:5 | a | +| main.rs:132:9:132:9 | a | main.rs:132:9:132:9 | [SSA] a | +| main.rs:132:13:137:5 | BlockExpr | main.rs:132:9:132:9 | a | +| main.rs:134:13:134:26 | BreakExpr | main.rs:132:13:137:5 | BlockExpr | +| main.rs:134:26:134:26 | 1 | main.rs:134:13:134:26 | BreakExpr | +| main.rs:136:9:136:22 | BreakExpr | main.rs:132:13:137:5 | BlockExpr | +| main.rs:136:22:136:22 | 2 | main.rs:136:9:136:22 | BreakExpr | +| main.rs:138:5:138:5 | a | main.rs:131:38:139:1 | BlockExpr | diff --git a/rust/ql/test/library-tests/dataflow/local/inline-flow.expected b/rust/ql/test/library-tests/dataflow/local/inline-flow.expected index 72273334c6f5..3cb35a1079fe 100644 --- a/rust/ql/test/library-tests/dataflow/local/inline-flow.expected +++ b/rust/ql/test/library-tests/dataflow/local/inline-flow.expected @@ -4,6 +4,7 @@ edges | main.rs:24:13:24:21 | CallExpr : unit | main.rs:27:10:27:10 | c | provenance | | | main.rs:31:13:31:21 | CallExpr : unit | main.rs:36:10:36:10 | b | provenance | | | main.rs:45:15:45:23 | CallExpr : unit | main.rs:47:10:47:10 | b | provenance | | +| main.rs:53:9:53:17 | CallExpr : unit | main.rs:54:10:54:10 | i | provenance | | nodes | main.rs:15:10:15:18 | CallExpr | semmle.label | CallExpr | | main.rs:19:13:19:21 | CallExpr : unit | semmle.label | CallExpr : unit | @@ -14,6 +15,8 @@ nodes | main.rs:36:10:36:10 | b | semmle.label | b | | main.rs:45:15:45:23 | CallExpr : unit | semmle.label | CallExpr : unit | | main.rs:47:10:47:10 | b | semmle.label | b | +| main.rs:53:9:53:17 | CallExpr : unit | semmle.label | CallExpr : unit | +| main.rs:54:10:54:10 | i | semmle.label | i | subpaths testFailures #select @@ -22,3 +25,4 @@ testFailures | main.rs:27:10:27:10 | c | main.rs:24:13:24:21 | CallExpr : unit | main.rs:27:10:27:10 | c | $@ | main.rs:24:13:24:21 | CallExpr : unit | CallExpr : unit | | main.rs:36:10:36:10 | b | main.rs:31:13:31:21 | CallExpr : unit | main.rs:36:10:36:10 | b | $@ | main.rs:31:13:31:21 | CallExpr : unit | CallExpr : unit | | main.rs:47:10:47:10 | b | main.rs:45:15:45:23 | CallExpr : unit | main.rs:47:10:47:10 | b | $@ | main.rs:45:15:45:23 | CallExpr : unit | CallExpr : unit | +| main.rs:54:10:54:10 | i | main.rs:53:9:53:17 | CallExpr : unit | main.rs:54:10:54:10 | i | $@ | main.rs:53:9:53:17 | CallExpr : unit | CallExpr : unit | diff --git a/rust/ql/test/library-tests/dataflow/local/main.rs b/rust/ql/test/library-tests/dataflow/local/main.rs index fb79baa70bdb..50aa4fdb965e 100644 --- a/rust/ql/test/library-tests/dataflow/local/main.rs +++ b/rust/ql/test/library-tests/dataflow/local/main.rs @@ -51,7 +51,7 @@ fn assignment() { let mut i = 1; sink(i); i = source(2); - sink(i); // $ MISSING: hasValueFlow=2 + sink(i); // $ hasValueFlow=2 } // ----------------------------------------------------------------------------- @@ -113,6 +113,31 @@ fn option_pattern_match() { } } +fn block_expression1() -> i64 { + let a = { 0 }; + a +} + +fn block_expression2(b: bool) -> i64 { + let a = 'block: { + if b { + break 'block 1; + }; + 2 + }; + a +} + +fn block_expression3(b: bool) -> i64 { + let a = 'block: { + if b { + break 'block 1; + } + break 'block 2; + }; + a +} + fn main() { direct(); variable_usage(); @@ -125,4 +150,7 @@ fn main() { struct_field(); struct_pattern_match(); option_pattern_match(); + block_expression1(); + block_expression2(true); + block_expression3(true); } diff --git a/rust/ql/test/query-tests/diagnostics/CfgConsistencyCounts.expected b/rust/ql/test/query-tests/diagnostics/CfgConsistencyCounts.expected index 7df2863da9e8..7056936908c0 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/ql/test/utils/InlineFlowTest.qll b/rust/ql/test/utils/InlineFlowTest.qll index b4960a055ee1..ad196871273f 100644 --- a/rust/ql/test/utils/InlineFlowTest.qll +++ b/rust/ql/test/utils/InlineFlowTest.qll @@ -5,26 +5,27 @@ import rust private import codeql.dataflow.test.InlineFlowTest +private import codeql.rust.controlflow.CfgNodes private import codeql.rust.dataflow.DataFlow private import codeql.rust.dataflow.internal.DataFlowImpl private import codeql.rust.dataflow.internal.TaintTrackingImpl private import internal.InlineExpectationsTestImpl as InlineExpectationsTestImpl // Holds if the target expression of `call` is a path and the string representation of the path is `name`. -private predicate callTargetName(CallExpr call, string name) { - call.getExpr().(PathExpr).toString() = name +private predicate callTargetName(CallExprCfgNode call, string name) { + call.getExpr().(PathExprCfgNode).toString() = name } private module FlowTestImpl implements InputSig { predicate defaultSource(DataFlow::Node source) { callTargetName(source.asExpr(), "source") } predicate defaultSink(DataFlow::Node sink) { - any(CallExpr call | callTargetName(call, "sink")).getArgList().getAnArg() = sink.asExpr() + any(CallExprCfgNode call | callTargetName(call, "sink")).getArgument(_) = sink.asExpr() } private string getSourceArgString(DataFlow::Node src) { defaultSource(src) and - result = src.asExpr().(CallExpr).getArgList().getArg(0).toString() + result = src.asExpr().(CallExprCfgNode).getArgument(0).toString() } bindingset[src, sink] diff --git a/rust/schema/annotations.py b/rust/schema/annotations.py index d8e9835b16a6..ae94b0604e7e 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: @@ -1467,7 +1467,7 @@ class _: """ -@annotate(SelfParam) +@annotate(SelfParam, cfg = True) class _: """ A SelfParam. 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: