diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 0991778f87d79..4c93e632ab467 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -315,6 +315,29 @@ impl SerializedSearchIndex { let other_entryid_offset = self.names.len(); let mut map_other_pathid_to_self_pathid = Vec::new(); let mut skips = FxHashSet::default(); + + fn remap_entry_data( + other_entry_data: &EntryData, + map_other_pathid_to_self_pathid: &[usize], + ) -> EntryData { + EntryData { + parent: other_entry_data + .parent + .map(|parent| map_other_pathid_to_self_pathid[parent]) + .clone(), + module_path: other_entry_data + .module_path + .map(|path| map_other_pathid_to_self_pathid[path]) + .clone(), + exact_module_path: other_entry_data + .exact_module_path + .map(|exact_path| map_other_pathid_to_self_pathid[exact_path]) + .clone(), + krate: map_other_pathid_to_self_pathid[other_entry_data.krate], + ..other_entry_data.clone() + } + } + for (other_pathid, other_path_data) in other.path_data.iter().enumerate() { if let Some(other_path_data) = other_path_data { let name = Symbol::intern(&other.names[other_pathid]); @@ -439,87 +462,72 @@ impl SerializedSearchIndex { } } for other_entryid in 0..other.names.len() { - if skips.contains(&other_entryid) { - // we push tombstone entries to keep the IDs lined up - self.push(String::new(), None, None, String::new(), None, None, None); - } else { - self.push( - other.names[other_entryid].clone(), - other.path_data[other_entryid].clone(), - other.entry_data[other_entryid].as_ref().map(|other_entry_data| EntryData { - parent: other_entry_data - .parent - .map(|parent| map_other_pathid_to_self_pathid[parent]) - .clone(), - module_path: other_entry_data - .module_path - .map(|path| map_other_pathid_to_self_pathid[path]) - .clone(), - exact_module_path: other_entry_data - .exact_module_path - .map(|exact_path| map_other_pathid_to_self_pathid[exact_path]) - .clone(), - krate: map_other_pathid_to_self_pathid[other_entry_data.krate], - ..other_entry_data.clone() - }), - other.descs[other_entryid].clone(), - other.function_data[other_entryid].clone().map(|mut func| { - fn map_fn_sig_item( - map_other_pathid_to_self_pathid: &Vec, - ty: &mut RenderType, - ) { - match ty.id { - None => {} - Some(RenderTypeId::Index(generic)) if generic < 0 => {} - Some(RenderTypeId::Index(id)) => { - let id = usize::try_from(id).unwrap(); - let id = map_other_pathid_to_self_pathid[id]; - assert!(id != !0); - ty.id = Some(RenderTypeId::Index(isize::try_from(id).unwrap())); - } - _ => unreachable!(), + self.push( + other.names[other_entryid].clone(), + if skips.contains(&other_entryid) { + None + } else { + other.path_data[other_entryid].clone() + }, + other.entry_data[other_entryid].as_ref().map(|other_entry_data| { + remap_entry_data(other_entry_data, &map_other_pathid_to_self_pathid) + }), + other.descs[other_entryid].clone(), + other.function_data[other_entryid].clone().map(|mut func| { + fn map_fn_sig_item( + map_other_pathid_to_self_pathid: &Vec, + ty: &mut RenderType, + ) { + match ty.id { + None => {} + Some(RenderTypeId::Index(generic)) if generic < 0 => {} + Some(RenderTypeId::Index(id)) => { + let id = usize::try_from(id).unwrap(); + let id = map_other_pathid_to_self_pathid[id]; + assert!(id != !0); + ty.id = Some(RenderTypeId::Index(isize::try_from(id).unwrap())); } - if let Some(generics) = &mut ty.generics { - for generic in generics { - map_fn_sig_item(map_other_pathid_to_self_pathid, generic); - } + _ => unreachable!(), + } + if let Some(generics) = &mut ty.generics { + for generic in generics { + map_fn_sig_item(map_other_pathid_to_self_pathid, generic); } - if let Some(bindings) = &mut ty.bindings { - for (param, constraints) in bindings { - *param = match *param { - param @ RenderTypeId::Index(generic) if generic < 0 => { - param - } - RenderTypeId::Index(id) => { - let id = usize::try_from(id).unwrap(); - let id = map_other_pathid_to_self_pathid[id]; - assert!(id != !0); - RenderTypeId::Index(isize::try_from(id).unwrap()) - } - _ => unreachable!(), - }; - for constraint in constraints { - map_fn_sig_item( - map_other_pathid_to_self_pathid, - constraint, - ); + } + if let Some(bindings) = &mut ty.bindings { + for (param, constraints) in bindings { + *param = match *param { + param @ RenderTypeId::Index(generic) if generic < 0 => param, + RenderTypeId::Index(id) => { + let id = usize::try_from(id).unwrap(); + let id = map_other_pathid_to_self_pathid[id]; + assert!(id != !0); + RenderTypeId::Index(isize::try_from(id).unwrap()) } + _ => unreachable!(), + }; + for constraint in constraints { + map_fn_sig_item(map_other_pathid_to_self_pathid, constraint); } } } - for input in &mut func.inputs { - map_fn_sig_item(&map_other_pathid_to_self_pathid, input); - } - for output in &mut func.output { - map_fn_sig_item(&map_other_pathid_to_self_pathid, output); - } - for clause in &mut func.where_clause { - for entry in clause { - map_fn_sig_item(&map_other_pathid_to_self_pathid, entry); - } + } + for input in &mut func.inputs { + map_fn_sig_item(&map_other_pathid_to_self_pathid, input); + } + for output in &mut func.output { + map_fn_sig_item(&map_other_pathid_to_self_pathid, output); + } + for clause in &mut func.where_clause { + for entry in clause { + map_fn_sig_item(&map_other_pathid_to_self_pathid, entry); } - func - }), + } + func + }), + if skips.contains(&other_entryid) { + None + } else { other.type_data[other_entryid].as_ref().map(|type_data| TypeData { inverted_function_inputs_index: type_data .inverted_function_inputs_index @@ -556,11 +564,11 @@ impl SerializedSearchIndex { }) .collect(), search_unbox: type_data.search_unbox, - }), - other.alias_pointers[other_entryid] - .map(|alias_pointer| alias_pointer + other_entryid_offset), - ); - } + }) + }, + other.alias_pointers[other_entryid] + .map(|alias_pointer| alias_pointer + other_entryid_offset), + ); } if other.generic_inverted_index.len() > self.generic_inverted_index.len() { self.generic_inverted_index.resize(other.generic_inverted_index.len(), Vec::new()); diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index b3c2563aa3f97..ab72edacae296 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -375,15 +375,20 @@ impl CrateInfo { .fold(Ok(Vec::new()), |acc, parts_path| { let mut acc = acc?; let dir = &parts_path.0; - acc.append(&mut try_err!(std::fs::read_dir(dir), dir.as_path()) + let mut files: Vec> = try_err!(std::fs::read_dir(dir), dir.as_path()) + .map(|file| Ok(file?.path())) + .collect(); + files.sort_by_key(|p| p.as_ref().map_or(PathBuf::new(), |p| p.clone())); + acc.append(&mut files + .into_iter() .filter_map(|file| { - let to_crate_info = |file: Result| -> Result, Error> { + let to_crate_info = |file: Result| -> Result, Error> { let file = try_err!(file, dir.as_path()); - if file.path().extension() != Some(OsStr::new("json")) { + if file.extension() != Some(OsStr::new("json")) { return Ok(None); } - let parts = try_err!(fs::read(file.path()), file.path()); - let parts: CrateInfo = try_err!(serde_json::from_slice(&parts), file.path()); + let parts = try_err!(fs::read(&file), &file); + let parts: CrateInfo = try_err!(serde_json::from_slice(&parts), &file); Ok(Some(parts)) }; to_crate_info(file).transpose() diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index 3459273c922a1..24e933c516f81 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -215,6 +215,8 @@ pub(crate) struct TestProps { pub(crate) disable_gdb_pretty_printers: bool, /// Compare the output by lines, rather than as a single string. pub(crate) compare_output_by_lines: bool, + /// Use CCI (`--read-doc-meta` and `--write-doc-meta`) merge mode. + pub(crate) use_rustdoc_cci_doc_meta_merge: bool, } mod directives { @@ -262,6 +264,7 @@ mod directives { pub(crate) const MINICORE_COMPILE_FLAGS: &str = "minicore-compile-flags"; pub(crate) const DISABLE_GDB_PRETTY_PRINTERS: &str = "disable-gdb-pretty-printers"; pub(crate) const COMPARE_OUTPUT_BY_LINES: &str = "compare-output-by-lines"; + pub(crate) const USE_RUSTDOC_CCI_DOC_META_MERGE: &str = "use-rustdoc-cci-doc-meta-merge"; } impl TestProps { @@ -319,6 +322,7 @@ impl TestProps { dont_require_annotations: Default::default(), disable_gdb_pretty_printers: false, compare_output_by_lines: false, + use_rustdoc_cci_doc_meta_merge: false, } } diff --git a/src/tools/compiletest/src/directives/directive_names.rs b/src/tools/compiletest/src/directives/directive_names.rs index d305aaaf9453f..eb7020a00aa29 100644 --- a/src/tools/compiletest/src/directives/directive_names.rs +++ b/src/tools/compiletest/src/directives/directive_names.rs @@ -310,6 +310,7 @@ pub(crate) const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "unset-rustc-env", // Used by the tidy check `unknown_revision`. "unused-revision-names", + "use-rustdoc-cci-doc-meta-merge", // tidy-alphabetical-end ]; diff --git a/src/tools/compiletest/src/directives/handlers.rs b/src/tools/compiletest/src/directives/handlers.rs index 3848bb4854e75..59656bd15ab15 100644 --- a/src/tools/compiletest/src/directives/handlers.rs +++ b/src/tools/compiletest/src/directives/handlers.rs @@ -364,6 +364,13 @@ fn make_directive_handlers_map() -> HashMap<&'static str, Handler> { &mut props.compare_output_by_lines, ); }), + handler(USE_RUSTDOC_CCI_DOC_META_MERGE, |config, ln, props| { + config.set_name_directive( + ln, + USE_RUSTDOC_CCI_DOC_META_MERGE, + &mut props.use_rustdoc_cci_doc_meta_merge, + ); + }), ]; handlers diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index a08a96f0d7be5..c728e56cf639d 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1047,14 +1047,21 @@ impl<'test> TestCx<'test> { .args(&self.props.doc_flags); match kind { - DocKind::Html => {} + DocKind::Html => { + if self.props.use_rustdoc_cci_doc_meta_merge { + rustdoc.arg("--write-doc-meta-dir").arg(out_dir.as_ref().join("doc.meta")); + } + } DocKind::Json => { rustdoc.arg("--output-format").arg("json"); } } // Both JSON output and `--disable-minification` are unstable rustdoc options. - if matches!(kind, DocKind::Json) || self.config.disable_minification { + if matches!(kind, DocKind::Json) + || self.config.disable_minification + || self.props.use_rustdoc_cci_doc_meta_merge + { rustdoc.arg("-Zunstable-options"); } if self.config.disable_minification { @@ -1065,7 +1072,31 @@ impl<'test> TestCx<'test> { rustdoc.arg(format!("-Clinker={}", linker)); } - self.compose_and_run_compiler(rustdoc, None) + let docres = self.compose_and_run_compiler(rustdoc, None); + if !docres.status.success() { + return docres; + } + if kind == DocKind::Html && self.props.use_rustdoc_cci_doc_meta_merge { + let mut rustdoc_merge = Command::new(rustdoc_path); + let current_dir = self.output_base_dir(); + rustdoc_merge.current_dir(current_dir); + rustdoc_merge + .arg("-o") + .arg(out_dir.as_ref()) + .args(&self.props.compile_flags) + .args(&self.props.doc_flags) + .arg("--read-doc-meta-dir") + .arg(out_dir.as_ref().join("doc.meta")) + .arg("-Zunstable-options"); + if self.config.disable_minification { + rustdoc_merge.arg("--disable-minification"); + } + let docmerge = self.compose_and_run_compiler(rustdoc_merge, None); + if !docmerge.status.success() { + return docmerge; + } + } + docres } fn exec_compiled_test(&self) -> ProcRes { diff --git a/tests/rustdoc-js-std/pathbuf.js b/tests/rustdoc-js-std/pathbuf.js new file mode 100644 index 0000000000000..97b11fabe0fb8 --- /dev/null +++ b/tests/rustdoc-js-std/pathbuf.js @@ -0,0 +1,17 @@ +// The PathBuf type is defined in std, +// but used in proc_macro. This means both crates' +// search indexes contain TypeData for it, +// but only std defines EntryData. +// This test case ensures we can merge them. +// +// https://github.com/rust-lang/rust/issues/162334 + + +const EXPECTED = [ + { + query: 'PathBuf', + others: [ + { 'path': 'std::path', 'name': 'PathBuf' }, + ], + }, +]; diff --git a/tests/rustdoc-js/auxiliary/upstream-type.rs b/tests/rustdoc-js/auxiliary/upstream-type.rs new file mode 100644 index 0000000000000..155d9c1626284 --- /dev/null +++ b/tests/rustdoc-js/auxiliary/upstream-type.rs @@ -0,0 +1,15 @@ +//@ use-rustdoc-cci-doc-meta-merge + +/// +pub struct FooBar; + +/// Test case for overlapping struct and function name +#[allow(nonstandard_style)] +pub struct overlapping_name { + _inner: (), +} + +/// Test case for overlapping function and struct name +pub fn overlapping_name() -> FooBar { + FooBar +} diff --git a/tests/rustdoc-js/downstream-type.js b/tests/rustdoc-js/downstream-type.js new file mode 100644 index 0000000000000..557042bb0ef53 --- /dev/null +++ b/tests/rustdoc-js/downstream-type.js @@ -0,0 +1,58 @@ +// exact-check +// ignore-order + +// The FooBar type is defined in upstream_type, +// but used in downstream_type. This means both crates' +// search indexes contain TypeData for it, +// but only upstream_type defines EntryData. +// This test case ensures we can merge them +// when running in CCI mode. +// https://github.com/rust-lang/rust/issues/162334 +const EXPECTED = [ + { + 'query': 'FooBar', + 'others': [ + { + 'path': 'upstream_type', + 'name': 'FooBar', + }, + ], + 'in_args': [ + { + 'path': 'downstream_type', + 'name': 'downstream_fn', + 'desc': 'https://github.com/rust-lang/rust/issues/162334', + }, + ], + 'returned': [ + { + 'path': 'upstream_type', + 'name': 'overlapping_name', + 'desc': 'Test case for overlapping function and struct name', + }, + ], + }, + { + 'query': 'overlapping_name', + 'others': [ + { + 'path': 'upstream_type', + 'name': 'overlapping_name', + 'ty': 5, + }, + { + 'path': 'upstream_type', + 'name': 'overlapping_name', + 'ty': 7, + }, + ], + 'returned': [], + 'in_args': [ + { + 'path': 'downstream_type', + 'name': 'with_overlap', + 'desc': '', + }, + ] + }, +]; diff --git a/tests/rustdoc-js/downstream-type.rs b/tests/rustdoc-js/downstream-type.rs new file mode 100644 index 0000000000000..16bba39aa1865 --- /dev/null +++ b/tests/rustdoc-js/downstream-type.rs @@ -0,0 +1,9 @@ +//@ aux-crate:upstream_type=upstream-type.rs +//@ aux-build:upstream-type.rs +//@ build-aux-docs +//@ use-rustdoc-cci-doc-meta-merge + +/// +pub fn downstream_fn(f: upstream_type::FooBar) {} + +pub fn with_overlap(f: upstream_type::overlapping_name) {}