1 use errors::Applicability;
2 use rustc::hir::def::{Res, DefKind, Namespace::{self, *}, PerNS};
3 use rustc::hir::def_id::DefId;
5 use rustc::lint as lint;
7 use rustc_resolve::ParentScope;
8 use rustc_feature::UnstableFeatures;
10 use syntax::ast::{self, Ident};
11 use syntax_expand::base::SyntaxExtensionKind;
12 use syntax::symbol::Symbol;
13 use syntax_pos::DUMMY_SP;
17 use crate::core::DocContext;
18 use crate::fold::DocFolder;
19 use crate::html::markdown::markdown_links;
21 use crate::passes::{look_for_tests, Pass};
23 use super::span_of_attrs;
25 pub const COLLECT_INTRA_DOC_LINKS: Pass = Pass {
26 name: "collect-intra-doc-links",
27 pass: collect_intra_doc_links,
28 description: "reads a crate's documentation to resolve intra-doc-links",
31 pub fn collect_intra_doc_links(krate: Crate, cx: &DocContext<'_>) -> Crate {
32 if !UnstableFeatures::from_environment().is_nightly_build() {
35 let mut coll = LinkCollector::new(cx);
37 coll.fold_crate(krate)
43 AnchorFailure(&'static str),
46 struct LinkCollector<'a, 'tcx> {
47 cx: &'a DocContext<'tcx>,
48 mod_ids: Vec<hir::HirId>,
51 impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
52 fn new(cx: &'a DocContext<'tcx>) -> Self {
62 current_item: &Option<String>,
63 module_id: syntax::ast::NodeId,
64 ) -> Result<(Res, Option<String>), ErrorKind> {
67 let mut split = path_str.rsplitn(3, "::");
68 let variant_field_name = split
70 .map(|f| Symbol::intern(f))
71 .ok_or(ErrorKind::ResolutionFailure)?;
72 let variant_name = split
74 .map(|f| Symbol::intern(f))
75 .ok_or(ErrorKind::ResolutionFailure)?;
76 let path = split.next().map(|f| {
77 if f == "self" || f == "Self" {
78 if let Some(name) = current_item.as_ref() {
83 }).ok_or(ErrorKind::ResolutionFailure)?;
84 let (_, ty_res) = cx.enter_resolver(|resolver| {
85 resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id)
86 }).map_err(|_| ErrorKind::ResolutionFailure)?;
87 if let Res::Err = ty_res {
88 return Err(ErrorKind::ResolutionFailure);
90 let ty_res = ty_res.map_id(|_| panic!("unexpected node_id"));
92 Res::Def(DefKind::Enum, did) => {
93 if cx.tcx.inherent_impls(did)
95 .flat_map(|imp| cx.tcx.associated_items(*imp))
96 .any(|item| item.ident.name == variant_name) {
97 return Err(ErrorKind::ResolutionFailure);
99 match cx.tcx.type_of(did).kind {
100 ty::Adt(def, _) if def.is_enum() => {
102 .any(|item| item.ident.name == variant_field_name) {
104 Some(format!("variant.{}.field.{}",
105 variant_name, variant_field_name))))
107 Err(ErrorKind::ResolutionFailure)
110 _ => Err(ErrorKind::ResolutionFailure),
113 _ => Err(ErrorKind::ResolutionFailure)
117 /// Resolves a string as a path within a particular namespace. Also returns an optional
118 /// URL fragment in the case of variants and methods.
123 current_item: &Option<String>,
124 parent_id: Option<hir::HirId>,
125 extra_fragment: &Option<String>,
126 ) -> Result<(Res, Option<String>), ErrorKind> {
129 // In case we're in a module, try to resolve the relative path.
130 if let Some(module_id) = parent_id.or(self.mod_ids.last().cloned()) {
131 let module_id = cx.tcx.hir().hir_to_node_id(module_id);
132 let result = cx.enter_resolver(|resolver| {
133 resolver.resolve_str_path_error(DUMMY_SP, &path_str, ns, module_id)
135 let result = match result {
136 Ok((_, Res::Err)) => Err(ErrorKind::ResolutionFailure),
137 _ => result.map_err(|_| ErrorKind::ResolutionFailure),
140 if let Ok((_, res)) = result {
141 let res = res.map_id(|_| panic!("unexpected node_id"));
142 // In case this is a trait item, skip the
143 // early return and try looking for the trait.
144 let value = match res {
145 Res::Def(DefKind::Method, _) | Res::Def(DefKind::AssocConst, _) => true,
146 Res::Def(DefKind::AssocTy, _) => false,
147 Res::Def(DefKind::Variant, _) => {
148 return handle_variant(cx, res, extra_fragment);
150 // Not a trait item; just return what we found.
152 if extra_fragment.is_some() {
154 ErrorKind::AnchorFailure(
155 "primitive types cannot be followed by anchors"));
157 return Ok((res, Some(path_str.to_owned())));
159 _ => return Ok((res, extra_fragment.clone()))
162 if value != (ns == ValueNS) {
163 return Err(ErrorKind::ResolutionFailure)
165 } else if let Some(prim) = is_primitive(path_str, ns) {
166 if extra_fragment.is_some() {
168 ErrorKind::AnchorFailure("primitive types cannot be followed by anchors"));
170 return Ok((prim, Some(path_str.to_owned())))
172 // If resolution failed, it may still be a method
173 // because methods are not handled by the resolver
174 // If so, bail when we're not looking for a value.
176 return Err(ErrorKind::ResolutionFailure)
180 // Try looking for methods and associated items.
181 let mut split = path_str.rsplitn(2, "::");
182 let item_name = split.next()
183 .map(|f| Symbol::intern(f))
184 .ok_or(ErrorKind::ResolutionFailure)?;
185 let path = split.next().map(|f| {
186 if f == "self" || f == "Self" {
187 if let Some(name) = current_item.as_ref() {
192 }).ok_or(ErrorKind::ResolutionFailure)?;
194 if let Some(prim) = is_primitive(&path, TypeNS) {
195 let did = primitive_impl(cx, &path).ok_or(ErrorKind::ResolutionFailure)?;
196 return cx.tcx.associated_items(did)
197 .find(|item| item.ident.name == item_name)
198 .and_then(|item| match item.kind {
199 ty::AssocKind::Method => Some("method"),
202 .map(|out| (prim, Some(format!("{}#{}.{}", path, out, item_name))))
203 .ok_or(ErrorKind::ResolutionFailure);
206 let (_, ty_res) = cx.enter_resolver(|resolver| {
207 resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id)
208 }).map_err(|_| ErrorKind::ResolutionFailure)?;
209 if let Res::Err = ty_res {
210 return self.variant_field(path_str, current_item, module_id);
212 let ty_res = ty_res.map_id(|_| panic!("unexpected node_id"));
214 Res::Def(DefKind::Struct, did)
215 | Res::Def(DefKind::Union, did)
216 | Res::Def(DefKind::Enum, did)
217 | Res::Def(DefKind::TyAlias, did) => {
218 let item = cx.tcx.inherent_impls(did)
220 .flat_map(|imp| cx.tcx.associated_items(*imp))
221 .find(|item| item.ident.name == item_name);
222 if let Some(item) = item {
223 let out = match item.kind {
224 ty::AssocKind::Method if ns == ValueNS => "method",
225 ty::AssocKind::Const if ns == ValueNS => "associatedconstant",
226 _ => return self.variant_field(path_str, current_item, module_id),
228 if extra_fragment.is_some() {
229 Err(ErrorKind::AnchorFailure(
230 if item.kind == ty::AssocKind::Method {
231 "methods cannot be followed by anchors"
233 "associated constants cannot be followed by anchors"
236 Ok((ty_res, Some(format!("{}.{}", out, item_name))))
239 match cx.tcx.type_of(did).kind {
241 if let Some(item) = if def.is_enum() {
242 def.all_fields().find(|item| item.ident.name == item_name)
244 def.non_enum_variant()
247 .find(|item| item.ident.name == item_name)
249 if extra_fragment.is_some() {
250 Err(ErrorKind::AnchorFailure(
252 "enum variants cannot be followed by anchors"
254 "struct fields cannot be followed by anchors"
258 Some(format!("{}.{}",
267 self.variant_field(path_str, current_item, module_id)
270 _ => self.variant_field(path_str, current_item, module_id),
274 Res::Def(DefKind::Trait, did) => {
275 let item = cx.tcx.associated_item_def_ids(did).iter()
276 .map(|item| cx.tcx.associated_item(*item))
277 .find(|item| item.ident.name == item_name);
278 if let Some(item) = item {
279 let kind = match item.kind {
280 ty::AssocKind::Const if ns == ValueNS => "associatedconstant",
281 ty::AssocKind::Type if ns == TypeNS => "associatedtype",
282 ty::AssocKind::Method if ns == ValueNS => {
283 if item.defaultness.has_value() {
289 _ => return self.variant_field(path_str, current_item, module_id),
292 if extra_fragment.is_some() {
293 Err(ErrorKind::AnchorFailure(
294 if item.kind == ty::AssocKind::Const {
295 "associated constants cannot be followed by anchors"
296 } else if item.kind == ty::AssocKind::Type {
297 "associated types cannot be followed by anchors"
299 "methods cannot be followed by anchors"
302 Ok((ty_res, Some(format!("{}.{}", kind, item_name))))
305 self.variant_field(path_str, current_item, module_id)
308 _ => self.variant_field(path_str, current_item, module_id),
311 debug!("attempting to resolve item without parent module: {}", path_str);
312 Err(ErrorKind::ResolutionFailure)
317 impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
318 fn fold_item(&mut self, mut item: Item) -> Option<Item> {
319 let item_hir_id = if item.is_mod() {
320 if let Some(id) = self.cx.tcx.hir().as_local_hir_id(item.def_id) {
323 debug!("attempting to fold on a non-local item: {:?}", item);
324 return self.fold_item_recur(item);
330 // FIXME: get the resolver to work with non-local resolve scopes.
331 let parent_node = self.cx.as_local_hir_id(item.def_id).and_then(|hir_id| {
332 // FIXME: this fails hard for impls in non-module scope, but is necessary for the
333 // current `resolve()` implementation.
334 match self.cx.tcx.hir().get_module_parent_node(hir_id) {
335 id if id != hir_id => Some(id),
340 if parent_node.is_some() {
341 debug!("got parent node for {:?} {:?}, id {:?}", item.type_(), item.name, item.def_id);
344 let current_item = match item.inner {
346 if item.attrs.inner_docs {
347 if item_hir_id.unwrap() != hir::CRATE_HIR_ID {
353 match parent_node.or(self.mod_ids.last().cloned()) {
354 Some(parent) if parent != hir::CRATE_HIR_ID => {
355 // FIXME: can we pull the parent module's name from elsewhere?
356 Some(self.cx.tcx.hir().name(parent).to_string())
362 ImplItem(Impl { ref for_, .. }) => {
363 for_.def_id().map(|did| self.cx.tcx.item_name(did).to_string())
365 // we don't display docs on `extern crate` items anyway, so don't process them.
366 ExternCrateItem(..) => return self.fold_item_recur(item),
367 ImportItem(Import::Simple(ref name, ..)) => Some(name.clone()),
368 MacroItem(..) => None,
369 _ => item.name.clone(),
372 if item.is_mod() && item.attrs.inner_docs {
373 self.mod_ids.push(item_hir_id.unwrap());
377 let dox = item.attrs.collapsed_doc_value().unwrap_or_else(String::new);
379 look_for_tests(&cx, &dox, &item, true);
381 for (ori_link, link_range) in markdown_links(&dox) {
382 // Bail early for real links.
383 if ori_link.contains('/') {
387 // [] is mostly likely not supposed to be a link
388 if ori_link.is_empty() {
392 let link = ori_link.replace("`", "");
393 let parts = link.split('#').collect::<Vec<_>>();
394 let (link, extra_fragment) = if parts.len() > 2 {
395 build_diagnostic(cx, &item, &link, &dox, link_range,
396 "has an issue with the link anchor.",
397 "only one `#` is allowed in a link",
400 } else if parts.len() == 2 {
401 if parts[0].trim().is_empty() {
402 // This is an anchor to an element of the current page, nothing to do in here!
405 (parts[0].to_owned(), Some(parts[1].to_owned()))
407 (parts[0].to_owned(), None)
409 let (res, fragment) = {
411 let path_str = if let Some(prefix) =
412 ["struct@", "enum@", "type@",
413 "trait@", "union@"].iter()
414 .find(|p| link.starts_with(**p)) {
416 link.trim_start_matches(prefix)
417 } else if let Some(prefix) =
418 ["const@", "static@",
419 "value@", "function@", "mod@",
420 "fn@", "module@", "method@"]
421 .iter().find(|p| link.starts_with(**p)) {
422 kind = Some(ValueNS);
423 link.trim_start_matches(prefix)
424 } else if link.ends_with("()") {
425 kind = Some(ValueNS);
426 link.trim_end_matches("()")
427 } else if link.starts_with("macro@") {
428 kind = Some(MacroNS);
429 link.trim_start_matches("macro@")
430 } else if link.ends_with('!') {
431 kind = Some(MacroNS);
432 link.trim_end_matches('!')
437 if path_str.contains(|ch: char| !(ch.is_alphanumeric() ||
438 ch == ':' || ch == '_')) {
442 // In order to correctly resolve intra-doc-links we need to
443 // pick a base AST node to work from. If the documentation for
444 // this module came from an inner comment (//!) then we anchor
445 // our name resolution *inside* the module. If, on the other
446 // hand it was an outer comment (///) then we anchor the name
447 // resolution in the parent module on the basis that the names
448 // used are more likely to be intended to be parent names. For
449 // this, we set base_node to None for inner comments since
450 // we've already pushed this node onto the resolution stack but
451 // for outer comments we explicitly try and resolve against the
452 // parent_node first.
453 let base_node = if item.is_mod() && item.attrs.inner_docs {
460 Some(ns @ ValueNS) => {
461 match self.resolve(path_str, ns, ¤t_item, base_node,
464 Err(ErrorKind::ResolutionFailure) => {
465 resolution_failure(cx, &item, path_str, &dox, link_range);
466 // This could just be a normal link or a broken link
467 // we could potentially check if something is
468 // "intra-doc-link-like" and warn in that case.
471 Err(ErrorKind::AnchorFailure(msg)) => {
472 anchor_failure(cx, &item, &ori_link, &dox, link_range, msg);
477 Some(ns @ TypeNS) => {
478 match self.resolve(path_str, ns, ¤t_item, base_node,
481 Err(ErrorKind::ResolutionFailure) => {
482 resolution_failure(cx, &item, path_str, &dox, link_range);
483 // This could just be a normal link.
486 Err(ErrorKind::AnchorFailure(msg)) => {
487 anchor_failure(cx, &item, &ori_link, &dox, link_range, msg);
494 let candidates = PerNS {
495 macro_ns: macro_resolve(cx, path_str)
496 .map(|res| (res, extra_fragment.clone())),
497 type_ns: match self.resolve(path_str, TypeNS, ¤t_item, base_node,
499 Err(ErrorKind::AnchorFailure(msg)) => {
500 anchor_failure(cx, &item, &ori_link, &dox, link_range, msg);
505 value_ns: match self.resolve(path_str, ValueNS, ¤t_item,
506 base_node, &extra_fragment) {
507 Err(ErrorKind::AnchorFailure(msg)) => {
508 anchor_failure(cx, &item, &ori_link, &dox, link_range, msg);
513 .and_then(|(res, fragment)| {
514 // Constructors are picked up in the type namespace.
516 Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) => None,
517 _ => match (fragment, extra_fragment) {
518 (Some(fragment), Some(_)) => {
519 // Shouldn't happen but who knows?
520 Some((res, Some(fragment)))
522 (fragment, None) | (None, fragment) => {
523 Some((res, fragment))
530 if candidates.is_empty() {
531 resolution_failure(cx, &item, path_str, &dox, link_range);
532 // this could just be a normal link
536 let is_unambiguous = candidates.clone().present_items().count() == 1;
538 candidates.present_items().next().unwrap()
546 candidates.map(|candidate| candidate.map(|(res, _)| res)),
552 if let Some(res) = macro_resolve(cx, path_str) {
553 (res, extra_fragment)
555 resolution_failure(cx, &item, path_str, &dox, link_range);
562 if let Res::PrimTy(_) = res {
563 item.attrs.links.push((ori_link, None, fragment));
565 let id = register_res(cx, res);
566 item.attrs.links.push((ori_link, Some(id), fragment));
570 if item.is_mod() && !item.attrs.inner_docs {
571 self.mod_ids.push(item_hir_id.unwrap());
575 let ret = self.fold_item_recur(item);
581 self.fold_item_recur(item)
585 // FIXME: if we can resolve intra-doc links from other crates, we can use the stock
586 // `fold_crate`, but until then we should avoid scanning `krate.external_traits` since those
587 // will never resolve properly
588 fn fold_crate(&mut self, mut c: Crate) -> Crate {
589 c.module = c.module.take().and_then(|module| self.fold_item(module));
595 /// Resolves a string as a macro.
596 fn macro_resolve(cx: &DocContext<'_>, path_str: &str) -> Option<Res> {
597 let path = ast::Path::from_ident(Ident::from_str(path_str));
598 cx.enter_resolver(|resolver| {
599 if let Ok((Some(ext), res)) = resolver.resolve_macro_path(
600 &path, None, &ParentScope::module(resolver.graph_root()), false, false
602 if let SyntaxExtensionKind::LegacyBang { .. } = ext.kind {
603 return Some(res.map_id(|_| panic!("unexpected id")));
606 if let Some(res) = resolver.all_macros().get(&Symbol::intern(path_str)) {
607 return Some(res.map_id(|_| panic!("unexpected id")));
618 link_range: Option<Range<usize>>,
621 help_msg: Option<&str>,
623 let hir_id = match cx.as_local_hir_id(item.def_id) {
624 Some(hir_id) => hir_id,
626 // If non-local, no need to check anything.
630 let attrs = &item.attrs;
631 let sp = span_of_attrs(attrs).unwrap_or(item.source.span());
633 let mut diag = cx.tcx.struct_span_lint_hir(
634 lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE,
637 &format!("`[{}]` {}", path_str, err_msg),
639 if let Some(link_range) = link_range {
640 if let Some(sp) = super::source_span_for_markdown_range(cx, dox, &link_range, attrs) {
642 diag.span_label(sp, short_err_msg);
644 // blah blah blah\nblah\nblah [blah] blah blah\nblah blah
647 // last_new_line_offset
648 let last_new_line_offset = dox[..link_range.start].rfind('\n').map_or(0, |n| n + 1);
649 let line = dox[last_new_line_offset..].lines().next().unwrap_or("");
651 // Print the line containing the `link_range` and manually mark it with '^'s.
653 "the link appears in this line:\n\n{line}\n\
654 {indicator: <before$}{indicator:^<found$}",
657 before=link_range.start - last_new_line_offset,
658 found=link_range.len(),
662 if let Some(help_msg) = help_msg {
668 /// Reports a resolution failure diagnostic.
670 /// If we cannot find the exact source span of the resolution failure, we use the span of the
671 /// documentation attributes themselves. This is a little heavy-handed, so we display the markdown
672 /// line containing the failure as a note as well.
673 fn resolution_failure(
678 link_range: Option<Range<usize>>,
680 build_diagnostic(cx, item, path_str, dox, link_range,
681 "cannot be resolved, ignoring it.",
682 "cannot be resolved, ignoring",
683 Some("to escape `[` and `]` characters, just add '\\' before them like `\\[` or `\\]`"));
691 link_range: Option<Range<usize>>,
694 build_diagnostic(cx, item, path_str, dox, link_range,
695 "has an issue with the link anchor.",
705 link_range: Option<Range<usize>>,
706 candidates: PerNS<Option<Res>>,
708 let hir_id = match cx.as_local_hir_id(item.def_id) {
709 Some(hir_id) => hir_id,
711 // If non-local, no need to check anything.
715 let attrs = &item.attrs;
716 let sp = span_of_attrs(attrs).unwrap_or(item.source.span());
718 let mut msg = format!("`{}` is ", path_str);
720 let candidates = [TypeNS, ValueNS, MacroNS].iter().filter_map(|&ns| {
721 candidates[ns].map(|res| (res, ns))
722 }).collect::<Vec<_>>();
723 match candidates.as_slice() {
724 [(first_def, _), (second_def, _)] => {
726 "both {} {} and {} {}",
729 second_def.article(),
734 let mut candidates = candidates.iter().peekable();
735 while let Some((res, _)) = candidates.next() {
736 if candidates.peek().is_some() {
737 msg += &format!("{} {}, ", res.article(), res.descr());
739 msg += &format!("and {} {}", res.article(), res.descr());
745 let mut diag = cx.tcx.struct_span_lint_hir(
746 lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE,
752 if let Some(link_range) = link_range {
753 if let Some(sp) = super::source_span_for_markdown_range(cx, dox, &link_range, attrs) {
755 diag.span_label(sp, "ambiguous link");
757 for (res, ns) in candidates {
758 let (action, mut suggestion) = match res {
759 Res::Def(DefKind::Method, _) | Res::Def(DefKind::Fn, _) => {
760 ("add parentheses", format!("{}()", path_str))
762 Res::Def(DefKind::Macro(..), _) => {
763 ("add an exclamation mark", format!("{}!", path_str))
766 let type_ = match (res, ns) {
767 (Res::Def(DefKind::Const, _), _) => "const",
768 (Res::Def(DefKind::Static, _), _) => "static",
769 (Res::Def(DefKind::Struct, _), _) => "struct",
770 (Res::Def(DefKind::Enum, _), _) => "enum",
771 (Res::Def(DefKind::Union, _), _) => "union",
772 (Res::Def(DefKind::Trait, _), _) => "trait",
773 (Res::Def(DefKind::Mod, _), _) => "module",
774 (_, TypeNS) => "type",
775 (_, ValueNS) => "value",
776 (_, MacroNS) => "macro",
779 // FIXME: if this is an implied shortcut link, it's bad style to suggest `@`
780 ("prefix with the item type", format!("{}@{}", type_, path_str))
784 if dox.bytes().nth(link_range.start) == Some(b'`') {
785 suggestion = format!("`{}`", suggestion);
788 diag.span_suggestion(
790 &format!("to link to the {}, {}", res.descr(), action),
792 Applicability::MaybeIncorrect,
796 // blah blah blah\nblah\nblah [blah] blah blah\nblah blah
799 // last_new_line_offset
800 let last_new_line_offset = dox[..link_range.start].rfind('\n').map_or(0, |n| n + 1);
801 let line = dox[last_new_line_offset..].lines().next().unwrap_or("");
803 // Print the line containing the `link_range` and manually mark it with '^'s.
805 "the link appears in this line:\n\n{line}\n\
806 {indicator: <before$}{indicator:^<found$}",
809 before=link_range.start - last_new_line_offset,
810 found=link_range.len(),
818 /// Given an enum variant's res, return the res of its enum and the associated fragment.
822 extra_fragment: &Option<String>,
823 ) -> Result<(Res, Option<String>), ErrorKind> {
824 use rustc::ty::DefIdTree;
826 if extra_fragment.is_some() {
827 return Err(ErrorKind::AnchorFailure("variants cannot be followed by anchors"));
829 let parent = if let Some(parent) = cx.tcx.parent(res.def_id()) {
832 return Err(ErrorKind::ResolutionFailure)
834 let parent_def = Res::Def(DefKind::Enum, parent);
835 let variant = cx.tcx.expect_variant_res(res);
836 Ok((parent_def, Some(format!("{}.v", variant.ident.name))))
839 const PRIMITIVES: &[(&str, Res)] = &[
840 ("u8", Res::PrimTy(hir::PrimTy::Uint(syntax::ast::UintTy::U8))),
841 ("u16", Res::PrimTy(hir::PrimTy::Uint(syntax::ast::UintTy::U16))),
842 ("u32", Res::PrimTy(hir::PrimTy::Uint(syntax::ast::UintTy::U32))),
843 ("u64", Res::PrimTy(hir::PrimTy::Uint(syntax::ast::UintTy::U64))),
844 ("u128", Res::PrimTy(hir::PrimTy::Uint(syntax::ast::UintTy::U128))),
845 ("usize", Res::PrimTy(hir::PrimTy::Uint(syntax::ast::UintTy::Usize))),
846 ("i8", Res::PrimTy(hir::PrimTy::Int(syntax::ast::IntTy::I8))),
847 ("i16", Res::PrimTy(hir::PrimTy::Int(syntax::ast::IntTy::I16))),
848 ("i32", Res::PrimTy(hir::PrimTy::Int(syntax::ast::IntTy::I32))),
849 ("i64", Res::PrimTy(hir::PrimTy::Int(syntax::ast::IntTy::I64))),
850 ("i128", Res::PrimTy(hir::PrimTy::Int(syntax::ast::IntTy::I128))),
851 ("isize", Res::PrimTy(hir::PrimTy::Int(syntax::ast::IntTy::Isize))),
852 ("f32", Res::PrimTy(hir::PrimTy::Float(syntax::ast::FloatTy::F32))),
853 ("f64", Res::PrimTy(hir::PrimTy::Float(syntax::ast::FloatTy::F64))),
854 ("str", Res::PrimTy(hir::PrimTy::Str)),
855 ("bool", Res::PrimTy(hir::PrimTy::Bool)),
856 ("char", Res::PrimTy(hir::PrimTy::Char)),
859 fn is_primitive(path_str: &str, ns: Namespace) -> Option<Res> {
861 PRIMITIVES.iter().find(|x| x.0 == path_str).map(|x| x.1)
867 fn primitive_impl(cx: &DocContext<'_>, path_str: &str) -> Option<DefId> {
870 "u8" => tcx.lang_items().u8_impl(),
871 "u16" => tcx.lang_items().u16_impl(),
872 "u32" => tcx.lang_items().u32_impl(),
873 "u64" => tcx.lang_items().u64_impl(),
874 "u128" => tcx.lang_items().u128_impl(),
875 "usize" => tcx.lang_items().usize_impl(),
876 "i8" => tcx.lang_items().i8_impl(),
877 "i16" => tcx.lang_items().i16_impl(),
878 "i32" => tcx.lang_items().i32_impl(),
879 "i64" => tcx.lang_items().i64_impl(),
880 "i128" => tcx.lang_items().i128_impl(),
881 "isize" => tcx.lang_items().isize_impl(),
882 "f32" => tcx.lang_items().f32_impl(),
883 "f64" => tcx.lang_items().f64_impl(),
884 "str" => tcx.lang_items().str_impl(),
885 "bool" => tcx.lang_items().bool_impl(),
886 "char" => tcx.lang_items().char_impl(),