about summary refs log tree commit diff
path: root/src/librustdoc/passes/collect_intra_doc_links.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/librustdoc/passes/collect_intra_doc_links.rs')
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs173
1 files changed, 15 insertions, 158 deletions
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 8435972bb11..692adcf0a80 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -15,7 +15,8 @@ use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
 use rustc_hir::Mutability;
 use rustc_middle::ty::{DefIdTree, Ty, TyCtxt};
 use rustc_middle::{bug, ty};
-use rustc_resolve::ParentScope;
+use rustc_resolve::rustdoc::MalformedGenerics;
+use rustc_resolve::rustdoc::{prepare_to_doc_link_resolution, strip_generics_from_path};
 use rustc_session::lint::Lint;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{sym, Ident, Symbol};
@@ -23,7 +24,6 @@ use rustc_span::BytePos;
 use smallvec::{smallvec, SmallVec};
 
 use std::borrow::Cow;
-use std::mem;
 use std::ops::Range;
 
 use crate::clean::{self, utils::find_nearest_parent_module};
@@ -179,47 +179,6 @@ enum ResolutionFailure<'a> {
     NotResolved(UnresolvedPath<'a>),
 }
 
-#[derive(Clone, Copy, Debug)]
-enum MalformedGenerics {
-    /// This link has unbalanced angle brackets.
-    ///
-    /// For example, `Vec<T` should trigger this, as should `Vec<T>>`.
-    UnbalancedAngleBrackets,
-    /// The generics are not attached to a type.
-    ///
-    /// For example, `<T>` should trigger this.
-    ///
-    /// This is detected by checking if the path is empty after the generics are stripped.
-    MissingType,
-    /// The link uses fully-qualified syntax, which is currently unsupported.
-    ///
-    /// For example, `<Vec as IntoIterator>::into_iter` should trigger this.
-    ///
-    /// This is detected by checking if ` as ` (the keyword `as` with spaces around it) is inside
-    /// angle brackets.
-    HasFullyQualifiedSyntax,
-    /// The link has an invalid path separator.
-    ///
-    /// For example, `Vec:<T>:new()` should trigger this. Note that `Vec:new()` will **not**
-    /// trigger this because it has no generics and thus [`strip_generics_from_path`] will not be
-    /// called.
-    ///
-    /// Note that this will also **not** be triggered if the invalid path separator is inside angle
-    /// brackets because rustdoc mostly ignores what's inside angle brackets (except for
-    /// [`HasFullyQualifiedSyntax`](MalformedGenerics::HasFullyQualifiedSyntax)).
-    ///
-    /// This is detected by checking if there is a colon followed by a non-colon in the link.
-    InvalidPathSeparator,
-    /// The link has too many angle brackets.
-    ///
-    /// For example, `Vec<<T>>` should trigger this.
-    TooManyAngleBrackets,
-    /// The link has empty angle brackets.
-    ///
-    /// For example, `Vec<>` should trigger this.
-    EmptyAngleBrackets,
-}
-
 #[derive(Clone, Debug, Hash, PartialEq, Eq)]
 pub(crate) enum UrlFragment {
     Item(DefId),
@@ -407,10 +366,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
             })
     }
 
-    /// Convenience wrapper around `resolve_rustdoc_path`.
+    /// Convenience wrapper around `doc_link_resolutions`.
     ///
     /// This also handles resolving `true` and `false` as booleans.
