Change all &Option<> to Option<&> (#768)

This commit is contained in:
Charlie Marsh 2022-11-16 09:40:01 -05:00 committed by GitHub
parent 910ee523dd
commit 7d8360a1de
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 81 additions and 59 deletions

View file

@ -226,13 +226,15 @@ pub fn is_super_call_with_arguments(func: &Expr, args: &[Expr]) -> bool {
} }
/// Format the module name for a relative import. /// Format the module name for a relative import.
pub fn format_import_from(level: &Option<usize>, module: &Option<String>) -> String { pub fn format_import_from(level: Option<&usize>, module: Option<&String>) -> String {
let mut module_name = String::with_capacity(16); let mut module_name = String::with_capacity(16);
for _ in 0..level.unwrap_or_default() { if let Some(level) = level {
module_name.push('.'); for _ in 0..*level {
module_name.push('.');
}
} }
if let Some(m) = module { if let Some(module) = module {
module_name.push_str(m); module_name.push_str(module);
} }
module_name module_name
} }

View file

@ -709,7 +709,8 @@ where
if !matches!(scope.kind, ScopeKind::Module) { if !matches!(scope.kind, ScopeKind::Module) {
self.add_check(Check::new( self.add_check(Check::new(
CheckKind::ImportStarNotPermitted(helpers::format_import_from( CheckKind::ImportStarNotPermitted(helpers::format_import_from(
level, module, level.as_ref(),
module.as_ref(),
)), )),
Range::from_located(stmt), Range::from_located(stmt),
)); ));
@ -719,7 +720,8 @@ where
if self.settings.enabled.contains(&CheckCode::F403) { if self.settings.enabled.contains(&CheckCode::F403) {
self.add_check(Check::new( self.add_check(Check::new(
CheckKind::ImportStarUsed(helpers::format_import_from( CheckKind::ImportStarUsed(helpers::format_import_from(
level, module, level.as_ref(),
module.as_ref(),
)), )),
Range::from_located(stmt), Range::from_located(stmt),
)); ));
@ -860,7 +862,12 @@ where
pyflakes::plugins::assert_tuple(self, stmt, test); pyflakes::plugins::assert_tuple(self, stmt, test);
} }
if self.settings.enabled.contains(&CheckCode::B011) { if self.settings.enabled.contains(&CheckCode::B011) {
flake8_bugbear::plugins::assert_false(self, stmt, test, msg); flake8_bugbear::plugins::assert_false(
self,
stmt,
test,
msg.as_ref().map(|expr| expr.deref()),
);
} }
if self.settings.enabled.contains(&CheckCode::S101) { if self.settings.enabled.contains(&CheckCode::S101) {
self.add_check(flake8_bandit::plugins::assert_used(stmt)); self.add_check(flake8_bandit::plugins::assert_used(stmt));
@ -2170,7 +2177,10 @@ impl<'a> Checker<'a> {
let scope = &self.scopes[*scope_index]; let scope = &self.scopes[*scope_index];
for binding in scope.values.values() { for binding in scope.values.values() {
if let BindingKind::StarImportation(level, module) = &binding.kind { if let BindingKind::StarImportation(level, module) = &binding.kind {
from_list.push(helpers::format_import_from(level, module)); from_list.push(helpers::format_import_from(
level.as_ref(),
module.as_ref(),
));
} }
} }
} }
@ -2496,7 +2506,10 @@ impl<'a> Checker<'a> {
let mut from_list = vec![]; let mut from_list = vec![];
for binding in scope.values.values() { for binding in scope.values.values() {
if let BindingKind::StarImportation(level, module) = &binding.kind { if let BindingKind::StarImportation(level, module) = &binding.kind {
from_list.push(helpers::format_import_from(level, module)); from_list.push(helpers::format_import_from(
level.as_ref(),
module.as_ref(),
));
} }
} }
from_list.sort(); from_list.sort();

View file

@ -152,7 +152,7 @@ pub fn warn_on(
cli_ignore: &[CheckCodePrefix], cli_ignore: &[CheckCodePrefix],
cli_extend_ignore: &[CheckCodePrefix], cli_extend_ignore: &[CheckCodePrefix],
pyproject_configuration: &Configuration, pyproject_configuration: &Configuration,
pyproject_path: &Option<PathBuf>, pyproject_path: Option<&PathBuf>,
) { ) {
for code in codes { for code in codes {
if !cli_ignore.is_empty() { if !cli_ignore.is_empty() {
@ -192,7 +192,7 @@ pub fn warn_on(
/// Convert a list of `PatternPrefixPair` structs to `PerFileIgnore`. /// Convert a list of `PatternPrefixPair` structs to `PerFileIgnore`.
pub fn collect_per_file_ignores( pub fn collect_per_file_ignores(
pairs: Vec<PatternPrefixPair>, pairs: Vec<PatternPrefixPair>,
project_root: &Option<PathBuf>, project_root: Option<&PathBuf>,
) -> Vec<PerFileIgnore> { ) -> Vec<PerFileIgnore> {
let mut per_file_ignores: FnvHashMap<String, Vec<CheckCodePrefix>> = FnvHashMap::default(); let mut per_file_ignores: FnvHashMap<String, Vec<CheckCodePrefix>> = FnvHashMap::default();
for pair in pairs { for pair in pairs {

View file

@ -1,3 +1,5 @@
use std::ops::Deref;
use rustpython_ast::{Arguments, Constant, Expr, ExprKind, Stmt, StmtKind}; use rustpython_ast::{Arguments, Constant, Expr, ExprKind, Stmt, StmtKind};
use crate::ast::types::Range; use crate::ast::types::Range;
@ -11,7 +13,7 @@ use crate::{visibility, Check};
#[derive(Default)] #[derive(Default)]
struct ReturnStatementVisitor<'a> { struct ReturnStatementVisitor<'a> {
returns: Vec<&'a Option<Box<Expr>>>, returns: Vec<Option<&'a Expr>>,
} }
impl<'a, 'b> Visitor<'b> for ReturnStatementVisitor<'a> impl<'a, 'b> Visitor<'b> for ReturnStatementVisitor<'a>
@ -23,7 +25,9 @@ where
StmtKind::FunctionDef { .. } | StmtKind::AsyncFunctionDef { .. } => { StmtKind::FunctionDef { .. } | StmtKind::AsyncFunctionDef { .. } => {
// No recurse. // No recurse.
} }
StmtKind::Return { value } => self.returns.push(value), StmtKind::Return { value } => {
self.returns.push(value.as_ref().map(|expr| expr.deref()))
}
_ => visitor::walk_stmt(self, stmt), _ => visitor::walk_stmt(self, stmt),
} }
} }

View file

@ -6,7 +6,7 @@ use crate::check_ast::Checker;
use crate::checks::{Check, CheckKind}; use crate::checks::{Check, CheckKind};
use crate::code_gen::SourceGenerator; use crate::code_gen::SourceGenerator;
fn assertion_error(msg: &Option<Box<Expr>>) -> Stmt { fn assertion_error(msg: Option<&Expr>) -> Stmt {
Stmt::new( Stmt::new(
Default::default(), Default::default(),
Default::default(), Default::default(),
@ -24,7 +24,7 @@ fn assertion_error(msg: &Option<Box<Expr>>) -> Stmt {
}, },
)), )),
args: if let Some(msg) = msg { args: if let Some(msg) = msg {
vec![*msg.clone()] vec![msg.clone()]
} else { } else {
vec![] vec![]
}, },
@ -36,7 +36,7 @@ fn assertion_error(msg: &Option<Box<Expr>>) -> Stmt {
) )
} }
pub fn assert_false(checker: &mut Checker, stmt: &Stmt, test: &Expr, msg: &Option<Box<Expr>>) { pub fn assert_false(checker: &mut Checker, stmt: &Stmt, test: &Expr, msg: Option<&Expr>) {
if let ExprKind::Constant { if let ExprKind::Constant {
value: Constant::Bool(false), value: Constant::Bool(false),
.. ..

View file

@ -202,7 +202,7 @@ mod tests {
let path = Path::new("foo").absolutize_from(project_root).unwrap(); let path = Path::new("foo").absolutize_from(project_root).unwrap();
let exclude = vec![FilePattern::from_user( let exclude = vec![FilePattern::from_user(
"foo", "foo",
&Some(project_root.to_path_buf()), Some(&project_root.to_path_buf()),
)]; )];
let (file_path, file_basename) = extract_path_names(&path)?; let (file_path, file_basename) = extract_path_names(&path)?;
assert!(is_excluded(file_path, file_basename, exclude.iter())); assert!(is_excluded(file_path, file_basename, exclude.iter()));
@ -210,7 +210,7 @@ mod tests {
let path = Path::new("foo/bar").absolutize_from(project_root).unwrap(); let path = Path::new("foo/bar").absolutize_from(project_root).unwrap();
let exclude = vec![FilePattern::from_user( let exclude = vec![FilePattern::from_user(
"bar", "bar",
&Some(project_root.to_path_buf()), Some(&project_root.to_path_buf()),
)]; )];
let (file_path, file_basename) = extract_path_names(&path)?; let (file_path, file_basename) = extract_path_names(&path)?;
assert!(is_excluded(file_path, file_basename, exclude.iter())); assert!(is_excluded(file_path, file_basename, exclude.iter()));
@ -220,7 +220,7 @@ mod tests {
.unwrap(); .unwrap();
let exclude = vec![FilePattern::from_user( let exclude = vec![FilePattern::from_user(
"baz.py", "baz.py",
&Some(project_root.to_path_buf()), Some(&project_root.to_path_buf()),
)]; )];
let (file_path, file_basename) = extract_path_names(&path)?; let (file_path, file_basename) = extract_path_names(&path)?;
assert!(is_excluded(file_path, file_basename, exclude.iter())); assert!(is_excluded(file_path, file_basename, exclude.iter()));
@ -228,7 +228,7 @@ mod tests {
let path = Path::new("foo/bar").absolutize_from(project_root).unwrap(); let path = Path::new("foo/bar").absolutize_from(project_root).unwrap();
let exclude = vec![FilePattern::from_user( let exclude = vec![FilePattern::from_user(
"foo/bar", "foo/bar",
&Some(project_root.to_path_buf()), Some(&project_root.to_path_buf()),
)]; )];
let (file_path, file_basename) = extract_path_names(&path)?; let (file_path, file_basename) = extract_path_names(&path)?;
assert!(is_excluded(file_path, file_basename, exclude.iter())); assert!(is_excluded(file_path, file_basename, exclude.iter()));
@ -238,7 +238,7 @@ mod tests {
.unwrap(); .unwrap();
let exclude = vec![FilePattern::from_user( let exclude = vec![FilePattern::from_user(
"foo/bar/baz.py", "foo/bar/baz.py",
&Some(project_root.to_path_buf()), Some(&project_root.to_path_buf()),
)]; )];
let (file_path, file_basename) = extract_path_names(&path)?; let (file_path, file_basename) = extract_path_names(&path)?;
assert!(is_excluded(file_path, file_basename, exclude.iter())); assert!(is_excluded(file_path, file_basename, exclude.iter()));
@ -248,7 +248,7 @@ mod tests {
.unwrap(); .unwrap();
let exclude = vec![FilePattern::from_user( let exclude = vec![FilePattern::from_user(
"foo/bar/*.py", "foo/bar/*.py",
&Some(project_root.to_path_buf()), Some(&project_root.to_path_buf()),
)]; )];
let (file_path, file_basename) = extract_path_names(&path)?; let (file_path, file_basename) = extract_path_names(&path)?;
assert!(is_excluded(file_path, file_basename, exclude.iter())); assert!(is_excluded(file_path, file_basename, exclude.iter()));
@ -258,7 +258,7 @@ mod tests {
.unwrap(); .unwrap();
let exclude = vec![FilePattern::from_user( let exclude = vec![FilePattern::from_user(
"baz", "baz",
&Some(project_root.to_path_buf()), Some(&project_root.to_path_buf()),
)]; )];
let (file_path, file_basename) = extract_path_names(&path)?; let (file_path, file_basename) = extract_path_names(&path)?;
assert!(!is_excluded(file_path, file_basename, exclude.iter())); assert!(!is_excluded(file_path, file_basename, exclude.iter()));

View file

@ -15,13 +15,13 @@ pub enum ImportType {
pub fn categorize( pub fn categorize(
module_base: &str, module_base: &str,
level: &Option<usize>, level: Option<&usize>,
src: &[PathBuf], src: &[PathBuf],
known_first_party: &BTreeSet<String>, known_first_party: &BTreeSet<String>,
known_third_party: &BTreeSet<String>, known_third_party: &BTreeSet<String>,
extra_standard_library: &BTreeSet<String>, extra_standard_library: &BTreeSet<String>,
) -> ImportType { ) -> ImportType {
if level.map(|level| level > 0).unwrap_or(false) { if level.map(|level| *level > 0).unwrap_or(false) {
ImportType::LocalFolder ImportType::LocalFolder
} else if known_first_party.contains(module_base) { } else if known_first_party.contains(module_base) {
ImportType::FirstParty ImportType::FirstParty

View file

@ -25,7 +25,7 @@ mod types;
#[derive(Debug)] #[derive(Debug)]
pub struct AnnotatedAliasData<'a> { pub struct AnnotatedAliasData<'a> {
pub name: &'a str, pub name: &'a str,
pub asname: &'a Option<String>, pub asname: Option<&'a String>,
pub atop: Vec<Comment<'a>>, pub atop: Vec<Comment<'a>>,
pub inline: Vec<Comment<'a>>, pub inline: Vec<Comment<'a>>,
} }
@ -37,9 +37,9 @@ pub enum AnnotatedImport<'a> {
inline: Vec<Comment<'a>>, inline: Vec<Comment<'a>>,
}, },
ImportFrom { ImportFrom {
module: &'a Option<String>, module: Option<&'a String>,
names: Vec<AnnotatedAliasData<'a>>, names: Vec<AnnotatedAliasData<'a>>,
level: &'a Option<usize>, level: Option<&'a usize>,
atop: Vec<Comment<'a>>, atop: Vec<Comment<'a>>,
inline: Vec<Comment<'a>>, inline: Vec<Comment<'a>>,
}, },
@ -75,7 +75,7 @@ fn annotate_imports<'a>(
.iter() .iter()
.map(|alias| AliasData { .map(|alias| AliasData {
name: &alias.node.name, name: &alias.node.name,
asname: &alias.node.asname, asname: alias.node.asname.as_ref(),
}) })
.collect(), .collect(),
atop, atop,
@ -124,16 +124,16 @@ fn annotate_imports<'a>(
aliases.push(AnnotatedAliasData { aliases.push(AnnotatedAliasData {
name: &alias.node.name, name: &alias.node.name,
asname: &alias.node.asname, asname: alias.node.asname.as_ref(),
atop: alias_atop, atop: alias_atop,
inline: alias_inline, inline: alias_inline,
}) })
} }
annotated.push(AnnotatedImport::ImportFrom { annotated.push(AnnotatedImport::ImportFrom {
module, module: module.as_ref(),
names: aliases, names: aliases,
level, level: level.as_ref(),
atop, atop,
inline, inline,
}); });
@ -278,7 +278,7 @@ fn categorize_imports<'a>(
for (alias, comments) in block.import { for (alias, comments) in block.import {
let import_type = categorize( let import_type = categorize(
&alias.module_base(), &alias.module_base(),
&None, None,
src, src,
known_first_party, known_first_party,
known_third_party, known_third_party,
@ -384,7 +384,7 @@ fn sort_imports(block: ImportBlock) -> OrderedImportBlock {
import_from import_from
.module .module
.as_ref() .as_ref()
.map(|module| module_key(module, &None)), .map(|module| module_key(module, None)),
aliases aliases
.first() .first()
.map(|(alias, _)| member_key(alias.name, alias.asname)), .map(|(alias, _)| member_key(alias.name, alias.asname)),

View file

@ -10,15 +10,15 @@ pub enum Prefix {
pub fn module_key<'a>( pub fn module_key<'a>(
name: &'a str, name: &'a str,
asname: &'a Option<String>, asname: Option<&'a String>,
) -> (String, &'a str, &'a Option<String>) { ) -> (String, &'a str, Option<&'a String>) {
(name.to_lowercase(), name, asname) (name.to_lowercase(), name, asname)
} }
pub fn member_key<'a>( pub fn member_key<'a>(
name: &'a str, name: &'a str,
asname: &'a Option<String>, asname: Option<&'a String>,
) -> (Prefix, String, &'a Option<String>) { ) -> (Prefix, String, Option<&'a String>) {
( (
if name.len() > 1 && string::is_upper(name) { if name.len() > 1 && string::is_upper(name) {
// Ex) `CONSTANT` // Ex) `CONSTANT`

View file

@ -6,14 +6,14 @@ use crate::ast;
#[derive(Debug, Hash, Ord, PartialOrd, Eq, PartialEq)] #[derive(Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
pub struct ImportFromData<'a> { pub struct ImportFromData<'a> {
pub module: &'a Option<String>, pub module: Option<&'a String>,
pub level: &'a Option<usize>, pub level: Option<&'a usize>,
} }
#[derive(Debug, Hash, Ord, PartialOrd, Eq, PartialEq)] #[derive(Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
pub struct AliasData<'a> { pub struct AliasData<'a> {
pub name: &'a str, pub name: &'a str,
pub asname: &'a Option<String>, pub asname: Option<&'a String>,
} }
#[derive(Debug, Default)] #[derive(Debug, Default)]

View file

@ -64,14 +64,16 @@ pub fn check(path: &Path, contents: &str, autofix: bool) -> Result<Vec<Check>> {
Some(path) => debug!("Found project root at: {:?}", path), Some(path) => debug!("Found project root at: {:?}", path),
None => debug!("Unable to identify project root; assuming current directory..."), None => debug!("Unable to identify project root; assuming current directory..."),
}; };
let pyproject = pyproject::find_pyproject_toml(&project_root); let pyproject = pyproject::find_pyproject_toml(project_root.as_ref());
match &pyproject { match &pyproject {
Some(path) => debug!("Found pyproject.toml at: {:?}", path), Some(path) => debug!("Found pyproject.toml at: {:?}", path),
None => debug!("Unable to find pyproject.toml; using default settings..."), None => debug!("Unable to find pyproject.toml; using default settings..."),
}; };
let settings = let settings = Settings::from_configuration(Configuration::from_pyproject(
Settings::from_configuration(Configuration::from_pyproject(&pyproject, &project_root)?); pyproject.as_ref(),
project_root.as_ref(),
)?);
// Tokenize once. // Tokenize once.
let tokens: Vec<LexResult> = tokenize(contents); let tokens: Vec<LexResult> = tokenize(contents);

View file

@ -208,7 +208,7 @@ fn inner_main() -> Result<ExitCode> {
}; };
let pyproject = cli let pyproject = cli
.config .config
.or_else(|| pyproject::find_pyproject_toml(&project_root)); .or_else(|| pyproject::find_pyproject_toml(project_root.as_ref()));
match &pyproject { match &pyproject {
Some(path) => debug!("Found pyproject.toml at: {:?}", path), Some(path) => debug!("Found pyproject.toml at: {:?}", path),
None => debug!("Unable to find pyproject.toml; using default settings..."), None => debug!("Unable to find pyproject.toml; using default settings..."),
@ -218,15 +218,16 @@ fn inner_main() -> Result<ExitCode> {
let exclude: Vec<FilePattern> = cli let exclude: Vec<FilePattern> = cli
.exclude .exclude
.iter() .iter()
.map(|path| FilePattern::from_user(path, &project_root)) .map(|path| FilePattern::from_user(path, project_root.as_ref()))
.collect(); .collect();
let extend_exclude: Vec<FilePattern> = cli let extend_exclude: Vec<FilePattern> = cli
.extend_exclude .extend_exclude
.iter() .iter()
.map(|path| FilePattern::from_user(path, &project_root)) .map(|path| FilePattern::from_user(path, project_root.as_ref()))
.collect(); .collect();
let mut configuration = Configuration::from_pyproject(&pyproject, &project_root)?; let mut configuration =
Configuration::from_pyproject(pyproject.as_ref(), project_root.as_ref())?;
if !exclude.is_empty() { if !exclude.is_empty() {
configuration.exclude = exclude; configuration.exclude = exclude;
} }
@ -235,7 +236,7 @@ fn inner_main() -> Result<ExitCode> {
} }
if !cli.per_file_ignores.is_empty() { if !cli.per_file_ignores.is_empty() {
configuration.per_file_ignores = configuration.per_file_ignores =
collect_per_file_ignores(cli.per_file_ignores, &project_root); collect_per_file_ignores(cli.per_file_ignores, project_root.as_ref());
} }
if !cli.select.is_empty() { if !cli.select.is_empty() {
warn_on( warn_on(
@ -244,7 +245,7 @@ fn inner_main() -> Result<ExitCode> {
&cli.ignore, &cli.ignore,
&cli.extend_ignore, &cli.extend_ignore,
&configuration, &configuration,
&pyproject, pyproject.as_ref(),
); );
configuration.select = cli.select; configuration.select = cli.select;
} }
@ -255,7 +256,7 @@ fn inner_main() -> Result<ExitCode> {
&cli.ignore, &cli.ignore,
&cli.extend_ignore, &cli.extend_ignore,
&configuration, &configuration,
&pyproject, pyproject.as_ref(),
); );
configuration.extend_select = cli.extend_select; configuration.extend_select = cli.extend_select;
} }

View file

@ -65,8 +65,8 @@ static DEFAULT_DUMMY_VARIABLE_RGX: Lazy<Regex> =
impl Configuration { impl Configuration {
pub fn from_pyproject( pub fn from_pyproject(
pyproject: &Option<PathBuf>, pyproject: Option<&PathBuf>,
project_root: &Option<PathBuf>, project_root: Option<&PathBuf>,
) -> Result<Self> { ) -> Result<Self> {
let options = load_options(pyproject)?; let options = load_options(pyproject)?;
Ok(Configuration { Ok(Configuration {

View file

@ -36,7 +36,7 @@ fn parse_pyproject_toml(path: &Path) -> Result<Pyproject> {
toml::from_str(&contents).map_err(|e| e.into()) toml::from_str(&contents).map_err(|e| e.into())
} }
pub fn find_pyproject_toml(path: &Option<PathBuf>) -> Option<PathBuf> { pub fn find_pyproject_toml(path: Option<&PathBuf>) -> Option<PathBuf> {
if let Some(path) = path { if let Some(path) = path {
let path_pyproject_toml = path.join("pyproject.toml"); let path_pyproject_toml = path.join("pyproject.toml");
if path_pyproject_toml.is_file() { if path_pyproject_toml.is_file() {
@ -80,7 +80,7 @@ pub fn find_project_root(sources: &[PathBuf]) -> Option<PathBuf> {
None None
} }
pub fn load_options(pyproject: &Option<PathBuf>) -> Result<Options> { pub fn load_options(pyproject: Option<&PathBuf>) -> Result<Options> {
match pyproject { match pyproject {
Some(pyproject) => Ok(parse_pyproject_toml(pyproject)? Some(pyproject) => Ok(parse_pyproject_toml(pyproject)?
.tool .tool
@ -323,7 +323,7 @@ other-attribute = 1
assert_eq!(project_root, cwd.join("resources/test/fixtures")); assert_eq!(project_root, cwd.join("resources/test/fixtures"));
let path = let path =
find_pyproject_toml(&Some(project_root)).expect("Unable to find pyproject.toml."); find_pyproject_toml(Some(&project_root)).expect("Unable to find pyproject.toml.");
assert_eq!(path, cwd.join("resources/test/fixtures/pyproject.toml")); assert_eq!(path, cwd.join("resources/test/fixtures/pyproject.toml"));
let pyproject = parse_pyproject_toml(&path)?; let pyproject = parse_pyproject_toml(&path)?;

View file

@ -51,7 +51,7 @@ pub enum FilePattern {
} }
impl FilePattern { impl FilePattern {
pub fn from_user(pattern: &str, project_root: &Option<PathBuf>) -> Self { pub fn from_user(pattern: &str, project_root: Option<&PathBuf>) -> Self {
let path = Path::new(pattern); let path = Path::new(pattern);
let absolute_path = match project_root { let absolute_path = match project_root {
Some(project_root) => fs::normalize_path_to(path, project_root), Some(project_root) => fs::normalize_path_to(path, project_root),
@ -79,7 +79,7 @@ impl PerFileIgnore {
pub fn new( pub fn new(
pattern: &str, pattern: &str,
prefixes: &[CheckCodePrefix], prefixes: &[CheckCodePrefix],
project_root: &Option<PathBuf>, project_root: Option<&PathBuf>,
) -> Self { ) -> Self {
let pattern = FilePattern::from_user(pattern, project_root); let pattern = FilePattern::from_user(pattern, project_root);
let codes = BTreeSet::from_iter(prefixes.iter().flat_map(|prefix| prefix.codes())); let codes = BTreeSet::from_iter(prefixes.iter().flat_map(|prefix| prefix.codes()));