]> git.lizzy.rs Git - rust.git/blobdiff - src/librustdoc/scrape_examples.rs
Fix remaining bugs
[rust.git] / src / librustdoc / scrape_examples.rs
index 05e746573f47989f19da6f5a963214726f1b8ff9..10b6fdf87f41972c414708bfa452b91b8c9fe61e 100644 (file)
@@ -10,7 +10,6 @@
 use rustc_hir::{
     self as hir,
     intravisit::{self, Visitor},
-    HirId,
 };
 use rustc_interface::interface;
 use rustc_macros::{Decodable, Encodable};
@@ -49,7 +48,7 @@ impl ScrapeExamplesOptions {
                 target_crates,
             })),
             (Some(_), false) | (None, true) => {
-                diag.err(&format!("must use --scrape-examples-output-path and --scrape-examples-target-crate together"));
+                diag.err("must use --scrape-examples-output-path and --scrape-examples-target-crate together");
                 Err(1)
             }
             (None, false) => Ok(None),
@@ -83,15 +82,10 @@ fn new(span: rustc_span::Span, file: &SourceFile) -> Self {
 
 impl CallLocation {
     fn new(
-        tcx: TyCtxt<'_>,
         expr_span: rustc_span::Span,
-        expr_id: HirId,
+        enclosing_item_span: rustc_span::Span,
         source_file: &SourceFile,
     ) -> Self {
-        let enclosing_item_span =
-            tcx.hir().span_with_body(tcx.hir().get_parent_item(expr_id)).source_callsite();
-        assert!(enclosing_item_span.contains(expr_span));
-
         CallLocation {
             call_expr: SyntaxRange::new(expr_span, source_file),
             enclosing_item: SyntaxRange::new(enclosing_item_span, source_file),
@@ -148,16 +142,21 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
             hir::ExprKind::Call(f, _) => {
                 let types = tcx.typeck(ex.hir_id.owner);
 
-                match types.node_type_opt(f.hir_id) {
-                    Some(ty) => (ty, ex.span),
-                    None => {
-                        return;
-                    }
+                if let Some(ty) = types.node_type_opt(f.hir_id) {
+                    (ty, ex.span)
+                } else {
+                    trace!("node_type_opt({}) = None", f.hir_id);
+                    return;
                 }
             }
             hir::ExprKind::MethodCall(_, _, _, span) => {
                 let types = tcx.typeck(ex.hir_id.owner);
-                let def_id = types.type_dependent_def_id(ex.hir_id).unwrap();
+                let def_id = if let Some(def_id) = types.type_dependent_def_id(ex.hir_id) {
+                    def_id
+                } else {
+                    trace!("type_dependent_def_id({}) = None", ex.hir_id);
+                    return;
+                };
                 (tcx.type_of(def_id), span)
             }
             _ => {
@@ -168,13 +167,29 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
         // If this span comes from a macro expansion, then the source code may not actually show
         // a use of the given item, so it would be a poor example. Hence, we skip all uses in macros.
         if span.from_expansion() {
+            trace!("Rejecting expr from macro: {:?}", span);
+            return;
+        }
+
+        // If the enclosing item has a span coming from a proc macro, then we also don't want to include
+        // the example.
+        let enclosing_item_span = tcx.hir().span_with_body(tcx.hir().get_parent_item(ex.hir_id));
+        if enclosing_item_span.from_expansion() {
+            trace!("Rejecting expr ({:?}) from macro item: {:?}", span, enclosing_item_span);
             return;
         }
 
+        assert!(
+            enclosing_item_span.contains(span),
+            "Attempted to scrape call at [{:?}] whose enclosing item [{:?}] doesn't contain the span of the call.",
+            span,
+            enclosing_item_span
+        );
+
         // Save call site if the function resolves to a concrete definition
         if let ty::FnDef(def_id, _) = ty.kind() {
-            // Ignore functions not from the crate being documented
             if self.target_crates.iter().all(|krate| *krate != def_id.krate) {
+                trace!("Rejecting expr from crate not being documented: {:?}", span);
                 return;
             }
 
@@ -198,7 +213,8 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
                 let fn_key = tcx.def_path_hash(*def_id);
                 let fn_entries = self.calls.entry(fn_key).or_default();
 
-                let location = CallLocation::new(tcx, span, ex.hir_id, &file);
+                trace!("Including expr: {:?}", span);
+                let location = CallLocation::new(span, enclosing_item_span, &file);
                 fn_entries.entry(abs_path).or_insert_with(mk_call_data).locations.push(location);
             }
         }
@@ -240,6 +256,13 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
         let mut finder = FindCalls { calls: &mut calls, tcx, map: tcx.hir(), cx, target_crates };
         tcx.hir().visit_all_item_likes(&mut finder.as_deep_visitor());
 
+        // Sort call locations within a given file in document order
+        for fn_calls in calls.values_mut() {
+            for file_calls in fn_calls.values_mut() {
+                file_calls.locations.sort_by_key(|loc| loc.call_expr.byte_span.0);
+            }
+        }
+
         // Save output to provided path
         let mut encoder = FileEncoder::new(options.output_path).map_err(|e| e.to_string())?;
         calls.encode(&mut encoder).map_err(|e| e.to_string())?;