Skip to content

Commit f2838bf

Browse files
committed
Refactor ModResolver.directory
Prefer replacing with a new function with_directory rather than modifying in place.
1 parent 70c7ab6 commit f2838bf

File tree

1 file changed

+53
-48
lines changed

1 file changed

+53
-48
lines changed

src/modules.rs

Lines changed: 53 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -220,13 +220,11 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
220220
sub_mod: Module<'_>,
221221
from_ast: bool,
222222
) -> Result<(), ModuleResolutionError> {
223-
let old_directory = self.directory.clone();
224223
let sub_mod_kind = self.peek_sub_mod(item, &sub_mod)?;
225224
if let Some(sub_mod_kind) = sub_mod_kind {
226225
self.insert_sub_mod(sub_mod_kind.clone())?;
227226
self.visit_sub_mod_inner(sub_mod, sub_mod_kind, from_ast)?;
228227
}
229-
self.directory = old_directory;
230228
Ok(())
231229
}
232230

@@ -284,39 +282,30 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
284282
path: mod_path.parent().unwrap().to_path_buf(),
285283
ownership: directory_ownership,
286284
};
287-
self.visit_sub_mod_after_directory_update(sub_mod, Some(directory), false)
285+
self.with_directory(directory, |this| this.visit_mod_outside_ast(&sub_mod.items))?;
288286
}
289287
SubModKind::Internal(item) => {
290-
self.push_inline_mod_directory(item.ident, &item.attrs);
291-
self.visit_sub_mod_after_directory_update(sub_mod, None, from_ast)
288+
let directory = self.inline_mod_directory(item.ident, &item.attrs);
289+
self.with_directory(directory, |this| {
290+
if from_ast {
291+
this.visit_mod_from_ast(&sub_mod.items)
292+
} else {
293+
this.visit_mod_outside_ast(&sub_mod.items)
294+
}
295+
})?;
292296
}
293297
SubModKind::MultiExternal(mods) => {
294298
for (mod_path, directory_ownership, sub_mod) in mods {
295299
let directory = Directory {
296300
path: mod_path.parent().unwrap().to_path_buf(),
297301
ownership: directory_ownership,
298302
};
299-
self.visit_sub_mod_after_directory_update(sub_mod, Some(directory), false)?;
303+
self.with_directory(directory, |this| {
304+
this.visit_mod_outside_ast(&sub_mod.items)
305+
})?;
300306
}
301-
Ok(())
302307
}
303308
}
304-
}
305-
306-
fn visit_sub_mod_after_directory_update(
307-
&mut self,
308-
sub_mod: Module<'_>,
309-
directory: Option<Directory>,
310-
from_ast: bool,
311-
) -> Result<(), ModuleResolutionError> {
312-
if let Some(directory) = directory {
313-
self.directory = directory;
314-
}
315-
if from_ast {
316-
self.visit_mod_from_ast(&sub_mod.items)?;
317-
} else {
318-
self.visit_mod_outside_ast(&sub_mod.items)?;
319-
}
320309
Ok(())
321310
}
322311

@@ -449,31 +438,41 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
449438
}
450439
}
451440

452-
fn push_inline_mod_directory(&mut self, id: symbol::Ident, attrs: &[ast::Attribute]) {
441+
fn inline_mod_directory(&mut self, id: symbol::Ident, attrs: &[ast::Attribute]) -> Directory {
453442
if let Some(path) = find_path_value(attrs) {
454-
self.directory.path.push(path.as_str());
455-
self.directory.ownership = DirectoryOwnership::Owned { relative: None };
456-
} else {
457-
let id = id.as_str();
458-
// We have to push on the current module name in the case of relative
459-
// paths in order to ensure that any additional module paths from inline
460-
// `mod x { ... }` come after the relative extension.
461-
//
462-
// For example, a `mod z { ... }` inside `x/y.rs` should set the current
463-
// directory path to `/x/y/z`, not `/x/z` with a relative offset of `y`.
464-
if let DirectoryOwnership::Owned { relative } = &mut self.directory.ownership {
465-
if let Some(ident) = relative.take() {
466-
// remove the relative offset
467-
self.directory.path.push(ident.as_str());
468-
469-
// In the case where there is an x.rs and an ./x directory we want
470-
// to prevent adding x twice. For example, ./x/x
471-
if self.directory.path.exists() && !self.directory.path.join(id).exists() {
472-
return;
473-
}
474-
}
443+
return Directory {
444+
path: self.directory.path.join(path.as_str()),
445+
ownership: DirectoryOwnership::Owned { relative: None },
446+
};
447+
}
448+
let id = id.as_str();
449+
// We have to push on the current module name in the case of relative
450+
// paths in order to ensure that any additional module paths from inline
451+
// `mod x { ... }` come after the relative extension.
452+
//
453+
// For example, a `mod z { ... }` inside `x/y.rs` should set the current
454+
// directory path to `/x/y/z`, not `/x/z` with a relative offset of `y`.
455+
let new_path = if let DirectoryOwnership::Owned {
456+
relative: Some(ident),
457+
} = self.directory.ownership
458+
{
459+
// remove the relative offset
460+
let relative = self.directory.path.join(ident.as_str());
461+
let nested = relative.join(id);
462+
463+
// In the case where there is an x.rs and an ./x directory we want
464+
// to prevent adding x twice. For example, ./x/x
465+
if relative.exists() && !nested.exists() {
466+
relative
467+
} else {
468+
nested
475469
}
476-
self.directory.path.push(id);
470+
} else {
471+
self.directory.path.join(id)
472+
};
473+
Directory {
474+
path: new_path,
475+
ownership: self.directory.ownership,
477476
}
478477
}
479478

@@ -491,8 +490,7 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
491490
}
492491
let mut result = vec![];
493492
for path in path_visitor.paths() {
494-
let mut actual_path = self.directory.path.clone();
495-
actual_path.push(&path);
493+
let actual_path = self.directory.path.join(path);
496494
if !actual_path.exists() {
497495
continue;
498496
}
@@ -520,6 +518,13 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
520518
}
521519
result
522520
}
521+
522+
fn with_directory<T>(&mut self, directory: Directory, f: impl FnOnce(&mut Self) -> T) -> T {
523+
let old = std::mem::replace(&mut self.directory, directory);
524+
let out = f(self);
525+
self.directory = old;
526+
out
527+
}
523528
}
524529

525530
fn path_value(attr: &ast::Attribute) -> Option<Symbol> {

0 commit comments

Comments
 (0)