Skip to content

Commit c82032d

Browse files
committed
Introduce a system of "directive handlers" indexed by directive name
1 parent 3a0d8a7 commit c82032d

File tree

3 files changed

+108
-16
lines changed

3 files changed

+108
-16
lines changed

src/tools/compiletest/src/directives.rs

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use crate::directives::directive_names::{
1414
KNOWN_DIRECTIVE_NAMES, KNOWN_HTMLDOCCK_DIRECTIVE_NAMES, KNOWN_JSONDOCCK_DIRECTIVE_NAMES,
1515
};
1616
pub(crate) use crate::directives::file::FileDirectives;
17+
use crate::directives::handlers::DIRECTIVE_HANDLERS_MAP;
1718
use crate::directives::line::{DirectiveLine, line_directive};
1819
use crate::directives::needs::CachedNeedsConditions;
1920
use crate::edition::{Edition, parse_edition};
@@ -26,6 +27,7 @@ mod auxiliary;
2627
mod cfg;
2728
mod directive_names;
2829
mod file;
30+
mod handlers;
2931
mod line;
3032
mod needs;
3133
#[cfg(test)]
@@ -369,22 +371,15 @@ impl TestProps {
369371
return;
370372
}
371373

374+
if let Some(handler) = DIRECTIVE_HANDLERS_MAP.get(ln.name) {
375+
handler.handle(config, ln, self);
376+
// This directive has been handled, so move on to the next one.
377+
return;
378+
}
379+
372380
use directives::*;
373381
let props = &mut *self;
374382

375-
config.push_name_value_directive(
376-
ln,
377-
ERROR_PATTERN,
378-
&mut props.error_patterns,
379-
|r| r,
380-
);
381-
config.push_name_value_directive(
382-
ln,
383-
REGEX_ERROR_PATTERN,
384-
&mut props.regex_error_patterns,
385-
|r| r,
386-
);
387-
388383
config.push_name_value_directive(ln, DOC_FLAGS, &mut props.doc_flags, |r| r);
389384

390385
fn split_flags(flags: &str) -> Vec<String> {
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
use std::collections::HashMap;
2+
use std::sync::{Arc, LazyLock};
3+
4+
use crate::common::Config;
5+
use crate::directives::{DirectiveLine, TestProps};
6+
7+
pub(crate) static DIRECTIVE_HANDLERS_MAP: LazyLock<HashMap<&str, Handler>> =
8+
LazyLock::new(make_directive_handlers_map);
9+
10+
#[derive(Clone)]
11+
pub(crate) struct Handler {
12+
handler_fn: Arc<dyn Fn(HandlerArgs<'_>) + Send + Sync>,
13+
}
14+
15+
impl Handler {
16+
pub(crate) fn handle(&self, config: &Config, line: &DirectiveLine<'_>, props: &mut TestProps) {
17+
(self.handler_fn)(HandlerArgs { config, line, props })
18+
}
19+
}
20+
21+
struct HandlerArgs<'a> {
22+
config: &'a Config,
23+
line: &'a DirectiveLine<'a>,
24+
props: &'a mut TestProps,
25+
}
26+
27+
/// Intermediate data structure, used for defining a list of handlers.
28+
struct NamedHandler {
29+
names: Vec<&'static str>,
30+
handler: Handler,
31+
}
32+
33+
/// Helper function to create a simple handler, so that changes can be made
34+
/// to the handler struct without disturbing existing handler declarations.
35+
fn handler(
36+
name: &'static str,
37+
handler_fn: impl Fn(&Config, &DirectiveLine<'_>, &mut TestProps) + Send + Sync + 'static,
38+
) -> NamedHandler {
39+
multi_handler(&[name], handler_fn)
40+
}
41+
42+
/// Associates the same handler function with multiple directive names.
43+
fn multi_handler(
44+
names: &[&'static str],
45+
handler_fn: impl Fn(&Config, &DirectiveLine<'_>, &mut TestProps) + Send + Sync + 'static,
46+
) -> NamedHandler {
47+
NamedHandler {
48+
names: names.to_owned(),
49+
handler: Handler {
50+
handler_fn: Arc::new(move |args| handler_fn(args.config, args.line, args.props)),
51+
},
52+
}
53+
}
54+
55+
fn make_directive_handlers_map() -> HashMap<&'static str, Handler> {
56+
use crate::directives::directives::*;
57+
58+
let handlers: Vec<NamedHandler> = vec![
59+
handler(ERROR_PATTERN, |config, ln, props| {
60+
config.push_name_value_directive(ln, ERROR_PATTERN, &mut props.error_patterns, |r| r);
61+
}),
62+
handler(REGEX_ERROR_PATTERN, |config, ln, props| {
63+
config.push_name_value_directive(
64+
ln,
65+
REGEX_ERROR_PATTERN,
66+
&mut props.regex_error_patterns,
67+
|r| r,
68+
);
69+
}),
70+
];
71+
72+
handlers
73+
.into_iter()
74+
.flat_map(|NamedHandler { names, handler }| {
75+
names.into_iter().map(move |name| (name, Handler::clone(&handler)))
76+
})
77+
.collect()
78+
}

src/tools/compiletest/src/directives/tests.rs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,33 @@
1+
use std::collections::{BTreeSet, HashSet};
2+
13
use camino::Utf8Path;
24
use semver::Version;
35

46
use crate::common::{Config, Debugger, TestMode};
57
use crate::directives::{
6-
AuxProps, DirectivesCache, EarlyProps, Edition, EditionRange, FileDirectives,
7-
extract_llvm_version, extract_version_range, iter_directives, line_directive, parse_edition,
8-
parse_normalize_rule,
8+
AuxProps, DIRECTIVE_HANDLERS_MAP, DirectivesCache, EarlyProps, Edition, EditionRange,
9+
FileDirectives, KNOWN_DIRECTIVE_NAMES, extract_llvm_version, extract_version_range,
10+
iter_directives, line_directive, parse_edition, parse_normalize_rule,
911
};
1012
use crate::executor::{CollectedTestDesc, ShouldFail};
1113

14+
/// All directive handlers should have a name that is also in `KNOWN_DIRECTIVE_NAMES`.
15+
#[test]
16+
fn handler_names() {
17+
let known_directive_names = KNOWN_DIRECTIVE_NAMES.iter().copied().collect::<HashSet<_>>();
18+
19+
let unknown_names = DIRECTIVE_HANDLERS_MAP
20+
.keys()
21+
.copied()
22+
.filter(|name| !known_directive_names.contains(name))
23+
.collect::<BTreeSet<_>>();
24+
25+
assert!(
26+
unknown_names.is_empty(),
27+
"Directive handler names not in `directive_names.rs`: {unknown_names:#?}"
28+
);
29+
}
30+
1231
fn make_test_description(
1332
config: &Config,
1433
name: String,

0 commit comments

Comments
 (0)