-    /// NOTE: `resolve_rustdoc_path` knows only about paths, not about types.
+    /// NOTE: `doc_link_resolutions` knows only about paths, not about types.
     /// Associated items will never be resolved by this function.
     fn resolve_path(
         &self,
@@ -426,17 +385,11 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
         // Resolver doesn't know about true, false, and types that aren't paths (e.g. `()`).
         let result = self
             .cx
-            .resolver_caches
-            .doc_link_resolutions
-            .get(&(Symbol::intern(path_str), ns, module_id))
+            .tcx
+            .doc_link_resolutions(module_id)
+            .get(&(Symbol::intern(path_str), ns))
             .copied()
-            .unwrap_or_else(|| {
-                self.cx.enter_resolver(|resolver| {
-                    let parent_scope =
-                        ParentScope::module(resolver.expect_module(module_id), resolver);
-                    resolver.resolve_rustdoc_path(path_str, ns, parent_scope)
-                })
-            })
+            .unwrap_or_else(|| panic!("no resolution for {:?} {:?} {:?}", path_str, ns, module_id))
             .and_then(|res| res.try_into().ok())
             .or_else(|| resolve_primitive(path_str, ns));
         debug!("{} resolved to {:?} in namespace {:?}", path_str, result, ns);
@@ -779,8 +732,7 @@ fn trait_impls_for<'a>(
     module: DefId,
 ) -> FxHashSet<(DefId, DefId)> {
     let tcx = cx.tcx;
-    let iter = cx.resolver_caches.traits_in_scope[&module].iter().flat_map(|trait_candidate| {
-        let trait_ = trait_candidate.def_id;
+    let iter = tcx.doc_link_traits_in_scope(module).iter().flat_map(|&trait_| {
         trace!("considering explicit impl for trait {:?}", trait_);
 
         // Look at each trait implementation to see if it's an impl for `did`
@@ -846,7 +798,7 @@ impl<'a, 'tcx> DocVisitor for LinkCollector<'a, 'tcx> {
         // In the presence of re-exports, this is not the same as the module of the item.
         // Rather than merging all documentation into one, resolve it one attribute at a time
         // so we know which module it came from.
-        for (parent_module, doc) in item.attrs.prepare_to_doc_link_resolution() {
+        for (parent_module, doc) in prepare_to_doc_link_resolution(&item.attrs.doc_strings) {
             if !may_have_doc_links(&doc) {
                 continue;
             }
@@ -975,16 +927,12 @@ fn preprocess_link(
     }
 
     // Strip generics from the path.
-    let path_str = if path_str.contains(['<', '>'].as_slice()) {
-        match strip_generics_from_path(path_str) {
-            Ok(path) => path,
-            Err(err) => {
-                debug!("link has malformed generics: {}", path_str);
-                return Some(Err(PreprocessingError::MalformedGenerics(err, path_str.to_owned())));
-            }
+    let path_str = match strip_generics_from_path(path_str) {
+        Ok(path) => path,
+        Err(err) => {
+            debug!("link has malformed generics: {}", path_str);
+            return Some(Err(PreprocessingError::MalformedGenerics(err, path_str.to_owned())));
         }
-    } else {
-        path_str.to_owned()
     };
 
     // Sanity check to make sure we don't have any angle brackets after stripping generics.
@@ -2064,94 +2012,3 @@ fn resolve_primitive(path_str: &str, ns: Namespace) -> Option<Res> {
     debug!("resolved primitives {:?}", prim);
     Some(Res::Primitive(prim))
 }
-
-fn strip_generics_from_path(path_str: &str) -> Result<String, MalformedGenerics> {
-    let mut stripped_segments = vec![];
-    let mut path = path_str.chars().peekable();
-    let mut segment = Vec::new();
-
-    while let Some(chr) = path.next() {
-        match chr {
-            ':' => {
-                if path.next_if_eq(&':').is_some() {
-                    let stripped_segment =
-                        strip_generics_from_path_segment(mem::take(&mut segment))?;
-                    if !stripped_segment.is_empty() {
-                        stripped_segments.push(stripped_segment);
-                    }
-                } else {
-                    return Err(MalformedGenerics::InvalidPathSeparator);
-                }
-            }
-            '<' => {
-                segment.push(chr);
-
-                match path.next() {
-                    Some('<') => {
-                        return Err(MalformedGenerics::TooManyAngleBrackets);
-                    }
-                    Some('>') => {
-                        return Err(MalformedGenerics::EmptyAngleBrackets);
-                    }
-                    Some(chr) => {
-                        segment.push(chr);
-
-                        while let Some(chr) = path.next_if(|c| *c != '>') {
-                            segment.push(chr);
-                        }
-                    }
-                    None => break,
-                }
-            }
-            _ => segment.push(chr),
-        }
-        trace!("raw segment: {:?}", segment);
-    }
-
-    if !segment.is_empty() {
-        let stripped_segment = strip_generics_from_path_segment(segment)?;
-        if !stripped_segment.is_empty() {
-            stripped_segments.push(stripped_segment);
-        }
-    }
-
-    debug!("path_str: {:?}\nstripped segments: {:?}", path_str, &stripped_segments);
-
-    let stripped_path = stripped_segments.join("::");
-
-    if !stripped_path.is_empty() { Ok(stripped_path) } else { Err(MalformedGenerics::MissingType) }
-}
-
-fn strip_generics_from_path_segment(segment: Vec<char>) -> Result<String, MalformedGenerics> {
-    let mut stripped_segment = String::new();
-    let mut param_depth = 0;
-
-    let mut latest_generics_chunk = String::new();
-
-    for c in segment {
-        if c == '<' {
-            param_depth += 1;
-            latest_generics_chunk.clear();
-        } else if c == '>' {
-            param_depth -= 1;
-            if latest_generics_chunk.contains(" as ") {
-                // The segment tries to use fully-qualified syntax, which is currently unsupported.
-                // Give a helpful error message instead of completely ignoring the angle brackets.
-                return Err(MalformedGenerics::HasFullyQualifiedSyntax);
-            }
-        } else {
-            if param_depth == 0 {
-                stripped_segment.push(c);
-            } else {
-                latest_generics_chunk.push(c);
-            }
-        }
-    }
-
-    if param_depth == 0 {
-        Ok(stripped_segment)
-    } else {
-        // The segment has unbalanced angle brackets, e.g. `Vec<T` or `Vec<T>>`
-        Err(MalformedGenerics::UnbalancedAngleBrackets)
-    }
-}