diff --git a/core/src/cli.rs b/core/src/cli.rs index ae7c8c92..738e32a7 100644 --- a/core/src/cli.rs +++ b/core/src/cli.rs @@ -33,7 +33,7 @@ pub struct Opts { #[clap(long, help = "Dump removal candidates and exit (for debugging)")] dump_candidates: bool, #[clap(long, help = "Assume testing framework is ")] - framework: Option>, + framework: Option>, #[clap(long, help = "Do not perform dry runs")] no_dry_run: bool, #[clap(long, help = "Do not output to an sqlite database")] @@ -64,7 +64,7 @@ pub struct Opts { } impl From> - for (Necessist, framework::Auto) + for (Necessist, framework::auto::Auto) { fn from(opts: Opts) -> Self { let Opts { diff --git a/core/src/core.rs b/core/src/core.rs index 3098cf9f..20a87165 100644 --- a/core/src/core.rs +++ b/core/src/core.rs @@ -92,7 +92,7 @@ pub struct Config { // to parameterize every function that takes a `Necessist` as an argument. pub fn necessist( opts: &Necessist, - framework: framework::Auto, + framework: framework::auto::Auto, ) -> Result<()> { let mut opts = opts.clone(); @@ -158,7 +158,7 @@ pub fn necessist( context: &LightContext, - framework: framework::Auto, + framework: framework::auto::Auto, ) -> Result< Option<( Option, @@ -387,7 +387,7 @@ fn dump(context: &LightContext, removals: &[Removal]) { fn find_framework( context: &LightContext, - identifier: framework::Auto, + identifier: framework::auto::Auto, ) -> Result> { let implementation = identifier.to_implementation(context)?; diff --git a/core/src/framework/auto.rs b/core/src/framework/auto.rs index 33fbd1ab..f8f4430c 100644 --- a/core/src/framework/auto.rs +++ b/core/src/framework/auto.rs @@ -1,4 +1,4 @@ -use super::{Applicable, Interface, ToImplementation, Union}; +use super::{union, Applicable, Interface, ToImplementation}; use crate::LightContext; use anyhow::{ensure, Result}; use std::fmt::Display; @@ -14,11 +14,11 @@ enum Singleton { } #[derive(Debug, Clone, Copy, Eq, PartialEq)] -pub struct Auto(Union); +pub struct Auto(union::Union); impl Default for Auto { fn default() -> Self { - Self(Union::Left(Singleton::Auto)) + Self(union::Union::Left(Singleton::Auto)) } } @@ -28,7 +28,7 @@ where { fn to_implementation(&self, context: &LightContext) -> Result>> { match &self.0 { - Union::Left(_) => { + union::Union::Left(_) => { let unflattened_frameworks = T::iter() .map(|framework| { if framework.applicable(context)? { @@ -61,7 +61,7 @@ where Ok(None) } } - Union::Right(framework) => framework.to_implementation(context), + union::Union::Right(framework) => framework.to_implementation(context), } } } @@ -73,7 +73,7 @@ where { fn value_variants<'a>() -> &'a [Self] { Box::leak( - Union::::value_variants() + union::Union::::value_variants() .iter() .cloned() .map(Self) @@ -87,6 +87,6 @@ where } fn from_str(input: &str, ignore_case: bool) -> Result { - Union::::from_str(input, ignore_case).map(Self) + union::Union::::from_str(input, ignore_case).map(Self) } } diff --git a/core/src/framework/mod.rs b/core/src/framework/mod.rs index e4b77614..5c8970e9 100644 --- a/core/src/framework/mod.rs +++ b/core/src/framework/mod.rs @@ -4,17 +4,14 @@ use heck::ToKebabCase; use std::{any::type_name, path::Path}; use subprocess::{Exec, Popen}; -mod auto; -pub use auto::Auto; +pub mod auto; -mod empty; -pub use empty::Empty; +pub mod empty; -mod union; -pub use union::Union; +pub mod union; #[allow(dead_code)] -type AutoUnion = Auto>; +type AutoUnion = auto::Auto>; pub type Postprocess = dyn Fn(&LightContext, Popen) -> Result; diff --git a/core/src/offset_based_rewriter/mod.rs b/core/src/offset_based_rewriter/mod.rs index d12b1566..20087d97 100644 --- a/core/src/offset_based_rewriter/mod.rs +++ b/core/src/offset_based_rewriter/mod.rs @@ -3,11 +3,6 @@ mod impls; -use impls::LazyRewriter; - -#[cfg(feature = "check-rewrites")] -use impls::EagerRewriter; - pub trait Interface { fn contents(self) -> String; fn rewrite(&mut self, start: usize, end: usize, replacement: &str) -> String; @@ -15,19 +10,19 @@ pub trait Interface { #[derive(Debug)] pub struct OffsetBasedRewriter<'original> { - lazy: LazyRewriter<'original>, + lazy: impls::LazyRewriter<'original>, #[cfg(feature = "check-rewrites")] - eager: EagerRewriter, + eager: impls::EagerRewriter, } impl<'original> OffsetBasedRewriter<'original> { pub fn new(original: &'original str) -> Self { Self { - lazy: LazyRewriter::new(original), + lazy: impls::LazyRewriter::new(original), #[cfg(feature = "check-rewrites")] - eager: EagerRewriter::new(original), + eager: impls::EagerRewriter::new(original), } } } diff --git a/core/src/offset_calculator/mod.rs b/core/src/offset_calculator/mod.rs index 2139f481..0b8f553c 100644 --- a/core/src/offset_calculator/mod.rs +++ b/core/src/offset_calculator/mod.rs @@ -5,30 +5,25 @@ use proc_macro2::LineColumn; mod impls; -use impls::CachingOffsetCalculator; - -#[cfg(feature = "check-offsets")] -use impls::StatelessOffsetCalculator; - pub trait Interface { fn offset_from_line_column(&mut self, line_column: LineColumn) -> (usize, bool); } #[derive(Debug)] pub struct OffsetCalculator<'original> { - caching: CachingOffsetCalculator<'original>, + caching: impls::CachingOffsetCalculator<'original>, #[cfg(feature = "check-offsets")] - stateless: StatelessOffsetCalculator<'original>, + stateless: impls::StatelessOffsetCalculator<'original>, } impl<'original> OffsetCalculator<'original> { pub fn new(original: &'original str) -> Self { Self { - caching: CachingOffsetCalculator::new(original), + caching: impls::CachingOffsetCalculator::new(original), #[cfg(feature = "check-offsets")] - stateless: StatelessOffsetCalculator::new(original), + stateless: impls::StatelessOffsetCalculator::new(original), } } } diff --git a/crates_io/src/main.rs b/crates_io/src/main.rs index 5ecf5abf..0a73541f 100644 --- a/crates_io/src/main.rs +++ b/crates_io/src/main.rs @@ -1,6 +1,6 @@ use anyhow::Result; use clap::Parser; -use necessist_core::{cli, framework::Auto, necessist, Necessist}; +use necessist_core::{cli, framework::auto::Auto, necessist, Necessist}; use necessist_frameworks::Identifier; use std::env::args; diff --git a/frameworks/src/foundry/mod.rs b/frameworks/src/foundry/mod.rs index d90fa940..5e6e072c 100644 --- a/frameworks/src/foundry/mod.rs +++ b/frameworks/src/foundry/mod.rs @@ -5,7 +5,6 @@ use std::{collections::BTreeMap, fs::read_to_string, path::Path, process::Comman use walkdir::WalkDir; mod visitor; -use visitor::visit; #[derive(Debug)] pub struct Foundry { @@ -52,7 +51,7 @@ impl Low for Foundry { util::strip_prefix(test_file, context.root).unwrap() ) })?; - let spans_visited = visit( + let spans_visited = visitor::visit( self, context.root.clone(), test_file, diff --git a/frameworks/src/golang/mod.rs b/frameworks/src/golang/mod.rs index 9d5dd6d1..925b5f0f 100644 --- a/frameworks/src/golang/mod.rs +++ b/frameworks/src/golang/mod.rs @@ -6,7 +6,6 @@ use tree_sitter::Parser; use walkdir::WalkDir; mod visitor; -use visitor::visit; #[derive(Debug)] pub struct Golang { @@ -55,7 +54,8 @@ impl Low for Golang { util::strip_prefix(test_file, context.root).unwrap() ) })?; - let spans_visited = visit(self, context.root.clone(), test_file, &text, &tree)?; + let spans_visited = + visitor::visit(self, context.root.clone(), test_file, &text, &tree)?; spans.extend(spans_visited); Ok(()) }; diff --git a/frameworks/src/hardhat_ts/mod.rs b/frameworks/src/hardhat_ts/mod.rs index aff35b08..469c85be 100644 --- a/frameworks/src/hardhat_ts/mod.rs +++ b/frameworks/src/hardhat_ts/mod.rs @@ -26,7 +26,6 @@ use swc_core::{ use walkdir::WalkDir; mod visitor; -use visitor::visit; #[derive(Debug, Eq, PartialEq)] enum ItMessageState { @@ -113,7 +112,7 @@ impl High for HardhatTs { util::strip_prefix(test_file, context.root).unwrap() ) })?; - let spans_visited = visit( + let spans_visited = visitor::visit( config, self, source_map, diff --git a/frameworks/src/rust/mod.rs b/frameworks/src/rust/mod.rs index 9cf462cc..e3dd932c 100644 --- a/frameworks/src/rust/mod.rs +++ b/frameworks/src/rust/mod.rs @@ -13,13 +13,12 @@ use syn::parse_file; use walkdir::WalkDir; mod parsing; -use parsing::{cached_test_file_fs_module_path, cached_test_file_package, Parsing}; mod try_insert; -use try_insert::TryInsert; +#[allow(unused_imports)] +use try_insert::{self as _, TryInsert}; mod visitor; -use visitor::visit; #[derive(Debug)] pub struct Rust { @@ -59,7 +58,7 @@ impl Low for Rust { ) -> Result> { check_config(context, config)?; - let mut parsing = Parsing::default(); + let mut parsing = parsing::Parsing::default(); let mut spans = Vec::new(); #[cfg_attr( @@ -77,7 +76,8 @@ impl Low for Rust { util::strip_prefix(test_file, context.root).unwrap() ) })?; - let spans_visited = visit(context, config, self, &mut parsing, test_file, &file)?; + let spans_visited = + visitor::visit(context, config, self, &mut parsing, test_file, &file)?; spans.extend(spans_visited); Ok(()) }; @@ -173,7 +173,7 @@ impl Rust { self.test_file_flags_cache .entry(test_file.to_path_buf()) .or_try_insert_with(|| { - let package = cached_test_file_package(test_file_package_map, test_file)?; + let package = parsing::cached_test_file_package(test_file_package_map, test_file)?; let mut flags = vec![ "--manifest-path".to_owned(), diff --git a/frameworks/src/rust/visitor.rs b/frameworks/src/rust/visitor.rs index 4cc99ff2..71bcbfad 100644 --- a/frameworks/src/rust/visitor.rs +++ b/frameworks/src/rust/visitor.rs @@ -1,4 +1,4 @@ -use super::{cached_test_file_fs_module_path, Parsing, Rust}; +use super::{parsing, Rust}; use anyhow::{Error, Result}; use necessist_core::{ warn, Config, LightContext, SourceFile, Span, ToInternalSpan, WarnFlags, Warning, @@ -23,7 +23,7 @@ pub(super) fn visit( context: &LightContext, config: &Config, framework: &mut Rust, - parsing: &mut Parsing, + parsing: &mut parsing::Parsing, test_file: &Path, file: &File, ) -> Result> { @@ -40,7 +40,7 @@ struct Visitor<'ast, 'context, 'config, 'framework, 'parsing> { context: &'context LightContext<'context>, config: &'config Config, framework: &'framework mut Rust, - parsing: &'parsing mut Parsing, + parsing: &'parsing mut parsing::Parsing, source_file: SourceFile, module_path: Vec<&'ast Ident>, test_ident: Option<&'ast Ident>, @@ -150,7 +150,7 @@ where context: &'context LightContext, config: &'config Config, framework: &'framework mut Rust, - parsing: &'parsing mut Parsing, + parsing: &'parsing mut parsing::Parsing, test_file: &Path, ) -> Self { Self { @@ -201,7 +201,7 @@ where } fn test_path(&mut self, span: &Span, ident: &Ident) -> Result> { - let mut test_path = cached_test_file_fs_module_path( + let mut test_path = parsing::cached_test_file_fs_module_path( &mut self.parsing.test_file_fs_module_path_cache, &mut self.parsing.test_file_package_cache, &span.source_file, diff --git a/necessist/src/main.rs b/necessist/src/main.rs index 97350812..312ae209 100644 --- a/necessist/src/main.rs +++ b/necessist/src/main.rs @@ -5,7 +5,7 @@ use anyhow::Result; use clap::Parser; use log::debug; -use necessist_core::{cli, framework::Auto, necessist, Necessist}; +use necessist_core::{cli, framework::auto::Auto, necessist, Necessist}; use necessist_frameworks::Identifier; use std::{ env::{args, var}, diff --git a/necessist/tests/ci.rs b/necessist/tests/ci.rs index 2bdcaaa5..0a0e3ad4 100644 --- a/necessist/tests/ci.rs +++ b/necessist/tests/ci.rs @@ -177,8 +177,8 @@ fn modules() { } } -/// `noninvasive_siblings` helps to expose circular module dependencies. See the [`modules`] test -/// within this file. +/// `noninvasive_siblings` and `semi_noninvasive_parents` help to expose circular module +/// dependencies. See the [`modules`] test within this file. #[test] fn noninvasive_siblings() { let re = Regex::new(r"use super::\{([^}]|\}[^;])*::").unwrap(); @@ -200,12 +200,48 @@ fn noninvasive_siblings() { } let contents = read_to_string(path).unwrap(); + if contents.contains("use super::{") { assert!(!re.is_match(&contents), "failed for {path:?}"); } } } +#[test] +fn semi_noninvasive_parents() { + let re = Regex::new(r"mod ([^;]*);").unwrap(); + + for entry in WalkDir::new(Path::new(env!("CARGO_MANIFEST_DIR")).join("..")) + .into_iter() + .filter_entry(|entry| entry.path().file_name() != Some(OsStr::new("target"))) + { + let entry = entry.unwrap(); + let path = entry.path(); + + if path.extension() != Some(OsStr::new("rs")) { + continue; + } + + // smoelius: `lib.rs` files get a pass. + if path.file_name() == Some(OsStr::new("lib.rs")) { + continue; + } + + let contents = read_to_string(path).unwrap(); + + for captures in re.captures_iter(&contents) { + assert_eq!(2, captures.len()); + let name = &captures[1]; + let pat = format!("use {name}::"); + let pat_self = pat.clone() + "{self"; + assert!( + !contents.contains(&pat) || contents.contains(&pat_self), + "{path:?} contains `{pat}` but not `{pat_self}`" + ); + } + } +} + #[test] fn prettier() { let tempdir = tempdir().unwrap();