Auto merge of #110324 - JohnTitor:rollup-jq31pd1, r=JohnTitor
Rollup of 7 pull requests Successful merges: - #103682 (Stabilize rustdoc `--test-run-directory`) - #106249 (Create "suggested tests" tool in `rustbuild`) - #110047 (Add link to `collections` docs to `extend` trait) - #110269 (Add `tidy-alphabetical` to features in `core`) - #110292 (Add `tidy-alphabetical` to features in `alloc` & `std`) - #110305 (rustdoc-search: use ES6 `Map` and `Set` where they make sense) - #110315 (Add a stable MIR way to get the main function) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
+11
-2
@@ -3451,9 +3451,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.16.0"
|
||||
version = "1.17.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
|
||||
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
|
||||
|
||||
[[package]]
|
||||
name = "opener"
|
||||
@@ -6101,6 +6101,15 @@ version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
|
||||
|
||||
[[package]]
|
||||
name = "suggest-tests"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"build_helper",
|
||||
"glob",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.102"
|
||||
|
||||
@@ -44,6 +44,7 @@ members = [
|
||||
"src/tools/lld-wrapper",
|
||||
"src/tools/collect-license-metadata",
|
||||
"src/tools/generate-copyright",
|
||||
"src/tools/suggest-tests",
|
||||
]
|
||||
|
||||
exclude = [
|
||||
|
||||
@@ -40,6 +40,10 @@ pub fn all_local_items() -> stable_mir::CrateItems {
|
||||
with(|tcx| tcx.mir_keys(()).iter().map(|item| crate_item(item.to_def_id())).collect())
|
||||
}
|
||||
|
||||
pub fn entry_fn() -> Option<stable_mir::CrateItem> {
|
||||
with(|tcx| Some(crate_item(tcx.entry_fn(())?.0)))
|
||||
}
|
||||
|
||||
/// Build a stable mir crate from a given crate number.
|
||||
fn smir_crate(tcx: TyCtxt<'_>, crate_num: CrateNum) -> stable_mir::Crate {
|
||||
let crate_name = tcx.crate_name(crate_num).to_string();
|
||||
|
||||
@@ -45,6 +45,13 @@ impl CrateItem {
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the function where execution starts if the current
|
||||
/// crate defines that. This is usually `main`, but could be
|
||||
/// `start` if the crate is a no-std crate.
|
||||
pub fn entry_fn() -> Option<CrateItem> {
|
||||
crate::rustc_smir::entry_fn()
|
||||
}
|
||||
|
||||
/// Access to the local crate.
|
||||
pub fn local_crate() -> Crate {
|
||||
crate::rustc_smir::local_crate()
|
||||
|
||||
+26
-22
@@ -90,6 +90,11 @@
|
||||
#![warn(multiple_supertrait_upcastable)]
|
||||
//
|
||||
// Library features:
|
||||
// tidy-alphabetical-start
|
||||
#![cfg_attr(not(no_global_oom_handling), feature(const_alloc_error))]
|
||||
#![cfg_attr(not(no_global_oom_handling), feature(const_btree_len))]
|
||||
#![cfg_attr(test, feature(is_sorted))]
|
||||
#![cfg_attr(test, feature(new_uninit))]
|
||||
#![feature(alloc_layout_extra)]
|
||||
#![feature(allocator_api)]
|
||||
#![feature(array_chunks)]
|
||||
@@ -99,23 +104,21 @@
|
||||
#![feature(assert_matches)]
|
||||
#![feature(async_iterator)]
|
||||
#![feature(coerce_unsized)]
|
||||
#![cfg_attr(not(no_global_oom_handling), feature(const_alloc_error))]
|
||||
#![feature(const_box)]
|
||||
#![cfg_attr(not(no_global_oom_handling), feature(const_btree_len))]
|
||||
#![feature(const_cow_is_borrowed)]
|
||||
#![feature(const_convert)]
|
||||
#![feature(const_size_of_val)]
|
||||
#![feature(const_align_of_val)]
|
||||
#![feature(const_ptr_read)]
|
||||
#![feature(const_maybe_uninit_zeroed)]
|
||||
#![feature(const_maybe_uninit_write)]
|
||||
#![feature(const_box)]
|
||||
#![feature(const_convert)]
|
||||
#![feature(const_cow_is_borrowed)]
|
||||
#![feature(const_eval_select)]
|
||||
#![feature(const_maybe_uninit_as_mut_ptr)]
|
||||
#![feature(const_maybe_uninit_write)]
|
||||
#![feature(const_maybe_uninit_zeroed)]
|
||||
#![feature(const_pin)]
|
||||
#![feature(const_ptr_read)]
|
||||
#![feature(const_refs_to_cell)]
|
||||
#![feature(const_size_of_val)]
|
||||
#![feature(const_waker)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(core_panic)]
|
||||
#![feature(const_eval_select)]
|
||||
#![feature(const_pin)]
|
||||
#![feature(const_waker)]
|
||||
#![feature(dispatch_from_dyn)]
|
||||
#![feature(error_generic_member_access)]
|
||||
#![feature(error_in_core)]
|
||||
@@ -126,7 +129,6 @@
|
||||
#![feature(hasher_prefixfree_extras)]
|
||||
#![feature(inline_const)]
|
||||
#![feature(inplace_iteration)]
|
||||
#![cfg_attr(test, feature(is_sorted))]
|
||||
#![feature(iter_advance_by)]
|
||||
#![feature(iter_next_chunk)]
|
||||
#![feature(iter_repeat_n)]
|
||||
@@ -134,7 +136,6 @@
|
||||
#![feature(maybe_uninit_slice)]
|
||||
#![feature(maybe_uninit_uninit_array)]
|
||||
#![feature(maybe_uninit_uninit_array_transpose)]
|
||||
#![cfg_attr(test, feature(new_uninit))]
|
||||
#![feature(pattern)]
|
||||
#![feature(pointer_byte_offsets)]
|
||||
#![feature(provide_any)]
|
||||
@@ -150,6 +151,7 @@
|
||||
#![feature(slice_ptr_get)]
|
||||
#![feature(slice_ptr_len)]
|
||||
#![feature(slice_range)]
|
||||
#![feature(std_internals)]
|
||||
#![feature(str_internals)]
|
||||
#![feature(strict_provenance)]
|
||||
#![feature(trusted_len)]
|
||||
@@ -160,41 +162,43 @@
|
||||
#![feature(unicode_internals)]
|
||||
#![feature(unsize)]
|
||||
#![feature(utf8_chunks)]
|
||||
#![feature(std_internals)]
|
||||
// tidy-alphabetical-end
|
||||
//
|
||||
// Language features:
|
||||
// tidy-alphabetical-start
|
||||
#![cfg_attr(not(test), feature(generator_trait))]
|
||||
#![cfg_attr(test, feature(panic_update_hook))]
|
||||
#![cfg_attr(test, feature(test))]
|
||||
#![feature(allocator_internals)]
|
||||
#![feature(allow_internal_unstable)]
|
||||
#![feature(associated_type_bounds)]
|
||||
#![feature(c_unwind)]
|
||||
#![feature(cfg_sanitize)]
|
||||
#![feature(const_deref)]
|
||||
#![feature(const_mut_refs)]
|
||||
#![feature(const_ptr_write)]
|
||||
#![feature(const_precise_live_drops)]
|
||||
#![feature(const_ptr_write)]
|
||||
#![feature(const_trait_impl)]
|
||||
#![feature(const_try)]
|
||||
#![feature(dropck_eyepatch)]
|
||||
#![feature(exclusive_range_pattern)]
|
||||
#![feature(fundamental)]
|
||||
#![cfg_attr(not(test), feature(generator_trait))]
|
||||
#![feature(hashmap_internals)]
|
||||
#![feature(lang_items)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(multiple_supertrait_upcastable)]
|
||||
#![feature(negative_impls)]
|
||||
#![feature(never_type)]
|
||||
#![feature(pointer_is_aligned)]
|
||||
#![feature(rustc_allow_const_fn_unstable)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![feature(pointer_is_aligned)]
|
||||
#![feature(slice_internals)]
|
||||
#![feature(staged_api)]
|
||||
#![feature(stmt_expr_attributes)]
|
||||
#![cfg_attr(test, feature(test))]
|
||||
#![feature(unboxed_closures)]
|
||||
#![feature(unsized_fn_params)]
|
||||
#![feature(c_unwind)]
|
||||
#![feature(with_negative_coherence)]
|
||||
#![cfg_attr(test, feature(panic_update_hook))]
|
||||
#![feature(multiple_supertrait_upcastable)]
|
||||
// tidy-alphabetical-end
|
||||
//
|
||||
// Rustdoc features:
|
||||
#![feature(doc_cfg)]
|
||||
|
||||
+29
-23
@@ -98,11 +98,14 @@
|
||||
#![warn(multiple_supertrait_upcastable)]
|
||||
//
|
||||
// Library features:
|
||||
#![feature(const_align_offset)]
|
||||
// tidy-alphabetical-start
|
||||
#![feature(char_indices_offset)]
|
||||
#![feature(const_align_of_val)]
|
||||
#![feature(const_align_of_val_raw)]
|
||||
#![feature(const_align_offset)]
|
||||
#![feature(const_alloc_layout)]
|
||||
#![feature(const_arguments_as_str)]
|
||||
#![feature(const_array_from_ref)]
|
||||
#![feature(const_array_into_iter_constructors)]
|
||||
#![feature(const_bigint_helper_methods)]
|
||||
#![feature(const_black_box)]
|
||||
@@ -111,6 +114,9 @@
|
||||
#![feature(const_char_from_u32_unchecked)]
|
||||
#![feature(const_clone)]
|
||||
#![feature(const_cmp)]
|
||||
#![feature(const_convert)]
|
||||
#![feature(const_cstr_methods)]
|
||||
#![feature(const_default_impls)]
|
||||
#![feature(const_discriminant)]
|
||||
#![feature(const_eval_select)]
|
||||
#![feature(const_exact_div)]
|
||||
@@ -119,17 +125,17 @@
|
||||
#![feature(const_fmt_arguments_new)]
|
||||
#![feature(const_hash)]
|
||||
#![feature(const_heap)]
|
||||
#![feature(const_convert)]
|
||||
#![feature(const_index_range_slice_index)]
|
||||
#![feature(const_inherent_unchecked_arith)]
|
||||
#![feature(const_int_unchecked_arith)]
|
||||
#![feature(const_intrinsic_forget)]
|
||||
#![feature(const_ipv4)]
|
||||
#![feature(const_ipv6)]
|
||||
#![feature(const_is_char_boundary)]
|
||||
#![feature(const_likely)]
|
||||
#![feature(const_maybe_uninit_uninit_array)]
|
||||
#![feature(const_maybe_uninit_as_mut_ptr)]
|
||||
#![feature(const_maybe_uninit_assume_init)]
|
||||
#![feature(const_maybe_uninit_uninit_array)]
|
||||
#![feature(const_nonnull_new)]
|
||||
#![feature(const_num_from_num)]
|
||||
#![feature(const_ops)]
|
||||
@@ -138,32 +144,35 @@
|
||||
#![feature(const_pin)]
|
||||
#![feature(const_pointer_byte_offsets)]
|
||||
#![feature(const_pointer_is_aligned)]
|
||||
#![feature(const_ptr_sub_ptr)]
|
||||
#![feature(const_replace)]
|
||||
#![feature(const_result_drop)]
|
||||
#![feature(const_ptr_as_ref)]
|
||||
#![feature(const_ptr_is_null)]
|
||||
#![feature(const_ptr_read)]
|
||||
#![feature(const_ptr_sub_ptr)]
|
||||
#![feature(const_ptr_write)]
|
||||
#![feature(const_raw_ptr_comparison)]
|
||||
#![feature(const_replace)]
|
||||
#![feature(const_result_drop)]
|
||||
#![feature(const_size_of_val)]
|
||||
#![feature(const_size_of_val_raw)]
|
||||
#![feature(const_slice_from_raw_parts_mut)]
|
||||
#![feature(const_slice_from_ref)]
|
||||
#![feature(const_slice_index)]
|
||||
#![feature(const_slice_ptr_len)]
|
||||
#![feature(const_slice_split_at_mut)]
|
||||
#![feature(const_str_from_utf8_unchecked_mut)]
|
||||
#![feature(const_swap)]
|
||||
#![feature(const_trait_impl)]
|
||||
#![feature(const_transmute_copy)]
|
||||
#![feature(const_try)]
|
||||
#![feature(const_type_id)]
|
||||
#![feature(const_type_name)]
|
||||
#![feature(const_default_impls)]
|
||||
#![feature(const_unicode_case_lookup)]
|
||||
#![feature(const_unsafecell_get_mut)]
|
||||
#![feature(const_waker)]
|
||||
#![feature(core_panic)]
|
||||
#![feature(char_indices_offset)]
|
||||
#![feature(duration_consts_float)]
|
||||
#![feature(ip)]
|
||||
#![feature(is_ascii_octdigit)]
|
||||
#![feature(maybe_uninit_uninit_array)]
|
||||
#![feature(ptr_alignment_type)]
|
||||
#![feature(ptr_metadata)]
|
||||
@@ -171,25 +180,21 @@
|
||||
#![feature(slice_ptr_get)]
|
||||
#![feature(slice_split_at_unchecked)]
|
||||
#![feature(str_internals)]
|
||||
#![feature(str_split_remainder)]
|
||||
#![feature(str_split_inclusive_remainder)]
|
||||
#![feature(str_split_remainder)]
|
||||
#![feature(strict_provenance)]
|
||||
#![feature(utf16_extra)]
|
||||
#![feature(utf16_extra_const)]
|
||||
#![feature(variant_count)]
|
||||
#![feature(const_array_from_ref)]
|
||||
#![feature(const_slice_from_ref)]
|
||||
#![feature(const_slice_index)]
|
||||
#![feature(const_is_char_boundary)]
|
||||
#![feature(const_cstr_methods)]
|
||||
#![feature(ip)]
|
||||
#![feature(is_ascii_octdigit)]
|
||||
// tidy-alphabetical-end
|
||||
//
|
||||
// Language features:
|
||||
// tidy-alphabetical-start
|
||||
#![feature(abi_unadjusted)]
|
||||
#![feature(adt_const_params)]
|
||||
#![feature(allow_internal_unsafe)]
|
||||
#![feature(allow_internal_unstable)]
|
||||
#![feature(asm_const)]
|
||||
#![feature(associated_type_bounds)]
|
||||
#![feature(auto_traits)]
|
||||
#![feature(c_unwind)]
|
||||
@@ -206,13 +211,12 @@
|
||||
#![feature(deprecated_suggestion)]
|
||||
#![feature(derive_const)]
|
||||
#![feature(doc_cfg)]
|
||||
#![feature(doc_notable_trait)]
|
||||
#![feature(generic_arg_infer)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![feature(exhaustive_patterns)]
|
||||
#![feature(doc_cfg_hide)]
|
||||
#![feature(doc_notable_trait)]
|
||||
#![feature(exhaustive_patterns)]
|
||||
#![feature(extern_types)]
|
||||
#![feature(fundamental)]
|
||||
#![feature(generic_arg_infer)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(inline_const)]
|
||||
#![feature(intra_doc_pointers)]
|
||||
@@ -221,6 +225,7 @@
|
||||
#![feature(link_llvm_intrinsics)]
|
||||
#![feature(macro_metavar_expr)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(multiple_supertrait_upcastable)]
|
||||
#![feature(must_not_suspend)]
|
||||
#![feature(negative_impls)]
|
||||
#![feature(never_type)]
|
||||
@@ -231,6 +236,7 @@
|
||||
#![feature(repr_simd)]
|
||||
#![feature(rustc_allow_const_fn_unstable)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![feature(simd_ffi)]
|
||||
#![feature(staged_api)]
|
||||
#![feature(stmt_expr_attributes)]
|
||||
@@ -240,11 +246,10 @@
|
||||
#![feature(try_blocks)]
|
||||
#![feature(unboxed_closures)]
|
||||
#![feature(unsized_fn_params)]
|
||||
#![feature(asm_const)]
|
||||
#![feature(const_transmute_copy)]
|
||||
#![feature(multiple_supertrait_upcastable)]
|
||||
// tidy-alphabetical-end
|
||||
//
|
||||
// Target features:
|
||||
// tidy-alphabetical-start
|
||||
#![feature(arm_target_feature)]
|
||||
#![feature(avx512_target_feature)]
|
||||
#![feature(hexagon_target_feature)]
|
||||
@@ -255,6 +260,7 @@
|
||||
#![feature(sse4a_target_feature)]
|
||||
#![feature(tbm_target_feature)]
|
||||
#![feature(wasm_target_feature)]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
// allow using `core::` in intra-doc links
|
||||
#[allow(unused_extern_crates)]
|
||||
|
||||
@@ -172,7 +172,8 @@
|
||||
//!
|
||||
//! ## Iterators
|
||||
//!
|
||||
//! Iterators are a powerful and robust mechanism used throughout Rust's
|
||||
//! [Iterators][crate::iter]
|
||||
//! are a powerful and robust mechanism used throughout Rust's
|
||||
//! standard libraries. Iterators provide a sequence of values in a generic,
|
||||
//! safe, efficient and convenient way. The contents of an iterator are usually
|
||||
//! *lazily* evaluated, so that only the values that are actually needed are
|
||||
@@ -252,7 +253,9 @@
|
||||
//!
|
||||
//! Several other collection methods also return iterators to yield a sequence
|
||||
//! of results but avoid allocating an entire collection to store the result in.
|
||||
//! This provides maximum flexibility as `collect` or `extend` can be called to
|
||||
//! This provides maximum flexibility as
|
||||
//! [`collect`][crate::iter::Iterator::collect] or
|
||||
//! [`extend`][crate::iter::Extend::extend] can be called to
|
||||
//! "pipe" the sequence into any collection if desired. Otherwise, the sequence
|
||||
//! can be looped over with a `for` loop. The iterator can also be discarded
|
||||
//! after partial use, preventing the computation of the unused items.
|
||||
|
||||
+19
-7
@@ -235,6 +235,7 @@
|
||||
#![cfg_attr(windows, feature(round_char_boundary))]
|
||||
//
|
||||
// Language features:
|
||||
// tidy-alphabetical-start
|
||||
#![feature(alloc_error_handler)]
|
||||
#![feature(allocator_internals)]
|
||||
#![feature(allow_internal_unsafe)]
|
||||
@@ -256,8 +257,8 @@
|
||||
#![feature(intra_doc_pointers)]
|
||||
#![feature(lang_items)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(linkage)]
|
||||
#![feature(link_cfg)]
|
||||
#![feature(linkage)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(must_not_suspend)]
|
||||
#![feature(needs_panic_runtime)]
|
||||
@@ -271,8 +272,10 @@
|
||||
#![feature(thread_local)]
|
||||
#![feature(try_blocks)]
|
||||
#![feature(utf8_chunks)]
|
||||
// tidy-alphabetical-end
|
||||
//
|
||||
// Library features (core):
|
||||
// tidy-alphabetical-start
|
||||
#![feature(char_internals)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(duration_constants)]
|
||||
@@ -289,6 +292,7 @@
|
||||
#![feature(ip)]
|
||||
#![feature(ip_in_core)]
|
||||
#![feature(maybe_uninit_slice)]
|
||||
#![feature(maybe_uninit_uninit_array)]
|
||||
#![feature(maybe_uninit_write_slice)]
|
||||
#![feature(panic_can_unwind)]
|
||||
#![feature(panic_info_message)]
|
||||
@@ -306,25 +310,28 @@
|
||||
#![feature(std_internals)]
|
||||
#![feature(str_internals)]
|
||||
#![feature(strict_provenance)]
|
||||
#![feature(maybe_uninit_uninit_array)]
|
||||
#![feature(const_maybe_uninit_uninit_array)]
|
||||
#![feature(const_waker)]
|
||||
// tidy-alphabetical-end
|
||||
//
|
||||
// Library features (alloc):
|
||||
// tidy-alphabetical-start
|
||||
#![feature(alloc_layout_extra)]
|
||||
#![feature(allocator_api)]
|
||||
#![feature(get_mut_unchecked)]
|
||||
#![feature(map_try_insert)]
|
||||
#![feature(new_uninit)]
|
||||
#![feature(slice_concat_trait)]
|
||||
#![feature(thin_box)]
|
||||
#![feature(try_reserve_kind)]
|
||||
#![feature(vec_into_raw_parts)]
|
||||
#![feature(slice_concat_trait)]
|
||||
// tidy-alphabetical-end
|
||||
//
|
||||
// Library features (unwind):
|
||||
// tidy-alphabetical-start
|
||||
#![feature(panic_unwind)]
|
||||
// tidy-alphabetical-end
|
||||
//
|
||||
// Only for re-exporting:
|
||||
// tidy-alphabetical-start
|
||||
#![feature(assert_matches)]
|
||||
#![feature(async_iterator)]
|
||||
#![feature(c_variadic)]
|
||||
@@ -336,24 +343,29 @@
|
||||
#![feature(custom_test_frameworks)]
|
||||
#![feature(edition_panic)]
|
||||
#![feature(format_args_nl)]
|
||||
#![feature(log_syntax)]
|
||||
#![feature(get_many_mut)]
|
||||
#![feature(lazy_cell)]
|
||||
#![feature(log_syntax)]
|
||||
#![feature(saturating_int_impl)]
|
||||
#![feature(stdsimd)]
|
||||
#![feature(test)]
|
||||
#![feature(trace_macros)]
|
||||
#![feature(get_many_mut)]
|
||||
// tidy-alphabetical-end
|
||||
//
|
||||
// Only used in tests/benchmarks:
|
||||
//
|
||||
// Only for const-ness:
|
||||
// tidy-alphabetical-start
|
||||
#![feature(const_collections_with_hasher)]
|
||||
#![feature(const_hash)]
|
||||
#![feature(const_io_structs)]
|
||||
#![feature(const_ip)]
|
||||
#![feature(const_ipv4)]
|
||||
#![feature(const_ipv6)]
|
||||
#![feature(const_maybe_uninit_uninit_array)]
|
||||
#![feature(const_waker)]
|
||||
#![feature(thread_local_internals)]
|
||||
// tidy-alphabetical-end
|
||||
//
|
||||
#![default_lib_allocator]
|
||||
|
||||
|
||||
@@ -591,6 +591,7 @@ pub enum Kind {
|
||||
Install,
|
||||
Run,
|
||||
Setup,
|
||||
Suggest,
|
||||
}
|
||||
|
||||
impl Kind {
|
||||
@@ -610,6 +611,7 @@ impl Kind {
|
||||
"install" => Kind::Install,
|
||||
"run" | "r" => Kind::Run,
|
||||
"setup" => Kind::Setup,
|
||||
"suggest" => Kind::Suggest,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
@@ -629,6 +631,7 @@ impl Kind {
|
||||
Kind::Install => "install",
|
||||
Kind::Run => "run",
|
||||
Kind::Setup => "setup",
|
||||
Kind::Suggest => "suggest",
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -709,6 +712,7 @@ impl<'a> Builder<'a> {
|
||||
test::CrateRustdoc,
|
||||
test::CrateRustdocJsonTypes,
|
||||
test::CrateJsonDocLint,
|
||||
test::SuggestTestsCrate,
|
||||
test::Linkcheck,
|
||||
test::TierCheck,
|
||||
test::ReplacePlaceholderTest,
|
||||
@@ -827,7 +831,7 @@ impl<'a> Builder<'a> {
|
||||
Kind::Setup => describe!(setup::Profile, setup::Hook, setup::Link, setup::Vscode),
|
||||
Kind::Clean => describe!(clean::CleanAll, clean::Rustc, clean::Std),
|
||||
// special-cased in Build::build()
|
||||
Kind::Format => vec![],
|
||||
Kind::Format | Kind::Suggest => vec![],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -891,6 +895,7 @@ impl<'a> Builder<'a> {
|
||||
Subcommand::Run { ref paths, .. } => (Kind::Run, &paths[..]),
|
||||
Subcommand::Clean { ref paths, .. } => (Kind::Clean, &paths[..]),
|
||||
Subcommand::Format { .. } => (Kind::Format, &[][..]),
|
||||
Subcommand::Suggest { .. } => (Kind::Suggest, &[][..]),
|
||||
Subcommand::Setup { profile: ref path } => (
|
||||
Kind::Setup,
|
||||
path.as_ref().map_or([].as_slice(), |path| std::slice::from_ref(path)),
|
||||
@@ -900,6 +905,21 @@ impl<'a> Builder<'a> {
|
||||
Self::new_internal(build, kind, paths.to_owned())
|
||||
}
|
||||
|
||||
/// Creates a new standalone builder for use outside of the normal process
|
||||
pub fn new_standalone(
|
||||
build: &mut Build,
|
||||
kind: Kind,
|
||||
paths: Vec<PathBuf>,
|
||||
stage: Option<u32>,
|
||||
) -> Builder<'_> {
|
||||
// FIXME: don't mutate `build`
|
||||
if let Some(stage) = stage {
|
||||
build.config.stage = stage;
|
||||
}
|
||||
|
||||
Self::new_internal(build, kind, paths.to_owned())
|
||||
}
|
||||
|
||||
pub fn execute_cli(&self) {
|
||||
self.run_step_descriptions(&Builder::get_step_descriptions(self.kind), &self.paths);
|
||||
}
|
||||
|
||||
+10
-14
@@ -56,8 +56,7 @@ pub enum DryRun {
|
||||
/// filled out from the decoded forms of the structs below. For documentation
|
||||
/// each field, see the corresponding fields in
|
||||
/// `config.example.toml`.
|
||||
#[derive(Default)]
|
||||
#[cfg_attr(test, derive(Clone))]
|
||||
#[derive(Default, Clone)]
|
||||
pub struct Config {
|
||||
pub changelog_seen: Option<usize>,
|
||||
pub ccache: Option<String>,
|
||||
@@ -240,23 +239,20 @@ pub struct Config {
|
||||
pub initial_rustfmt: RefCell<RustfmtState>,
|
||||
}
|
||||
|
||||
#[derive(Default, Deserialize)]
|
||||
#[cfg_attr(test, derive(Clone))]
|
||||
#[derive(Default, Deserialize, Clone)]
|
||||
pub struct Stage0Metadata {
|
||||
pub compiler: CompilerMetadata,
|
||||
pub config: Stage0Config,
|
||||
pub checksums_sha256: HashMap<String, String>,
|
||||
pub rustfmt: Option<RustfmtMetadata>,
|
||||
}
|
||||
#[derive(Default, Deserialize)]
|
||||
#[cfg_attr(test, derive(Clone))]
|
||||
#[derive(Default, Deserialize, Clone)]
|
||||
pub struct CompilerMetadata {
|
||||
pub date: String,
|
||||
pub version: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Deserialize)]
|
||||
#[cfg_attr(test, derive(Clone))]
|
||||
#[derive(Default, Deserialize, Clone)]
|
||||
pub struct Stage0Config {
|
||||
pub dist_server: String,
|
||||
pub artifacts_server: String,
|
||||
@@ -264,8 +260,7 @@ pub struct Stage0Config {
|
||||
pub git_merge_commit_email: String,
|
||||
pub nightly_branch: String,
|
||||
}
|
||||
#[derive(Default, Deserialize)]
|
||||
#[cfg_attr(test, derive(Clone))]
|
||||
#[derive(Default, Deserialize, Clone)]
|
||||
pub struct RustfmtMetadata {
|
||||
pub date: String,
|
||||
pub version: String,
|
||||
@@ -443,8 +438,7 @@ impl PartialEq<&str> for TargetSelection {
|
||||
}
|
||||
|
||||
/// Per-target configuration stored in the global configuration structure.
|
||||
#[derive(Default)]
|
||||
#[cfg_attr(test, derive(Clone))]
|
||||
#[derive(Default, Clone)]
|
||||
pub struct Target {
|
||||
/// Some(path to llvm-config) if using an external LLVM.
|
||||
pub llvm_config: Option<PathBuf>,
|
||||
@@ -1396,7 +1390,8 @@ impl Config {
|
||||
| Subcommand::Fix { .. }
|
||||
| Subcommand::Run { .. }
|
||||
| Subcommand::Setup { .. }
|
||||
| Subcommand::Format { .. } => flags.stage.unwrap_or(0),
|
||||
| Subcommand::Format { .. }
|
||||
| Subcommand::Suggest { .. } => flags.stage.unwrap_or(0),
|
||||
};
|
||||
|
||||
// CI should always run stage 2 builds, unless it specifically states otherwise
|
||||
@@ -1421,7 +1416,8 @@ impl Config {
|
||||
| Subcommand::Fix { .. }
|
||||
| Subcommand::Run { .. }
|
||||
| Subcommand::Setup { .. }
|
||||
| Subcommand::Format { .. } => {}
|
||||
| Subcommand::Format { .. }
|
||||
| Subcommand::Suggest { .. } => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+11
-3
@@ -84,8 +84,7 @@ pub struct Flags {
|
||||
pub free_args: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(test, derive(Clone))]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Subcommand {
|
||||
Build {
|
||||
paths: Vec<PathBuf>,
|
||||
@@ -149,6 +148,9 @@ pub enum Subcommand {
|
||||
Setup {
|
||||
profile: Option<PathBuf>,
|
||||
},
|
||||
Suggest {
|
||||
run: bool,
|
||||
},
|
||||
}
|
||||
|
||||
impl Default for Subcommand {
|
||||
@@ -183,6 +185,7 @@ Subcommands:
|
||||
install Install distribution artifacts
|
||||
run, r Run tools contained in this repository
|
||||
setup Create a config.toml (making it easier to use `x.py` itself)
|
||||
suggest Suggest a subset of tests to run, based on modified files
|
||||
|
||||
To learn more about a subcommand, run `./x.py <subcommand> -h`",
|
||||
);
|
||||
@@ -349,6 +352,9 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`",
|
||||
Kind::Run => {
|
||||
opts.optmulti("", "args", "arguments for the tool", "ARGS");
|
||||
}
|
||||
Kind::Suggest => {
|
||||
opts.optflag("", "run", "run suggested tests");
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
|
||||
@@ -565,7 +571,7 @@ Arguments:
|
||||
Profile::all_for_help(" ").trim_end()
|
||||
));
|
||||
}
|
||||
Kind::Bench | Kind::Clean | Kind::Dist | Kind::Install => {}
|
||||
Kind::Bench | Kind::Clean | Kind::Dist | Kind::Install | Kind::Suggest => {}
|
||||
};
|
||||
// Get any optional paths which occur after the subcommand
|
||||
let mut paths = matches.free[1..].iter().map(|p| p.into()).collect::<Vec<PathBuf>>();
|
||||
@@ -626,6 +632,7 @@ Arguments:
|
||||
Kind::Format => Subcommand::Format { check: matches.opt_present("check"), paths },
|
||||
Kind::Dist => Subcommand::Dist { paths },
|
||||
Kind::Install => Subcommand::Install { paths },
|
||||
Kind::Suggest => Subcommand::Suggest { run: matches.opt_present("run") },
|
||||
Kind::Run => {
|
||||
if paths.is_empty() {
|
||||
println!("\nrun requires at least a path!\n");
|
||||
@@ -734,6 +741,7 @@ impl Subcommand {
|
||||
Subcommand::Install { .. } => Kind::Install,
|
||||
Subcommand::Run { .. } => Kind::Run,
|
||||
Subcommand::Setup { .. } => Kind::Setup,
|
||||
Subcommand::Suggest { .. } => Kind::Suggest,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+14
-5
@@ -58,6 +58,7 @@ mod render_tests;
|
||||
mod run;
|
||||
mod sanity;
|
||||
mod setup;
|
||||
mod suggest;
|
||||
mod tarball;
|
||||
mod test;
|
||||
mod tool;
|
||||
@@ -190,6 +191,7 @@ pub enum GitRepo {
|
||||
/// although most functions are implemented as free functions rather than
|
||||
/// methods specifically on this structure itself (to make it easier to
|
||||
/// organize).
|
||||
#[cfg_attr(not(feature = "build-metrics"), derive(Clone))]
|
||||
pub struct Build {
|
||||
/// User-specified configuration from `config.toml`.
|
||||
config: Config,
|
||||
@@ -243,7 +245,7 @@ pub struct Build {
|
||||
metrics: metrics::BuildMetrics,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
struct Crate {
|
||||
name: Interned<String>,
|
||||
deps: HashSet<Interned<String>>,
|
||||
@@ -657,13 +659,20 @@ impl Build {
|
||||
job::setup(self);
|
||||
}
|
||||
|
||||
if let Subcommand::Format { check, paths } = &self.config.cmd {
|
||||
return format::format(&builder::Builder::new(&self), *check, &paths);
|
||||
}
|
||||
|
||||
// Download rustfmt early so that it can be used in rust-analyzer configs.
|
||||
let _ = &builder::Builder::new(&self).initial_rustfmt();
|
||||
|
||||
// hardcoded subcommands
|
||||
match &self.config.cmd {
|
||||
Subcommand::Format { check, paths } => {
|
||||
return format::format(&builder::Builder::new(&self), *check, &paths);
|
||||
}
|
||||
Subcommand::Suggest { run } => {
|
||||
return suggest::suggest(&builder::Builder::new(&self), *run);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
{
|
||||
let builder = builder::Builder::new(&self);
|
||||
if let Some(path) = builder.paths.get(0) {
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
#![cfg_attr(feature = "build-metrics", allow(unused))]
|
||||
|
||||
use std::str::FromStr;
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::{
|
||||
builder::{Builder, Kind},
|
||||
tool::Tool,
|
||||
};
|
||||
|
||||
#[cfg(feature = "build-metrics")]
|
||||
pub fn suggest(builder: &Builder<'_>, run: bool) {
|
||||
panic!("`x suggest` is not supported with `build-metrics`")
|
||||
}
|
||||
|
||||
/// Suggests a list of possible `x.py` commands to run based on modified files in branch.
|
||||
#[cfg(not(feature = "build-metrics"))]
|
||||
pub fn suggest(builder: &Builder<'_>, run: bool) {
|
||||
let suggestions =
|
||||
builder.tool_cmd(Tool::SuggestTests).output().expect("failed to run `suggest-tests` tool");
|
||||
|
||||
if !suggestions.status.success() {
|
||||
println!("failed to run `suggest-tests` tool ({})", suggestions.status);
|
||||
println!(
|
||||
"`suggest_tests` stdout:\n{}`suggest_tests` stderr:\n{}",
|
||||
String::from_utf8(suggestions.stdout).unwrap(),
|
||||
String::from_utf8(suggestions.stderr).unwrap()
|
||||
);
|
||||
panic!("failed to run `suggest-tests`");
|
||||
}
|
||||
|
||||
let suggestions = String::from_utf8(suggestions.stdout).unwrap();
|
||||
let suggestions = suggestions
|
||||
.lines()
|
||||
.map(|line| {
|
||||
let mut sections = line.split_ascii_whitespace();
|
||||
|
||||
// this code expects one suggestion per line in the following format:
|
||||
// <x_subcommand> {some number of flags} [optional stage number]
|
||||
let cmd = sections.next().unwrap();
|
||||
let stage = sections.next_back().map(|s| str::parse(s).ok()).flatten();
|
||||
let paths: Vec<PathBuf> = sections.map(|p| PathBuf::from_str(p).unwrap()).collect();
|
||||
|
||||
(cmd, stage, paths)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if !suggestions.is_empty() {
|
||||
println!("==== SUGGESTIONS ====");
|
||||
for sug in &suggestions {
|
||||
print!("x {} ", sug.0);
|
||||
if let Some(stage) = sug.1 {
|
||||
print!("--stage {stage} ");
|
||||
}
|
||||
|
||||
for path in &sug.2 {
|
||||
print!("{} ", path.display());
|
||||
}
|
||||
println!();
|
||||
}
|
||||
println!("=====================");
|
||||
} else {
|
||||
println!("No suggestions found!");
|
||||
return;
|
||||
}
|
||||
|
||||
if run {
|
||||
for sug in suggestions {
|
||||
let mut build = builder.build.clone();
|
||||
|
||||
let builder =
|
||||
Builder::new_standalone(&mut build, Kind::parse(&sug.0).unwrap(), sug.2, sug.1);
|
||||
|
||||
builder.execute_cli()
|
||||
}
|
||||
} else {
|
||||
println!("help: consider using the `--run` flag to automatically run suggested tests");
|
||||
}
|
||||
}
|
||||
@@ -128,6 +128,42 @@ impl Step for CrateJsonDocLint {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct SuggestTestsCrate {
|
||||
host: TargetSelection,
|
||||
}
|
||||
|
||||
impl Step for SuggestTestsCrate {
|
||||
type Output = ();
|
||||
const ONLY_HOSTS: bool = true;
|
||||
const DEFAULT: bool = true;
|
||||
|
||||
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||
run.path("src/tools/suggest-tests")
|
||||
}
|
||||
|
||||
fn make_run(run: RunConfig<'_>) {
|
||||
run.builder.ensure(SuggestTestsCrate { host: run.target });
|
||||
}
|
||||
|
||||
fn run(self, builder: &Builder<'_>) {
|
||||
let bootstrap_host = builder.config.build;
|
||||
let compiler = builder.compiler(0, bootstrap_host);
|
||||
|
||||
let suggest_tests = tool::prepare_tool_cargo(
|
||||
builder,
|
||||
compiler,
|
||||
Mode::ToolBootstrap,
|
||||
bootstrap_host,
|
||||
"test",
|
||||
"src/tools/suggest-tests",
|
||||
SourceType::InTree,
|
||||
&[],
|
||||
);
|
||||
add_flags_and_try_run_tests(builder, &mut suggest_tests.into());
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct Linkcheck {
|
||||
host: TargetSelection,
|
||||
|
||||
@@ -433,6 +433,7 @@ bootstrap_tool!(
|
||||
ReplaceVersionPlaceholder, "src/tools/replace-version-placeholder", "replace-version-placeholder";
|
||||
CollectLicenseMetadata, "src/tools/collect-license-metadata", "collect-license-metadata";
|
||||
GenerateCopyright, "src/tools/generate-copyright", "generate-copyright";
|
||||
SuggestTests, "src/tools/suggest-tests", "suggest-tests";
|
||||
);
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
|
||||
|
||||
@@ -179,7 +179,7 @@ $ rustdoc src/lib.rs --test
|
||||
This flag will run your code examples as tests. For more, see [the chapter
|
||||
on documentation tests](write-documentation/documentation-tests.md).
|
||||
|
||||
See also `--test-args`.
|
||||
See also `--test-args` and `--test-run-directory`.
|
||||
|
||||
## `--test-args`: pass options to test runner
|
||||
|
||||
@@ -194,6 +194,19 @@ For more, see [the chapter on documentation tests](write-documentation/documenta
|
||||
|
||||
See also `--test`.
|
||||
|
||||
## `--test-run-directory`: run code examples in a specific directory
|
||||
|
||||
Using this flag looks like this:
|
||||
|
||||
```bash
|
||||
$ rustdoc src/lib.rs --test --test-run-directory=/path/to/working/directory
|
||||
```
|
||||
|
||||
This flag will run your code examples in the specified working directory.
|
||||
For more, see [the chapter on documentation tests](write-documentation/documentation-tests.md).
|
||||
|
||||
See also `--test`.
|
||||
|
||||
## `--target`: generate documentation for the specified target triple
|
||||
|
||||
Using this flag looks like this:
|
||||
|
||||
@@ -443,3 +443,15 @@ pub struct ReadmeDoctests;
|
||||
|
||||
This will include your README as documentation on the hidden struct `ReadmeDoctests`, which will
|
||||
then be tested alongside the rest of your doctests.
|
||||
|
||||
## Controlling the compilation and run directories
|
||||
|
||||
By default, `rustdoc --test` will compile and run documentation test examples
|
||||
from the same working directory.
|
||||
The compilation directory is being used for compiler diagnostics, the `file!()` macro and
|
||||
the output of `rustdoc` test runner itself, whereas the run directory has an influence on file-system
|
||||
operations within documentation test examples, such as `std::fs::read_to_string`.
|
||||
|
||||
The `--test-run-directory` flag allows controlling the run directory separately from the compilation directory.
|
||||
This is particularly useful in workspaces, where compiler invocations and thus diagnostics should be
|
||||
relative to the workspace directory, but documentation test examples should run relative to the crate directory.
|
||||
|
||||
@@ -65,6 +65,11 @@ let Row;
|
||||
*/
|
||||
let ResultsTable;
|
||||
|
||||
/**
|
||||
* @typedef {Map<String, ResultObject>}
|
||||
*/
|
||||
let Results;
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* desc: string,
|
||||
@@ -80,7 +85,7 @@ let ResultsTable;
|
||||
* ty: number,
|
||||
* }}
|
||||
*/
|
||||
let Results;
|
||||
let ResultObject;
|
||||
|
||||
/**
|
||||
* A pair of [inputs, outputs], or 0 for null. This is stored in the search index.
|
||||
|
||||
@@ -191,7 +191,7 @@ function initSearch(rawSearchIndex) {
|
||||
*/
|
||||
let searchIndex;
|
||||
let currentResults;
|
||||
const ALIASES = Object.create(null);
|
||||
const ALIASES = new Map();
|
||||
|
||||
function isWhitespace(c) {
|
||||
return " \t\n\r".indexOf(c) !== -1;
|
||||
@@ -903,10 +903,18 @@ function initSearch(rawSearchIndex) {
|
||||
* @return {ResultsTable}
|
||||
*/
|
||||
function execQuery(parsedQuery, searchWords, filterCrates, currentCrate) {
|
||||
const results_others = {}, results_in_args = {}, results_returned = {};
|
||||
const results_others = new Map(), results_in_args = new Map(),
|
||||
results_returned = new Map();
|
||||
|
||||
/**
|
||||
* Add extra data to result objects, and filter items that have been
|
||||
* marked for removal.
|
||||
*
|
||||
* @param {[ResultObject]} results
|
||||
* @returns {[ResultObject]}
|
||||
*/
|
||||
function transformResults(results) {
|
||||
const duplicates = {};
|
||||
const duplicates = new Set();
|
||||
const out = [];
|
||||
|
||||
for (const result of results) {
|
||||
@@ -919,10 +927,10 @@ function initSearch(rawSearchIndex) {
|
||||
// To be sure than it some items aren't considered as duplicate.
|
||||
obj.fullPath += "|" + obj.ty;
|
||||
|
||||
if (duplicates[obj.fullPath]) {
|
||||
if (duplicates.has(obj.fullPath)) {
|
||||
continue;
|
||||
}
|
||||
duplicates[obj.fullPath] = true;
|
||||
duplicates.add(obj.fullPath);
|
||||
|
||||
obj.href = res[1];
|
||||
out.push(obj);
|
||||
@@ -934,24 +942,30 @@ function initSearch(rawSearchIndex) {
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function takes a result map, and sorts it by various criteria, including edit
|
||||
* distance, substring match, and the crate it comes from.
|
||||
*
|
||||
* @param {Results} results
|
||||
* @param {boolean} isType
|
||||
* @param {string} preferredCrate
|
||||
* @returns {[ResultObject]}
|
||||
*/
|
||||
function sortResults(results, isType, preferredCrate) {
|
||||
const userQuery = parsedQuery.userQuery;
|
||||
const ar = [];
|
||||
for (const entry in results) {
|
||||
if (hasOwnPropertyRustdoc(results, entry)) {
|
||||
const result = results[entry];
|
||||
result.word = searchWords[result.id];
|
||||
result.item = searchIndex[result.id] || {};
|
||||
ar.push(result);
|
||||
}
|
||||
}
|
||||
results = ar;
|
||||
// if there are no results then return to default and fail
|
||||
if (results.length === 0) {
|
||||
if (results.size === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
results.sort((aaa, bbb) => {
|
||||
const userQuery = parsedQuery.userQuery;
|
||||
const result_list = [];
|
||||
for (const result of results.values()) {
|
||||
result.word = searchWords[result.id];
|
||||
result.item = searchIndex[result.id] || {};
|
||||
result_list.push(result);
|
||||
}
|
||||
|
||||
result_list.sort((aaa, bbb) => {
|
||||
let a, b;
|
||||
|
||||
// sort by exact match with regard to the last word (mismatch goes later)
|
||||
@@ -1060,7 +1074,7 @@ function initSearch(rawSearchIndex) {
|
||||
nameSplit = hasPath ? null : parsedQuery.elems[0].path;
|
||||
}
|
||||
|
||||
for (const result of results) {
|
||||
for (const result of result_list) {
|
||||
// this validation does not make sense when searching by types
|
||||
if (result.dontValidate) {
|
||||
continue;
|
||||
@@ -1073,7 +1087,7 @@ function initSearch(rawSearchIndex) {
|
||||
result.id = -1;
|
||||
}
|
||||
}
|
||||
return transformResults(results);
|
||||
return transformResults(result_list);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1096,7 +1110,7 @@ function initSearch(rawSearchIndex) {
|
||||
// The names match, but we need to be sure that all generics kinda
|
||||
// match as well.
|
||||
if (elem.generics.length > 0 && row.generics.length >= elem.generics.length) {
|
||||
const elems = Object.create(null);
|
||||
const elems = new Map();
|
||||
for (const entry of row.generics) {
|
||||
if (entry.name === "") {
|
||||
// Pure generic, needs to check into it.
|
||||
@@ -1106,39 +1120,30 @@ function initSearch(rawSearchIndex) {
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (elems[entry.name] === undefined) {
|
||||
elems[entry.name] = [];
|
||||
let currentEntryElems;
|
||||
if (elems.has(entry.name)) {
|
||||
currentEntryElems = elems.get(entry.name);
|
||||
} else {
|
||||
currentEntryElems = [];
|
||||
elems.set(entry.name, currentEntryElems);
|
||||
}
|
||||
elems[entry.name].push(entry.ty);
|
||||
currentEntryElems.push(entry.ty);
|
||||
}
|
||||
// We need to find the type that matches the most to remove it in order
|
||||
// to move forward.
|
||||
const handleGeneric = generic => {
|
||||
let match = null;
|
||||
if (elems[generic.name]) {
|
||||
match = generic.name;
|
||||
} else {
|
||||
for (const elem_name in elems) {
|
||||
if (!hasOwnPropertyRustdoc(elems, elem_name)) {
|
||||
continue;
|
||||
}
|
||||
if (elem_name === generic) {
|
||||
match = elem_name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (match === null) {
|
||||
if (!elems.has(generic.name)) {
|
||||
return false;
|
||||
}
|
||||
const matchIdx = elems[match].findIndex(tmp_elem =>
|
||||
const matchElems = elems.get(generic.name);
|
||||
const matchIdx = matchElems.findIndex(tmp_elem =>
|
||||
typePassesFilter(generic.typeFilter, tmp_elem));
|
||||
if (matchIdx === -1) {
|
||||
return false;
|
||||
}
|
||||
elems[match].splice(matchIdx, 1);
|
||||
if (elems[match].length === 0) {
|
||||
delete elems[match];
|
||||
matchElems.splice(matchIdx, 1);
|
||||
if (matchElems.length === 0) {
|
||||
elems.delete(generic.name);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
@@ -1424,22 +1429,22 @@ function initSearch(rawSearchIndex) {
|
||||
const aliases = [];
|
||||
const crateAliases = [];
|
||||
if (filterCrates !== null) {
|
||||
if (ALIASES[filterCrates] && ALIASES[filterCrates][lowerQuery]) {
|
||||
const query_aliases = ALIASES[filterCrates][lowerQuery];
|
||||
if (ALIASES.has(filterCrates) && ALIASES.get(filterCrates).has(lowerQuery)) {
|
||||
const query_aliases = ALIASES.get(filterCrates).get(lowerQuery);
|
||||
for (const alias of query_aliases) {
|
||||
aliases.push(createAliasFromItem(searchIndex[alias]));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Object.keys(ALIASES).forEach(crate => {
|
||||
if (ALIASES[crate][lowerQuery]) {
|
||||
for (const [crate, crateAliasesIndex] of ALIASES) {
|
||||
if (crateAliasesIndex.has(lowerQuery)) {
|
||||
const pushTo = crate === currentCrate ? crateAliases : aliases;
|
||||
const query_aliases = ALIASES[crate][lowerQuery];
|
||||
const query_aliases = crateAliasesIndex.get(lowerQuery);
|
||||
for (const alias of query_aliases) {
|
||||
pushTo.push(createAliasFromItem(searchIndex[alias]));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const sortFunc = (aaa, bbb) => {
|
||||
@@ -1496,19 +1501,19 @@ function initSearch(rawSearchIndex) {
|
||||
function addIntoResults(results, fullId, id, index, dist, path_dist, maxEditDistance) {
|
||||
const inBounds = dist <= maxEditDistance || index !== -1;
|
||||
if (dist === 0 || (!parsedQuery.literalSearch && inBounds)) {
|
||||
if (results[fullId] !== undefined) {
|
||||
const result = results[fullId];
|
||||
if (results.has(fullId)) {
|
||||
const result = results.get(fullId);
|
||||
if (result.dontValidate || result.dist <= dist) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
results[fullId] = {
|
||||
results.set(fullId, {
|
||||
id: id,
|
||||
index: index,
|
||||
dontValidate: parsedQuery.literalSearch,
|
||||
dist: dist,
|
||||
path_dist: path_dist,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2345,17 +2350,22 @@ function initSearch(rawSearchIndex) {
|
||||
}
|
||||
|
||||
if (aliases) {
|
||||
ALIASES[crate] = Object.create(null);
|
||||
const currentCrateAliases = new Map();
|
||||
ALIASES.set(crate, currentCrateAliases);
|
||||
for (const alias_name in aliases) {
|
||||
if (!hasOwnPropertyRustdoc(aliases, alias_name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!hasOwnPropertyRustdoc(ALIASES[crate], alias_name)) {
|
||||
ALIASES[crate][alias_name] = [];
|
||||
let currentNameAliases;
|
||||
if (currentCrateAliases.has(alias_name)) {
|
||||
currentNameAliases = currentCrateAliases.get(alias_name);
|
||||
} else {
|
||||
currentNameAliases = [];
|
||||
currentCrateAliases.set(alias_name, currentNameAliases);
|
||||
}
|
||||
for (const local_alias of aliases[alias_name]) {
|
||||
ALIASES[crate][alias_name].push(local_alias + currentIndex);
|
||||
currentNameAliases.push(local_alias + currentIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -284,7 +284,7 @@ fn opts() -> Vec<RustcOptGroup> {
|
||||
stable("test-args", |o| {
|
||||
o.optmulti("", "test-args", "arguments to pass to the test runner", "ARGS")
|
||||
}),
|
||||
unstable("test-run-directory", |o| {
|
||||
stable("test-run-directory", |o| {
|
||||
o.optopt(
|
||||
"",
|
||||
"test-run-directory",
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "suggest-tests"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
glob = "0.3.0"
|
||||
build_helper = { version = "0.1.0", path = "../build_helper" }
|
||||
once_cell = "1.17.1"
|
||||
@@ -0,0 +1,23 @@
|
||||
use std::path::Path;
|
||||
|
||||
use crate::Suggestion;
|
||||
|
||||
type DynamicSuggestion = fn(&Path) -> Vec<Suggestion>;
|
||||
|
||||
pub(crate) const DYNAMIC_SUGGESTIONS: &[DynamicSuggestion] = &[|path: &Path| -> Vec<Suggestion> {
|
||||
if path.starts_with("compiler/") || path.starts_with("library/") {
|
||||
let path = path.components().take(2).collect::<Vec<_>>();
|
||||
|
||||
vec![Suggestion::with_single_path(
|
||||
"test",
|
||||
None,
|
||||
&format!(
|
||||
"{}/{}",
|
||||
path[0].as_os_str().to_str().unwrap(),
|
||||
path[1].as_os_str().to_str().unwrap()
|
||||
),
|
||||
)]
|
||||
} else {
|
||||
Vec::new()
|
||||
}
|
||||
}];
|
||||
@@ -0,0 +1,96 @@
|
||||
use std::{
|
||||
fmt::{self, Display},
|
||||
path::Path,
|
||||
};
|
||||
|
||||
use dynamic_suggestions::DYNAMIC_SUGGESTIONS;
|
||||
use glob::Pattern;
|
||||
use static_suggestions::STATIC_SUGGESTIONS;
|
||||
|
||||
mod dynamic_suggestions;
|
||||
mod static_suggestions;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
macro_rules! sug {
|
||||
($cmd:expr) => {
|
||||
Suggestion::new($cmd, None, &[])
|
||||
};
|
||||
|
||||
($cmd:expr, $paths:expr) => {
|
||||
Suggestion::new($cmd, None, $paths.as_slice())
|
||||
};
|
||||
|
||||
($cmd:expr, $stage:expr, $paths:expr) => {
|
||||
Suggestion::new($cmd, Some($stage), $paths.as_slice())
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) use sug;
|
||||
|
||||
pub fn get_suggestions<T: AsRef<str>>(modified_files: &[T]) -> Vec<Suggestion> {
|
||||
let mut suggestions = Vec::new();
|
||||
|
||||
// static suggestions
|
||||
for sug in STATIC_SUGGESTIONS.iter() {
|
||||
let glob = Pattern::new(&sug.0).expect("Found invalid glob pattern!");
|
||||
|
||||
for file in modified_files {
|
||||
if glob.matches(file.as_ref()) {
|
||||
suggestions.extend_from_slice(&sug.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// dynamic suggestions
|
||||
for sug in DYNAMIC_SUGGESTIONS {
|
||||
for file in modified_files {
|
||||
let sugs = sug(Path::new(file.as_ref()));
|
||||
|
||||
suggestions.extend_from_slice(&sugs);
|
||||
}
|
||||
}
|
||||
|
||||
suggestions.sort();
|
||||
suggestions.dedup();
|
||||
|
||||
suggestions
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialOrd, Ord, PartialEq, Eq, Debug)]
|
||||
pub struct Suggestion {
|
||||
pub cmd: String,
|
||||
pub stage: Option<u32>,
|
||||
pub paths: Vec<String>,
|
||||
}
|
||||
|
||||
impl Suggestion {
|
||||
pub fn new(cmd: &str, stage: Option<u32>, paths: &[&str]) -> Self {
|
||||
Self { cmd: cmd.to_owned(), stage, paths: paths.iter().map(|p| p.to_string()).collect() }
|
||||
}
|
||||
|
||||
pub fn with_single_path(cmd: &str, stage: Option<u32>, path: &str) -> Self {
|
||||
Self::new(cmd, stage, &[path])
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Suggestion {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
write!(f, "{} ", self.cmd)?;
|
||||
|
||||
for path in &self.paths {
|
||||
write!(f, "{} ", path)?;
|
||||
}
|
||||
|
||||
if let Some(stage) = self.stage {
|
||||
write!(f, "{}", stage)?;
|
||||
} else {
|
||||
// write a sentinel value here (in place of a stage) to be consumed
|
||||
// by the shim in bootstrap, it will be read and ignored.
|
||||
write!(f, "N/A")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
use std::process::ExitCode;
|
||||
|
||||
use build_helper::git::get_git_modified_files;
|
||||
use suggest_tests::get_suggestions;
|
||||
|
||||
fn main() -> ExitCode {
|
||||
let modified_files = get_git_modified_files(None, &Vec::new());
|
||||
let modified_files = match modified_files {
|
||||
Ok(Some(files)) => files,
|
||||
Ok(None) => {
|
||||
eprintln!("git error");
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
Err(err) => {
|
||||
eprintln!("Could not get modified files from git: \"{err}\"");
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
};
|
||||
|
||||
let suggestions = get_suggestions(&modified_files);
|
||||
|
||||
for sug in &suggestions {
|
||||
println!("{sug}");
|
||||
}
|
||||
|
||||
ExitCode::SUCCESS
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
use crate::{sug, Suggestion};
|
||||
|
||||
// FIXME: perhaps this could use `std::lazy` when it is stablizied
|
||||
macro_rules! static_suggestions {
|
||||
($( $glob:expr => [ $( $suggestion:expr ),* ] ),*) => {
|
||||
pub(crate) const STATIC_SUGGESTIONS: ::once_cell::unsync::Lazy<Vec<(&'static str, Vec<Suggestion>)>>
|
||||
= ::once_cell::unsync::Lazy::new(|| vec![ $( ($glob, vec![ $($suggestion),* ]) ),*]);
|
||||
}
|
||||
}
|
||||
|
||||
static_suggestions! {
|
||||
"*.md" => [
|
||||
sug!("test", 0, ["linkchecker"])
|
||||
],
|
||||
|
||||
"compiler/*" => [
|
||||
sug!("check"),
|
||||
sug!("test", 1, ["src/test/ui", "src/test/run-make"])
|
||||
],
|
||||
|
||||
"src/librustdoc/*" => [
|
||||
sug!("test", 1, ["rustdoc"])
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
macro_rules! sugg_test {
|
||||
( $( $name:ident: $paths:expr => $suggestions:expr ),* ) => {
|
||||
$(
|
||||
#[test]
|
||||
fn $name() {
|
||||
let suggestions = crate::get_suggestions(&$paths).into_iter().map(|s| s.to_string()).collect::<Vec<_>>();
|
||||
assert_eq!(suggestions, $suggestions);
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
sugg_test! {
|
||||
test_error_code_docs: ["compiler/rustc_error_codes/src/error_codes/E0000.md"] =>
|
||||
["check N/A", "test compiler/rustc_error_codes N/A", "test linkchecker 0", "test src/test/ui src/test/run-make 1"],
|
||||
|
||||
test_rustdoc: ["src/librustdoc/src/lib.rs"] => ["test rustdoc 1"],
|
||||
|
||||
test_rustdoc_and_libstd: ["src/librustdoc/src/lib.rs", "library/std/src/lib.rs"] =>
|
||||
["test library/std N/A", "test rustdoc 1"]
|
||||
}
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
// revisions: correct incorrect
|
||||
// check-pass
|
||||
// [correct]compile-flags:--test --test-run-directory={{src-base}} -Zunstable-options
|
||||
// [incorrect]compile-flags:--test --test-run-directory={{src-base}}/coverage -Zunstable-options
|
||||
// [correct]compile-flags:--test --test-run-directory={{src-base}}
|
||||
// [incorrect]compile-flags:--test --test-run-directory={{src-base}}/coverage
|
||||
// normalize-stdout-test: "tests/rustdoc-ui" -> "$$DIR"
|
||||
// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
|
||||
|
||||
|
||||
@@ -29,6 +29,8 @@ fn test_stable_mir(tcx: TyCtxt<'_>) {
|
||||
let local = stable_mir::local_crate();
|
||||
assert_eq!(&local.name, CRATE_NAME);
|
||||
|
||||
assert_eq!(stable_mir::entry_fn(), None);
|
||||
|
||||
// Find items in the local crate.
|
||||
let items = stable_mir::all_local_items();
|
||||
assert!(get_item(tcx, &items, (DefKind::Fn, "foo_bar")).is_some());
|
||||
|
||||
Reference in New Issue
Block a user