X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Flibrustdoc%2Fscrape_examples.rs;h=10b6fdf87f41972c414708bfa452b91b8c9fe61e;hb=1e55c31cbbc43a21c93ed5652dc39c267e6557af;hp=05e746573f47989f19da6f5a963214726f1b8ff9;hpb=6225262562f06d8a52624e7898098b58789a6ae5;p=rust.git diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs index 05e746573f4..10b6fdf87f4 100644 --- a/src/librustdoc/scrape_examples.rs +++ b/src/librustdoc/scrape_examples.rs @@ -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())?;