Skip to content

Commit 5a89f40

Browse files
committed
Handle methods
1 parent f0e7677 commit 5a89f40

File tree

1 file changed

+76
-19
lines changed

1 file changed

+76
-19
lines changed

src/librustdoc/clean/mod.rs

Lines changed: 76 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -659,7 +659,8 @@ pub struct Attributes {
659659
pub other_attrs: Vec<ast::Attribute>,
660660
pub cfg: Option<Rc<Cfg>>,
661661
pub span: Option<syntax_pos::Span>,
662-
pub links: Vec<(String, DefId)>,
662+
/// map from Rust paths to resolved defs and potential URL fragments
663+
pub links: Vec<(String, DefId, Option<String>)>,
663664
}
664665

665666
impl Attributes {
@@ -820,8 +821,12 @@ impl Attributes {
820821
/// Cache must be populated before call
821822
pub fn links(&self) -> Vec<(String, String)> {
822823
use html::format::href;
823-
self.links.iter().filter_map(|&(ref s, did)| {
824-
if let Some((href, ..)) = href(did) {
824+
self.links.iter().filter_map(|&(ref s, did, ref fragment)| {
825+
if let Some((mut href, ..)) = href(did) {
826+
if let Some(ref fragment) = *fragment {
827+
href.push_str("#");
828+
href.push_str(fragment);
829+
}
825830
Some((s.clone(), href))
826831
} else {
827832
None
@@ -893,16 +898,67 @@ fn ambiguity_error(cx: &DocContext, attrs: &Attributes,
893898
}
894899

895900
/// Resolve a given string as a path, along with whether or not it is
896-
/// in the value namespace
897-
fn resolve(cx: &DocContext, path_str: &str, is_val: bool) -> Result<Def, ()> {
901+
/// in the value namespace. Also returns an optional URL fragment in the case
902+
/// of variants and methods
903+
fn resolve(cx: &DocContext, path_str: &str, is_val: bool) -> Result<(Def, Option<String>), ()> {
898904
// In case we're in a module, try to resolve the relative
899905
// path
900906
if let Some(id) = cx.mod_ids.borrow().last() {
901-
cx.resolver.borrow_mut()
902-
.with_scope(*id, |resolver| {
903-
resolver.resolve_str_path_error(DUMMY_SP,
904-
&path_str, is_val)
905-
}).map(|path| path.def)
907+
let result = cx.resolver.borrow_mut()
908+
.with_scope(*id,
909+
|resolver| {
910+
resolver.resolve_str_path_error(DUMMY_SP,
911+
&path_str, is_val)
912+
});
913+
914+
if result.is_ok() {
915+
return result.map(|path| (path.def, None));
916+
}
917+
918+
// Try looking for methods and other associated items
919+
let mut split = path_str.rsplitn(2, "::");
920+
let mut item_name = if let Some(first) = split.next() {
921+
first
922+
} else {
923+
return Err(())
924+
};
925+
926+
let mut path = if let Some(second) = split.next() {
927+
second
928+
} else {
929+
return Err(())
930+
};
931+
932+
let ty = cx.resolver.borrow_mut()
933+
.with_scope(*id,
934+
|resolver| {
935+
resolver.resolve_str_path_error(DUMMY_SP,
936+
&path, false)
937+
})?;
938+
939+
940+
match ty.def {
941+
Def::Struct(did) | Def::Union(did) | Def::Enum(did) | Def::TyAlias(did) => {
942+
let item = cx.tcx.inherent_impls(did).iter()
943+
.flat_map(|imp| cx.tcx.associated_items(*imp))
944+
.find(|item| item.name == item_name);
945+
if let Some(item) = item {
946+
if item.kind == ty::AssociatedKind::Method && is_val {
947+
Ok((ty.def, Some(format!("method.{}", item_name))))
948+
} else {
949+
Err(())
950+
}
951+
} else {
952+
Err(())
953+
}
954+
}
955+
Def::Trait(_) => {
956+
// XXXManishearth todo
957+
Err(())
958+
}
959+
_ => Err(())
960+
}
961+
906962
} else {
907963
Err(())
908964
}
@@ -953,7 +1009,7 @@ impl Clean<Attributes> for [ast::Attribute] {
9531009
if UnstableFeatures::from_environment().is_nightly_build() {
9541010
let dox = attrs.collapsed_doc_value().unwrap_or_else(String::new);
9551011
for link in markdown_links(&dox, cx.render_type) {
956-
let def = {
1012+
let (def, fragment) = {
9571013
let mut kind = PathKind::Unknown;
9581014
let path_str = if let Some(prefix) =
9591015
["struct@", "enum@", "type@",
@@ -963,7 +1019,8 @@ impl Clean<Attributes> for [ast::Attribute] {
9631019
link.trim_left_matches(prefix)
9641020
} else if let Some(prefix) =
9651021
["const@", "static@",
966-
"value@", "function@", "mod@", "fn@", "module@"]
1022+
"value@", "function@", "mod@",
1023+
"fn@", "module@", "method@"]
9671024
.iter().find(|p| link.starts_with(**p)) {
9681025
kind = PathKind::Value;
9691026
link.trim_left_matches(prefix)
@@ -1013,31 +1070,31 @@ impl Clean<Attributes> for [ast::Attribute] {
10131070
if let Some(macro_def) = macro_resolve(cx, path_str) {
10141071
if let Ok(type_def) = resolve(cx, path_str, false) {
10151072
let (type_kind, article, type_disambig)
1016-
= type_ns_kind(type_def, path_str);
1073+
= type_ns_kind(type_def.0, path_str);
10171074
ambiguity_error(cx, &attrs, path_str,
10181075
article, type_kind, &type_disambig,
10191076
"a", "macro", &format!("macro@{}", path_str));
10201077
continue;
10211078
} else if let Ok(value_def) = resolve(cx, path_str, true) {
10221079
let (value_kind, value_disambig)
1023-
= value_ns_kind(value_def, path_str)
1080+
= value_ns_kind(value_def.0, path_str)
10241081
.expect("struct and mod cases should have been \
10251082
caught in previous branch");
10261083
ambiguity_error(cx, &attrs, path_str,
10271084
"a", value_kind, &value_disambig,
10281085
"a", "macro", &format!("macro@{}", path_str));
10291086
}
1030-
macro_def
1087+
(macro_def, None)
10311088
} else if let Ok(type_def) = resolve(cx, path_str, false) {
10321089
// It is imperative we search for not-a-value first
10331090
// Otherwise we will find struct ctors for when we are looking
10341091
// for structs, and the link won't work.
10351092
// if there is something in both namespaces
10361093
if let Ok(value_def) = resolve(cx, path_str, true) {
1037-
let kind = value_ns_kind(value_def, path_str);
1094+
let kind = value_ns_kind(value_def.0, path_str);
10381095
if let Some((value_kind, value_disambig)) = kind {
10391096
let (type_kind, article, type_disambig)
1040-
= type_ns_kind(type_def, path_str);
1097+
= type_ns_kind(type_def.0, path_str);
10411098
ambiguity_error(cx, &attrs, path_str,
10421099
article, type_kind, &type_disambig,
10431100
"a", value_kind, &value_disambig);
@@ -1054,7 +1111,7 @@ impl Clean<Attributes> for [ast::Attribute] {
10541111
}
10551112
PathKind::Macro => {
10561113
if let Some(def) = macro_resolve(cx, path_str) {
1057-
def
1114+
(def, None)
10581115
} else {
10591116
continue
10601117
}
@@ -1064,7 +1121,7 @@ impl Clean<Attributes> for [ast::Attribute] {
10641121

10651122

10661123
let id = register_def(cx, def);
1067-
attrs.links.push((link, id));
1124+
attrs.links.push((link, id, fragment));
10681125
}
10691126

10701127
cx.sess().abort_if_errors();

0 commit comments

Comments
 (0)