diff options
| -rw-r--r-- | src/librustdoc/html/render/mod.rs | 33 | ||||
| -rw-r--r-- | src/librustdoc/scrape_examples.rs | 55 | ||||
| -rw-r--r-- | src/test/run-make/rustdoc-scrape-examples-ordering/src/lib.rs | 5 |
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) {} |
