Skip to content

Commit 55d092f

Browse files
authored
Merge pull request github#17835 from github/redsun82/rust-qltest
Rust: move `qltest` to rust code, add `options` with cargo check
2 parents e920a4c + 41d0085 commit 55d092f

File tree

20 files changed

+197
-62
lines changed

20 files changed

+197
-62
lines changed

Cargo.lock

Lines changed: 27 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/extractor/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ edition = "2021"
66
[dependencies]
77
anyhow = "1.0.86"
88
clap = { version = "4.5.16", features = ["derive"] }
9-
figment = { version = "0.10.19", features = ["env"]}
9+
figment = { version = "0.10.19", features = ["env", "yaml"] }
1010
log = "0.4.22"
1111
num-traits = "0.2.19"
1212
ra_ap_base_db = "0.0.232"
@@ -29,3 +29,4 @@ argfile = "0.2.1"
2929
codeql-extractor = { path = "../../shared/tree-sitter-extractor" }
3030
rust-extractor-macros = { path = "macros" }
3131
itertools = "0.13.0"
32+
glob = "0.3.1"

rust/extractor/macros/src/lib.rs

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ use quote::{format_ident, quote};
66
pub fn extractor_cli_config(_attr: TokenStream, item: TokenStream) -> TokenStream {
77
let ast = syn::parse_macro_input!(item as syn::ItemStruct);
88
let name = &ast.ident;
9-
let new_name = format_ident!("Cli{}", name);
10-
let fields: Vec<_> = ast
9+
let cli_name = format_ident!("Cli{}", name);
10+
let cli_fields = ast
1111
.fields
1212
.iter()
1313
.map(|f| {
@@ -39,17 +39,42 @@ pub fn extractor_cli_config(_attr: TokenStream, item: TokenStream) -> TokenStrea
3939
}
4040
}
4141
})
42-
.collect();
42+
.collect::<Vec<_>>();
43+
let debug_fields = ast
44+
.fields
45+
.iter()
46+
.map(|f| {
47+
let id = f.ident.as_ref().unwrap();
48+
if id == &format_ident!("inputs") {
49+
quote! {
50+
.field("number of inputs", &self.#id.len())
51+
}
52+
} else {
53+
quote! {
54+
.field(stringify!(#id), &self.#id)
55+
}
56+
}
57+
})
58+
.collect::<Vec<_>>();
59+
4360
let gen = quote! {
4461
#[serde_with::apply(_ => #[serde(default)])]
45-
#[derive(Debug, Deserialize, Default)]
62+
#[derive(Deserialize, Default)]
4663
#ast
4764

65+
impl Debug for #name {
66+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
67+
f.debug_struct("configuration:")
68+
#(#debug_fields)*
69+
.finish()
70+
}
71+
}
72+
4873
#[serde_with::skip_serializing_none]
4974
#[derive(clap::Parser, Serialize)]
5075
#[command(about, long_about = None)]
51-
struct #new_name {
52-
#(#fields)*
76+
struct #cli_name {
77+
#(#cli_fields)*
5378
}
5479
};
5580
gen.into()

rust/extractor/src/config.rs

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@ use anyhow::Context;
22
use clap::Parser;
33
use codeql_extractor::trap;
44
use figment::{
5-
providers::{Env, Serialized},
5+
providers::{Env, Format, Serialized, Yaml},
6+
value::Value,
67
Figment,
78
};
9+
use itertools::Itertools;
810
use num_traits::Zero;
911
use rust_extractor_macros::extractor_cli_config;
1012
use serde::{Deserialize, Serialize};
13+
use std::fmt::Debug;
1114
use std::ops::Not;
1215
use std::path::PathBuf;
1316

@@ -38,19 +41,34 @@ pub struct Config {
3841
pub verbose: u8,
3942
pub compression: Compression,
4043
pub inputs: Vec<PathBuf>,
44+
pub qltest: bool,
45+
pub qltest_cargo_check: bool,
4146
}
4247

4348
impl Config {
4449
pub fn extract() -> anyhow::Result<Config> {
4550
let args = argfile::expand_args(argfile::parse_fromfile, argfile::PREFIX)
4651
.context("expanding parameter files")?;
4752
let cli_args = CliConfig::parse_from(args);
48-
Figment::new()
53+
let mut figment = Figment::new()
4954
.merge(Env::prefixed("CODEQL_"))
5055
.merge(Env::prefixed("CODEQL_EXTRACTOR_RUST_"))
5156
.merge(Env::prefixed("CODEQL_EXTRACTOR_RUST_OPTION_"))
52-
.merge(Serialized::defaults(cli_args))
53-
.extract()
54-
.context("loading configuration")
57+
.merge(Serialized::defaults(cli_args));
58+
if let Ok(Value::Bool(_, true)) = figment.find_value("qltest") {
59+
let cwd = std::env::current_dir()?;
60+
let mut option_files = cwd
61+
.ancestors()
62+
// only travel up while we're within the test pack
63+
.take_while_inclusive(|p| !p.join("qlpack.yml").exists())
64+
.map(|p| p.join("options"))
65+
.filter(|p| p.exists())
66+
.collect_vec();
67+
option_files.reverse();
68+
for path in option_files {
69+
figment = figment.merge(Yaml::file_exact(path));
70+
}
71+
}
72+
figment.extract().context("loading configuration")
5573
}
5674
}

