Rust: enhance macro expansion testing

This commit is contained in:
Paolo Tranquilli
2025-05-14 10:01:44 +02:00
parent a99556e021
commit f5438390d5
16 changed files with 349 additions and 0 deletions

1
rust/ql/integration-tests/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
target/

View File

@@ -0,0 +1,53 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "macro_expansion"
version = "0.1.0"
dependencies = [
"macros",
]
[[package]]
name = "macros"
version = "0.1.0"
dependencies = [
"quote",
"syn",
]
[[package]]
name = "proc-macro2"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [
"proc-macro2",
]
[[package]]
name = "syn"
version = "2.0.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"

View File

@@ -0,0 +1,11 @@
[workspace]
members = ["macros"]
resolver = "2"
[package]
name = "macro_expansion"
version = "0.1.0"
edition = "2024"
[dependencies]
macros = { path = "macros" }

View File

@@ -0,0 +1,47 @@
{
"attributes": {
"durations": {
"crateGraph": {
"ms": "__REDACTED__",
"pretty": "__REDACTED__"
},
"extract": {
"ms": "__REDACTED__",
"pretty": "__REDACTED__"
},
"findManifests": {
"ms": "__REDACTED__",
"pretty": "__REDACTED__"
},
"loadManifest": {
"ms": "__REDACTED__",
"pretty": "__REDACTED__"
},
"loadSource": {
"ms": "__REDACTED__",
"pretty": "__REDACTED__"
},
"parse": {
"ms": "__REDACTED__",
"pretty": "__REDACTED__"
},
"total": {
"ms": "__REDACTED__",
"pretty": "__REDACTED__"
}
},
"numberOfFiles": 3,
"numberOfManifests": 1
},
"severity": "note",
"source": {
"extractorName": "rust",
"id": "rust/extractor/telemetry",
"name": "telemetry"
},
"visibility": {
"cliSummaryTable": false,
"statusPage": false,
"telemetry": true
}
}

View File

@@ -0,0 +1,11 @@
[package]
name = "macros"
version = "0.1.0"
edition = "2024"
[lib]
proc-macro = true
[dependencies]
quote = "1.0.40"
syn = { version = "2.0.100", features = ["full"] }

View File

@@ -0,0 +1,18 @@
use proc_macro::TokenStream;
use quote::quote;
#[proc_macro_attribute]
pub fn repeat(attr: TokenStream, item: TokenStream) -> TokenStream {
let number = syn::parse_macro_input!(attr as syn::LitInt).base10_parse::<usize>().unwrap();
let ast = syn::parse_macro_input!(item as syn::ItemFn);
let items = (0..number)
.map(|i| {
let mut new_ast = ast.clone();
new_ast.sig.ident = syn::Ident::new(&format!("{}_{}", ast.sig.ident, i), ast.sig.ident.span());
new_ast
})
.collect::<Vec<_>>();
quote! {
#(#items)*
}.into()
}

View File

@@ -0,0 +1,2 @@
macros/src/lib.rs
src/lib.rs

View File

@@ -0,0 +1,11 @@
use macros::repeat;
#[repeat(3)]
fn foo() {}
#[repeat(2)]
#[repeat(3)]
fn bar() {}
#[repeat(0)]
fn baz() {}

View File

@@ -0,0 +1,11 @@
| src/lib.rs:3:1:4:11 | fn foo | 0 | src/lib.rs:4:1:4:10 | fn foo_0 |
| src/lib.rs:3:1:4:11 | fn foo | 1 | src/lib.rs:4:1:4:10 | fn foo_1 |
| src/lib.rs:3:1:4:11 | fn foo | 2 | src/lib.rs:4:1:4:10 | fn foo_2 |
| src/lib.rs:6:1:8:11 | fn bar | 0 | src/lib.rs:7:1:8:10 | fn bar_0 |
| src/lib.rs:6:1:8:11 | fn bar | 1 | src/lib.rs:7:1:8:10 | fn bar_1 |
| src/lib.rs:7:1:8:10 | fn bar_0 | 0 | src/lib.rs:8:1:8:10 | fn bar_0_0 |
| src/lib.rs:7:1:8:10 | fn bar_0 | 1 | src/lib.rs:8:1:8:10 | fn bar_0_1 |
| src/lib.rs:7:1:8:10 | fn bar_0 | 2 | src/lib.rs:8:1:8:10 | fn bar_0_2 |
| src/lib.rs:7:1:8:10 | fn bar_1 | 0 | src/lib.rs:8:1:8:10 | fn bar_1_0 |
| src/lib.rs:7:1:8:10 | fn bar_1 | 1 | src/lib.rs:8:1:8:10 | fn bar_1_1 |
| src/lib.rs:7:1:8:10 | fn bar_1 | 2 | src/lib.rs:8:1:8:10 | fn bar_1_2 |

View File

@@ -0,0 +1,5 @@
import rust
from Item i, MacroItems items, int index, Item expanded
where i.getAttributeMacroExpansion() = items and items.getItem(index) = expanded
select i, index, expanded

View File

@@ -0,0 +1,2 @@
def test_macro_expansion(codeql, rust, check_source_archive, rust_check_diagnostics):
codeql.database.create()

View File

@@ -0,0 +1,155 @@
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(): [LiteralExpr] 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

View File

@@ -0,0 +1 @@
utils/PrintAst.ql

View File

@@ -1,2 +1,8 @@
#[ctor::ctor]
fn foo() {}
#[cfg(any(linux, not(linux)))]
fn bar() {}
#[cfg(all(linux, not(linux)))]
fn baz() {}

View File

View File

@@ -0,0 +1,15 @@
/**
* @name Print AST
* @description Outputs a representation of a file's Abstract Syntax Tree
* @id rust/test/print-ast
* @kind graph
*/
import rust
import codeql.rust.printast.PrintAst
import codeql.rust.elements.internal.generated.ParentChild
import TestUtils
predicate shouldPrint(Locatable e) { toBeTested(e) }
import PrintAst<shouldPrint/1>