mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
Rust: Auto-generate CfgNodes.qll
This commit is contained in:
@@ -64,6 +64,8 @@ def _parse_args() -> argparse.Namespace:
|
|||||||
help="registry file containing information about checked-in generated code. A .gitattributes"
|
help="registry file containing information about checked-in generated code. A .gitattributes"
|
||||||
"file is generated besides it to mark those files with linguist-generated=true. Must"
|
"file is generated besides it to mark those files with linguist-generated=true. Must"
|
||||||
"be in a directory containing all generated code."),
|
"be in a directory containing all generated code."),
|
||||||
|
p.add_argument("--ql-cfg-output",
|
||||||
|
help="output directory for QL CFG layer (optional)."),
|
||||||
]
|
]
|
||||||
p.add_argument("--script-name",
|
p.add_argument("--script-name",
|
||||||
help="script name to put in header comments of generated files. By default, the path of this "
|
help="script name to put in header comments of generated files. By default, the path of this "
|
||||||
|
|||||||
@@ -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)
|
prop = get_ql_property(cls, p, lookup, prev_child)
|
||||||
if prop.is_child:
|
if prop.is_child:
|
||||||
prev_child = prop.singular
|
prev_child = prop.singular
|
||||||
|
if prop.type in lookup and lookup[prop.type].cfg:
|
||||||
|
prop.cfg = True
|
||||||
properties.append(prop)
|
properties.append(prop)
|
||||||
return ql.Class(
|
return ql.Class(
|
||||||
name=cls.name,
|
name=cls.name,
|
||||||
@@ -171,6 +173,16 @@ def get_ql_class(cls: schema.Class, lookup: typing.Dict[str, schema.Class]) -> q
|
|||||||
doc=cls.doc,
|
doc=cls.doc,
|
||||||
hideable="ql_hideable" in cls.pragmas,
|
hideable="ql_hideable" in cls.pragmas,
|
||||||
internal="ql_internal" 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
|
input = opts.schema
|
||||||
out = opts.ql_output
|
out = opts.ql_output
|
||||||
stub_out = opts.ql_stub_output
|
stub_out = opts.ql_stub_output
|
||||||
|
cfg_out = opts.ql_cfg_output
|
||||||
test_out = opts.ql_test_output
|
test_out = opts.ql_test_output
|
||||||
missing_test_source_filename = "MISSING_SOURCE.txt"
|
missing_test_source_filename = "MISSING_SOURCE.txt"
|
||||||
include_file = stub_out.with_suffix(".qll")
|
include_file = stub_out.with_suffix(".qll")
|
||||||
@@ -385,6 +398,7 @@ def generate(opts, renderer):
|
|||||||
imports = {}
|
imports = {}
|
||||||
imports_impl = {}
|
imports_impl = {}
|
||||||
classes_used_by = {}
|
classes_used_by = {}
|
||||||
|
cfg_classes = []
|
||||||
generated_import_prefix = get_import(out, opts.root_dir)
|
generated_import_prefix = get_import(out, opts.root_dir)
|
||||||
registry = opts.generated_registry or pathlib.Path(
|
registry = opts.generated_registry or pathlib.Path(
|
||||||
os.path.commonpath((out, stub_out, test_out)), ".generated.list")
|
os.path.commonpath((out, stub_out, test_out)), ".generated.list")
|
||||||
@@ -402,6 +416,8 @@ def generate(opts, renderer):
|
|||||||
imports[c.name] = path
|
imports[c.name] = path
|
||||||
path_impl = get_import(stub_out / c.dir / "internal" / c.name, opts.root_dir)
|
path_impl = get_import(stub_out / c.dir / "internal" / c.name, opts.root_dir)
|
||||||
imports_impl[c.name + "Impl"] = path_impl + "Impl"
|
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():
|
for c in classes.values():
|
||||||
qll = out / c.path.with_suffix(".qll")
|
qll = out / c.path.with_suffix(".qll")
|
||||||
@@ -411,6 +427,14 @@ def generate(opts, renderer):
|
|||||||
c.import_prefix = generated_import_prefix
|
c.import_prefix = generated_import_prefix
|
||||||
renderer.render(c, qll)
|
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():
|
for c in data.classes.values():
|
||||||
path = _get_path(c)
|
path = _get_path(c)
|
||||||
path_impl = _get_path_impl(c)
|
path_impl = _get_path_impl(c)
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ class Property:
|
|||||||
synth: bool = False
|
synth: bool = False
|
||||||
type_is_hideable: bool = False
|
type_is_hideable: bool = False
|
||||||
internal: bool = False
|
internal: bool = False
|
||||||
|
cfg: bool = False
|
||||||
|
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
if self.tableparams:
|
if self.tableparams:
|
||||||
@@ -110,6 +111,7 @@ class Class:
|
|||||||
internal: bool = False
|
internal: bool = False
|
||||||
doc: List[str] = field(default_factory=list)
|
doc: List[str] = field(default_factory=list)
|
||||||
hideable: bool = False
|
hideable: bool = False
|
||||||
|
cfg: bool = False
|
||||||
|
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
def get_bases(bases): return [Base(str(b), str(prev)) for b, prev in zip(bases, itertools.chain([""], bases))]
|
def get_bases(bases): return [Base(str(b), str(prev)) for b, prev in zip(bases, itertools.chain([""], bases))]
|
||||||
@@ -333,3 +335,18 @@ class Synth:
|
|||||||
|
|
||||||
cls: "Synth.FinalClass"
|
cls: "Synth.FinalClass"
|
||||||
import_prefix: str
|
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)
|
||||||
|
|||||||
@@ -94,6 +94,7 @@ class Class:
|
|||||||
properties: List[Property] = field(default_factory=list)
|
properties: List[Property] = field(default_factory=list)
|
||||||
pragmas: List[str] | Dict[str, object] = field(default_factory=dict)
|
pragmas: List[str] | Dict[str, object] = field(default_factory=dict)
|
||||||
doc: List[str] = field(default_factory=list)
|
doc: List[str] = field(default_factory=list)
|
||||||
|
cfg: bool = False
|
||||||
|
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
if not isinstance(self.pragmas, dict):
|
if not isinstance(self.pragmas, dict):
|
||||||
|
|||||||
@@ -279,7 +279,7 @@ _ = _PropertyAnnotation()
|
|||||||
drop = object()
|
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.
|
Add or modify schema annotations after a class has been defined previously.
|
||||||
|
|
||||||
@@ -298,6 +298,7 @@ def annotate(annotated_cls: type, add_bases: _Iterable[type] | None = None, repl
|
|||||||
annotated_cls.__bases__ = tuple(replace_bases.get(b, b) for b in annotated_cls.__bases__)
|
annotated_cls.__bases__ = tuple(replace_bases.get(b, b) for b in annotated_cls.__bases__)
|
||||||
if add_bases:
|
if add_bases:
|
||||||
annotated_cls.__bases__ += tuple(add_bases)
|
annotated_cls.__bases__ += tuple(add_bases)
|
||||||
|
annotated_cls.__cfg__ = cfg
|
||||||
for a in dir(cls):
|
for a in dir(cls):
|
||||||
if a.startswith(_schema.inheritable_pragma_prefix):
|
if a.startswith(_schema.inheritable_pragma_prefix):
|
||||||
setattr(annotated_cls, a, getattr(cls, a))
|
setattr(annotated_cls, a, getattr(cls, a))
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ def _get_class(cls: type) -> schema.Class:
|
|||||||
bases=[b.__name__ for b in cls.__bases__ if b is not object],
|
bases=[b.__name__ for b in cls.__bases__ if b is not object],
|
||||||
derived=derived,
|
derived=derived,
|
||||||
pragmas=pragmas,
|
pragmas=pragmas,
|
||||||
|
cfg=cls.__cfg__ if hasattr(cls, "__cfg__") else False,
|
||||||
# in the following we don't use `getattr` to avoid inheriting
|
# in the following we don't use `getattr` to avoid inheriting
|
||||||
properties=[
|
properties=[
|
||||||
a | _PropertyNamer(n)
|
a | _PropertyNamer(n)
|
||||||
|
|||||||
199
misc/codegen/templates/ql_cfg_nodes.mustache
Normal file
199
misc/codegen/templates/ql_cfg_nodes.mustache
Normal file
@@ -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<LocationSig Loc> {
|
||||||
|
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<LocationSig Loc, InputSig<Loc> 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}}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
--dbscheme=ql/lib/rust.dbscheme
|
--dbscheme=ql/lib/rust.dbscheme
|
||||||
--ql-output=ql/lib/codeql/rust/elements/internal/generated
|
--ql-output=ql/lib/codeql/rust/elements/internal/generated
|
||||||
--ql-stub-output=ql/lib/codeql/rust/elements
|
--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
|
--ql-test-output=ql/test/extractor-tests/generated
|
||||||
--rust-output=extractor/src/generated
|
--rust-output=extractor/src/generated
|
||||||
--script-name=codegen
|
--script-name=codegen
|
||||||
|
|||||||
1
rust/ql/.generated.list
generated
1
rust/ql/.generated.list
generated
@@ -1,3 +1,4 @@
|
|||||||
|
lib/codeql/rust/controlflow/internal/generated/CfgNodes.qll 55c20303ad50f17ddea728eb840304e0a634821adb7b13471a9ce55b71ed3886 13509512ffb59a9634ed2dc3c4969af26d5ba2d1502d98dc0c107a99392ce892
|
||||||
lib/codeql/rust/elements/Abi.qll 4c973d28b6d628f5959d1f1cc793704572fd0acaae9a97dfce82ff9d73f73476 250f68350180af080f904cd34cb2af481c5c688dc93edf7365fd0ae99855e893
|
lib/codeql/rust/elements/Abi.qll 4c973d28b6d628f5959d1f1cc793704572fd0acaae9a97dfce82ff9d73f73476 250f68350180af080f904cd34cb2af481c5c688dc93edf7365fd0ae99855e893
|
||||||
lib/codeql/rust/elements/ArgList.qll 661f5100f5d3ef8351452d9058b663a2a5c720eea8cf11bedd628969741486a2 28e424aac01a90fb58cd6f9f83c7e4cf379eea39e636bc0ba07efc818be71c71
|
lib/codeql/rust/elements/ArgList.qll 661f5100f5d3ef8351452d9058b663a2a5c720eea8cf11bedd628969741486a2 28e424aac01a90fb58cd6f9f83c7e4cf379eea39e636bc0ba07efc818be71c71
|
||||||
lib/codeql/rust/elements/ArrayExpr.qll a3e6e122632f4011644ec31b37f88b32fe3f2b7e388e7e878a6883309937049f 12ccb5873d95c433da5606fd371d182ef2f71b78d0c53c2d6dec10fa45852bdc
|
lib/codeql/rust/elements/ArrayExpr.qll a3e6e122632f4011644ec31b37f88b32fe3f2b7e388e7e878a6883309937049f 12ccb5873d95c433da5606fd371d182ef2f71b78d0c53c2d6dec10fa45852bdc
|
||||||
|
|||||||
1
rust/ql/.gitattributes
generated
vendored
1
rust/ql/.gitattributes
generated
vendored
@@ -1,5 +1,6 @@
|
|||||||
/.generated.list linguist-generated
|
/.generated.list linguist-generated
|
||||||
/.gitattributes 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/Abi.qll linguist-generated
|
||||||
/lib/codeql/rust/elements/ArgList.qll linguist-generated
|
/lib/codeql/rust/elements/ArgList.qll linguist-generated
|
||||||
/lib/codeql/rust/elements/ArrayExpr.qll linguist-generated
|
/lib/codeql/rust/elements/ArrayExpr.qll linguist-generated
|
||||||
|
|||||||
@@ -5,7 +5,9 @@
|
|||||||
|
|
||||||
private import rust
|
private import rust
|
||||||
private import ControlFlowGraph
|
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. */
|
/** A CFG node that corresponds to an element in the AST. */
|
||||||
class AstCfgNode extends CfgNode {
|
class AstCfgNode extends CfgNode {
|
||||||
@@ -57,4 +59,4 @@ class MethodCallExprCfgNode extends ExprCfgNode {
|
|||||||
MethodCallExpr getMethodCallExpr() { result = node }
|
MethodCallExpr getMethodCallExpr() { result = node }
|
||||||
}
|
}
|
||||||
|
|
||||||
final class ExitCfgNode = ExitNode;
|
final class ExitCfgNode = CfgImpl::ExitNode;
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import Consistency
|
|||||||
private import codeql.rust.controlflow.ControlFlowGraph
|
private import codeql.rust.controlflow.ControlFlowGraph
|
||||||
private import codeql.rust.controlflow.internal.ControlFlowGraphImpl as CfgImpl
|
private import codeql.rust.controlflow.internal.ControlFlowGraphImpl as CfgImpl
|
||||||
private import codeql.rust.controlflow.internal.Completion
|
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) {
|
private predicate nonPostOrderExpr(Expr e) {
|
||||||
not e instanceof LetExpr and
|
not e instanceof LetExpr and
|
||||||
@@ -54,6 +56,24 @@ query predicate deadEnd(CfgImpl::Node node) {
|
|||||||
not letElsePanic(node.getAstNode())
|
not letElsePanic(node.getAstNode())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate successfullyExtractedFile(File f) {
|
||||||
|
not exists(ExtractionWarning ee | ee.getLocation().getFile() = f)
|
||||||
|
}
|
||||||
|
|
||||||
|
query predicate missingCfgChild(CfgNode parent, string pred, int i, AstNode child) {
|
||||||
|
CfgNodes::missingCfgChild(parent, pred, i, child) and
|
||||||
|
successfullyExtractedFile(child.getLocation().getFile()) and
|
||||||
|
not exists(AstNode last, CfgImpl::Completion c | CfgImpl::last(child, last, c) |
|
||||||
|
// In for example `if (a && true) ...` there is no RHS CFG node going into the
|
||||||
|
// `[false] a && true` operation
|
||||||
|
strictcount(ConditionalSuccessor cs | exists(last.getACfgNode().getASuccessor(cs)) | cs) = 1
|
||||||
|
or
|
||||||
|
// In for example `x && return`, there is no RHS CFG node going into the `&&` operation
|
||||||
|
not c instanceof CfgImpl::NormalCompletion
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets counts of control flow graph inconsistencies of each type.
|
* Gets counts of control flow graph inconsistencies of each type.
|
||||||
*/
|
*/
|
||||||
@@ -99,4 +119,7 @@ int getCfgInconsistencyCounts(string type) {
|
|||||||
or
|
or
|
||||||
type = "Non-PostOrderTree Expr node" and
|
type = "Non-PostOrderTree Expr node" and
|
||||||
result = count(Expr e | nonPostOrderExpr(e) | e)
|
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, _))
|
||||||
}
|
}
|
||||||
|
|||||||
116
rust/ql/lib/codeql/rust/controlflow/internal/CfgNodes.qll
Normal file
116
rust/ql/lib/codeql/rust/controlflow/internal/CfgNodes.qll
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
private import rust
|
||||||
|
private import codeql.rust.controlflow.internal.generated.CfgNodes
|
||||||
|
private import codeql.rust.controlflow.internal.ControlFlowGraphImpl as CfgImpl
|
||||||
|
private import codeql.rust.controlflow.ControlFlowGraph
|
||||||
|
private import codeql.rust.controlflow.BasicBlocks
|
||||||
|
private import codeql.rust.controlflow.CfgNodes
|
||||||
|
private import codeql.rust.internal.CachedStages
|
||||||
|
|
||||||
|
private predicate isPostOrder(AstNode n) {
|
||||||
|
n instanceof Expr and
|
||||||
|
not n instanceof LetExpr
|
||||||
|
or
|
||||||
|
n instanceof OrPat
|
||||||
|
or
|
||||||
|
n instanceof IdentPat
|
||||||
|
or
|
||||||
|
n instanceof LiteralPat
|
||||||
|
or
|
||||||
|
n instanceof Param
|
||||||
|
}
|
||||||
|
|
||||||
|
private module CfgNodesInput implements InputSig<Location> {
|
||||||
|
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<Location, CfgNodesInput>
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
3657
rust/ql/lib/codeql/rust/controlflow/internal/generated/CfgNodes.qll
generated
Normal file
3657
rust/ql/lib/codeql/rust/controlflow/internal/generated/CfgNodes.qll
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -14,6 +14,7 @@ private import codeql.rust.controlflow.ControlFlowGraph
|
|||||||
module Impl {
|
module Impl {
|
||||||
private import rust
|
private import rust
|
||||||
private import codeql.rust.elements.internal.generated.ParentChild
|
private import codeql.rust.elements.internal.generated.ParentChild
|
||||||
|
private import codeql.rust.controlflow.ControlFlowGraph
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the immediate parent of a non-`AstNode` element `e`.
|
* Gets the immediate parent of a non-`AstNode` element `e`.
|
||||||
@@ -62,5 +63,37 @@ module Impl {
|
|||||||
or
|
or
|
||||||
this.getParentNode().isInMacroExpansion()
|
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() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ module Stages {
|
|||||||
private import codeql.rust.controlflow.internal.Splitting
|
private import codeql.rust.controlflow.internal.Splitting
|
||||||
private import codeql.rust.controlflow.internal.SuccessorType
|
private import codeql.rust.controlflow.internal.SuccessorType
|
||||||
private import codeql.rust.controlflow.internal.ControlFlowGraphImpl
|
private import codeql.rust.controlflow.internal.ControlFlowGraphImpl
|
||||||
|
private import codeql.rust.controlflow.CfgNodes
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Always holds.
|
* Always holds.
|
||||||
@@ -93,6 +94,8 @@ module Stages {
|
|||||||
exists(TNormalSuccessor())
|
exists(TNormalSuccessor())
|
||||||
or
|
or
|
||||||
exists(AstCfgNode n)
|
exists(AstCfgNode n)
|
||||||
|
or
|
||||||
|
exists(CallExprCfgNode n | exists(n.getExpr()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
| CFG scope lacks initial AST node | 0 |
|
| CFG scope lacks initial AST node | 0 |
|
||||||
| Dead end | 0 |
|
| Dead end | 0 |
|
||||||
|
| Missing CFG child | 0 |
|
||||||
| Multiple successors of the same type | 0 |
|
| Multiple successors of the same type | 0 |
|
||||||
| Multiple toStrings | 0 |
|
| Multiple toStrings | 0 |
|
||||||
| Non-PostOrderTree Expr node | 0 |
|
| Non-PostOrderTree Expr node | 0 |
|
||||||
|
|||||||
@@ -18,14 +18,14 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(Expr)
|
@annotate(Expr, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
The base class for expressions.
|
The base class for expressions.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(Pat)
|
@annotate(Pat, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
The base class for patterns.
|
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 _:
|
class _:
|
||||||
"""
|
"""
|
||||||
A path expression. For example:
|
A path expression. For example:
|
||||||
@@ -119,7 +119,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(IfExpr)
|
@annotate(IfExpr, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
An `if` expression. For example:
|
An `if` expression. For example:
|
||||||
@@ -138,7 +138,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(LetExpr)
|
@annotate(LetExpr, cfg = True)
|
||||||
@rust.doc_test_signature("(maybe_some: Option<String>) -> ()")
|
@rust.doc_test_signature("(maybe_some: Option<String>) -> ()")
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
@@ -151,7 +151,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(BlockExpr)
|
@annotate(BlockExpr, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
A block expression. For example:
|
A block expression. For example:
|
||||||
@@ -169,7 +169,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(LoopExpr)
|
@annotate(LoopExpr, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
A loop expression. For example:
|
A loop expression. For example:
|
||||||
@@ -205,7 +205,7 @@ class CallExprBase(Expr):
|
|||||||
attrs: list["Attr"] | child
|
attrs: list["Attr"] | child
|
||||||
|
|
||||||
|
|
||||||
@annotate(CallExpr, replace_bases={Expr: CallExprBase})
|
@annotate(CallExpr, replace_bases={Expr: CallExprBase}, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
A function call expression. For example:
|
A function call expression. For example:
|
||||||
@@ -220,7 +220,7 @@ class _:
|
|||||||
attrs: drop
|
attrs: drop
|
||||||
|
|
||||||
|
|
||||||
@annotate(MethodCallExpr, replace_bases={Expr: CallExprBase}, add_bases=(Resolvable,))
|
@annotate(MethodCallExpr, replace_bases={Expr: CallExprBase}, add_bases=(Resolvable,), cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
A method call expression. For example:
|
A method call expression. For example:
|
||||||
@@ -253,7 +253,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(MatchExpr)
|
@annotate(MatchExpr, cfg = True)
|
||||||
@rust.doc_test_signature("(x: i32) -> i32")
|
@rust.doc_test_signature("(x: i32) -> i32")
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
@@ -273,7 +273,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(ContinueExpr)
|
@annotate(ContinueExpr, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
A continue expression. For example:
|
A continue expression. For example:
|
||||||
@@ -294,7 +294,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(BreakExpr)
|
@annotate(BreakExpr, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
A break expression. For example:
|
A break expression. For example:
|
||||||
@@ -323,7 +323,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(ReturnExpr)
|
@annotate(ReturnExpr, cfg = True)
|
||||||
@rust.doc_test_signature(None)
|
@rust.doc_test_signature(None)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
@@ -341,7 +341,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(BecomeExpr)
|
@annotate(BecomeExpr, cfg = True)
|
||||||
@rust.doc_test_signature(None)
|
@rust.doc_test_signature(None)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
@@ -358,7 +358,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(YieldExpr)
|
@annotate(YieldExpr, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
A `yield` expression. For example:
|
A `yield` expression. For example:
|
||||||
@@ -371,7 +371,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(YeetExpr)
|
@annotate(YeetExpr, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
A `yeet` expression. For example:
|
A `yeet` expression. For example:
|
||||||
@@ -393,7 +393,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(RecordExpr)
|
@annotate(RecordExpr, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
A record expression. For example:
|
A record expression. For example:
|
||||||
@@ -406,7 +406,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(FieldExpr)
|
@annotate(FieldExpr, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
A field access expression. For example:
|
A field access expression. For example:
|
||||||
@@ -416,7 +416,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(AwaitExpr)
|
@annotate(AwaitExpr, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
An `await` expression. For example:
|
An `await` expression. For example:
|
||||||
@@ -439,7 +439,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(RefExpr)
|
@annotate(RefExpr, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
A reference expression. For example:
|
A reference expression. For example:
|
||||||
@@ -452,7 +452,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(PrefixExpr)
|
@annotate(PrefixExpr, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
A unary operation expression. For example:
|
A unary operation expression. For example:
|
||||||
@@ -464,7 +464,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(BinaryExpr)
|
@annotate(BinaryExpr, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
A binary operation expression. For example:
|
A binary operation expression. For example:
|
||||||
@@ -478,7 +478,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(RangeExpr)
|
@annotate(RangeExpr, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
A range expression. For example:
|
A range expression. For example:
|
||||||
@@ -493,7 +493,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(IndexExpr)
|
@annotate(IndexExpr, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
An index expression. For example:
|
An index expression. For example:
|
||||||
@@ -520,7 +520,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(TupleExpr)
|
@annotate(TupleExpr, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
A tuple expression. For example:
|
A tuple expression. For example:
|
||||||
@@ -531,7 +531,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(ArrayExpr)
|
@annotate(ArrayExpr, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
An array expression. For example:
|
An array expression. For example:
|
||||||
@@ -542,7 +542,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(LiteralExpr)
|
@annotate(LiteralExpr, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
A literal expression. For example:
|
A literal expression. For example:
|
||||||
@@ -559,7 +559,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(UnderscoreExpr)
|
@annotate(UnderscoreExpr, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
An underscore expression. For example:
|
An underscore expression. For example:
|
||||||
@@ -569,7 +569,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(OffsetOfExpr)
|
@annotate(OffsetOfExpr, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
An `offset_of` expression. For example:
|
An `offset_of` expression. For example:
|
||||||
@@ -579,7 +579,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(AsmExpr)
|
@annotate(AsmExpr, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
An inline assembly expression. For example:
|
An inline assembly expression. For example:
|
||||||
@@ -591,7 +591,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(LetStmt)
|
@annotate(LetStmt, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
A let statement. For example:
|
A let statement. For example:
|
||||||
@@ -620,7 +620,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(WildcardPat)
|
@annotate(WildcardPat, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
A wildcard pattern. For example:
|
A wildcard pattern. For example:
|
||||||
@@ -630,7 +630,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(TuplePat)
|
@annotate(TuplePat, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
A tuple pattern. For example:
|
A tuple pattern. For example:
|
||||||
@@ -641,7 +641,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(OrPat)
|
@annotate(OrPat, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
An or pattern. For example:
|
An or pattern. For example:
|
||||||
@@ -663,7 +663,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(RecordPat)
|
@annotate(RecordPat, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
A record pattern. For example:
|
A record pattern. For example:
|
||||||
@@ -676,7 +676,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(RangePat)
|
@annotate(RangePat, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
A range pattern. For example:
|
A range pattern. For example:
|
||||||
@@ -690,7 +690,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(SlicePat)
|
@annotate(SlicePat, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
A slice pattern. For example:
|
A slice pattern. For example:
|
||||||
@@ -704,7 +704,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(PathPat)
|
@annotate(PathPat, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
A path pattern. For example:
|
A path pattern. For example:
|
||||||
@@ -717,7 +717,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(LiteralPat)
|
@annotate(LiteralPat, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
A literal pattern. For example:
|
A literal pattern. For example:
|
||||||
@@ -730,7 +730,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(IdentPat)
|
@annotate(IdentPat, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
A binding pattern. For example:
|
A binding pattern. For example:
|
||||||
@@ -749,7 +749,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(TupleStructPat)
|
@annotate(TupleStructPat, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
A tuple struct pattern. For example:
|
A tuple struct pattern. For example:
|
||||||
@@ -763,7 +763,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(RefPat)
|
@annotate(RefPat, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
A reference pattern. For example:
|
A reference pattern. For example:
|
||||||
@@ -776,7 +776,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(BoxPat)
|
@annotate(BoxPat, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
A box pattern. For example:
|
A box pattern. For example:
|
||||||
@@ -789,7 +789,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(ConstBlockPat)
|
@annotate(ConstBlockPat, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
A const block pattern. For example:
|
A const block pattern. For example:
|
||||||
@@ -990,7 +990,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(ForExpr)
|
@annotate(ForExpr, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
A ForExpr. For example:
|
A ForExpr. For example:
|
||||||
@@ -1020,7 +1020,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(FormatArgsExpr)
|
@annotate(FormatArgsExpr, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
A FormatArgsExpr. For example:
|
A FormatArgsExpr. For example:
|
||||||
@@ -1150,7 +1150,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(MacroCall)
|
@annotate(MacroCall, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
A MacroCall. For example:
|
A MacroCall. For example:
|
||||||
@@ -1171,7 +1171,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(MacroExpr)
|
@annotate(MacroExpr, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
A MacroExpr. For example:
|
A MacroExpr. For example:
|
||||||
@@ -1194,7 +1194,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(MacroPat)
|
@annotate(MacroPat, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
A MacroPat. For example:
|
A MacroPat. For example:
|
||||||
@@ -1297,7 +1297,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(Param)
|
@annotate(Param, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
A Param. For example:
|
A Param. For example:
|
||||||
@@ -1437,7 +1437,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(RestPat)
|
@annotate(RestPat, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
A RestPat. For example:
|
A RestPat. For example:
|
||||||
@@ -1564,7 +1564,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(TryExpr)
|
@annotate(TryExpr, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
A TryExpr. For example:
|
A TryExpr. For example:
|
||||||
@@ -1744,7 +1744,7 @@ class _:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@annotate(WhileExpr)
|
@annotate(WhileExpr, cfg = True)
|
||||||
class _:
|
class _:
|
||||||
"""
|
"""
|
||||||
A WhileExpr. For example:
|
A WhileExpr. For example:
|
||||||
|
|||||||
Reference in New Issue
Block a user