rust/extractor/src/main.rs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
1-
use std::{
2-
collections::HashMap,
3-
path::{Path, PathBuf},
4-
};
5-
61
use anyhow::Context;
72
use archive::Archiver;
3+
use log::info;
84
use ra_ap_ide_db::line_index::{LineCol, LineIndex};
95
use ra_ap_project_model::ProjectManifest;
106
use rust_analyzer::{ParseResult, RustAnalyzer};
7+
use std::{
8+
collections::HashMap,
9+
path::{Path, PathBuf},
10+
};
1111
mod archive;
1212
mod config;
1313
pub mod generated;
14+
mod qltest;
1415
mod rust_analyzer;
1516
mod translate;
1617
pub mod trap;
@@ -65,16 +66,21 @@ fn extract(
6566
)
6667
});
6768
}
69+
6870
fn main() -> anyhow::Result<()> {
69-
let cfg = config::Config::extract().context("failed to load configuration")?;
71+
let mut cfg = config::Config::extract().context("failed to load configuration")?;
7072
stderrlog::new()
7173
.module(module_path!())
72-
.verbosity(1 + cfg.verbose as usize)
74+
.verbosity(2 + cfg.verbose as usize)
7375
.init()?;
76+
if cfg.qltest {
77+
qltest::prepare(&mut cfg)?;
78+
}
79+
info!("{cfg:#?}\n");
7480

7581
let traps = trap::TrapFileProvider::new(&cfg).context("failed to set up trap files")?;
7682
let archiver = archive::Archiver {
77-
root: cfg.source_archive_dir,
83+
root: cfg.source_archive_dir.clone(),
7884
};
7985
let files: Vec<PathBuf> = cfg
8086
.inputs

rust/extractor/src/qltest.rs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
use crate::config::Config;
2+
use anyhow::Context;
3+
use glob::glob;
4+
use itertools::Itertools;
5+
use log::info;
6+
use std::ffi::OsStr;
7+
use std::fs;
8+
use std::process::Command;
9+
10+
fn dump_lib() -> anyhow::Result<()> {
11+
let path_iterator = glob("*.rs").context("globbing test sources")?;
12+
let paths = path_iterator
13+
.collect::<Result<Vec<_>, _>>()
14+
.context("fetching test sources")?;
15+
let lib = paths
16+
.iter()
17+
.map(|p| p.file_stem().expect("results of glob must have a name"))
18+
.filter(|&p| !["main", "lib"].map(OsStr::new).contains(&p))
19+
.map(|p| format!("mod {};", p.to_string_lossy()))
20+
.join("\n");
21+
fs::write("lib.rs", lib).context("writing lib.rs")
22+
}
23+
24+
fn dump_cargo_manifest() -> anyhow::Result<()> {
25+
let mut manifest = String::from(
26+
r#"[workspace]
27+
[package]
28+
name = "test"
29+
version="0.0.1"
30+
edition="2021"
31+
[lib]
32+
path="lib.rs"
33+
"#,
34+
);
35+
if fs::exists("main.rs").context("checking existence of main.rs")? {
36+
manifest.push_str(
37+
r#"[[bin]]
38+
name = "main"
39+
path = "main.rs"
40+
"#,
41+
);
42+
}
43+
fs::write("Cargo.toml", manifest).context("writing Cargo.toml")
44+
}
45+
46+
fn set_sources(config: &mut Config) -> anyhow::Result<()> {
47+
let path_iterator = glob("*.rs").context("globbing test sources")?;
48+
config.inputs = path_iterator
49+
.collect::<Result<Vec<_>, _>>()
50+
.context("fetching test sources")?;
51+
Ok(())
52+
}
53+
54+
pub(crate) fn prepare(config: &mut Config) -> anyhow::Result<()> {
55+
dump_lib()?;
56+
set_sources(config)?;
57+
dump_cargo_manifest()?;
58+
if config.qltest_cargo_check {
59+
let status = Command::new("cargo")
60+
.env("RUSTFLAGS", "-Awarnings")
61+
.arg("check")
62+
.arg("-q")
63+
.status()
64+
.context("spawning cargo check")?;
65+
if status.success() {
66+
info!("cargo check successful");
67+
} else {
68+
anyhow::bail!("requested cargo check failed");
69+
}
70+
}
71+
Ok(())
72+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
| gen_module.rs:3:1:4:8 | Module | getNumberOfAttrs: | 0 | hasItemList: | no | hasName: | yes | hasVisibility: | no |
22
| gen_module.rs:5:1:7:1 | Module | getNumberOfAttrs: | 0 | hasItemList: | yes | hasName: | yes | hasVisibility: | no |
3-
| lib.rs:2:1:2:15 | Module | getNumberOfAttrs: | 0 | hasItemList: | no | hasName: | yes | hasVisibility: | no |
3+
| lib.rs:1:1:1:15 | Module | getNumberOfAttrs: | 0 | hasItemList: | no | hasName: | yes | hasVisibility: | no |
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
| gen_module.rs:3:1:4:8 | Module | gen_module.rs:4:5:4:7 | Name |
22
| gen_module.rs:5:1:7:1 | Module | gen_module.rs:5:5:5:7 | Name |
3-
| lib.rs:2:1:2:15 | Module | lib.rs:2:5:2:14 | Name |
3+
| lib.rs:1:1:1:15 | Module | lib.rs:1:5:1:14 | Name |
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
| gen_name.rs:3:4:3:12 | Name | hasText: | yes |
2-
| lib.rs:2:5:2:12 | Name | hasText: | yes |
2+
| lib.rs:1:5:1:12 | Name | hasText: | yes |
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
| gen_name.rs:3:4:3:12 | Name | test_name |
2-
| lib.rs:2:5:2:12 | Name | gen_name |
2+
| lib.rs:1:5:1:12 | Name | gen_name |

0 commit comments

Comments
 (0)