Skip to content

Commit

Permalink
Resolve foreign macros
Browse files Browse the repository at this point in the history
  • Loading branch information
Manishearth committed Jan 22, 2018
1 parent d6dd902 commit 7ac48d7
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 34 deletions.
2 changes: 1 addition & 1 deletion src/librustc_resolve/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ impl<'a> Resolver<'a> {
def
}

fn resolve_macro_to_def_inner(&mut self, scope: Mark, path: &ast::Path,
pub fn resolve_macro_to_def_inner(&mut self, scope: Mark, path: &ast::Path,
kind: MacroKind, force: bool)
-> Result<Def, Determinacy> {
let ast::Path { ref segments, span } = *path;
Expand Down
6 changes: 5 additions & 1 deletion src/librustdoc/clean/inline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,11 @@ pub fn record_extern_fqn(cx: &DocContext, did: DefId, kind: clean::TypeKind) {
None
}
});
let fqn = once(crate_name).chain(relative).collect();
let fqn = if let clean::TypeKind::Macro = kind {
vec![crate_name, relative.last().unwrap()]
} else {
once(crate_name).chain(relative).collect()
};
cx.renderinfo.borrow_mut().external_paths.insert(did, (fqn, kind));
}

Expand Down
107 changes: 76 additions & 31 deletions src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -824,34 +824,43 @@ impl AttributesExt for Attributes {
}
}

enum PathKind {
/// can be either value or type, not a macro
Unknown,
/// macro
Macro,
/// values, functions, consts, statics, everything in the value namespace
Value,
/// types, traits, everything in the type namespace
Type
}
impl Clean<Attributes> for [ast::Attribute] {
fn clean(&self, cx: &DocContext) -> Attributes {
let mut attrs = Attributes::from_ast(cx.sess().diagnostic(), self);

if UnstableFeatures::from_environment().is_nightly_build() {
let dox = attrs.collapsed_doc_value().unwrap_or_else(String::new);
for link in markdown_links(&dox, cx.render_type) {
let path = {
let is_value;
let def = {
let mut kind = PathKind::Unknown;
let path_str = if let Some(prefix) =
["struct", "enum", "type",
"trait", "union"].iter()
.find(|p| link.starts_with(**p)) {
is_value = Some(false);
kind = PathKind::Type;
link.trim_left_matches(prefix).trim()
} else if let Some(prefix) =
["const", "static"].iter()
.find(|p| link.starts_with(**p)) {
is_value = Some(true);
kind = PathKind::Value;
link.trim_left_matches(prefix).trim()
} else if link.ends_with("()") {
is_value = Some(true);
kind = PathKind::Value;
link.trim_right_matches("()").trim()
} else if link.ends_with("!") {
// FIXME (misdreavus): macros are resolved with different machinery
continue;
} else if link.ends_with('!') {
kind = PathKind::Macro;
link.trim_right_matches('!').trim()
} else {
is_value = None;
link.trim()
};

Expand Down Expand Up @@ -879,34 +888,68 @@ impl Clean<Attributes> for [ast::Attribute] {
}
};

if let Some(is_value) = is_value {
if let Ok(path) = resolve(is_value) {
path
} else {
// this could just be a normal link or a broken link
// we could potentially check if something is
// "intra-doc-link-like" and warn in that case
continue;
match kind {
PathKind::Value => {
if let Ok(path) = resolve(true) {
path.def
} else {
// this could just be a normal link or a broken link
// we could potentially check if something is
// "intra-doc-link-like" and warn in that case
continue;
}
}
} else {
// try both!
// It is imperative we search for not-a-value first
// Otherwise we will find struct ctors for when we are looking
// for structs, etc, and the link won't work.
if let Ok(path) = resolve(false) {
path
} else if let Ok(path) = resolve(true) {
path
} else {
// this could just be a normal link
continue;
PathKind::Type => {
if let Ok(path) = resolve(false) {
path.def
} else {
// this could just be a normal link
continue;
}
}
PathKind::Unknown => {
// try both!
// It is imperative we search for not-a-value first
// Otherwise we will find struct ctors for when we are looking
// for structs, etc, and the link won't work.
if let Ok(path) = resolve(false) {
path.def
} else if let Ok(path) = resolve(true) {
path.def
} else {
// this could just be a normal link
continue;
}
}
PathKind::Macro => {
use syntax::ext::base::MacroKind;
use syntax::ext::hygiene::Mark;
let segment = ast::PathSegment {
identifier: ast::Ident::from_str(path_str),
span: DUMMY_SP,
parameters: None,
};
let path = ast::Path {
span: DUMMY_SP,
segments: vec![segment],
};

let mut resolver = cx.resolver.borrow_mut();
let mark = Mark::root();
let res = resolver
.resolve_macro_to_def_inner(mark, &path, MacroKind::Bang, false);
if let Ok(def) = res {
def
} else {
continue;
}
}
}
};

register_def(cx, def);

attrs.links.push((link, path.def.def_id()));
register_def(cx, def);
attrs.links.push((link, def.def_id()));
}

cx.sess().abort_if_errors();
Expand Down Expand Up @@ -1970,6 +2013,7 @@ pub enum TypeKind {
Variant,
Typedef,
Foreign,
Macro,
}

pub trait GetDefId {
Expand Down Expand Up @@ -3271,6 +3315,7 @@ fn register_def(cx: &DocContext, def: Def) -> DefId {
Def::TyForeign(i) => (i, TypeKind::Foreign),
Def::Static(i, _) => (i, TypeKind::Static),
Def::Variant(i) => (cx.tcx.parent_def_id(i).unwrap(), TypeKind::Enum),
Def::Macro(i, _) => (i, TypeKind::Macro),
Def::SelfTy(Some(def_id), _) => (def_id, TypeKind::Trait),
Def::SelfTy(_, Some(impl_def_id)) => {
return impl_def_id
Expand Down
1 change: 1 addition & 0 deletions src/librustdoc/html/item_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ impl From<clean::TypeKind> for ItemType {
clean::TypeKind::Variant => ItemType::Variant,
clean::TypeKind::Typedef => ItemType::Typedef,
clean::TypeKind::Foreign => ItemType::ForeignType,
clean::TypeKind::Macro => ItemType::Macro,
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/html/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1284,7 +1284,7 @@ impl DocFolder for Cache {
clean::FunctionItem(..) | clean::ModuleItem(..) |
clean::ForeignFunctionItem(..) | clean::ForeignStaticItem(..) |
clean::ConstantItem(..) | clean::StaticItem(..) |
clean::UnionItem(..) | clean::ForeignTypeItem
clean::UnionItem(..) | clean::ForeignTypeItem | clean::MacroItem(..)
if !self.stripped_mod => {
// Re-exported items mean that the same id can show up twice
// in the rustdoc ast that we're looking at. We know,
Expand Down

0 comments on commit 7ac48d7

Please sign in to comment.