Skip to content

Commit 84cd134

Browse files
authored
List Subcommand: include crate name (#4024)
Update the list subcommand to include the crate name as part of the markdown table and printed table output. By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.
1 parent 150ccd1 commit 84cd134

File tree

6 files changed

+236
-136
lines changed

6 files changed

+236
-136
lines changed

kani-driver/src/list/collect_metadata.rs

Lines changed: 34 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -10,69 +10,64 @@ use crate::{
1010
VerificationArgs,
1111
list_args::{CargoListArgs, StandaloneListArgs},
1212
},
13-
list::ListMetadata,
1413
list::output::output_list_results,
14+
list::{FileName, HarnessName, ListMetadata},
1515
project::{Project, cargo_project, standalone_project, std_project},
1616
session::KaniSession,
1717
version::print_kani_version,
1818
};
1919
use anyhow::Result;
20-
use kani_metadata::{ContractedFunction, HarnessKind, KaniMetadata};
20+
use kani_metadata::{ContractedFunction, HarnessKind, HarnessMetadata, KaniMetadata};
2121

2222
/// Process the KaniMetadata output from kani-compiler and output the list subcommand results
23-
pub fn process_metadata(metadata: Vec<KaniMetadata>) -> ListMetadata {
24-
// We use ordered maps and sets so that the output is in lexicographic order (and consistent across invocations).
25-
26-
// Map each file to a vector of its harnesses.
27-
let mut standard_harnesses: BTreeMap<String, BTreeSet<String>> = BTreeMap::new();
28-
let mut contract_harnesses: BTreeMap<String, BTreeSet<String>> = BTreeMap::new();
23+
pub fn process_metadata(metadata: Vec<KaniMetadata>) -> BTreeSet<ListMetadata> {
24+
let mut list_metadata: BTreeSet<ListMetadata> = BTreeSet::new();
25+
26+
let insert = |harness_meta: HarnessMetadata,
27+
map: &mut BTreeMap<FileName, BTreeSet<HarnessName>>,
28+
count: &mut usize| {
29+
*count += 1;
30+
if let Some(harnesses) = map.get_mut(&harness_meta.original_file) {
31+
harnesses.insert(harness_meta.pretty_name);
32+
} else {
33+
map.insert(harness_meta.original_file, BTreeSet::from([harness_meta.pretty_name]));
34+
};
35+
};
2936

30-
let mut contracted_functions: BTreeSet<ContractedFunction> = BTreeSet::new();
37+
for kani_meta in metadata {
38+
// We use ordered maps and sets so that the output is in lexicographic order (and consistent across invocations).
39+
let mut standard_harnesses: BTreeMap<FileName, BTreeSet<HarnessName>> = BTreeMap::new();
40+
let mut contract_harnesses: BTreeMap<FileName, BTreeSet<HarnessName>> = BTreeMap::new();
41+
let mut contracted_functions: BTreeSet<ContractedFunction> = BTreeSet::new();
3142

32-
let mut standard_harnesses_count = 0;
33-
let mut contract_harnesses_count = 0;
43+
let mut standard_harnesses_count = 0;
44+
let mut contract_harnesses_count = 0;
3445

35-
for kani_meta in metadata {
3646
for harness_meta in kani_meta.proof_harnesses {
3747
match harness_meta.attributes.kind {
3848
HarnessKind::Proof => {
39-
standard_harnesses_count += 1;
40-
if let Some(harnesses) = standard_harnesses.get_mut(&harness_meta.original_file)
41-
{
42-
harnesses.insert(harness_meta.pretty_name);
43-
} else {
44-
standard_harnesses.insert(
45-
harness_meta.original_file,
46-
BTreeSet::from([harness_meta.pretty_name]),
47-
);
48-
}
49+
insert(harness_meta, &mut standard_harnesses, &mut standard_harnesses_count);
4950
}
5051
HarnessKind::ProofForContract { .. } => {
51-
contract_harnesses_count += 1;
52-
if let Some(harnesses) = contract_harnesses.get_mut(&harness_meta.original_file)
53-
{
54-
harnesses.insert(harness_meta.pretty_name);
55-
} else {
56-
contract_harnesses.insert(
57-
harness_meta.original_file,
58-
BTreeSet::from([harness_meta.pretty_name]),
59-
);
60-
}
52+
insert(harness_meta, &mut contract_harnesses, &mut contract_harnesses_count);
6153
}
6254
HarnessKind::Test => {}
6355
}
6456
}
6557

6658
contracted_functions.extend(kani_meta.contracted_functions.into_iter());
67-
}
6859

69-
ListMetadata {
70-
standard_harnesses,
71-
standard_harnesses_count,
72-
contract_harnesses,
73-
contract_harnesses_count,
74-
contracted_functions,
60+
list_metadata.insert(ListMetadata {
61+
crate_name: kani_meta.crate_name,
62+
standard_harnesses,
63+
standard_harnesses_count,
64+
contract_harnesses,
65+
contract_harnesses_count,
66+
contracted_functions,
67+
});
7568
}
69+
70+
list_metadata
7671
}
7772

7873
pub fn list_cargo(args: CargoListArgs, mut verify_opts: VerificationArgs) -> Result<()> {

kani-driver/src/list/mod.rs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,41 @@ use std::collections::{BTreeMap, BTreeSet};
88
pub mod collect_metadata;
99
pub mod output;
1010

11+
type FileName = String;
12+
type HarnessName = String;
13+
14+
/// Metadata for the list subcommand for a given crate.
15+
/// It is important that crate_name is the first field so that `Ord` orders two ListMetadata objects by crate name.
16+
#[derive(PartialEq, Eq, PartialOrd, Ord)]
1117
pub struct ListMetadata {
18+
crate_name: String,
1219
// Files mapped to their #[kani::proof] harnesses
13-
standard_harnesses: BTreeMap<String, BTreeSet<String>>,
20+
standard_harnesses: BTreeMap<FileName, BTreeSet<HarnessName>>,
1421
// Total number of #[kani::proof] harnesses
1522
standard_harnesses_count: usize,
1623
// Files mapped to their #[kani::proof_for_contract] harnesses
17-
contract_harnesses: BTreeMap<String, BTreeSet<String>>,
24+
contract_harnesses: BTreeMap<FileName, BTreeSet<HarnessName>>,
1825
// Total number of #[kani:proof_for_contract] harnesses
1926
contract_harnesses_count: usize,
2027
// Set of all functions under contract
2128
contracted_functions: BTreeSet<ContractedFunction>,
2229
}
30+
31+
/// Given a collection of ListMetadata objects, merge them into a single ListMetadata object.
32+
pub fn merge_list_metadata<T>(collection: T) -> ListMetadata
33+
where
34+
T: Extend<ListMetadata>,
35+
T: IntoIterator<Item = ListMetadata>,
36+
{
37+
collection
38+
.into_iter()
39+
.reduce(|mut acc, item| {
40+
acc.standard_harnesses.extend(item.standard_harnesses);
41+
acc.standard_harnesses_count += item.standard_harnesses_count;
42+
acc.contract_harnesses.extend(item.contract_harnesses);
43+
acc.contract_harnesses_count += item.contract_harnesses_count;
44+
acc.contracted_functions.extend(item.contracted_functions);
45+
acc
46+
})
47+
.expect("Cannot merge empty collection of ListMetadata objects")
48+
}

0 commit comments

Comments
 (0)