Skip to content

Commit 7eaf617

Browse files
committed
rust: interpreter factory method simplified
1 parent fda853b commit 7eaf617

File tree

3 files changed

+96
-90
lines changed

3 files changed

+96
-90
lines changed

rust/bear/src/modes/semantic.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
use crate::intercept::Envelope;
44
use crate::output::OutputWriter;
5-
use crate::semantic::interpreters::Builder;
5+
use crate::semantic::interpreters::create_interpreter;
66
use crate::semantic::transformation::Transformation;
77
use crate::{args, config, output, semantic};
88
use anyhow::Context;
@@ -20,7 +20,7 @@ pub(super) struct SemanticAnalysisPipeline {
2020
impl SemanticAnalysisPipeline {
2121
/// Create a new semantic mode instance.
2222
pub(super) fn from(output: args::BuildSemantic, config: &config::Main) -> anyhow::Result<Self> {
23-
let interpreter = Builder::from(config);
23+
let interpreter = create_interpreter(config);
2424
let transform = Transformation::from(&config.output);
2525
let output_writer = OutputWriterImpl::create(&output, &config.output)?;
2626

rust/bear/src/semantic/interpreters/ignore.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ impl IgnoreByPath {
2222
}
2323
}
2424

25+
impl Default for IgnoreByPath {
26+
fn default() -> Self {
27+
Self::new()
28+
}
29+
}
30+
2531
/// A tool to ignore a command execution by arguments.
2632
impl Interpreter for IgnoreByPath {
2733
fn recognize(&self, execution: &Execution) -> Recognition<CompilerCall> {

rust/bear/src/semantic/interpreters/mod.rs

Lines changed: 88 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -13,84 +13,47 @@ mod generic;
1313
mod ignore;
1414
mod matchers;
1515

16-
/// A builder for creating a tool which can recognize the semantic of a compiler,
17-
/// or ignore known non-compilers.
18-
pub struct Builder {
19-
interpreters: Vec<Box<dyn Interpreter>>,
20-
}
21-
22-
impl Builder {
23-
/// Creates an interpreter to recognize the compiler calls.
24-
///
25-
/// Using the configuration we can define which compilers to include and exclude.
26-
/// Also read the environment variables to detect the compiler to include (and
27-
/// make sure those are not excluded either).
28-
// TODO: Use the CC or CXX environment variables to detect the compiler to include.
29-
// Use the CC or CXX environment variables and make sure those are not excluded.
30-
// Make sure the environment variables are passed to the method.
31-
// TODO: Take environment variables as input.
32-
pub fn from(config: &config::Main) -> impl Interpreter {
33-
let compilers_to_include = match &config.intercept {
34-
config::Intercept::Wrapper { executables, .. } => executables.clone(),
35-
_ => vec![],
36-
};
37-
let compilers_to_exclude = match &config.output {
38-
config::Output::Clang { compilers, .. } => compilers
39-
.iter()
40-
.filter(|compiler| compiler.ignore == config::IgnoreOrConsider::Always)
41-
.map(|compiler| compiler.path.clone())
42-
.collect(),
43-
_ => vec![],
44-
};
45-
Builder::new()
46-
.compilers_to_recognize(compilers_to_include.as_slice())
47-
.compilers_to_exclude(compilers_to_exclude.as_slice())
48-
.build()
49-
}
50-
51-
/// Creates a new builder with default settings.
52-
fn new() -> Self {
53-
// FIXME: replace generic with gcc, when it's implemented
54-
Builder {
55-
interpreters: vec![
56-
// ignore executables which are not compilers,
57-
Box::new(IgnoreByPath::new()),
58-
// recognize default compiler
59-
Box::new(Generic::from(&[PathBuf::from("/usr/bin/g++")])),
60-
],
61-
}
16+
/// Creates an interpreter to recognize the compiler calls.
17+
///
18+
/// Using the configuration we can define which compilers to include and exclude.
19+
/// Also read the environment variables to detect the compiler to include (and
20+
/// make sure those are not excluded either).
21+
// TODO: Use the CC or CXX environment variables to detect the compiler to include.
22+
// Use the CC or CXX environment variables and make sure those are not excluded.
23+
// Make sure the environment variables are passed to the method.
24+
// TODO: Take environment variables as input.
25+
pub fn create_interpreter<'a>(config: &config::Main) -> impl Interpreter + 'a {
26+
let compilers_to_include = match &config.intercept {
27+
config::Intercept::Wrapper { executables, .. } => executables.clone(),
28+
_ => vec![],
29+
};
30+
let compilers_to_exclude = match &config.output {
31+
config::Output::Clang { compilers, .. } => compilers
32+
.iter()
33+
.filter(|compiler| compiler.ignore == config::IgnoreOrConsider::Always)
34+
.map(|compiler| compiler.path.clone())
35+
.collect(),
36+
_ => vec![],
37+
};
38+
39+
let mut interpreters: Vec<Box<dyn Interpreter>> = vec![
40+
// ignore executables which are not compilers,
41+
Box::new(IgnoreByPath::default()),
42+
// recognize default compiler
43+
Box::new(Generic::from(&[PathBuf::from("/usr/bin/cc")])),
44+
];
45+
46+
if !compilers_to_include.is_empty() {
47+
let tool = Generic::from(&compilers_to_include);
48+
interpreters.push(Box::new(tool));
6249
}
6350

64-
/// Factory method to create a new tool from the builder.
65-
fn build(self) -> impl Interpreter {
66-
Any::new(self.interpreters)
67-
}
68-
69-
/// Adds new interpreters to recognize as compilers by executable name.
70-
fn compilers_to_recognize(mut self, compilers: &[PathBuf]) -> Self {
71-
if !compilers.is_empty() {
72-
// Add the new compilers at the end of the interpreters.
73-
let tool = Generic::from(compilers);
74-
self.interpreters.push(Box::new(tool));
75-
}
76-
self
51+
if !compilers_to_exclude.is_empty() {
52+
let tool = IgnoreByPath::from(&compilers_to_exclude);
53+
interpreters.insert(0, Box::new(tool));
7754
}
7855

79-
/// Adds new interpreters to recognize as non-compilers by executable names.
80-
fn compilers_to_exclude(mut self, compilers: &[PathBuf]) -> Self {
81-
if !compilers.is_empty() {
82-
// Add these new compilers at the front of the interpreters.
83-
let tool = IgnoreByPath::from(compilers);
84-
self.interpreters.insert(0, Box::new(tool));
85-
}
86-
self
87-
}
88-
}
89-
90-
impl Default for Builder {
91-
fn default() -> Self {
92-
Builder::new()
93-
}
56+
Any::new(interpreters)
9457
}
9558

9659
#[cfg(test)]
@@ -100,37 +63,74 @@ mod test {
10063

10164
use super::super::{CompilerCall, Execution, Recognition};
10265
use super::*;
66+
use crate::config;
67+
use crate::config::{DuplicateFilter, Format, SourceFilter};
10368
use crate::{vec_of_pathbuf, vec_of_strings};
10469

70+
fn any_execution() -> Execution {
71+
Execution {
72+
executable: PathBuf::from("/usr/bin/cc"),
73+
arguments: vec_of_strings!["cc", "-c", "-Wall", "main.c"],
74+
environment: HashMap::new(),
75+
working_dir: PathBuf::from("/home/user"),
76+
}
77+
}
78+
10579
#[test]
106-
fn test_builder() {
107-
let sut = Builder::new().build();
80+
fn test_create_interpreter_with_default_config() {
81+
let config = config::Main::default();
10882

83+
let interpreter = create_interpreter(&config);
10984
let input = any_execution();
110-
match sut.recognize(&input) {
85+
86+
match interpreter.recognize(&input) {
11187
Recognition::Success(CompilerCall { .. }) => assert!(true),
11288
_ => assert!(false),
11389
}
11490
}
11591

11692
#[test]
117-
fn test_builder_with_compilers_to_exclude() {
118-
let compilers = vec_of_pathbuf!["/usr/bin/g++"];
119-
let sut = Builder::new().compilers_to_exclude(&compilers).build();
93+
fn test_create_interpreter_with_compilers_to_include() {
94+
let config = config::Main {
95+
intercept: config::Intercept::Wrapper {
96+
executables: vec_of_pathbuf!["/usr/bin/cc"],
97+
path: PathBuf::from("/usr/libexec/bear"),
98+
directory: PathBuf::from("/tmp"),
99+
},
100+
..Default::default()
101+
};
120102

103+
let interpreter = create_interpreter(&config);
121104
let input = any_execution();
122-
match sut.recognize(&input) {
123-
Recognition::Ignored => assert!(true),
105+
106+
match interpreter.recognize(&input) {
107+
Recognition::Success(CompilerCall { .. }) => assert!(true),
124108
_ => assert!(false),
125109
}
126110
}
127111

128-
fn any_execution() -> Execution {
129-
Execution {
130-
executable: PathBuf::from("/usr/bin/g++"),
131-
arguments: vec_of_strings!["g++", "-c", "main.cpp"],
132-
environment: HashMap::new(),
133-
working_dir: PathBuf::from("/home/user"),
112+
#[test]
113+
fn test_create_interpreter_with_compilers_to_exclude() {
114+
let config = config::Main {
115+
output: config::Output::Clang {
116+
compilers: vec![config::Compiler {
117+
path: PathBuf::from("/usr/bin/cc"),
118+
ignore: config::IgnoreOrConsider::Always,
119+
arguments: config::Arguments::default(),
120+
}],
121+
sources: SourceFilter::default(),
122+
duplicates: DuplicateFilter::default(),
123+
format: Format::default(),
124+
},
125+
..Default::default()
126+
};
127+
128+
let interpreter = create_interpreter(&config);
129+
let input = any_execution();
130+
131+
match interpreter.recognize(&input) {
132+
Recognition::Ignored => assert!(true),
133+
_ => assert!(false),
134134
}
135135
}
136136
}

0 commit comments

Comments
 (0)