Skip to content

Commit 093fc6b

Browse files
committed
change arguments to no longer be exclusive; make --exclude take precedence
Also rename them to reference patterns to make it clearer how one might use them together.
1 parent c0430ec commit 093fc6b

File tree

10 files changed

+70
-48
lines changed

10 files changed

+70
-48
lines changed

docs/src/reference/experimental/autoharness.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,16 @@ autoharness feature means that you are also opting into the function contracts a
4343
Kani generates and runs these harnesses internally—the user only sees the verification results.
4444

4545
### Options
46-
The `autoharness` subcommand has options `--include-function` and `--exclude-function` to include and exclude particular functions.
46+
The `autoharness` subcommand has options `--include-pattern` and `--exclude-pattern` to include and exclude particular functions.
4747
These flags look for partial matches against the fully qualified name of a function.
4848

4949
For example, if a module `my_module` has many functions, but we are only interested in `my_module::foo` and `my_module::bar`, we can run:
5050
```
51-
cargo run autoharness -Z autoharness --include-function foo --include-function bar
51+
cargo run autoharness -Z autoharness --include-pattern foo --include-pattern bar
5252
```
5353
To exclude `my_module` entirely, run:
5454
```
55-
cargo run autoharness -Z autoharness --exclude-function my_module
55+
cargo run autoharness -Z autoharness --exclude-pattern my_module
5656
```
5757

5858
## Example

kani-compiler/src/args.rs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -91,16 +91,14 @@ pub struct Arguments {
9191
/// Print the final LLBC file to stdout.
9292
#[clap(long)]
9393
pub print_llbc: bool,
94-
/// If we are running the autoharness subcommand, the functions to include
95-
#[arg(
96-
long = "autoharness-include-function",
97-
num_args(1),
98-
conflicts_with = "autoharness_excluded_functions"
99-
)]
100-
pub autoharness_included_functions: Vec<String>,
101-
/// If we are running the autoharness subcommand, the functions to exclude
102-
#[arg(long = "autoharness-exclude-function", num_args(1))]
103-
pub autoharness_excluded_functions: Vec<String>,
94+
/// If we are running the autoharness subcommand, the paths to include.
95+
/// See kani_driver::autoharness_args for documentation.
96+
#[arg(long = "autoharness-include-pattern", num_args(1))]
97+
pub autoharness_included_patterns: Vec<String>,
98+
/// If we are running the autoharness subcommand, the paths to exclude.
99+
/// See kani_driver::autoharness_args for documentation.
100+
#[arg(long = "autoharness-exclude-pattern", num_args(1))]
101+
pub autoharness_excluded_patterns: Vec<String>,
104102
}
105103

106104
#[derive(Debug, Clone, Copy, AsRefStr, EnumString, VariantNames, PartialEq, Eq)]

kani-compiler/src/kani_middle/codegen_units.rs

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -394,12 +394,34 @@ fn automatic_harness_partition(
394394
return Some(AutoHarnessSkipReason::KaniImpl);
395395
}
396396

397-
if (!args.autoharness_included_functions.is_empty()
398-
&& !filter_contains(&name, &args.autoharness_included_functions))
399-
|| (!args.autoharness_excluded_functions.is_empty()
400-
&& filter_contains(&name, &args.autoharness_excluded_functions))
401-
{
402-
return Some(AutoHarnessSkipReason::UserFilter);
397+
match (
398+
args.autoharness_included_patterns.is_empty(),
399+
args.autoharness_excluded_patterns.is_empty(),
400+
) {
401+
// If no filters were specified, then continue.
402+
(true, true) => {}
403+
// If only --exclude-pattern was provided, filter out the function if excluded_patterns contains its name.
404+
(true, false) => {
405+
if filter_contains(&name, &args.autoharness_excluded_patterns) {
406+
return Some(AutoHarnessSkipReason::UserFilter);
407+
}
408+
}
409+
// If only --include-pattern was provided, filter out the function if included_patterns does not contain its name.
410+
(false, true) => {
411+
if !filter_contains(&name, &args.autoharness_included_patterns) {
412+
return Some(AutoHarnessSkipReason::UserFilter);
413+
}
414+
}
415+
// If both are specified, filter out the function if included_patterns does not contain its name.
416+
// Then, filter out any functions that excluded_patterns does match.
417+
// This order is important, since it preserves the semantics described in kani_driver::autoharness_args where exclude takes precedence over include.
418+
(false, false) => {
419+
if !filter_contains(&name, &args.autoharness_included_patterns)
420+
|| filter_contains(&name, &args.autoharness_excluded_patterns)
421+
{
422+
return Some(AutoHarnessSkipReason::UserFilter);
423+
}
424+
}
403425
}
404426

405427
// Each argument of `instance` must implement Arbitrary.

kani-driver/src/args/autoharness_args.rs

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,27 +9,28 @@ use crate::args::{ValidateArgs, VerificationArgs, validate_std_path};
99
use clap::{Error, Parser, error::ErrorKind};
1010
use kani_metadata::UnstableFeature;
1111

12+
// TODO: It would be nice if we could borrow --exact here from VerificationArgs to differentiate between partial/exact matches,
13+
// like --harnesses does. Sharing arguments with VerificationArgs doesn't work with our current structure, though.
1214
#[derive(Debug, Parser)]
1315
pub struct CommonAutoharnessArgs {
14-
/// If specified, only autoharness functions that match this filter. This option can be provided
15-
/// multiple times, which will verify all functions matching any of the filters.
16-
/// Note that this filter will match against partial names, i.e., providing the name of a module will include all functions from that module.
17-
/// Also note that if the function specified is unable to be automatically verified, this flag will have no effect.
18-
#[arg(
19-
long = "include-function",
20-
num_args(1),
21-
value_name = "FUNCTION",
22-
conflicts_with = "exclude_function"
23-
)]
24-
pub include_function: Vec<String>,
25-
26-
/// If specified, only autoharness functions that do not match this filter. This option can be provided
27-
/// multiple times, which will verify all functions that do not match any of the filters.
28-
/// Note that this filter will match against partial names, i.e., providing the name of a module will exclude all functions from that module.
29-
#[arg(long = "exclude-function", num_args(1), value_name = "FUNCTION")]
30-
pub exclude_function: Vec<String>,
31-
// TODO: It would be nice if we could borrow --exact here from VerificationArgs to differentiate between partial/exact matches,
32-
// like --harnesses does. Sharing arguments with VerificationArgs doesn't work with our current structure, though.
16+
/// Only create automatic harnesses for functions that match the given pattern.
17+
/// This option can be provided multiple times, which will verify functions matching any of the patterns.
18+
/// Kani considers a function to match the pattern if its fully qualified path contains PATTERN as a substring.
19+
/// Example: `--include-pattern foo` matches all functions whose fully qualified paths contain the substring "foo".
20+
#[arg(long = "include-pattern", num_args(1), value_name = "PATTERN")]
21+
pub include_pattern: Vec<String>,
22+
23+
/// Only create automatic harnesses for functions that do not match the given pattern.
24+
/// This option can be provided multiple times, which will verify functions that do not match any of the patterns.
25+
/// Kani considers a function to match the pattern if its fully qualified path contains PATTERN as a substring.
26+
27+
/// This option takes precedence over `--include-pattern`, i.e., Kani will first select all functions that match `--include-pattern`,
28+
/// then exclude those that match `--exclude-pattern.`
29+
/// Example: `--include-pattern foo --exclude-pattern foo::bar` creates automatic harnesses for all functions whose paths contain "foo" without "foo::bar".
30+
/// Example: `--include-pattern foo::bar --exclude-pattern foo` makes the `--include-pattern` a no-op, since the exclude pattern is a superset of the include pattern.
31+
#[arg(long = "exclude-pattern", num_args(1), value_name = "PATTERN")]
32+
pub exclude_pattern: Vec<String>,
33+
3334
/// Run the `list` subcommand after generating the automatic harnesses. Requires -Z list. Note that this option implies --only-codegen.
3435
#[arg(long)]
3536
pub list: bool,

