Skip to content

Commit

Permalink
Handle relative paths
Browse files Browse the repository at this point in the history
  • Loading branch information
Manishearth committed Jan 1, 2018
1 parent 08a89b3 commit 7effbeb
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 43 deletions.
64 changes: 36 additions & 28 deletions src/librustc_resolve/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1413,25 +1413,6 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> {

fn resolve_str_path(&mut self, span: Span, crate_root: Option<&str>,
components: &[&str], is_value: bool) -> hir::Path {
self.resolve_str_path_cb(span, crate_root, components, is_value,
|resolver, span, error| resolve_error(resolver, span, error))
}

fn get_resolution(&mut self, id: NodeId) -> Option<PathResolution> {
self.def_map.get(&id).cloned()
}

fn definitions(&mut self) -> &mut Definitions {
&mut self.definitions
}
}

impl<'a> Resolver<'a> {
/// resolve_str_path, but takes a callback in case there was an error
fn resolve_str_path_cb<F>(&mut self, span: Span, crate_root: Option<&str>,
components: &[&str], is_value: bool, error_callback: F) -> hir::Path
where F: for<'b, 'c> FnOnce(&'c mut Resolver, Span, ResolutionError<'b>)
{
use std::iter;
let mut path = hir::Path {
span,
Expand All @@ -1441,19 +1422,45 @@ impl<'a> Resolver<'a> {
}).map(hir::PathSegment::from_name).collect(),
};

self.resolve_hir_path_cb(&mut path, is_value, error_callback);
self.resolve_hir_path(&mut path, is_value);
path
}

fn get_resolution(&mut self, id: NodeId) -> Option<PathResolution> {
self.def_map.get(&id).cloned()
}

fn definitions(&mut self) -> &mut Definitions {
&mut self.definitions
}
}

