mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
Rust: add proc-macro capabilities to QL tests
This adds the possibility to add a special `proc_macro.rs` source file to QL tests, which will be generated into a `proc_macro` crate the usual `lib` crate depends on. This allow to define procedural macros in QL tests, and is here used to move the `macro-expansion` integration test to be a language test instead. As the generated manifests involved were starting to get a bit complex, they are now generated from a `mustache` template.
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -426,6 +426,7 @@ dependencies = [
|
|||||||
"figment",
|
"figment",
|
||||||
"glob",
|
"glob",
|
||||||
"itertools 0.14.0",
|
"itertools 0.14.0",
|
||||||
|
"mustache",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"ra_ap_base_db",
|
"ra_ap_base_db",
|
||||||
"ra_ap_cfg",
|
"ra_ap_cfg",
|
||||||
|
|||||||
1
misc/bazel/3rdparty/tree_sitter_extractors_deps/defs.bzl
generated
vendored
1
misc/bazel/3rdparty/tree_sitter_extractors_deps/defs.bzl
generated
vendored
@@ -334,6 +334,7 @@ _NORMAL_DEPENDENCIES = {
|
|||||||
"figment": Label("@vendor_ts__figment-0.10.19//:figment"),
|
"figment": Label("@vendor_ts__figment-0.10.19//:figment"),
|
||||||
"glob": Label("@vendor_ts__glob-0.3.2//:glob"),
|
"glob": Label("@vendor_ts__glob-0.3.2//:glob"),
|
||||||
"itertools": Label("@vendor_ts__itertools-0.14.0//:itertools"),
|
"itertools": Label("@vendor_ts__itertools-0.14.0//:itertools"),
|
||||||
|
"mustache": Label("@vendor_ts__mustache-0.9.0//:mustache"),
|
||||||
"num-traits": Label("@vendor_ts__num-traits-0.2.19//:num_traits"),
|
"num-traits": Label("@vendor_ts__num-traits-0.2.19//:num_traits"),
|
||||||
"ra_ap_base_db": Label("@vendor_ts__ra_ap_base_db-0.0.273//:ra_ap_base_db"),
|
"ra_ap_base_db": Label("@vendor_ts__ra_ap_base_db-0.0.273//:ra_ap_base_db"),
|
||||||
"ra_ap_cfg": Label("@vendor_ts__ra_ap_cfg-0.0.273//:ra_ap_cfg"),
|
"ra_ap_cfg": Label("@vendor_ts__ra_ap_cfg-0.0.273//:ra_ap_cfg"),
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ codeql_rust_binary(
|
|||||||
name = "extractor",
|
name = "extractor",
|
||||||
srcs = glob(["src/**/*.rs"]),
|
srcs = glob(["src/**/*.rs"]),
|
||||||
aliases = aliases(),
|
aliases = aliases(),
|
||||||
|
compile_data = ["src/qltest_cargo.mustache"],
|
||||||
proc_macro_deps = all_crate_deps(
|
proc_macro_deps = all_crate_deps(
|
||||||
proc_macro = True,
|
proc_macro = True,
|
||||||
) + [
|
) + [
|
||||||
|
|||||||
@@ -41,3 +41,4 @@ tracing = "0.1.41"
|
|||||||
tracing-flame = "0.2.0"
|
tracing-flame = "0.2.0"
|
||||||
tracing-subscriber = "0.3.19"
|
tracing-subscriber = "0.3.19"
|
||||||
chalk-ir = "0.100.0"
|
chalk-ir = "0.100.0"
|
||||||
|
mustache = "0.9.0"
|
||||||
|
|||||||
@@ -16,39 +16,54 @@ fn dump_lib() -> anyhow::Result<()> {
|
|||||||
let lib = paths
|
let lib = paths
|
||||||
.iter()
|
.iter()
|
||||||
.map(|p| p.file_stem().expect("results of glob must have a name"))
|
.map(|p| p.file_stem().expect("results of glob must have a name"))
|
||||||
.filter(|&p| !["main", "lib"].map(OsStr::new).contains(&p))
|
.filter(|&p| !["main", "lib", "proc_macro"].map(OsStr::new).contains(&p))
|
||||||
.map(|p| format!("mod {};", p.to_string_lossy()))
|
.map(|p| format!("mod {};", p.to_string_lossy()))
|
||||||
.join("\n");
|
.join("\n");
|
||||||
fs::write("lib.rs", lib).context("writing lib.rs")
|
fs::write("lib.rs", lib).context("writing lib.rs")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Serialize)]
|
||||||
|
enum TestCargoManifest<'a> {
|
||||||
|
Workspace {},
|
||||||
|
Lib {
|
||||||
|
uses_proc_macro: bool,
|
||||||
|
uses_main: bool,
|
||||||
|
dependencies: &'a [String],
|
||||||
|
},
|
||||||
|
Macro {},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestCargoManifest<'_> {
|
||||||
|
pub fn dump(&self, path: impl AsRef<Path>) -> anyhow::Result<()> {
|
||||||
|
static TEMPLATE: std::sync::LazyLock<mustache::Template> = std::sync::LazyLock::new(|| {
|
||||||
|
mustache::compile_str(include_str!("qltest_cargo.mustache"))
|
||||||
|
.expect("compiling template")
|
||||||
|
});
|
||||||
|
|
||||||
|
let path = path.as_ref();
|
||||||
|
fs::create_dir_all(path).with_context(|| format!("creating {}", path.display()))?;
|
||||||
|
let path = path.join("Cargo.toml");
|
||||||
|
let rendered = TEMPLATE
|
||||||
|
.render_to_string(&self)
|
||||||
|
.with_context(|| format!("rendering {}", path.display()))?;
|
||||||
|
fs::write(&path, rendered).with_context(|| format!("writing {}", path.display()))
|
||||||
|
}
|
||||||
|
}
|
||||||
fn dump_cargo_manifest(dependencies: &[String]) -> anyhow::Result<()> {
|
fn dump_cargo_manifest(dependencies: &[String]) -> anyhow::Result<()> {
|
||||||
let mut manifest = String::from(
|
let uses_proc_macro =
|
||||||
r#"[workspace]
|
fs::exists("proc_macro.rs").context("checking existence of proc_macro.rs")?;
|
||||||
[package]
|
let lib_manifest = TestCargoManifest::Lib {
|
||||||
name = "test"
|
uses_proc_macro,
|
||||||
version="0.0.1"
|
uses_main: fs::exists("main.rs").context("checking existence of main.rs")?,
|
||||||
edition="2021"
|
dependencies,
|
||||||
[lib]
|
};
|
||||||
path="lib.rs"
|
if uses_proc_macro {
|
||||||
"#,
|
TestCargoManifest::Workspace {}.dump("")?;
|
||||||
);
|
lib_manifest.dump(".lib")?;
|
||||||
if fs::exists("main.rs").context("checking existence of main.rs")? {
|
TestCargoManifest::Macro {}.dump(".proc_macro")
|
||||||
manifest.push_str(
|
} else {
|
||||||
r#"[[bin]]
|
lib_manifest.dump("")
|
||||||
name = "main"
|
|
||||||
path = "main.rs"
|
|
||||||
"#,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if !dependencies.is_empty() {
|
|
||||||
manifest.push_str("[dependencies]\n");
|
|
||||||
for dep in dependencies {
|
|
||||||
manifest.push_str(dep);
|
|
||||||
manifest.push('\n');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fs::write("Cargo.toml", manifest).context("writing Cargo.toml")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_sources(config: &mut Config) -> anyhow::Result<()> {
|
fn set_sources(config: &mut Config) -> anyhow::Result<()> {
|
||||||
|
|||||||
42
rust/extractor/src/qltest_cargo.mustache
Normal file
42
rust/extractor/src/qltest_cargo.mustache
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
{{#Workspace}}
|
||||||
|
[workspace]
|
||||||
|
resolver = "2"
|
||||||
|
members = [".lib", ".proc_macro"]
|
||||||
|
{{/Workspace}}
|
||||||
|
|
||||||
|
{{#Lib}}
|
||||||
|
{{^uses_proc_macro}}
|
||||||
|
[workspace]
|
||||||
|
{{/uses_proc_macro}}
|
||||||
|
[package]
|
||||||
|
name = "test"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
[lib]
|
||||||
|
path = "{{#uses_proc_macro}}../{{/uses_proc_macro}}lib.rs"
|
||||||
|
{{#uses_main}}
|
||||||
|
[[bin]]
|
||||||
|
name = "main"
|
||||||
|
path = "{{#uses_proc_macro}}../{{/uses_proc_macro}}main.rs"
|
||||||
|
{{/uses_main}}
|
||||||
|
[dependencies]
|
||||||
|
{{#uses_proc_macro}}
|
||||||
|
proc_macro = { path = "../.proc_macro" }
|
||||||
|
{{/uses_proc_macro}}
|
||||||
|
{{#dependencies}}
|
||||||
|
{{.}}
|
||||||
|
{{/dependencies}}
|
||||||
|
{{/Lib}}
|
||||||
|
|
||||||
|
{{#Macro}}
|
||||||
|
[package]
|
||||||
|
name = "proc_macro"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
[lib]
|
||||||
|
path = "../proc_macro.rs"
|
||||||
|
proc_macro = true
|
||||||
|
[dependencies]
|
||||||
|
quote = "1.0.40"
|
||||||
|
syn = { version = "2.0.100", features = ["full"] }
|
||||||
|
{{/Macro}}
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
[workspace]
|
|
||||||
members = [ "attributes", "calls", "proc_macros"]
|
|
||||||
resolver = "2"
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "attributes"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2024"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
proc_macros = { path = "../proc_macros" }
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
use proc_macros::repeat;
|
|
||||||
|
|
||||||
#[repeat(3)]
|
|
||||||
fn foo() {
|
|
||||||
_ = concat!("Hello ", "world!");
|
|
||||||
|
|
||||||
#[repeat(2)]
|
|
||||||
fn inner() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repeat(2)]
|
|
||||||
#[repeat(3)]
|
|
||||||
fn bar() {}
|
|
||||||
|
|
||||||
#[repeat(0)]
|
|
||||||
fn baz() {}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "calls"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2024"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
struct S;
|
|
||||||
|
|
||||||
macro_rules! def_x {
|
|
||||||
() => {
|
|
||||||
fn x() {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
impl S {
|
|
||||||
def_x!(); // this doesn't expand since 0.0.274
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! my_macro {
|
|
||||||
($head:expr, $($tail:tt)*) => { format!($head, $($tail)*) };
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn test() {
|
|
||||||
_ = concat!("x", "y");
|
|
||||||
|
|
||||||
_ = my_macro!(
|
|
||||||
concat!("<", "{}", ">"), // this doesn't expand since 0.0.274
|
|
||||||
"hi",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
include!("included.rs");
|
|
||||||
|
|
||||||
#[doc = include_str!("some.txt")] // this doesn't expand since 0.0.274
|
|
||||||
fn documented() {}
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
{
|
|
||||||
"attributes": {
|
|
||||||
"durations": {
|
|
||||||
"crateGraph": {
|
|
||||||
"ms": "__REDACTED__",
|
|
||||||
"pretty": "__REDACTED__"
|
|
||||||
},
|
|
||||||
"extract": {
|
|
||||||
"ms": "__REDACTED__",
|
|
||||||
"pretty": "__REDACTED__"
|
|
||||||
},
|
|
||||||
"extractLibrary": {
|
|
||||||
"ms": "__REDACTED__",
|
|
||||||
"pretty": "__REDACTED__"
|
|
||||||
},
|
|
||||||
"findManifests": {
|
|
||||||
"ms": "__REDACTED__",
|
|
||||||
"pretty": "__REDACTED__"
|
|
||||||
},
|
|
||||||
"loadManifest": {
|
|
||||||
"ms": "__REDACTED__",
|
|
||||||
"pretty": "__REDACTED__"
|
|
||||||
},
|
|
||||||
"loadSource": {
|
|
||||||
"ms": "__REDACTED__",
|
|
||||||
"pretty": "__REDACTED__"
|
|
||||||
},
|
|
||||||
"parse": {
|
|
||||||
"ms": "__REDACTED__",
|
|
||||||
"pretty": "__REDACTED__"
|
|
||||||
},
|
|
||||||
"parseLibrary": {
|
|
||||||
"ms": "__REDACTED__",
|
|
||||||
"pretty": "__REDACTED__"
|
|
||||||
},
|
|
||||||
"total": {
|
|
||||||
"ms": "__REDACTED__",
|
|
||||||
"pretty": "__REDACTED__"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"numberOfFiles": 4,
|
|
||||||
"numberOfManifests": 1
|
|
||||||
},
|
|
||||||
"severity": "note",
|
|
||||||
"source": {
|
|
||||||
"extractorName": "rust",
|
|
||||||
"id": "rust/extractor/telemetry",
|
|
||||||
"name": "telemetry"
|
|
||||||
},
|
|
||||||
"visibility": {
|
|
||||||
"cliSummaryTable": false,
|
|
||||||
"statusPage": false,
|
|
||||||
"telemetry": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "proc_macros"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2024"
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
proc-macro = true
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
quote = "1.0.40"
|
|
||||||
syn = { version = "2.0.100", features = ["full"] }
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
attributes/src/lib.rs
|
|
||||||
calls/src/included.rs
|
|
||||||
calls/src/lib.rs
|
|
||||||
proc_macros/src/lib.rs
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
attribute_macros
|
|
||||||
| attributes/src/lib.rs:3:1:9:1 | fn foo | 0 | attributes/src/lib.rs:4:1:8:16 | fn foo_0 |
|
|
||||||
| attributes/src/lib.rs:3:1:9:1 | fn foo | 1 | attributes/src/lib.rs:4:1:8:16 | fn foo_1 |
|
|
||||||
| attributes/src/lib.rs:3:1:9:1 | fn foo | 2 | attributes/src/lib.rs:4:1:8:16 | fn foo_2 |
|
|
||||||
| attributes/src/lib.rs:7:5:8:16 | fn inner | 0 | attributes/src/lib.rs:8:5:8:16 | fn inner_0 |
|
|
||||||
| attributes/src/lib.rs:7:5:8:16 | fn inner | 0 | attributes/src/lib.rs:8:5:8:16 | fn inner_0 |
|
|
||||||
| attributes/src/lib.rs:7:5:8:16 | fn inner | 0 | attributes/src/lib.rs:8:5:8:16 | fn inner_0 |
|
|
||||||
| attributes/src/lib.rs:7:5:8:16 | fn inner | 1 | attributes/src/lib.rs:8:5:8:16 | fn inner_1 |
|
|
||||||
| attributes/src/lib.rs:7:5:8:16 | fn inner | 1 | attributes/src/lib.rs:8:5:8:16 | fn inner_1 |
|
|
||||||
| attributes/src/lib.rs:7:5:8:16 | fn inner | 1 | attributes/src/lib.rs:8:5:8:16 | fn inner_1 |
|
|
||||||
| attributes/src/lib.rs:11:1:13:11 | fn bar | 0 | attributes/src/lib.rs:12:1:13:10 | fn bar_0 |
|
|
||||||
| attributes/src/lib.rs:11:1:13:11 | fn bar | 1 | attributes/src/lib.rs:12:1:13:10 | fn bar_1 |
|
|
||||||
| attributes/src/lib.rs:12:1:13:10 | fn bar_0 | 0 | attributes/src/lib.rs:13:1:13:10 | fn bar_0_0 |
|
|
||||||
| attributes/src/lib.rs:12:1:13:10 | fn bar_0 | 1 | attributes/src/lib.rs:13:1:13:10 | fn bar_0_1 |
|
|
||||||
| attributes/src/lib.rs:12:1:13:10 | fn bar_0 | 2 | attributes/src/lib.rs:13:1:13:10 | fn bar_0_2 |
|
|
||||||
| attributes/src/lib.rs:12:1:13:10 | fn bar_1 | 0 | attributes/src/lib.rs:13:1:13:10 | fn bar_1_0 |
|
|
||||||
| attributes/src/lib.rs:12:1:13:10 | fn bar_1 | 1 | attributes/src/lib.rs:13:1:13:10 | fn bar_1_1 |
|
|
||||||
| attributes/src/lib.rs:12:1:13:10 | fn bar_1 | 2 | attributes/src/lib.rs:13:1:13:10 | fn bar_1_2 |
|
|
||||||
macro_calls
|
|
||||||
| attributes/src/lib.rs:5:9:5:34 | concat!... | attributes/src/lib.rs:5:17:5:34 | "Hello world!" |
|
|
||||||
| attributes/src/lib.rs:5:9:5:34 | concat!... | attributes/src/lib.rs:5:17:5:34 | "Hello world!" |
|
|
||||||
| attributes/src/lib.rs:5:9:5:34 | concat!... | attributes/src/lib.rs:5:17:5:34 | "Hello world!" |
|
|
||||||
| calls/src/included.rs:2:9:2:39 | concat!... | calls/src/included.rs:2:17:2:38 | "Hello world!" |
|
|
||||||
| calls/src/lib.rs:10:5:10:13 | def_x!... | calls/src/lib.rs:10:5:10:13 | MacroItems |
|
|
||||||
| calls/src/lib.rs:19:9:19:25 | concat!... | calls/src/lib.rs:19:17:19:24 | "xy" |
|
|
||||||
| calls/src/lib.rs:21:9:24:5 | my_macro!... | calls/src/lib.rs:22:9:23:13 | MacroExpr |
|
|
||||||
| calls/src/lib.rs:22:9:22:31 | concat!... | calls/src/lib.rs:22:17:22:30 | "<{}>" |
|
|
||||||
| calls/src/lib.rs:22:9:23:13 | ...::format_args!... | calls/src/lib.rs:22:9:23:13 | FormatArgsExpr |
|
|
||||||
| calls/src/lib.rs:22:9:23:13 | format!... | calls/src/lib.rs:22:9:23:13 | ...::must_use(...) |
|
|
||||||
| calls/src/lib.rs:27:1:27:24 | concat!... | calls/src/lib.rs:27:1:27:24 | "Hello world!" |
|
|
||||||
| calls/src/lib.rs:27:1:27:24 | include!... | calls/src/lib.rs:27:1:27:24 | MacroItems |
|
|
||||||
| calls/src/lib.rs:29:9:29:32 | include_str!... | calls/src/lib.rs:29:22:29:31 | "" |
|
|
||||||
unexpanded_macro_calls
|
|
||||||
| attributes/src/lib.rs:5:9:5:35 | concat!... |
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
def test_macro_expansion(codeql, rust, check_source_archive, rust_check_diagnostics):
|
|
||||||
codeql.database.create()
|
|
||||||
3
rust/ql/test/.gitignore
vendored
3
rust/ql/test/.gitignore
vendored
@@ -1,3 +1,6 @@
|
|||||||
Cargo.toml
|
Cargo.toml
|
||||||
lib.rs
|
lib.rs
|
||||||
target/
|
target/
|
||||||
|
.proc_macro/
|
||||||
|
.lib/
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
multiplePathResolutions
|
||||||
|
| macro_expansion.rs:1:5:1:14 | proc_macro | file://:0:0:0:0 | Crate(proc_macro@0.0.0) |
|
||||||
|
| macro_expansion.rs:1:5:1:14 | proc_macro | proc_macro.rs:0:0:0:0 | Crate(proc_macro@0.1.0) |
|
||||||
@@ -2,16 +2,6 @@
|
|||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 4
|
version = 4
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ctor"
|
|
||||||
version = "0.2.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501"
|
|
||||||
dependencies = [
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.95"
|
version = "1.0.95"
|
||||||
@@ -21,6 +11,14 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc_macro"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.40"
|
version = "1.0.40"
|
||||||
@@ -43,9 +41,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "test"
|
name = "test"
|
||||||
version = "0.0.1"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ctor",
|
"proc_macro",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
2174
rust/ql/test/extractor-tests/macro-expansion/PrintAst.expected
Normal file
2174
rust/ql/test/extractor-tests/macro-expansion/PrintAst.expected
Normal file
File diff suppressed because it is too large
Load Diff
14
rust/ql/test/extractor-tests/macro-expansion/call.rs
Normal file
14
rust/ql/test/extractor-tests/macro-expansion/call.rs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
use crate::macro_expansion;
|
||||||
|
|
||||||
|
fn call_some_functions() {
|
||||||
|
macro_expansion::foo();
|
||||||
|
macro_expansion::foo_new();
|
||||||
|
macro_expansion::bar_0();
|
||||||
|
macro_expansion::bar_1();
|
||||||
|
macro_expansion::bar_0_new();
|
||||||
|
macro_expansion::bar_1_new();
|
||||||
|
macro_expansion::S::bzz_0();
|
||||||
|
macro_expansion::S::bzz_1();
|
||||||
|
macro_expansion::S::bzz_2();
|
||||||
|
macro_expansion::S::x();
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
use proc_macro::{repeat, add_one, erase};
|
||||||
|
|
||||||
|
#[add_one]
|
||||||
|
pub fn foo() {
|
||||||
|
_ = concat!("Hello ", "world!");
|
||||||
|
|
||||||
|
#[repeat(2)]
|
||||||
|
fn inner() {}
|
||||||
|
|
||||||
|
inner_0();
|
||||||
|
inner_1();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repeat(2)]
|
||||||
|
#[add_one]
|
||||||
|
pub fn bar() {}
|
||||||
|
|
||||||
|
#[erase]
|
||||||
|
pub fn baz() {}
|
||||||
|
|
||||||
|
|
||||||
|
macro_rules! hello {
|
||||||
|
() => {
|
||||||
|
println!("hello!");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct S;
|
||||||
|
|
||||||
|
impl S {
|
||||||
|
#[repeat(3)]
|
||||||
|
pub fn bzz() {
|
||||||
|
hello!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! def_x {
|
||||||
|
() => {
|
||||||
|
pub fn x() {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl S {
|
||||||
|
def_x!(); // this doesn't expand since 0.0.274
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! my_macro {
|
||||||
|
($head:expr, $($tail:tt)*) => { format!($head, $($tail)*) };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn test() {
|
||||||
|
_ = concat!("x", "y");
|
||||||
|
|
||||||
|
_ = my_macro!(
|
||||||
|
concat!("<", "{}", ">"), // this doesn't expand since 0.0.274
|
||||||
|
"hi",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
include!("included/included.rs");
|
||||||
|
|
||||||
|
#[doc = include_str!("some.txt")] // this doesn't expand since 0.0.274
|
||||||
|
fn documented() {}
|
||||||
|
|
||||||
|
macro_rules! my_int {
|
||||||
|
() => { i32 };
|
||||||
|
}
|
||||||
|
|
||||||
|
fn answer() -> my_int!() { // this didn't expand in 0.0.274..0.0.287
|
||||||
|
let a: my_int!() = 42; // this is fine
|
||||||
|
a as my_int!() // this is fine too
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type MyInt = my_int!(); // this didn't expand in 0.0.274..0.0.287
|
||||||
|
|
||||||
|
struct MyStruct {
|
||||||
|
field: my_int!(), // this didn't expand in 0.0.274..0.0.287
|
||||||
|
}
|
||||||
@@ -16,3 +16,19 @@ pub fn repeat(attr: TokenStream, item: TokenStream) -> TokenStream {
|
|||||||
#(#items)*
|
#(#items)*
|
||||||
}.into()
|
}.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[proc_macro_attribute]
|
||||||
|
pub fn add_one(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
|
let ast = syn::parse_macro_input!(item as syn::ItemFn);
|
||||||
|
let mut new_ast = ast.clone();
|
||||||
|
new_ast.sig.ident = syn::Ident::new(&format!("{}_new", ast.sig.ident), ast.sig.ident.span());
|
||||||
|
quote! {
|
||||||
|
#ast
|
||||||
|
#new_ast
|
||||||
|
}.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proc_macro_attribute]
|
||||||
|
pub fn erase(_attr: TokenStream, _item: TokenStream) -> TokenStream {
|
||||||
|
TokenStream::new()
|
||||||
|
}
|
||||||
37
rust/ql/test/extractor-tests/macro-expansion/test.expected
Normal file
37
rust/ql/test/extractor-tests/macro-expansion/test.expected
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
attribute_macros
|
||||||
|
| macro_expansion.rs:3:1:12:1 | fn foo | 0 | macro_expansion.rs:4:1:11:14 | fn foo |
|
||||||
|
| macro_expansion.rs:3:1:12:1 | fn foo | 1 | macro_expansion.rs:4:1:11:14 | fn foo_new |
|
||||||
|
| macro_expansion.rs:7:5:8:16 | fn inner | 0 | macro_expansion.rs:8:5:8:16 | fn inner_0 |
|
||||||
|
| macro_expansion.rs:7:5:8:16 | fn inner | 0 | macro_expansion.rs:8:5:8:16 | fn inner_0 |
|
||||||
|
| macro_expansion.rs:7:5:8:16 | fn inner | 1 | macro_expansion.rs:8:5:8:16 | fn inner_1 |
|
||||||
|
| macro_expansion.rs:7:5:8:16 | fn inner | 1 | macro_expansion.rs:8:5:8:16 | fn inner_1 |
|
||||||
|
| macro_expansion.rs:14:1:16:15 | fn bar | 0 | macro_expansion.rs:15:1:16:14 | fn bar_0 |
|
||||||
|
| macro_expansion.rs:14:1:16:15 | fn bar | 1 | macro_expansion.rs:15:1:16:14 | fn bar_1 |
|
||||||
|
| macro_expansion.rs:15:1:16:14 | fn bar_0 | 0 | macro_expansion.rs:16:1:16:14 | fn bar_0 |
|
||||||
|
| macro_expansion.rs:15:1:16:14 | fn bar_0 | 1 | macro_expansion.rs:16:1:16:14 | fn bar_0_new |
|
||||||
|
| macro_expansion.rs:15:1:16:14 | fn bar_1 | 0 | macro_expansion.rs:16:1:16:14 | fn bar_1 |
|
||||||
|
| macro_expansion.rs:15:1:16:14 | fn bar_1 | 1 | macro_expansion.rs:16:1:16:14 | fn bar_1_new |
|
||||||
|
macro_calls
|
||||||
|
| included/included.rs:2:9:2:39 | concat!... | included/included.rs:2:17:2:38 | "Hello world!" |
|
||||||
|
| macro_expansion.rs:5:9:5:34 | concat!... | macro_expansion.rs:5:17:5:34 | "Hello world!" |
|
||||||
|
| macro_expansion.rs:5:9:5:34 | concat!... | macro_expansion.rs:5:17:5:34 | "Hello world!" |
|
||||||
|
| macro_expansion.rs:33:9:33:16 | ...::format_args_nl!... | macro_expansion.rs:33:9:33:16 | FormatArgsExpr |
|
||||||
|
| macro_expansion.rs:33:9:33:16 | hello!... | macro_expansion.rs:33:9:33:16 | MacroBlockExpr |
|
||||||
|
| macro_expansion.rs:33:9:33:16 | println!... | macro_expansion.rs:33:9:33:16 | MacroBlockExpr |
|
||||||
|
| macro_expansion.rs:44:5:44:13 | def_x!... | macro_expansion.rs:44:5:44:13 | MacroItems |
|
||||||
|
| macro_expansion.rs:53:9:53:25 | concat!... | macro_expansion.rs:53:17:53:24 | "xy" |
|
||||||
|
| macro_expansion.rs:55:9:58:5 | my_macro!... | macro_expansion.rs:56:9:57:13 | MacroExpr |
|
||||||
|
| macro_expansion.rs:56:9:56:31 | concat!... | macro_expansion.rs:56:17:56:30 | "<{}>" |
|
||||||
|
| macro_expansion.rs:56:9:57:13 | ...::format_args!... | macro_expansion.rs:56:9:57:13 | FormatArgsExpr |
|
||||||
|
| macro_expansion.rs:56:9:57:13 | format!... | macro_expansion.rs:56:9:57:13 | ...::must_use(...) |
|
||||||
|
| macro_expansion.rs:61:1:61:33 | concat!... | macro_expansion.rs:61:1:61:33 | "Hello world!" |
|
||||||
|
| macro_expansion.rs:61:1:61:33 | include!... | macro_expansion.rs:61:1:61:33 | MacroItems |
|
||||||
|
| macro_expansion.rs:63:9:63:32 | include_str!... | macro_expansion.rs:63:22:63:31 | "" |
|
||||||
|
| macro_expansion.rs:70:16:70:24 | my_int!... | macro_expansion.rs:70:16:70:24 | i32 |
|
||||||
|
| macro_expansion.rs:71:12:71:20 | my_int!... | macro_expansion.rs:71:12:71:20 | i32 |
|
||||||
|
| macro_expansion.rs:72:10:72:18 | my_int!... | macro_expansion.rs:72:10:72:18 | i32 |
|
||||||
|
| macro_expansion.rs:76:14:76:22 | my_int!... | macro_expansion.rs:76:14:76:22 | i32 |
|
||||||
|
| macro_expansion.rs:79:12:79:20 | my_int!... | macro_expansion.rs:79:12:79:20 | i32 |
|
||||||
|
unexpanded_macro_calls
|
||||||
|
| macro_expansion.rs:5:9:5:35 | concat!... |
|
||||||
|
warnings
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import rust
|
import rust
|
||||||
|
import codeql.rust.Diagnostics
|
||||||
|
|
||||||
query predicate attribute_macros(Item i, int index, Item expanded) {
|
query predicate attribute_macros(Item i, int index, Item expanded) {
|
||||||
i.fromSource() and expanded = i.getAttributeMacroExpansion().getItem(index)
|
i.fromSource() and expanded = i.getAttributeMacroExpansion().getItem(index)
|
||||||
@@ -6,10 +7,12 @@ query predicate attribute_macros(Item i, int index, Item expanded) {
|
|||||||
|
|
||||||
query predicate macro_calls(MacroCall c, AstNode expansion) {
|
query predicate macro_calls(MacroCall c, AstNode expansion) {
|
||||||
c.fromSource() and
|
c.fromSource() and
|
||||||
not c.getLocation().getFile().getAbsolutePath().matches("%proc_macros%") and
|
not c.getLocation().getFile().getAbsolutePath().matches("%proc_macro.rs") and
|
||||||
expansion = c.getMacroCallExpansion()
|
expansion = c.getMacroCallExpansion()
|
||||||
}
|
}
|
||||||
|
|
||||||
query predicate unexpanded_macro_calls(MacroCall c) {
|
query predicate unexpanded_macro_calls(MacroCall c) {
|
||||||
c.fromSource() and not c.hasMacroCallExpansion()
|
c.fromSource() and not c.hasMacroCallExpansion()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
query predicate warnings(ExtractionWarning w) { any() }
|
||||||
@@ -1,155 +0,0 @@
|
|||||||
lib.rs:
|
|
||||||
# 1| [SourceFile] SourceFile
|
|
||||||
# 1| getItem(0): [Module] mod macro_expansion
|
|
||||||
# 1| getName(): [Name] macro_expansion
|
|
||||||
macro_expansion.rs:
|
|
||||||
# 1| [SourceFile] SourceFile
|
|
||||||
# 1| getItem(0): [Function] fn foo
|
|
||||||
# 2| getAttributeMacroExpansion(): [MacroItems] MacroItems
|
|
||||||
# 2| getItem(0): [Function] fn foo
|
|
||||||
# 1| getParamList(): [ParamList] ParamList
|
|
||||||
# 1| getAbi(): [Abi] Abi
|
|
||||||
# 2| getBody(): [BlockExpr] { ... }
|
|
||||||
# 2| getStmtList(): [StmtList] StmtList
|
|
||||||
# 2| getName(): [Name] foo
|
|
||||||
# 2| getItem(1): [Static] Static
|
|
||||||
# 1| getAttr(0): [Attr] Attr
|
|
||||||
# 1| getMeta(): [Meta] Meta
|
|
||||||
# 1| getPath(): [Path] used
|
|
||||||
# 1| getSegment(): [PathSegment] used
|
|
||||||
# 1| getIdentifier(): [NameRef] used
|
|
||||||
# 1| getAttr(1): [Attr] Attr
|
|
||||||
# 1| getMeta(): [Meta] Meta
|
|
||||||
# 1| getPath(): [Path] allow
|
|
||||||
# 1| getSegment(): [PathSegment] allow
|
|
||||||
# 1| getIdentifier(): [NameRef] allow
|
|
||||||
# 1| getTokenTree(): [TokenTree] TokenTree
|
|
||||||
# 1| getAttr(2): [Attr] Attr
|
|
||||||
# 1| getMeta(): [Meta] Meta
|
|
||||||
# 1| getPath(): [Path] doc
|
|
||||||
# 1| getSegment(): [PathSegment] doc
|
|
||||||
# 1| getIdentifier(): [NameRef] doc
|
|
||||||
# 1| getTokenTree(): [TokenTree] TokenTree
|
|
||||||
# 1| getAttr(3): [Attr] Attr
|
|
||||||
# 1| getMeta(): [Meta] Meta
|
|
||||||
# 1| getPath(): [Path] cfg_attr
|
|
||||||
# 1| getSegment(): [PathSegment] cfg_attr
|
|
||||||
# 1| getIdentifier(): [NameRef] cfg_attr
|
|
||||||
# 1| getTokenTree(): [TokenTree] TokenTree
|
|
||||||
# 1| getAttr(4): [Attr] Attr
|
|
||||||
# 1| getMeta(): [Meta] Meta
|
|
||||||
# 1| getPath(): [Path] cfg_attr
|
|
||||||
# 1| getSegment(): [PathSegment] cfg_attr
|
|
||||||
# 1| getIdentifier(): [NameRef] cfg_attr
|
|
||||||
# 1| getTokenTree(): [TokenTree] TokenTree
|
|
||||||
# 1| getAttr(5): [Attr] Attr
|
|
||||||
# 1| getMeta(): [Meta] Meta
|
|
||||||
# 1| getPath(): [Path] cfg_attr
|
|
||||||
# 1| getSegment(): [PathSegment] cfg_attr
|
|
||||||
# 1| getIdentifier(): [NameRef] cfg_attr
|
|
||||||
# 1| getTokenTree(): [TokenTree] TokenTree
|
|
||||||
# 1| getAttr(6): [Attr] Attr
|
|
||||||
# 1| getMeta(): [Meta] Meta
|
|
||||||
# 1| getPath(): [Path] cfg_attr
|
|
||||||
# 1| getSegment(): [PathSegment] cfg_attr
|
|
||||||
# 1| getIdentifier(): [NameRef] cfg_attr
|
|
||||||
# 1| getTokenTree(): [TokenTree] TokenTree
|
|
||||||
# 1| getAttr(7): [Attr] Attr
|
|
||||||
# 1| getMeta(): [Meta] Meta
|
|
||||||
# 1| getPath(): [Path] cfg_attr
|
|
||||||
# 1| getSegment(): [PathSegment] cfg_attr
|
|
||||||
# 1| getIdentifier(): [NameRef] cfg_attr
|
|
||||||
# 1| getTokenTree(): [TokenTree] TokenTree
|
|
||||||
# 1| getAttr(8): [Attr] Attr
|
|
||||||
# 1| getMeta(): [Meta] Meta
|
|
||||||
# 1| getPath(): [Path] cfg_attr
|
|
||||||
# 1| getSegment(): [PathSegment] cfg_attr
|
|
||||||
# 1| getIdentifier(): [NameRef] cfg_attr
|
|
||||||
# 1| getTokenTree(): [TokenTree] TokenTree
|
|
||||||
# 1| getAttr(9): [Attr] Attr
|
|
||||||
# 1| getMeta(): [Meta] Meta
|
|
||||||
# 1| getPath(): [Path] cfg_attr
|
|
||||||
# 1| getSegment(): [PathSegment] cfg_attr
|
|
||||||
# 1| getIdentifier(): [NameRef] cfg_attr
|
|
||||||
# 1| getTokenTree(): [TokenTree] TokenTree
|
|
||||||
# 1| getAttr(10): [Attr] Attr
|
|
||||||
# 1| getMeta(): [Meta] Meta
|
|
||||||
# 1| getPath(): [Path] cfg_attr
|
|
||||||
# 1| getSegment(): [PathSegment] cfg_attr
|
|
||||||
# 1| getIdentifier(): [NameRef] cfg_attr
|
|
||||||
# 1| getTokenTree(): [TokenTree] TokenTree
|
|
||||||
# 1| getAttr(11): [Attr] Attr
|
|
||||||
# 1| getMeta(): [Meta] Meta
|
|
||||||
# 1| getPath(): [Path] cfg_attr
|
|
||||||
# 1| getSegment(): [PathSegment] cfg_attr
|
|
||||||
# 1| getIdentifier(): [NameRef] cfg_attr
|
|
||||||
# 1| getTokenTree(): [TokenTree] TokenTree
|
|
||||||
# 2| getBody(): [BlockExpr] { ... }
|
|
||||||
# 2| getStmtList(): [StmtList] StmtList
|
|
||||||
# 2| getStatement(0): [Function] fn foo___rust_ctor___ctor
|
|
||||||
# 1| getParamList(): [ParamList] ParamList
|
|
||||||
# 1| getAttr(0): [Attr] Attr
|
|
||||||
# 1| getMeta(): [Meta] Meta
|
|
||||||
# 1| getPath(): [Path] allow
|
|
||||||
# 1| getSegment(): [PathSegment] allow
|
|
||||||
# 1| getIdentifier(): [NameRef] allow
|
|
||||||
# 1| getTokenTree(): [TokenTree] TokenTree
|
|
||||||
# 1| getAttr(1): [Attr] Attr
|
|
||||||
# 1| getMeta(): [Meta] Meta
|
|
||||||
# 1| getPath(): [Path] cfg_attr
|
|
||||||
# 1| getSegment(): [PathSegment] cfg_attr
|
|
||||||
# 1| getIdentifier(): [NameRef] cfg_attr
|
|
||||||
# 1| getTokenTree(): [TokenTree] TokenTree
|
|
||||||
# 1| getAbi(): [Abi] Abi
|
|
||||||
# 2| getBody(): [BlockExpr] { ... }
|
|
||||||
# 2| getStmtList(): [StmtList] StmtList
|
|
||||||
# 2| getStatement(0): [ExprStmt] ExprStmt
|
|
||||||
# 2| getExpr(): [CallExpr] foo(...)
|
|
||||||
# 1| getArgList(): [ArgList] ArgList
|
|
||||||
# 2| getFunction(): [PathExpr] foo
|
|
||||||
# 2| getPath(): [Path] foo
|
|
||||||
# 2| getSegment(): [PathSegment] foo
|
|
||||||
# 2| getIdentifier(): [NameRef] foo
|
|
||||||
# 1| getTailExpr(): [IntegerLiteralExpr] 0
|
|
||||||
# 1| getName(): [Name] foo___rust_ctor___ctor
|
|
||||||
# 1| getRetType(): [RetTypeRepr] RetTypeRepr
|
|
||||||
# 1| getTypeRepr(): [PathTypeRepr] usize
|
|
||||||
# 1| getPath(): [Path] usize
|
|
||||||
# 1| getSegment(): [PathSegment] usize
|
|
||||||
# 1| getIdentifier(): [NameRef] usize
|
|
||||||
# 1| getTailExpr(): [PathExpr] foo___rust_ctor___ctor
|
|
||||||
# 1| getPath(): [Path] foo___rust_ctor___ctor
|
|
||||||
# 1| getSegment(): [PathSegment] foo___rust_ctor___ctor
|
|
||||||
# 1| getIdentifier(): [NameRef] foo___rust_ctor___ctor
|
|
||||||
# 1| getName(): [Name] foo___rust_ctor___ctor
|
|
||||||
# 1| getTypeRepr(): [FnPtrTypeRepr] FnPtrTypeRepr
|
|
||||||
# 1| getAbi(): [Abi] Abi
|
|
||||||
# 1| getParamList(): [ParamList] ParamList
|
|
||||||
# 1| getRetType(): [RetTypeRepr] RetTypeRepr
|
|
||||||
# 1| getTypeRepr(): [PathTypeRepr] usize
|
|
||||||
# 1| getPath(): [Path] usize
|
|
||||||
# 1| getSegment(): [PathSegment] usize
|
|
||||||
# 1| getIdentifier(): [NameRef] usize
|
|
||||||
# 2| getParamList(): [ParamList] ParamList
|
|
||||||
# 1| getAttr(0): [Attr] Attr
|
|
||||||
# 1| getMeta(): [Meta] Meta
|
|
||||||
# 1| getPath(): [Path] ...::ctor
|
|
||||||
# 1| getQualifier(): [Path] ctor
|
|
||||||
# 1| getSegment(): [PathSegment] ctor
|
|
||||||
# 1| getIdentifier(): [NameRef] ctor
|
|
||||||
# 1| getSegment(): [PathSegment] ctor
|
|
||||||
# 1| getIdentifier(): [NameRef] ctor
|
|
||||||
# 2| getBody(): [BlockExpr] { ... }
|
|
||||||
# 2| getStmtList(): [StmtList] StmtList
|
|
||||||
# 2| getName(): [Name] foo
|
|
||||||
# 4| getItem(1): [Function] fn bar
|
|
||||||
# 5| getParamList(): [ParamList] ParamList
|
|
||||||
# 4| getAttr(0): [Attr] Attr
|
|
||||||
# 4| getMeta(): [Meta] Meta
|
|
||||||
# 4| getPath(): [Path] cfg
|
|
||||||
# 4| getSegment(): [PathSegment] cfg
|
|
||||||
# 4| getIdentifier(): [NameRef] cfg
|
|
||||||
# 4| getTokenTree(): [TokenTree] TokenTree
|
|
||||||
# 5| getBody(): [BlockExpr] { ... }
|
|
||||||
# 5| getStmtList(): [StmtList] StmtList
|
|
||||||
# 5| getName(): [Name] bar
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
#[ctor::ctor]
|
|
||||||
fn foo() {}
|
|
||||||
|
|
||||||
#[cfg(any(linux, not(linux)))]
|
|
||||||
fn bar() {}
|
|
||||||
|
|
||||||
#[cfg(all(linux, not(linux)))]
|
|
||||||
fn baz() {}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
qltest_dependencies:
|
|
||||||
- ctor = { version = "0.2.9" }
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
| macro_expansion.rs:1:1:2:11 | fn foo | 0 | macro_expansion.rs:2:4:2:10 | fn foo |
|
|
||||||
| macro_expansion.rs:1:1:2:11 | fn foo | 1 | macro_expansion.rs:2:4:2:6 | Static |
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
import rust
|
|
||||||
import TestUtils
|
|
||||||
|
|
||||||
from Item i, MacroItems items, int index, Item expanded
|
|
||||||
where toBeTested(i) and i.getAttributeMacroExpansion() = items and items.getItem(index) = expanded
|
|
||||||
select i, index, expanded
|
|
||||||
Reference in New Issue
Block a user