kani-driver/src/args/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ pub enum CargoKaniSubcommand {
178178
List(Box<list_args::CargoListArgs>),
179179

180180
/// Create and run harnesses automatically for eligible functions. Implies -Z function-contracts and -Z loop-contracts.
181+
/// See https://model-checking.github.io/kani/reference/experimental/autoharness.html for documentation.
181182
Autoharness(Box<autoharness_args::CargoAutoharnessArgs>),
182183
}
183184

kani-driver/src/autoharness/mod.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ fn setup_session(session: &mut KaniSession, common_autoharness_args: &CommonAuto
5555
session.enable_autoharness();
5656
session.add_default_bounds();
5757
session.add_auto_harness_args(
58-
&common_autoharness_args.include_function,
59-
&common_autoharness_args.exclude_function,
58+
&common_autoharness_args.include_pattern,
59+
&common_autoharness_args.exclude_pattern,
6060
);
6161
}
6262

@@ -163,11 +163,11 @@ impl KaniSession {
163163
/// Add the compiler arguments specific to the `autoharness` subcommand.
164164
pub fn add_auto_harness_args(&mut self, included: &[String], excluded: &[String]) {
165165
let mut args = vec![];
166-
for func in included {
167-
args.push(format!("--autoharness-include-function {}", func));
166+
for pattern in included {
167+
args.push(format!("--autoharness-include-pattern {}", pattern));
168168
}
169-
for func in excluded {
170-
args.push(format!("--autoharness-exclude-function {}", func));
169+
for pattern in excluded {
170+
args.push(format!("--autoharness-exclude-pattern {}", pattern));
171171
}
172172
self.autoharness_compiler_flags = Some(args);
173173
}

tests/script-based-pre/cargo_autoharness_exclude/exclude.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
# Copyright Kani Contributors
33
# SPDX-License-Identifier: Apache-2.0 OR MIT
44

5-
cargo kani autoharness -Z autoharness --exclude-function exclude
5+
cargo kani autoharness -Z autoharness --exclude-pattern exclude

tests/script-based-pre/cargo_autoharness_exclude/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// SPDX-License-Identifier: Apache-2.0 OR MIT
33
//
44
// Test that the automatic harness generation feature selects functions correctly
5-
// when --exclude-function is provided.
5+
// when --exclude-pattern is provided.
66

77
mod include {
88
fn simple(x: u8, _y: u16) -> u8 {

tests/script-based-pre/cargo_autoharness_include/include.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
# Copyright Kani Contributors
33
# SPDX-License-Identifier: Apache-2.0 OR MIT
44

5-
cargo kani autoharness -Z autoharness --include-function include
5+
cargo kani autoharness -Z autoharness --include-pattern include

tests/script-based-pre/cargo_autoharness_include/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// SPDX-License-Identifier: Apache-2.0 OR MIT
33
//
44
// Test that the automatic harness generation feature selects functions correctly
5-
// when --include-function is provided.
5+
// when --include-pattern is provided.
66

77
// Each function inside this module matches the filter.
88
mod include {

0 commit comments

Comments
 (0)