impl<'a> Resolver<'a> {
/// Rustdoc uses this to resolve things in a recoverable way. ResolutionError<'a>
/// isn't something that can be returned because it can't be made to live that long,
/// and also it's a private type. Fortunately rustdoc doesn't need to know the error,
/// just that an error occured.
pub fn resolve_str_path_error(&mut self, span: Span, crate_root: Option<&str>,
components: &[&str], is_value: bool) -> Result<hir::Path, ()> {
pub fn resolve_str_path_error(&mut self, span: Span, path_str: &str, is_value: bool) -> Result<hir::Path, ()> {
use std::iter;
let mut errored = false;
let path = self.resolve_str_path_cb(span, crate_root, components, is_value,
|_, _, _| errored = true);

let mut path = if path_str.starts_with("::") {
hir::Path {
span,
def: Def::Err,
segments: iter::once(keywords::CrateRoot.name()).chain({
path_str.split("::").skip(1).map(Symbol::intern)
}).map(hir::PathSegment::from_name).collect(),
}
} else {
hir::Path {
span,
def: Def::Err,
segments: path_str.split("::").map(Symbol::intern)
.map(hir::PathSegment::from_name).collect(),
}
};
self.resolve_hir_path_cb(&mut path, is_value, |_, _, _| errored = true);
if errored || path.def == Def::Err {
Err(())
} else {
Expand Down Expand Up @@ -1874,8 +1881,8 @@ impl<'a> Resolver<'a> {
// generate a fake "implementation scope" containing all the
// implementations thus found, for compatibility with old resolve pass.

fn with_scope<F>(&mut self, id: NodeId, f: F)
where F: FnOnce(&mut Resolver)
pub fn with_scope<F, T>(&mut self, id: NodeId, f: F) -> T
where F: FnOnce(&mut Resolver) -> T
{
let id = self.definitions.local_def_id(id);
let module = self.module_map.get(&id).cloned(); // clones a reference
Expand All @@ -1886,13 +1893,14 @@ impl<'a> Resolver<'a> {
self.ribs[TypeNS].push(Rib::new(ModuleRibKind(module)));

self.finalize_current_module_macro_resolutions();
f(self);
let ret = f(self);

self.current_module = orig_module;
self.ribs[ValueNS].pop();
self.ribs[TypeNS].pop();
ret
} else {
f(self);
f(self)
}
}

Expand Down
36 changes: 21 additions & 15 deletions src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,11 @@ impl Clean<Item> for doctree::Module {
"".to_string()
};

// maintain a stack of mod ids
// we could also pass this down through clean()
// but that might complicate things.
cx.mod_ids.borrow_mut().push(self.id);

let mut items: Vec<Item> = vec![];
items.extend(self.extern_crates.iter().map(|x| x.clean(cx)));
items.extend(self.imports.iter().flat_map(|x| x.clean(cx)));
Expand All @@ -490,6 +495,8 @@ impl Clean<Item> for doctree::Module {
items.extend(self.macros.iter().map(|x| x.clean(cx)));
items.extend(self.def_traits.iter().map(|x| x.clean(cx)));

cx.mod_ids.borrow_mut().pop();

// determine if we should display the inner contents or
// the outer `mod` item for the source code.
let whence = {
Expand Down Expand Up @@ -849,21 +856,20 @@ impl Clean<Attributes> for [ast::Attribute] {
link.trim()
};

if !path_str.starts_with("::") {
// FIXME (misdreavus): can only support absolute paths because of limitations
// in Resolver. this may, with a lot of effort, figure out how to resolve paths
// within scopes, but the one use of `resolve_hir_path` i found in the HIR
// lowering code itself used an absolute path. we're brushing up against some
// structural limitations in the compiler already, but this may be a design one
// as well >_>
continue;
}

// This allocation could be avoided if resolve_str_path could take an iterator;
// but it can't because that would break object safety. This can still be
// fixed.
let components = path_str.split("::").skip(1).collect::<Vec<_>>();
let resolve = |is_val| cx.resolver.borrow_mut().resolve_str_path_error(DUMMY_SP, None, &components, is_val);
let resolve = |is_val| {
// In case we're in a module, try to resolve the relative
// path
if let Some(id) = cx.mod_ids.borrow().last() {
cx.resolver.borrow_mut()
.with_scope(*id, |resolver| {
resolver.resolve_str_path_error(DUMMY_SP, &path_str, is_val)
})
} else {
// FIXME(Manishearth) this branch doesn't seem to ever be hit, really
cx.resolver.borrow_mut()
.resolve_str_path_error(DUMMY_SP, &path_str, is_val)
}
};

if let Some(is_value) = is_value {
if let Ok(path) = resolve(is_value) {
Expand Down
4 changes: 4 additions & 0 deletions src/librustdoc/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use rustc_resolve as resolve;
use rustc_metadata::creader::CrateLoader;
use rustc_metadata::cstore::CStore;

use syntax::ast::NodeId;
use syntax::codemap;
use syntax::feature_gate::UnstableFeatures;
use errors;
Expand All @@ -48,6 +49,8 @@ pub type ExternalPaths = FxHashMap<DefId, (Vec<String>, clean::TypeKind)>;
pub struct DocContext<'a, 'tcx: 'a, 'rcx: 'a> {
pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
pub resolver: &'a RefCell<resolve::Resolver<'rcx>>,
/// The stack of module NodeIds up till this point
pub mod_ids: RefCell<Vec<NodeId>>,
pub populated_all_crate_impls: Cell<bool>,
// Note that external items for which `doc(hidden)` applies to are shown as
// non-reachable while local items aren't. This is because we're reusing
Expand Down Expand Up @@ -243,6 +246,7 @@ pub fn run_core(search_paths: SearchPaths,
render_type,
ty_substs: Default::default(),
lt_substs: Default::default(),
mod_ids: Default::default(),
};
debug!("crate: {:?}", tcx.hir.krate());

Expand Down

0 comments on commit 7effbeb

Please sign in to comment.