about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustdoc/html/render/mod.rs33
-rw-r--r--src/librustdoc/scrape_examples.rs55
-rw-r--r--src/test/run-make/rustdoc-scrape-examples-ordering/src/lib.rs5
3 files changed, 44 insertions, 49 deletions
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 23ce3b131bb..6b57ff5eeba 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -2717,45 +2717,20 @@ fn render_call_locations(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item) {
         // The output code is limited to that byte range.
         let contents_subset = &contents[(byte_min as usize)..(byte_max as usize)];
 
-        // Given a call-site range, return the set of sub-ranges that exclude leading whitespace
-        // when the range spans multiple lines.
-        let strip_leading_whitespace = |(lo, hi): (u32, u32)| -> Vec<(u32, u32)> {
-            let contents_range = &contents_subset[(lo as usize)..(hi as usize)];
-            let mut ignoring_whitespace = false;
-            let mut ranges = Vec::new();
-            let mut cur_lo = 0;
-            for (idx, chr) in contents_range.char_indices() {
-                let idx = idx as u32;
-                if ignoring_whitespace {
-                    if !chr.is_whitespace() {
-                        ignoring_whitespace = false;
-                        cur_lo = idx;
-                    }
-                } else if chr == '\n' {
-                    ranges.push((lo + cur_lo, lo + idx));
-                    cur_lo = idx;
-                    ignoring_whitespace = true;
-                }
-            }
-            ranges.push((lo + cur_lo, hi));
-            ranges
-        };
-
         // The call locations need to be updated to reflect that the size of the program has changed.
         // Specifically, the ranges are all subtracted by `byte_min` since that's the new zero point.
         let (mut byte_ranges, line_ranges): (Vec<_>, Vec<_>) = call_data
             .locations
             .iter()
             .map(|loc| {
-                let (byte_lo, byte_hi) = loc.call_expr.byte_span;
+                let (byte_lo, byte_hi) = loc.call_ident.byte_span;
                 let (line_lo, line_hi) = loc.call_expr.line_span;
                 let byte_range = (byte_lo - byte_min, byte_hi - byte_min);
-                let byte_ranges = strip_leading_whitespace(byte_range);
 
                 let line_range = (line_lo - line_min, line_hi - line_min);
                 let (line_url, line_title) = link_to_loc(call_data, loc);
 
-                (byte_ranges, (line_range, line_url, line_title))
+                (byte_range, (line_range, line_url, line_title))
             })
             .unzip();
 
@@ -2810,8 +2785,8 @@ fn render_call_locations(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item) {
         let root_path = vec!["../"; cx.current.len() - 1].join("");
 
         let mut decoration_info = FxHashMap::default();
-        decoration_info.insert("highlight focus", byte_ranges.remove(0));
-        decoration_info.insert("highlight", byte_ranges.into_iter().flatten().collect());
+        decoration_info.insert("highlight focus", vec![byte_ranges.remove(0)]);
+        decoration_info.insert("highlight", byte_ranges);
 
         sources::print_src(
             w,
diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs
index 7cf0ea9e84e..21af26a1c91 100644
--- a/src/librustdoc/scrape_examples.rs
+++ b/src/librustdoc/scrape_examples.rs
@@ -85,17 +85,20 @@ impl SyntaxRange {
 #[derive(Encodable, Decodable, Debug, Clone)]
 crate struct CallLocation {
     crate call_expr: SyntaxRange,
+    crate call_ident: SyntaxRange,
     crate enclosing_item: SyntaxRange,
 }
 
 impl CallLocation {
     fn new(
         expr_span: rustc_span::Span,
+        ident_span: rustc_span::Span,
         enclosing_item_span: rustc_span::Span,
         source_file: &SourceFile,
     ) -> Self {
         CallLocation {
             call_expr: SyntaxRange::new(expr_span, source_file),
+            call_ident: SyntaxRange::new(ident_span, source_file),
             enclosing_item: SyntaxRange::new(enclosing_item_span, source_file),
         }
     }
@@ -146,24 +149,39 @@ where
         }
 
         // Get type of function if expression is a function call
-        let (ty, span) = match ex.kind {
+        let (ty, call_span, ident_span) = match ex.kind {
             hir::ExprKind::Call(f, _) => {
                 let types = tcx.typeck(ex.hir_id.owner);
 
                 if let Some(ty) = types.node_type_opt(f.hir_id) {
-                    (ty, ex.span)
+                    (ty, ex.span, f.span)
                 } else {
                     trace!("node_type_opt({}) = None", f.hir_id);
                     return;
                 }
             }
-            hir::ExprKind::MethodCall(_, _, span) => {
+            hir::ExprKind::MethodCall(_, args, call_span) => {
                 let types = tcx.typeck(ex.hir_id.owner);
                 let Some(def_id) = types.type_dependent_def_id(ex.hir_id) else {
                     trace!("type_dependent_def_id({}) = None", ex.hir_id);
                     return;
                 };
-                (tcx.type_of(def_id), span)
+
+                // The MethodCall node doesn't directly contain a span for the
+                // method identifier, so we have to compute it by trimming the full
+                // span based on the arguments.
+                let ident_span = match args.get(1) {
+                    // If there is an argument, e.g. "f(x)", then
+                    // get the span "f(" and delete the lparen.
+                    Some(arg) => {
+                        let with_paren = call_span.until(arg.span);
+                        with_paren.with_hi(with_paren.hi() - BytePos(1))
+                    }
+                    // Otherwise, just delete both parens directly.
+                    None => call_span.with_hi(call_span.hi() - BytePos(2)),
+                };
+
+                (tcx.type_of(def_id), call_span, ident_span)
             }
             _ => {
                 return;
@@ -172,8 +190,8 @@ where
 
         // 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);
+        if call_span.from_expansion() {
+            trace!("Rejecting expr from macro: {:?}", call_span);
             return;
         }
 
@@ -183,26 +201,29 @@ where
             .hir()
             .span_with_body(tcx.hir().local_def_id_to_hir_id(tcx.hir().get_parent_item(ex.hir_id)));
         if enclosing_item_span.from_expansion() {
-            trace!("Rejecting expr ({:?}) from macro item: {:?}", span, enclosing_item_span);
+            trace!("Rejecting expr ({:?}) from macro item: {:?}", call_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
+            enclosing_item_span.contains(call_span),
+            "Attempted to scrape call at [{call_span:?}] whose enclosing item [{enclosing_item_span:?}] doesn't contain the span of the call.",
+        );
+
+        assert!(
+            call_span.contains(ident_span),
+            "Attempted to scrape call at [{call_span:?}] whose identifier [{ident_span:?}] was not contained in the span of the call."
         );
 
         // Save call site if the function resolves to a concrete definition
         if let ty::FnDef(def_id, _) = ty.kind() {
             if self.target_crates.iter().all(|krate| *krate != def_id.krate) {
-                trace!("Rejecting expr from crate not being documented: {:?}", span);
+                trace!("Rejecting expr from crate not being documented: {call_span:?}");
                 return;
             }
 
             let source_map = tcx.sess.source_map();
-            let file = source_map.lookup_char_pos(span.lo()).file;
+            let file = source_map.lookup_char_pos(call_span.lo()).file;
             let file_path = match file.name.clone() {
                 FileName::Real(real_filename) => real_filename.into_local_path(),
                 _ => None,
@@ -212,20 +233,20 @@ where
                 let abs_path = fs::canonicalize(file_path.clone()).unwrap();
                 let cx = &self.cx;
                 let mk_call_data = || {
-                    let clean_span = crate::clean::types::Span::new(span);
+                    let clean_span = crate::clean::types::Span::new(call_span);
                     let url = cx.href_from_span(clean_span, false).unwrap();
                     let display_name = file_path.display().to_string();
-                    let edition = span.edition();
+                    let edition = call_span.edition();
                     CallData { locations: Vec::new(), url, display_name, edition }
                 };
 
                 let fn_key = tcx.def_path_hash(*def_id);
                 let fn_entries = self.calls.entry(fn_key).or_default();
 
-                trace!("Including expr: {:?}", span);
+                trace!("Including expr: {:?}", call_span);
                 let enclosing_item_span =
                     source_map.span_extend_to_prev_char(enclosing_item_span, '\n', false);
-                let location = CallLocation::new(span, enclosing_item_span, &file);
+                let location = CallLocation::new(call_span, ident_span, enclosing_item_span, &file);
                 fn_entries.entry(abs_path).or_insert_with(mk_call_data).locations.push(location);
             }
         }
diff --git a/src/test/run-make/rustdoc-scrape-examples-ordering/src/lib.rs b/src/test/run-make/rustdoc-scrape-examples-ordering/src/lib.rs
index 5afffffdf99..7bd57609fa2 100644
--- a/src/test/run-make/rustdoc-scrape-examples-ordering/src/lib.rs
+++ b/src/test/run-make/rustdoc-scrape-examples-ordering/src/lib.rs
@@ -1,7 +1,6 @@
 // @has foobar/fn.ok.html '//*[@class="docblock scraped-example-list"]' 'ex2'
 // @has foobar/fn.ok.html '//*[@class="more-scraped-examples"]' 'ex1'
-// @has foobar/fn.ok.html '//*[@class="highlight focus"]' '1'
-// @has foobar/fn.ok.html '//*[@class="highlight"]' '2'
-// @has foobar/fn.ok.html '//*[@class="highlight focus"]' '0'
+// @has foobar/fn.ok.html '//*[@class="highlight focus"]' ''
+// @has foobar/fn.ok.html '//*[@class="highlight"]' ''
 
 pub fn ok(_x: i32) {}