mirror of
https://github.com/github/codeql.git
synced 2026-04-28 10:15:14 +02:00
Rust: Implement path resolution in QL
This commit is contained in:
@@ -73,6 +73,14 @@ query predicate multiplePositions(Element parent, int pos1, int pos2, string acc
|
||||
pos1 != pos2
|
||||
}
|
||||
|
||||
private import codeql.rust.elements.internal.PathResolution
|
||||
|
||||
/** Holds if `p` may resolve to multiple items. */
|
||||
query predicate multiplePathResolutions(Path p, Item i) {
|
||||
i = resolvePath(p) and
|
||||
strictcount(resolvePath(p)) > 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets counts of abstract syntax tree inconsistencies of each type.
|
||||
*/
|
||||
@@ -98,4 +106,7 @@ int getAstInconsistencyCounts(string type) {
|
||||
or
|
||||
type = "Multiple positions" and
|
||||
result = count(Element e | multiplePositions(_, _, _, _, e) | e)
|
||||
or
|
||||
type = "Multiple path resolutions" and
|
||||
result = count(Path p | multiplePathResolutions(p, _) | p)
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ module Impl {
|
||||
private import codeql.rust.elements.internal.MethodCallExprImpl::Impl
|
||||
private import codeql.rust.elements.internal.CallExprImpl::Impl
|
||||
private import codeql.rust.elements.internal.PathExprImpl::Impl
|
||||
private import codeql.rust.elements.internal.PathResolution
|
||||
|
||||
pragma[nomagic]
|
||||
Resolvable getCallResolvable(CallExprBase call) {
|
||||
@@ -33,6 +34,10 @@ module Impl {
|
||||
* Gets the target callable of this call, if a unique such target can
|
||||
* be statically resolved.
|
||||
*/
|
||||
Callable getStaticTarget() { getCallResolvable(this).resolvesAsItem(result) }
|
||||
Callable getStaticTarget() {
|
||||
getCallResolvable(this).resolvesAsItem(result)
|
||||
or
|
||||
result = resolvePath(this.(CallExpr).getFunction().(PathExpr).getPath())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
464
rust/ql/lib/codeql/rust/elements/internal/PathResolution.qll
Normal file
464
rust/ql/lib/codeql/rust/elements/internal/PathResolution.qll
Normal file
@@ -0,0 +1,464 @@
|
||||
/** Provides functionality for resolving paths. */
|
||||
|
||||
private import rust
|
||||
private import codeql.rust.elements.internal.generated.ParentChild
|
||||
|
||||
/**
|
||||
* An item that may be referred to by a path, and which is a node in
|
||||
* the _item graph_.
|
||||
*
|
||||
* The item graph is a labeled directed graph, where an edge
|
||||
* `item1 --name--> item2` means that `item2` is available inside the
|
||||
* scope of `item1` under the name `name`. For example, if we have
|
||||
*
|
||||
* ```rust
|
||||
* mod m1 {
|
||||
* mod m2 { }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* then there is an edge `m1 --m2--> m1::m2`.
|
||||
*
|
||||
* Source files are also considered nodes in the item graph, and for
|
||||
* each source file `f` there is an edge `f --name--> item` when `f`
|
||||
* declares `item` with the name `name`.
|
||||
*
|
||||
* For imports like
|
||||
*
|
||||
* ```rust
|
||||
* mod m1 {
|
||||
* mod m2;
|
||||
* use m2::foo;
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* we first generate an edge `m1::m2 --name--> f::item`, where `item` is
|
||||
* any item (named `name`) inside the imported source file `f`. Using this
|
||||
* edge, `m2::foo` can resolve to `f::foo`, which results in the edge
|
||||
* `m1::use m2 --foo--> f::foo`. Lastly, all edges out of `use` nodes are
|
||||
* lifted to predecessors in the graph, so we get an edge `m1 --foo--> f::foo`.
|
||||
*
|
||||
*
|
||||
* References:
|
||||
* - https://doc.rust-lang.org/reference/items/modules.html
|
||||
* - https://doc.rust-lang.org/reference/names/scopes.html
|
||||
* - https://doc.rust-lang.org/reference/paths.html
|
||||
* - https://doc.rust-lang.org/reference/visibility-and-privacy.html
|
||||
*/
|
||||
abstract class ItemNode extends AstNode {
|
||||
/** Gets the (original) name of this item. */
|
||||
abstract string getName();
|
||||
|
||||
/** Gets the visibility of this item, if any. */
|
||||
abstract Visibility getVisibility();
|
||||
|
||||
/** Holds if this item is declared as `pub`. */
|
||||
bindingset[this]
|
||||
pragma[inline_late]
|
||||
predicate isPublic() { exists(this.getVisibility()) }
|
||||
|
||||
/** Gets an element that has this item as immediately enlcosing item. */
|
||||
pragma[nomagic]
|
||||
Element getADescendant() {
|
||||
getImmediateParent(result) = this
|
||||
or
|
||||
exists(Element mid |
|
||||
mid = this.getADescendant() and
|
||||
getImmediateParent(result) = mid and
|
||||
not mid instanceof ItemNode
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the immediately enclosing item of this item, if any. */
|
||||
pragma[nomagic]
|
||||
ItemNode getImmediateParent() { this = result.getADescendant() }
|
||||
|
||||
/** Gets the immediately enclosing module (or source file) of this item. */
|
||||
pragma[nomagic]
|
||||
ModuleLikeNode getImmediateParentModule() { this = result.getAnItemInScope() }
|
||||
|
||||
/** Gets a successor named `name` of this item, if any. */
|
||||
pragma[nomagic]
|
||||
ItemNode getASuccessor(string name) {
|
||||
sourceFileEdge(this, name, result)
|
||||
or
|
||||
this = result.getImmediateParent() and
|
||||
name = result.getName()
|
||||
or
|
||||
fileImportEdge(this, name, result)
|
||||
or
|
||||
useImportEdge(this, name, result)
|
||||
or
|
||||
// items made available through `use` are available to nodes that contain the `use`
|
||||
exists(UseItemNode use |
|
||||
use = this.getASuccessor(_) and
|
||||
result = use.getASuccessor(name)
|
||||
)
|
||||
or
|
||||
// items made available through macro calls are available to nodes that contain the macro call
|
||||
exists(MacroCallItemNode call |
|
||||
call = this.getASuccessor(_) and
|
||||
result = call.getASuccessor(name)
|
||||
)
|
||||
or
|
||||
name = "super" and
|
||||
if this instanceof Module
|
||||
then result = this.getImmediateParentModule()
|
||||
else result = this.getImmediateParentModule().getImmediateParentModule()
|
||||
or
|
||||
name = "self" and
|
||||
if this instanceof Module then result = this else result = this.getImmediateParentModule()
|
||||
or
|
||||
name = "Self" and
|
||||
this = result.(ImplOrTraitItemNode).getAnItemInSelfScope()
|
||||
or
|
||||
name = "crate" and
|
||||
result.(SourceFileItemNode).getFile() = this.getFile()
|
||||
}
|
||||
}
|
||||
|
||||
/** A module or a source file. */
|
||||
abstract private class ModuleLikeNode extends ItemNode {
|
||||
/** Gets an item that may refer directly to items defined in this module. */
|
||||
pragma[nomagic]
|
||||
ItemNode getAnItemInScope() {
|
||||
result.getImmediateParent() = this
|
||||
or
|
||||
exists(ItemNode mid |
|
||||
mid = this.getAnItemInScope() and
|
||||
result.getImmediateParent() = mid and
|
||||
not mid instanceof ModuleLikeNode
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class SourceFileItemNode extends ModuleLikeNode, SourceFile {
|
||||
override string getName() { result = "(source file)" }
|
||||
|
||||
override Visibility getVisibility() { none() }
|
||||
}
|
||||
|
||||
private class ConstItemNode extends ItemNode instanceof Const {
|
||||
override string getName() { result = Const.super.getName().getText() }
|
||||
|
||||
override Visibility getVisibility() { result = Const.super.getVisibility() }
|
||||
}
|
||||
|
||||
private class EnumItemNode extends ItemNode instanceof Enum {
|
||||
override string getName() { result = Enum.super.getName().getText() }
|
||||
|
||||
override Visibility getVisibility() { result = Enum.super.getVisibility() }
|
||||
}
|
||||
|
||||
private class VariantItemNode extends ItemNode instanceof Variant {
|
||||
override string getName() { result = Variant.super.getName().getText() }
|
||||
|
||||
override Visibility getVisibility() { result = Variant.super.getVisibility() }
|
||||
}
|
||||
|
||||
private class FunctionItemNode extends ItemNode instanceof Function {
|
||||
override string getName() { result = Function.super.getName().getText() }
|
||||
|
||||
override Visibility getVisibility() { result = Function.super.getVisibility() }
|
||||
}
|
||||
|
||||
abstract private class ImplOrTraitItemNode extends ItemNode {
|
||||
/** Gets an item that may refer to this node using `Self`. */
|
||||
pragma[nomagic]
|
||||
ItemNode getAnItemInSelfScope() {
|
||||
result.getImmediateParent() = this
|
||||
or
|
||||
exists(ItemNode mid |
|
||||
mid = this.getAnItemInSelfScope() and
|
||||
result.getImmediateParent() = mid and
|
||||
not mid instanceof ImplOrTraitItemNode
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class ImplItemNode extends ImplOrTraitItemNode instanceof Impl {
|
||||
override string getName() { result = "(impl)" }
|
||||
|
||||
override Visibility getVisibility() { none() }
|
||||
}
|
||||
|
||||
private class MacroCallItemNode extends ItemNode instanceof MacroCall {
|
||||
override string getName() { result = "(macro call)" }
|
||||
|
||||
override Visibility getVisibility() { none() }
|
||||
}
|
||||
|
||||
private class ModuleItemNode extends ModuleLikeNode instanceof Module {
|
||||
override string getName() { result = Module.super.getName().getText() }
|
||||
|
||||
override Visibility getVisibility() { result = Module.super.getVisibility() }
|
||||
}
|
||||
|
||||
private class StructItemNode extends ItemNode instanceof Struct {
|
||||
override string getName() { result = Struct.super.getName().getText() }
|
||||
|
||||
override Visibility getVisibility() { result = Struct.super.getVisibility() }
|
||||
}
|
||||
|
||||
private class TraitItemNode extends ImplOrTraitItemNode instanceof Trait {
|
||||
override string getName() { result = Trait.super.getName().getText() }
|
||||
|
||||
override Visibility getVisibility() { result = Trait.super.getVisibility() }
|
||||
}
|
||||
|
||||
private class UnionItemNode extends ItemNode instanceof Union {
|
||||
override string getName() { result = Union.super.getName().getText() }
|
||||
|
||||
override Visibility getVisibility() { result = Union.super.getVisibility() }
|
||||
}
|
||||
|
||||
private class UseItemNode extends ItemNode instanceof Use {
|
||||
override string getName() { result = "(use)" }
|
||||
|
||||
override Visibility getVisibility() { none() }
|
||||
}
|
||||
|
||||
private class BlockExprItemNode extends ItemNode instanceof BlockExpr {
|
||||
override string getName() { result = "(block expr)" }
|
||||
|
||||
override Visibility getVisibility() { none() }
|
||||
}
|
||||
|
||||
private predicate sourceFileEdge(SourceFile f, string name, ItemNode item) {
|
||||
item = f.getAnItem() and
|
||||
name = item.getName()
|
||||
}
|
||||
|
||||
/** Holds if `f` is available as `mod name;` inside `folder`. */
|
||||
private predicate fileModule(SourceFile f, string name, Folder folder) {
|
||||
exists(File file | file = f.getFile() |
|
||||
file.getBaseName() = name + ".rs" and
|
||||
folder = file.getParentContainer()
|
||||
or
|
||||
exists(Folder encl |
|
||||
file.getBaseName() = "mod.rs" and
|
||||
encl = file.getParentContainer() and
|
||||
name = encl.getBaseName() and
|
||||
folder = encl.getParentContainer()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `m` is a `mod name;` module declaration happening in a file named
|
||||
* `fileName.rs`, inside the folder `parent`.
|
||||
*/
|
||||
private predicate modImport(Module m, string fileName, string name, Folder parent) {
|
||||
exists(File f |
|
||||
f = m.getFile() and
|
||||
not m.hasItemList() and
|
||||
// TODO: handle
|
||||
// ```
|
||||
// #[path = "foo.rs"]
|
||||
// mod bar;
|
||||
// ```
|
||||
not m.getAnAttr().getMeta().getPath().getPart().getNameRef().getText() = "path" and
|
||||
name = m.getName().getText() and
|
||||
parent = f.getParentContainer() and
|
||||
fileName = f.getStem()
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `m` is a `mod name;` item importing file `f`. */
|
||||
private predicate fileImport(Module m, SourceFile f) {
|
||||
exists(string fileName, string name, Folder parent | modImport(m, fileName, name, parent) |
|
||||
// sibling import
|
||||
fileModule(f, name, parent)
|
||||
or
|
||||
// child import
|
||||
fileModule(f, name, parent.getFolder(fileName))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `mod` is a `mod name;` item targeting a file resulting in `item` being
|
||||
* in scope under the name `name`.
|
||||
*/
|
||||
private predicate fileImportEdge(Module mod, string name, ItemNode item) {
|
||||
item.isPublic() and
|
||||
exists(SourceFile f |
|
||||
fileImport(mod, f) and
|
||||
sourceFileEdge(f, name, item)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate useTreeIsGlobImport(UseTree use) {
|
||||
// TODO: the extractor should provide this information
|
||||
use.getLocation() != use.getPath().getLocation() and
|
||||
not use.hasUseTreeList() and
|
||||
not use.hasRename()
|
||||
}
|
||||
|
||||
private predicate useTreeDeclares(UseTree tree, string name) {
|
||||
not useTreeIsGlobImport(tree) and
|
||||
not exists(tree.getUseTreeList()) and
|
||||
(
|
||||
name = tree.getRename().getName().getText() and
|
||||
name != "_"
|
||||
or
|
||||
not tree.hasRename() and
|
||||
name = tree.getPath().getPart().getNameRef().getText()
|
||||
)
|
||||
or
|
||||
exists(UseTree mid |
|
||||
useTreeDeclares(mid, name) and
|
||||
mid = tree.getUseTreeList().getAUseTree()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `item` explicitly declares a sub item named `name`. This includes
|
||||
* items declared by `use` statements, except for glob imports.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate declares(ItemNode item, string name) {
|
||||
exists(ItemNode child | child.getImmediateParent() = item |
|
||||
child.getName() = name
|
||||
or
|
||||
useTreeDeclares(child.(Use).getUseTree(), name)
|
||||
)
|
||||
or
|
||||
exists(MacroCallItemNode call |
|
||||
declares(call, name) and
|
||||
call.getImmediateParent() = item
|
||||
)
|
||||
}
|
||||
|
||||
private class RelevantPath extends Path {
|
||||
RelevantPath() { not this = any(VariableAccess va).(PathExpr).getPath() }
|
||||
|
||||
pragma[nomagic]
|
||||
predicate isRoot(string name) {
|
||||
not exists(this.getQualifier()) and
|
||||
not this = any(UseTreeList list).getAUseTree().getPath() and
|
||||
name = this.getPart().getNameRef().getText()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the root path `root` references an item named `name`, and `name`
|
||||
* may be looked up inside enclosing item `encl`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate rootPathLookup(RelevantPath root, string name, ItemNode encl) {
|
||||
exists(ItemNode encl0 |
|
||||
// lookup in the immediately enclosing item
|
||||
root.isRoot(name) and
|
||||
encl0.getADescendant() = root
|
||||
or
|
||||
// lookup in an outer scope, but only if the item is not declared in inner scope
|
||||
exists(ItemNode mid |
|
||||
rootPathLookup(root, name, mid) and
|
||||
not declares(mid, name)
|
||||
|
|
||||
// nested modules do not have unqualified access to items from outer modules,
|
||||
// except for items declared at top-level in the source file
|
||||
if mid instanceof Module
|
||||
then encl0.(SourceFileItemNode) = mid.getImmediateParent+()
|
||||
else encl0 = mid.getImmediateParent()
|
||||
)
|
||||
|
|
||||
// functions in `impl` blocks need to use explicit `Self::` to access other
|
||||
// functions in the `impl` block
|
||||
if encl0 instanceof ImplOrTraitItemNode then encl = encl0.getImmediateParent() else encl = encl0
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the item that `path` resolves to, if any. */
|
||||
cached
|
||||
ItemNode resolvePath(RelevantPath path) {
|
||||
exists(ItemNode encl, string name |
|
||||
rootPathLookup(path, name, encl) and
|
||||
result = encl.getASuccessor(name)
|
||||
)
|
||||
or
|
||||
exists(ItemNode q, string name |
|
||||
q = resolvePathQualifier(path, name) and
|
||||
result = q.getASuccessor(name)
|
||||
)
|
||||
or
|
||||
result = resolveUseTreeListItem(_, _, path)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private ItemNode resolvePathQualifier(RelevantPath path, string name) {
|
||||
result = resolvePath(path.getQualifier()) and
|
||||
name = path.getPart().getNameRef().getText()
|
||||
}
|
||||
|
||||
private predicate isUseTreeSubPath(UseTree tree, RelevantPath path) {
|
||||
path = tree.getPath()
|
||||
or
|
||||
exists(RelevantPath mid |
|
||||
isUseTreeSubPath(tree, mid) and
|
||||
path = mid.getQualifier()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate isUseTreeSubPathUnqualified(UseTree tree, RelevantPath path, string name) {
|
||||
isUseTreeSubPath(tree, path) and
|
||||
not exists(path.getQualifier()) and
|
||||
name = path.getPart().getNameRef().getText()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private ItemNode resolveUseTreeListItem(Use use, UseTree tree, RelevantPath path) {
|
||||
exists(UseTree midTree, ItemNode mid, string name |
|
||||
mid = resolveUseTreeListItem(use, midTree) and
|
||||
tree = midTree.getUseTreeList().getAUseTree() and
|
||||
isUseTreeSubPathUnqualified(tree, path, pragma[only_bind_into](name)) and
|
||||
result = mid.getASuccessor(pragma[only_bind_into](name))
|
||||
)
|
||||
or
|
||||
exists(ItemNode q, string name |
|
||||
q = resolveUseTreeListItemQualifier(use, tree, path, name) and
|
||||
result = q.getASuccessor(name)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private ItemNode resolveUseTreeListItemQualifier(
|
||||
Use use, UseTree tree, RelevantPath path, string name
|
||||
) {
|
||||
result = resolveUseTreeListItem(use, tree, path.getQualifier()) and
|
||||
name = path.getPart().getNameRef().getText()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private ItemNode resolveUseTreeListItem(Use use, UseTree tree) {
|
||||
tree = use.getUseTree() and
|
||||
result = resolvePath(tree.getPath())
|
||||
or
|
||||
result = resolveUseTreeListItem(use, tree, tree.getPath())
|
||||
}
|
||||
|
||||
/** Holds if `use` imports `item` as `name`. */
|
||||
pragma[nomagic]
|
||||
private predicate useImportEdge(Use use, string name, ItemNode item) {
|
||||
exists(UseTree tree, ItemNode used |
|
||||
used = resolveUseTreeListItem(use, tree) and
|
||||
not exists(tree.getUseTreeList()) and
|
||||
if useTreeIsGlobImport(tree)
|
||||
then
|
||||
exists(ItemNode encl |
|
||||
encl.getADescendant() = use and
|
||||
item = used.getASuccessor(name) and
|
||||
// glob imports can be shadowed
|
||||
not declares(encl, name)
|
||||
)
|
||||
else item = used
|
||||
|
|
||||
not tree.hasRename() and
|
||||
name = item.getName()
|
||||
or
|
||||
name = tree.getRename().getName().getText() and
|
||||
name != "_"
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
multiplePathResolutions
|
||||
| main.rs:118:9:118:9 | f | main.rs:104:5:106:5 | fn f |
|
||||
| main.rs:118:9:118:9 | f | main.rs:110:5:112:5 | fn f |
|
||||
201
rust/ql/test/library-tests/modules/main.rs
Normal file
201
rust/ql/test/library-tests/modules/main.rs
Normal file
@@ -0,0 +1,201 @@
|
||||
mod my; // I1
|
||||
|
||||
use my::*; // $ item=I1
|
||||
|
||||
use my::nested::nested1::nested2::*; // $ item=I3
|
||||
|
||||
mod my2; // I14
|
||||
|
||||
use my2::*; // $ item=I14
|
||||
|
||||
use my2::nested2::nested3::nested4::{f, g}; // $ item=I11 item=I12 item=I13
|
||||
|
||||
mod m1 {
|
||||
fn f() {
|
||||
println!("main.rs::m1::f");
|
||||
} // I16
|
||||
|
||||
pub mod m2 {
|
||||
fn f() {
|
||||
println!("main.rs::m1::m2::f");
|
||||
} // I18
|
||||
|
||||
pub fn g() {
|
||||
println!("main.rs::m1::m2::g");
|
||||
f(); // $ item=I18
|
||||
super::f(); // $ item=I16
|
||||
} // I19
|
||||
|
||||
pub mod m3 {
|
||||
use super::f; // $ item=I18
|
||||
pub fn h() {
|
||||
println!("main.rs::m1::m2::m3::h");
|
||||
f(); // $ item=I18
|
||||
} // I21
|
||||
} // I20
|
||||
} // I17
|
||||
} // I15
|
||||
|
||||
mod m4 {
|
||||
use super::m1::m2::g; // $ item=I19
|
||||
|
||||
pub fn i() {
|
||||
println!("main.rs::m4::i");
|
||||
g(); // $ item=I19
|
||||
} // I23
|
||||
} // I22
|
||||
|
||||
struct Foo {} // I24
|
||||
|
||||
fn h() {
|
||||
println!("main.rs::h");
|
||||
|
||||
struct Foo {} // I26
|
||||
|
||||
fn f() {
|
||||
use m1::m2::g; // $ item=I19
|
||||
g(); // $ item=I19
|
||||
|
||||
struct Foo {} // I28
|
||||
println!("main.rs::h::f");
|
||||
let _ = Foo {}; // $ item=I28
|
||||
} // I27
|
||||
|
||||
let _ = Foo {}; // $ item=I26
|
||||
|
||||
f(); // $ item=I27
|
||||
|
||||
self::i(); // $ item=I29
|
||||
} // I25
|
||||
|
||||
fn i() {
|
||||
println!("main.rs::i");
|
||||
|
||||
let _ = Foo {}; // $ item=I24
|
||||
|
||||
{
|
||||
struct Foo {
|
||||
x: i32,
|
||||
} // I30
|
||||
|
||||
let _ = Foo { x: 0 }; // $ item=I30
|
||||
}
|
||||
} // I29
|
||||
|
||||
use my2::nested2 as my2_nested2_alias; // $ item=I8
|
||||
|
||||
use my2_nested2_alias::nested3::{nested4::f as f_alias, nested4::g as g_alias, nested4::*}; // $ item=I10 item=I12 item=I13 item=I11
|
||||
|
||||
macro_rules! fn_in_macro {
|
||||
($e:expr) => {
|
||||
fn f_defined_in_macro() {
|
||||
$e
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn j() {
|
||||
println!("main.rs::j");
|
||||
fn_in_macro!(println!("main.rs::j::f"));
|
||||
f_defined_in_macro(); // $ item=f_defined_in_macro
|
||||
} // I31
|
||||
|
||||
mod m5 {
|
||||
pub fn f() {
|
||||
println!("main.rs::m5::f");
|
||||
} // I33
|
||||
} // I32
|
||||
|
||||
mod m6 {
|
||||
fn f() {
|
||||
println!("main.rs::m6::f");
|
||||
} // I35
|
||||
|
||||
pub fn g() {
|
||||
println!("main.rs::m6::g");
|
||||
// this import shadows the definition `I35`, which we don't currently handle
|
||||
use super::m5::*; // $ item=I32
|
||||
f(); // $ item=I33 $ SPURIOUS: item=I35
|
||||
} // I36
|
||||
} // I34
|
||||
|
||||
mod m7 {
|
||||
pub enum MyEnum {
|
||||
A(i32), // I42
|
||||
B { x: i32 }, // I43
|
||||
C, // I44
|
||||
} // I41
|
||||
|
||||
#[rustfmt::skip]
|
||||
pub fn f() -> MyEnum // $ item=I41
|
||||
{
|
||||
println!("main.rs::m7::f");
|
||||
let _ = MyEnum::A(0); // $ item=I42
|
||||
let _ = MyEnum::B { x: 0 }; // $ item=I43
|
||||
MyEnum::C // $ item=I44
|
||||
} // I45
|
||||
} // I40
|
||||
|
||||
mod m8 {
|
||||
trait MyTrait {
|
||||
fn f(&self); // I48
|
||||
|
||||
fn g(&self) {
|
||||
println!("main.rs::m8::MyTrait::g");
|
||||
f(); // $ item=I51
|
||||
Self::f(self); // $ item=I48
|
||||
} // I49
|
||||
} // I47
|
||||
|
||||
struct MyStruct {} // I50
|
||||
|
||||
fn f() {
|
||||
println!("main.rs::m8::f");
|
||||
} // I51
|
||||
|
||||
#[rustfmt::skip]
|
||||
impl MyTrait for MyStruct { // $ item=I47 item=I50
|
||||
fn f(&self) {
|
||||
println!("main.rs::m8::<MyStruct as MyTrait>::f");
|
||||
f(); // $ item=I51
|
||||
Self::g(self); // $ item=I54
|
||||
} // I53
|
||||
|
||||
fn g(&self) {
|
||||
println!("main.rs::m8::<MyStruct as MyTrait>::g");
|
||||
} // I54
|
||||
} // I52
|
||||
|
||||
#[rustfmt::skip]
|
||||
pub fn g() {
|
||||
let x = MyStruct {}; // $ item=I50
|
||||
MyTrait::f(&x); // $ item=I48
|
||||
<MyStruct as // $ item=I50
|
||||
MyTrait // $ MISSING: item=I47
|
||||
> // $ MISSING: item=52
|
||||
::f(&x); // $ MISSING: item=I53
|
||||
let x = MyStruct {}; // $ item=I50
|
||||
x.f(); // $ MISSING: item=I53
|
||||
let x = MyStruct {}; // $ item=I50
|
||||
x.g(); // $ MISSING: item=I54
|
||||
} // I55
|
||||
} // I46
|
||||
|
||||
fn main() {
|
||||
my::nested::nested1::nested2::f(); // $ item=I4
|
||||
my::f(); // $ item=I38
|
||||
nested2::nested3::nested4::f(); // $ item=I12
|
||||
f(); // $ item=I12
|
||||
g(); // $ item=I13
|
||||
crate::h(); // $ item=I25
|
||||
m1::m2::g(); // $ item=I19
|
||||
m1::m2::m3::h(); // $ item=I21
|
||||
m4::i(); // $ item=I23
|
||||
h(); // $ item=I25
|
||||
f_alias(); // $ item=I12
|
||||
g_alias(); // $ item=I13
|
||||
j(); // $ item=I31
|
||||
m6::g(); // $ item=I36
|
||||
m7::f(); // $ item=I45
|
||||
m8::g(); // $ item=I55
|
||||
}
|
||||
137
rust/ql/test/library-tests/modules/modules.expected
Normal file
137
rust/ql/test/library-tests/modules/modules.expected
Normal file
@@ -0,0 +1,137 @@
|
||||
testFailures
|
||||
mod
|
||||
| lib.rs:1:1:1:7 | mod my |
|
||||
| main.rs:1:1:1:7 | mod my |
|
||||
| main.rs:7:1:7:8 | mod my2 |
|
||||
| main.rs:13:1:37:1 | mod m1 |
|
||||
| main.rs:18:5:36:5 | mod m2 |
|
||||
| main.rs:29:9:35:9 | mod m3 |
|
||||
| main.rs:39:1:46:1 | mod m4 |
|
||||
| main.rs:103:1:107:1 | mod m5 |
|
||||
| main.rs:109:1:120:1 | mod m6 |
|
||||
| main.rs:122:1:137:1 | mod m7 |
|
||||
| main.rs:139:1:182:1 | mod m8 |
|
||||
| my2/mod.rs:1:1:1:16 | mod nested2 |
|
||||
| my2/nested2.rs:1:1:11:1 | mod nested3 |
|
||||
| my2/nested2.rs:2:5:10:5 | mod nested4 |
|
||||
| my.rs:1:1:1:15 | mod nested |
|
||||
| my/nested.rs:1:1:17:1 | mod nested1 |
|
||||
| my/nested.rs:2:5:11:5 | mod nested2 |
|
||||
resolvePath
|
||||
| main.rs:3:5:3:6 | my | main.rs:1:1:1:7 | mod my |
|
||||
| main.rs:5:5:5:6 | my | main.rs:1:1:1:7 | mod my |
|
||||
| main.rs:5:5:5:14 | ...::nested | my.rs:1:1:1:15 | mod nested |
|
||||
| main.rs:5:5:5:23 | ...::nested1 | my/nested.rs:1:1:17:1 | mod nested1 |
|
||||
| main.rs:5:5:5:32 | ...::nested2 | my/nested.rs:2:5:11:5 | mod nested2 |
|
||||
| main.rs:9:5:9:7 | my2 | main.rs:7:1:7:8 | mod my2 |
|
||||
| main.rs:11:5:11:7 | my2 | main.rs:7:1:7:8 | mod my2 |
|
||||
| main.rs:11:5:11:16 | ...::nested2 | my2/mod.rs:1:1:1:16 | mod nested2 |
|
||||
| main.rs:11:5:11:25 | ...::nested3 | my2/nested2.rs:1:1:11:1 | mod nested3 |
|
||||
| main.rs:11:5:11:34 | ...::nested4 | my2/nested2.rs:2:5:10:5 | mod nested4 |
|
||||
| main.rs:11:38:11:38 | f | my2/nested2.rs:3:9:5:9 | fn f |
|
||||
| main.rs:11:41:11:41 | g | my2/nested2.rs:7:9:9:9 | fn g |
|
||||
| main.rs:25:13:25:13 | f | main.rs:19:9:21:9 | fn f |
|
||||
| main.rs:26:13:26:17 | super | main.rs:13:1:37:1 | mod m1 |
|
||||
| main.rs:26:13:26:20 | ...::f | main.rs:14:5:16:5 | fn f |
|
||||
| main.rs:30:17:30:21 | super | main.rs:18:5:36:5 | mod m2 |
|
||||
| main.rs:30:17:30:24 | ...::f | main.rs:19:9:21:9 | fn f |
|
||||
| main.rs:33:17:33:17 | f | main.rs:19:9:21:9 | fn f |
|
||||
| main.rs:40:9:40:13 | super | main.rs:1:1:201:2 | SourceFile |
|
||||
| main.rs:40:9:40:17 | ...::m1 | main.rs:13:1:37:1 | mod m1 |
|
||||
| main.rs:40:9:40:21 | ...::m2 | main.rs:18:5:36:5 | mod m2 |
|
||||
| main.rs:40:9:40:24 | ...::g | main.rs:23:9:27:9 | fn g |
|
||||
| main.rs:44:9:44:9 | g | main.rs:23:9:27:9 | fn g |
|
||||
| main.rs:56:13:56:14 | m1 | main.rs:13:1:37:1 | mod m1 |
|
||||
| main.rs:56:13:56:18 | ...::m2 | main.rs:18:5:36:5 | mod m2 |
|
||||
| main.rs:56:13:56:21 | ...::g | main.rs:23:9:27:9 | fn g |
|
||||
| main.rs:57:9:57:9 | g | main.rs:23:9:27:9 | fn g |
|
||||
| main.rs:61:17:61:19 | Foo | main.rs:59:9:59:21 | struct Foo |
|
||||
| main.rs:64:13:64:15 | Foo | main.rs:53:5:53:17 | struct Foo |
|
||||
| main.rs:66:5:66:5 | f | main.rs:55:5:62:5 | fn f |
|
||||
| main.rs:68:5:68:8 | self | main.rs:1:1:201:2 | SourceFile |
|
||||
| main.rs:68:5:68:11 | ...::i | main.rs:71:1:83:1 | fn i |
|
||||
| main.rs:74:13:74:15 | Foo | main.rs:48:1:48:13 | struct Foo |
|
||||
| main.rs:81:17:81:19 | Foo | main.rs:77:9:79:9 | struct Foo |
|
||||
| main.rs:85:5:85:7 | my2 | main.rs:7:1:7:8 | mod my2 |
|
||||
| main.rs:85:5:85:16 | ...::nested2 | my2/mod.rs:1:1:1:16 | mod nested2 |
|
||||
| main.rs:87:5:87:21 | my2_nested2_alias | my2/mod.rs:1:1:1:16 | mod nested2 |
|
||||
| main.rs:87:5:87:30 | ...::nested3 | my2/nested2.rs:1:1:11:1 | mod nested3 |
|
||||
| main.rs:87:34:87:40 | nested4 | my2/nested2.rs:2:5:10:5 | mod nested4 |
|
||||
| main.rs:87:34:87:43 | ...::f | my2/nested2.rs:3:9:5:9 | fn f |
|
||||
| main.rs:87:57:87:63 | nested4 | my2/nested2.rs:2:5:10:5 | mod nested4 |
|
||||
| main.rs:87:57:87:66 | ...::g | my2/nested2.rs:7:9:9:9 | fn g |
|
||||
| main.rs:87:80:87:86 | nested4 | my2/nested2.rs:2:5:10:5 | mod nested4 |
|
||||
| main.rs:100:5:100:22 | f_defined_in_macro | main.rs:99:18:99:42 | fn f_defined_in_macro |
|
||||
| main.rs:117:13:117:17 | super | main.rs:1:1:201:2 | SourceFile |
|
||||
| main.rs:117:13:117:21 | ...::m5 | main.rs:103:1:107:1 | mod m5 |
|
||||
| main.rs:118:9:118:9 | f | main.rs:104:5:106:5 | fn f |
|
||||
| main.rs:118:9:118:9 | f | main.rs:110:5:112:5 | fn f |
|
||||
| main.rs:130:19:130:24 | MyEnum | main.rs:123:5:127:5 | enum MyEnum |
|
||||
| main.rs:133:17:133:22 | MyEnum | main.rs:123:5:127:5 | enum MyEnum |
|
||||
| main.rs:133:17:133:25 | ...::A | main.rs:124:9:124:14 | A |
|
||||
| main.rs:134:17:134:22 | MyEnum | main.rs:123:5:127:5 | enum MyEnum |
|
||||
| main.rs:134:17:134:25 | ...::B | main.rs:124:23:125:20 | B |
|
||||
| main.rs:135:9:135:14 | MyEnum | main.rs:123:5:127:5 | enum MyEnum |
|
||||
| main.rs:135:9:135:17 | ...::C | main.rs:125:23:126:9 | C |
|
||||
| main.rs:145:13:145:13 | f | main.rs:152:5:154:5 | fn f |
|
||||
| main.rs:146:13:146:16 | Self | main.rs:140:5:148:5 | trait MyTrait |
|
||||
| main.rs:146:13:146:19 | ...::f | main.rs:141:9:141:20 | fn f |
|
||||
| main.rs:157:10:157:16 | MyTrait | main.rs:140:5:148:5 | trait MyTrait |
|
||||
| main.rs:157:22:157:29 | MyStruct | main.rs:150:5:150:22 | struct MyStruct |
|
||||
| main.rs:160:13:160:13 | f | main.rs:152:5:154:5 | fn f |
|
||||
| main.rs:161:13:161:16 | Self | main.rs:156:5:167:5 | impl MyTrait for MyStruct { ... } |
|
||||
| main.rs:161:13:161:19 | ...::g | main.rs:164:9:166:9 | fn g |
|
||||
| main.rs:171:17:171:24 | MyStruct | main.rs:150:5:150:22 | struct MyStruct |
|
||||
| main.rs:172:9:172:15 | MyTrait | main.rs:140:5:148:5 | trait MyTrait |
|
||||
| main.rs:172:9:172:18 | ...::f | main.rs:141:9:141:20 | fn f |
|
||||
| main.rs:173:10:173:17 | MyStruct | main.rs:150:5:150:22 | struct MyStruct |
|
||||
| main.rs:173:10:173:17 | MyStruct | main.rs:150:5:150:22 | struct MyStruct |
|
||||
| main.rs:177:17:177:24 | MyStruct | main.rs:150:5:150:22 | struct MyStruct |
|
||||
| main.rs:179:17:179:24 | MyStruct | main.rs:150:5:150:22 | struct MyStruct |
|
||||
| main.rs:185:5:185:6 | my | main.rs:1:1:1:7 | mod my |
|
||||
| main.rs:185:5:185:14 | ...::nested | my.rs:1:1:1:15 | mod nested |
|
||||
| main.rs:185:5:185:23 | ...::nested1 | my/nested.rs:1:1:17:1 | mod nested1 |
|
||||
| main.rs:185:5:185:32 | ...::nested2 | my/nested.rs:2:5:11:5 | mod nested2 |
|
||||
| main.rs:185:5:185:35 | ...::f | my/nested.rs:3:9:5:9 | fn f |
|
||||
| main.rs:186:5:186:6 | my | main.rs:1:1:1:7 | mod my |
|
||||
| main.rs:186:5:186:9 | ...::f | my.rs:5:1:7:1 | fn f |
|
||||
| main.rs:187:5:187:11 | nested2 | my2/mod.rs:1:1:1:16 | mod nested2 |
|
||||
| main.rs:187:5:187:20 | ...::nested3 | my2/nested2.rs:1:1:11:1 | mod nested3 |
|
||||
| main.rs:187:5:187:29 | ...::nested4 | my2/nested2.rs:2:5:10:5 | mod nested4 |
|
||||
| main.rs:187:5:187:32 | ...::f | my2/nested2.rs:3:9:5:9 | fn f |
|
||||
| main.rs:188:5:188:5 | f | my2/nested2.rs:3:9:5:9 | fn f |
|
||||
| main.rs:189:5:189:5 | g | my2/nested2.rs:7:9:9:9 | fn g |
|
||||
| main.rs:190:5:190:9 | crate | main.rs:1:1:201:2 | SourceFile |
|
||||
| main.rs:190:5:190:12 | ...::h | main.rs:50:1:69:1 | fn h |
|
||||
| main.rs:191:5:191:6 | m1 | main.rs:13:1:37:1 | mod m1 |
|
||||
| main.rs:191:5:191:10 | ...::m2 | main.rs:18:5:36:5 | mod m2 |
|
||||
| main.rs:191:5:191:13 | ...::g | main.rs:23:9:27:9 | fn g |
|
||||
| main.rs:192:5:192:6 | m1 | main.rs:13:1:37:1 | mod m1 |
|
||||
| main.rs:192:5:192:10 | ...::m2 | main.rs:18:5:36:5 | mod m2 |
|
||||
| main.rs:192:5:192:14 | ...::m3 | main.rs:29:9:35:9 | mod m3 |
|
||||
| main.rs:192:5:192:17 | ...::h | main.rs:30:27:34:13 | fn h |
|
||||
| main.rs:193:5:193:6 | m4 | main.rs:39:1:46:1 | mod m4 |
|
||||
| main.rs:193:5:193:9 | ...::i | main.rs:42:5:45:5 | fn i |
|
||||
| main.rs:194:5:194:5 | h | main.rs:50:1:69:1 | fn h |
|
||||
| main.rs:195:5:195:11 | f_alias | my2/nested2.rs:3:9:5:9 | fn f |
|
||||
| main.rs:196:5:196:11 | g_alias | my2/nested2.rs:7:9:9:9 | fn g |
|
||||
| main.rs:197:5:197:5 | j | main.rs:97:1:101:1 | fn j |
|
||||
| main.rs:198:5:198:6 | m6 | main.rs:109:1:120:1 | mod m6 |
|
||||
| main.rs:198:5:198:9 | ...::g | main.rs:114:5:119:5 | fn g |
|
||||
| main.rs:199:5:199:6 | m7 | main.rs:122:1:137:1 | mod m7 |
|
||||
| main.rs:199:5:199:9 | ...::f | main.rs:129:5:136:5 | fn f |
|
||||
| main.rs:200:5:200:6 | m8 | main.rs:139:1:182:1 | mod m8 |
|
||||
| main.rs:200:5:200:9 | ...::g | main.rs:169:5:181:5 | fn g |
|
||||
| my2/mod.rs:5:5:5:11 | nested2 | my2/mod.rs:1:1:1:16 | mod nested2 |
|
||||
| my2/mod.rs:5:5:5:20 | ...::nested3 | my2/nested2.rs:1:1:11:1 | mod nested3 |
|
||||
| my2/mod.rs:5:5:5:29 | ...::nested4 | my2/nested2.rs:2:5:10:5 | mod nested4 |
|
||||
| my2/mod.rs:5:5:5:32 | ...::f | my2/nested2.rs:3:9:5:9 | fn f |
|
||||
| my.rs:3:5:3:10 | nested | my.rs:1:1:1:15 | mod nested |
|
||||
| my.rs:3:5:3:13 | ...::g | my/nested.rs:19:1:22:1 | fn g |
|
||||
| my.rs:11:5:11:5 | g | my/nested.rs:19:1:22:1 | fn g |
|
||||
| my/nested.rs:9:13:9:13 | f | my/nested.rs:3:9:5:9 | fn f |
|
||||
| my/nested.rs:15:9:15:15 | nested2 | my/nested.rs:2:5:11:5 | mod nested2 |
|
||||
| my/nested.rs:15:9:15:18 | ...::f | my/nested.rs:3:9:5:9 | fn f |
|
||||
| my/nested.rs:21:5:21:11 | nested1 | my/nested.rs:1:1:17:1 | mod nested1 |
|
||||
| my/nested.rs:21:5:21:20 | ...::nested2 | my/nested.rs:2:5:11:5 | mod nested2 |
|
||||
| my/nested.rs:21:5:21:23 | ...::f | my/nested.rs:3:9:5:9 | fn f |
|
||||
49
rust/ql/test/library-tests/modules/modules.ql
Normal file
49
rust/ql/test/library-tests/modules/modules.ql
Normal file
@@ -0,0 +1,49 @@
|
||||
import rust
|
||||
import codeql.rust.elements.internal.PathResolution
|
||||
import utils.test.InlineExpectationsTest
|
||||
|
||||
query predicate mod(Module m) { any() }
|
||||
|
||||
query predicate resolvePath(Path p, ItemNode i) { i = resolvePath(p) }
|
||||
|
||||
module ResolveTest implements TestSig {
|
||||
string getARelevantTag() { result = "item" }
|
||||
|
||||
private predicate itemAt(ItemNode i, string filepath, int line, boolean inMacro) {
|
||||
i.getLocation().hasLocationInfo(filepath, _, _, line, _) and
|
||||
if i.isInMacroExpansion() then inMacro = true else inMacro = false
|
||||
}
|
||||
|
||||
private predicate commmentAt(string text, string filepath, int line) {
|
||||
exists(Comment c |
|
||||
c.getLocation().hasLocationInfo(filepath, line, _, _, _) and
|
||||
c.getCommentText() = text
|
||||
)
|
||||
}
|
||||
|
||||
private predicate item(ItemNode i, string value) {
|
||||
exists(string filepath, int line, boolean inMacro | itemAt(i, filepath, line, inMacro) |
|
||||
commmentAt(value, filepath, line) and
|
||||
inMacro = false
|
||||
or
|
||||
(
|
||||
not commmentAt(_, filepath, line)
|
||||
or
|
||||
inMacro = true
|
||||
) and
|
||||
value = i.getName()
|
||||
)
|
||||
}
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(Path p |
|
||||
not p = any(Path parent).getQualifier() and
|
||||
location = p.getLocation() and
|
||||
element = p.toString() and
|
||||
item(resolvePath(p), value) and
|
||||
tag = "item"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import MakeTest<ResolveTest>
|
||||
12
rust/ql/test/library-tests/modules/my.rs
Normal file
12
rust/ql/test/library-tests/modules/my.rs
Normal file
@@ -0,0 +1,12 @@
|
||||
pub mod nested; // I37
|
||||
|
||||
use nested::g; // $ item=I7
|
||||
|
||||
pub fn f() {
|
||||
println!("my.rs::f");
|
||||
} // I38
|
||||
|
||||
pub fn h() {
|
||||
println!("my.rs::h");
|
||||
g(); // $ item=I7
|
||||
} // I39
|
||||
22
rust/ql/test/library-tests/modules/my/nested.rs
Normal file
22
rust/ql/test/library-tests/modules/my/nested.rs
Normal file
@@ -0,0 +1,22 @@
|
||||
pub mod nested1 {
|
||||
pub mod nested2 {
|
||||
pub fn f() {
|
||||
println!("nested.rs:nested1::nested2::f");
|
||||
} // I4
|
||||
|
||||
fn g() {
|
||||
println!("nested.rs:nested1::nested2::g");
|
||||
f(); // $ item=I4
|
||||
} // I5
|
||||
} // I3
|
||||
|
||||
fn g() {
|
||||
println!("nested.rs:nested1::g");
|
||||
nested2::f(); // $ item=I4
|
||||
} // I6
|
||||
} // I1
|
||||
|
||||
pub fn g() {
|
||||
println!("nested.rs::g");
|
||||
nested1::nested2::f(); // $ item=I4
|
||||
} // I7
|
||||
6
rust/ql/test/library-tests/modules/my2/mod.rs
Normal file
6
rust/ql/test/library-tests/modules/my2/mod.rs
Normal file
@@ -0,0 +1,6 @@
|
||||
pub mod nested2; // I8
|
||||
|
||||
fn g() {
|
||||
println!("mod.rs::g");
|
||||
nested2::nested3::nested4::f(); // $ item=I12
|
||||
} // I9
|
||||
11
rust/ql/test/library-tests/modules/my2/nested2.rs
Normal file
11
rust/ql/test/library-tests/modules/my2/nested2.rs
Normal file
@@ -0,0 +1,11 @@
|
||||
pub mod nested3 {
|
||||
pub mod nested4 {
|
||||
pub fn f() {
|
||||
println!("nested2.rs::nested3::nested4::f");
|
||||
} // I12
|
||||
|
||||
pub fn g() {
|
||||
println!("nested2.rs::nested3::nested4::g");
|
||||
} // I13
|
||||
} // I11
|
||||
} // I10
|
||||
@@ -1,6 +1,7 @@
|
||||
| Multiple children | 0 |
|
||||
| Multiple locations | 0 |
|
||||
| Multiple parents | 0 |
|
||||
| Multiple path resolutions | 0 |
|
||||
| Multiple positions | 0 |
|
||||
| Multiple primary QL classes | 0 |
|
||||
| Multiple toStrings | 0 |
|
||||
|
||||
@@ -1,44 +1,49 @@
|
||||
#select
|
||||
| test.rs:31:9:31:25 | ...::stdout(...) | test.rs:29:1:29:13 | Attr | test.rs:31:9:31:25 | ...::stdout(...) | Call to ...::stdout(...) in a function with the ctor attribute. |
|
||||
| test.rs:36:9:36:25 | ...::stdout(...) | test.rs:34:1:34:13 | Attr | test.rs:36:9:36:25 | ...::stdout(...) | Call to ...::stdout(...) in a function with the dtor attribute. |
|
||||
| test.rs:43:9:43:25 | ...::stdout(...) | test.rs:40:1:40:13 | Attr | test.rs:43:9:43:25 | ...::stdout(...) | Call to ...::stdout(...) in a function with the dtor attribute. |
|
||||
| test.rs:53:9:53:16 | stdout(...) | test.rs:51:1:51:7 | Attr | test.rs:53:9:53:16 | stdout(...) | Call to stdout(...) in a function with the ctor attribute. |
|
||||
| test.rs:58:9:58:16 | stderr(...) | test.rs:56:1:56:7 | Attr | test.rs:58:9:58:16 | stderr(...) | Call to stderr(...) in a function with the ctor attribute. |
|
||||
| test.rs:63:14:63:28 | ...::_print(...) | test.rs:61:1:61:7 | Attr | test.rs:63:14:63:28 | ...::_print(...) | Call to ...::_print(...) in a function with the ctor attribute. |
|
||||
| test.rs:69:9:69:24 | ...::stdin(...) | test.rs:66:1:66:7 | Attr | test.rs:69:9:69:24 | ...::stdin(...) | Call to ...::stdin(...) in a function with the ctor attribute. |
|
||||
| test.rs:90:5:90:35 | ...::sleep(...) | test.rs:88:1:88:7 | Attr | test.rs:90:5:90:35 | ...::sleep(...) | Call to ...::sleep(...) in a function with the ctor attribute. |
|
||||
| test.rs:97:5:97:23 | ...::exit(...) | test.rs:95:1:95:7 | Attr | test.rs:97:5:97:23 | ...::exit(...) | Call to ...::exit(...) in a function with the ctor attribute. |
|
||||
| test.rs:126:9:126:16 | stderr(...) | test.rs:129:1:129:7 | Attr | test.rs:126:9:126:16 | stderr(...) | Call to stderr(...) in a function with the ctor attribute. |
|
||||
| test.rs:126:9:126:16 | stderr(...) | test.rs:145:1:145:7 | Attr | test.rs:126:9:126:16 | stderr(...) | Call to stderr(...) in a function with the ctor attribute. |
|
||||
| test.rs:126:9:126:44 | ... .write_all(...) | test.rs:129:1:129:7 | Attr | test.rs:126:9:126:44 | ... .write_all(...) | Call to ... .write_all(...) in a function with the ctor attribute. |
|
||||
| test.rs:126:9:126:44 | ... .write_all(...) | test.rs:145:1:145:7 | Attr | test.rs:126:9:126:44 | ... .write_all(...) | Call to ... .write_all(...) in a function with the ctor attribute. |
|
||||
| test.rs:171:5:171:15 | ...::stdout(...) | test.rs:169:1:169:7 | Attr | test.rs:171:5:171:15 | ...::stdout(...) | Call to ...::stdout(...) in a function with the ctor attribute. |
|
||||
| test.rs:30:9:30:25 | ...::stdout(...) | test.rs:28:1:28:13 | Attr | test.rs:30:9:30:25 | ...::stdout(...) | Call to ...::stdout(...) in a function with the ctor attribute. |
|
||||
| test.rs:35:9:35:25 | ...::stdout(...) | test.rs:33:1:33:13 | Attr | test.rs:35:9:35:25 | ...::stdout(...) | Call to ...::stdout(...) in a function with the dtor attribute. |
|
||||
| test.rs:42:9:42:25 | ...::stdout(...) | test.rs:39:1:39:13 | Attr | test.rs:42:9:42:25 | ...::stdout(...) | Call to ...::stdout(...) in a function with the dtor attribute. |
|
||||
| test.rs:52:9:52:16 | stdout(...) | test.rs:50:1:50:7 | Attr | test.rs:52:9:52:16 | stdout(...) | Call to stdout(...) in a function with the ctor attribute. |
|
||||
| test.rs:57:9:57:16 | stderr(...) | test.rs:55:1:55:7 | Attr | test.rs:57:9:57:16 | stderr(...) | Call to stderr(...) in a function with the ctor attribute. |
|
||||
| test.rs:62:14:62:28 | ...::_print(...) | test.rs:60:1:60:7 | Attr | test.rs:62:14:62:28 | ...::_print(...) | Call to ...::_print(...) in a function with the ctor attribute. |
|
||||
| test.rs:68:9:68:24 | ...::stdin(...) | test.rs:65:1:65:7 | Attr | test.rs:68:9:68:24 | ...::stdin(...) | Call to ...::stdin(...) in a function with the ctor attribute. |
|
||||
| test.rs:89:5:89:35 | ...::sleep(...) | test.rs:87:1:87:7 | Attr | test.rs:89:5:89:35 | ...::sleep(...) | Call to ...::sleep(...) in a function with the ctor attribute. |
|
||||
| test.rs:96:5:96:23 | ...::exit(...) | test.rs:94:1:94:7 | Attr | test.rs:96:5:96:23 | ...::exit(...) | Call to ...::exit(...) in a function with the ctor attribute. |
|
||||
| test.rs:125:9:125:16 | stderr(...) | test.rs:128:1:128:7 | Attr | test.rs:125:9:125:16 | stderr(...) | Call to stderr(...) in a function with the ctor attribute. |
|
||||
| test.rs:125:9:125:16 | stderr(...) | test.rs:144:1:144:7 | Attr | test.rs:125:9:125:16 | stderr(...) | Call to stderr(...) in a function with the ctor attribute. |
|
||||
| test.rs:125:9:125:16 | stderr(...) | test.rs:150:1:150:7 | Attr | test.rs:125:9:125:16 | stderr(...) | Call to stderr(...) in a function with the ctor attribute. |
|
||||
| test.rs:125:9:125:44 | ... .write_all(...) | test.rs:128:1:128:7 | Attr | test.rs:125:9:125:44 | ... .write_all(...) | Call to ... .write_all(...) in a function with the ctor attribute. |
|
||||
| test.rs:125:9:125:44 | ... .write_all(...) | test.rs:144:1:144:7 | Attr | test.rs:125:9:125:44 | ... .write_all(...) | Call to ... .write_all(...) in a function with the ctor attribute. |
|
||||
| test.rs:125:9:125:44 | ... .write_all(...) | test.rs:150:1:150:7 | Attr | test.rs:125:9:125:44 | ... .write_all(...) | Call to ... .write_all(...) in a function with the ctor attribute. |
|
||||
| test.rs:170:5:170:15 | ...::stdout(...) | test.rs:168:1:168:7 | Attr | test.rs:170:5:170:15 | ...::stdout(...) | Call to ...::stdout(...) in a function with the ctor attribute. |
|
||||
edges
|
||||
| test.rs:29:1:29:13 | Attr | test.rs:29:1:32:1 | fn bad1_1 |
|
||||
| test.rs:29:1:32:1 | fn bad1_1 | test.rs:31:9:31:25 | ...::stdout(...) |
|
||||
| test.rs:34:1:34:13 | Attr | test.rs:34:1:37:1 | fn bad1_2 |
|
||||
| test.rs:34:1:37:1 | fn bad1_2 | test.rs:36:9:36:25 | ...::stdout(...) |
|
||||
| test.rs:39:1:44:1 | fn bad1_3 | test.rs:43:9:43:25 | ...::stdout(...) |
|
||||
| test.rs:40:1:40:13 | Attr | test.rs:39:1:44:1 | fn bad1_3 |
|
||||
| test.rs:51:1:51:7 | Attr | test.rs:51:1:54:1 | fn bad2_1 |
|
||||
| test.rs:51:1:54:1 | fn bad2_1 | test.rs:53:9:53:16 | stdout(...) |
|
||||
| test.rs:56:1:56:7 | Attr | test.rs:56:1:59:1 | fn bad2_2 |
|
||||
| test.rs:56:1:59:1 | fn bad2_2 | test.rs:58:9:58:16 | stderr(...) |
|
||||
| test.rs:61:1:61:7 | Attr | test.rs:61:1:64:1 | fn bad2_3 |
|
||||
| test.rs:61:1:64:1 | fn bad2_3 | test.rs:63:14:63:28 | ...::_print(...) |
|
||||
| test.rs:66:1:66:7 | Attr | test.rs:66:1:70:1 | fn bad2_4 |
|
||||
| test.rs:66:1:70:1 | fn bad2_4 | test.rs:69:9:69:24 | ...::stdin(...) |
|
||||
| test.rs:88:1:88:7 | Attr | test.rs:88:1:91:1 | fn bad2_7 |
|
||||
| test.rs:88:1:91:1 | fn bad2_7 | test.rs:90:5:90:35 | ...::sleep(...) |
|
||||
| test.rs:95:1:95:7 | Attr | test.rs:95:1:98:1 | fn bad2_8 |
|
||||
| test.rs:95:1:98:1 | fn bad2_8 | test.rs:97:5:97:23 | ...::exit(...) |
|
||||
| test.rs:125:1:127:1 | fn call_target3_1 | test.rs:126:9:126:16 | stderr(...) |
|
||||
| test.rs:125:1:127:1 | fn call_target3_1 | test.rs:126:9:126:44 | ... .write_all(...) |
|
||||
| test.rs:129:1:129:7 | Attr | test.rs:129:1:132:1 | fn bad3_1 |
|
||||
| test.rs:129:1:132:1 | fn bad3_1 | test.rs:131:5:131:20 | call_target3_1(...) |
|
||||
| test.rs:131:5:131:20 | call_target3_1(...) | test.rs:125:1:127:1 | fn call_target3_1 |
|
||||
| test.rs:145:1:145:7 | Attr | test.rs:145:1:149:1 | fn bad3_3 |
|
||||
| test.rs:145:1:149:1 | fn bad3_3 | test.rs:147:5:147:20 | call_target3_1(...) |
|
||||
| test.rs:147:5:147:20 | call_target3_1(...) | test.rs:125:1:127:1 | fn call_target3_1 |
|
||||
| test.rs:169:1:169:7 | Attr | test.rs:169:1:172:1 | fn bad4_1 |
|
||||
| test.rs:169:1:172:1 | fn bad4_1 | test.rs:171:5:171:15 | ...::stdout(...) |
|
||||
| test.rs:28:1:28:13 | Attr | test.rs:28:1:31:1 | fn bad1_1 |
|
||||
| test.rs:28:1:31:1 | fn bad1_1 | test.rs:30:9:30:25 | ...::stdout(...) |
|
||||
| test.rs:33:1:33:13 | Attr | test.rs:33:1:36:1 | fn bad1_2 |
|
||||
| test.rs:33:1:36:1 | fn bad1_2 | test.rs:35:9:35:25 | ...::stdout(...) |
|
||||
| test.rs:38:1:43:1 | fn bad1_3 | test.rs:42:9:42:25 | ...::stdout(...) |
|
||||
| test.rs:39:1:39:13 | Attr | test.rs:38:1:43:1 | fn bad1_3 |
|
||||
| test.rs:50:1:50:7 | Attr | test.rs:50:1:53:1 | fn bad2_1 |
|
||||
| test.rs:50:1:53:1 | fn bad2_1 | test.rs:52:9:52:16 | stdout(...) |
|
||||
| test.rs:55:1:55:7 | Attr | test.rs:55:1:58:1 | fn bad2_2 |
|
||||
| test.rs:55:1:58:1 | fn bad2_2 | test.rs:57:9:57:16 | stderr(...) |
|
||||
| test.rs:60:1:60:7 | Attr | test.rs:60:1:63:1 | fn bad2_3 |
|
||||
| test.rs:60:1:63:1 | fn bad2_3 | test.rs:62:14:62:28 | ...::_print(...) |
|
||||
| test.rs:65:1:65:7 | Attr | test.rs:65:1:69:1 | fn bad2_4 |
|
||||
| test.rs:65:1:69:1 | fn bad2_4 | test.rs:68:9:68:24 | ...::stdin(...) |
|
||||
| test.rs:87:1:87:7 | Attr | test.rs:87:1:90:1 | fn bad2_7 |
|
||||
| test.rs:87:1:90:1 | fn bad2_7 | test.rs:89:5:89:35 | ...::sleep(...) |
|
||||
| test.rs:94:1:94:7 | Attr | test.rs:94:1:97:1 | fn bad2_8 |
|
||||
| test.rs:94:1:97:1 | fn bad2_8 | test.rs:96:5:96:23 | ...::exit(...) |
|
||||
| test.rs:124:1:126:1 | fn call_target3_1 | test.rs:125:9:125:16 | stderr(...) |
|
||||
| test.rs:124:1:126:1 | fn call_target3_1 | test.rs:125:9:125:44 | ... .write_all(...) |
|
||||
| test.rs:128:1:128:7 | Attr | test.rs:128:1:131:1 | fn bad3_1 |
|
||||
| test.rs:128:1:131:1 | fn bad3_1 | test.rs:130:5:130:20 | call_target3_1(...) |
|
||||
| test.rs:130:5:130:20 | call_target3_1(...) | test.rs:124:1:126:1 | fn call_target3_1 |
|
||||
| test.rs:144:1:144:7 | Attr | test.rs:144:1:148:1 | fn bad3_3 |
|
||||
| test.rs:144:1:148:1 | fn bad3_3 | test.rs:146:5:146:20 | call_target3_1(...) |
|
||||
| test.rs:146:5:146:20 | call_target3_1(...) | test.rs:124:1:126:1 | fn call_target3_1 |
|
||||
| test.rs:150:1:150:7 | Attr | test.rs:150:1:153:1 | fn bad3_4 |
|
||||
| test.rs:150:1:153:1 | fn bad3_4 | test.rs:152:5:152:12 | bad3_3(...) |
|
||||
| test.rs:152:5:152:12 | bad3_3(...) | test.rs:144:1:148:1 | fn bad3_3 |
|
||||
| test.rs:168:1:168:7 | Attr | test.rs:168:1:171:1 | fn bad4_1 |
|
||||
| test.rs:168:1:171:1 | fn bad4_1 | test.rs:170:5:170:15 | ...::stdout(...) |
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
// --- attribute variants ---
|
||||
|
||||
use std::io::Write;
|
||||
@@ -123,7 +122,7 @@ unsafe fn harmless2_11() {
|
||||
// --- transitive cases ---
|
||||
|
||||
fn call_target3_1() {
|
||||
_ = stderr().write_all(b"Hello, world!"); // $ Alert=source3_1 Alert=source3_3 MISSING: Alert=source3_4
|
||||
_ = stderr().write_all(b"Hello, world!"); // $ Alert=source3_1 Alert=source3_3 Alert=source3_4
|
||||
}
|
||||
|
||||
#[ctor] // $ Source=source3_1
|
||||
@@ -148,7 +147,7 @@ fn bad3_3() {
|
||||
call_target3_2();
|
||||
}
|
||||
|
||||
#[ctor] // $ MISSING: Source=source3_4
|
||||
#[ctor] // $ Source=source3_4
|
||||
fn bad3_4() {
|
||||
bad3_3();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user