diff options
Diffstat (limited to 'src')
701 files changed, 9220 insertions, 5177 deletions
diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs index 885fcfff030..a881512e988 100644 --- a/src/bootstrap/builder/tests.rs +++ b/src/bootstrap/builder/tests.rs @@ -585,8 +585,11 @@ mod dist { rustfix_coverage: false, pass: None, }; + // Make sure rustfmt binary not being found isn't an error. + config.channel = "beta".to_string(); let build = Build::new(config); let mut builder = Builder::new(&build); + builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Test), &[]); let a = TargetSelection::from_user("A"); diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index fb5127bac54..305ff071dbb 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -347,11 +347,11 @@ fn check_llvm_version(builder: &Builder<'_>, llvm_config: &Path) { let version = output(cmd.arg("--version")); let mut parts = version.split('.').take(2).filter_map(|s| s.parse::<u32>().ok()); if let (Some(major), Some(_minor)) = (parts.next(), parts.next()) { - if major >= 9 { + if major >= 10 { return; } } - panic!("\n\nbad LLVM version: {}, need >=9.0\n\n", version) + panic!("\n\nbad LLVM version: {}, need >=10.0\n\n", version) } fn configure_cmake( diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 86d940cd733..adb0a372c64 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -108,6 +108,19 @@ impl Step for Linkcheck { /// documentation to ensure we don't have a bunch of dead ones. fn run(self, builder: &Builder<'_>) { let host = self.host; + let hosts = &builder.hosts; + let targets = &builder.targets; + + // if we have different hosts and targets, some things may be built for + // the host (e.g. rustc) and others for the target (e.g. std). The + // documentation built for each will contain broken links to + // docs built for the other platform (e.g. rustc linking to cargo) + if (hosts != targets) && !hosts.is_empty() && !targets.is_empty() { + panic!( + "Linkcheck currently does not support builds with different hosts and targets. +You can skip linkcheck with --exclude src/tools/linkchecker" + ); + } builder.info(&format!("Linkcheck ({})", host)); @@ -122,7 +135,8 @@ impl Step for Linkcheck { fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let builder = run.builder; - run.path("src/tools/linkchecker").default_condition(builder.config.docs) + let run = run.path("src/tools/linkchecker"); + run.default_condition(builder.config.docs) } fn make_run(run: RunConfig<'_>) { @@ -452,7 +466,14 @@ impl Step for Miri { cargo.add_rustc_lib_path(builder, compiler); - if !try_run(builder, &mut cargo.into()) { + let mut cargo = Command::from(cargo); + if !try_run(builder, &mut cargo) { + return; + } + + // # Run `cargo test` with `-Zmir-opt-level=4`. + cargo.env("MIRIFLAGS", "-O -Zmir-opt-level=4"); + if !try_run(builder, &mut cargo) { return; } diff --git a/src/ci/docker/host-x86_64/disabled/riscv64gc-linux/Dockerfile b/src/ci/docker/host-x86_64/disabled/riscv64gc-linux/Dockerfile index f3f52ed61d1..4377608700b 100644 --- a/src/ci/docker/host-x86_64/disabled/riscv64gc-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/disabled/riscv64gc-linux/Dockerfile @@ -98,6 +98,6 @@ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh ENV RUST_CONFIGURE_ARGS --qemu-riscv64-rootfs=/tmp/rootfs -ENV SCRIPT python3 ../x.py --stage 2 test --target riscv64gc-unknown-linux-gnu +ENV SCRIPT python3 ../x.py --stage 2 test --host='' --target riscv64gc-unknown-linux-gnu ENV NO_CHANGE_USER=1 diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-9/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-10/Dockerfile index 38eac6588b0..c34198708c4 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-9/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-10/Dockerfile @@ -13,8 +13,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ cmake \ sudo \ gdb \ - llvm-9-tools \ - llvm-9-dev \ + llvm-10-tools \ + llvm-10-dev \ libedit-dev \ libssl-dev \ pkg-config \ @@ -28,7 +28,7 @@ RUN sh /scripts/sccache.sh # using llvm-link-shared due to libffi issues -- see #34486 ENV RUST_CONFIGURE_ARGS \ --build=x86_64-unknown-linux-gnu \ - --llvm-root=/usr/lib/llvm-9 \ + --llvm-root=/usr/lib/llvm-10 \ --enable-llvm-link-shared \ --set rust.thin-lto-import-instr-limit=10 @@ -46,6 +46,7 @@ ENV SCRIPT python2.7 ../x.py --stage 2 test --exclude src/tools/tidy && \ # This is intended to make sure that both `--pass=check` continues to # work. # - python2.7 ../x.py --stage 2 test src/test/ui --pass=check --target=i686-unknown-linux-gnu && \ + python2.7 ../x.py --stage 2 test src/test/ui --pass=check \ + --host='' --target=i686-unknown-linux-gnu && \ # Run tidy at the very end, after all the other tests. python2.7 ../x.py --stage 2 test src/tools/tidy diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index c0a84444a59..a59a90b86bc 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -280,7 +280,7 @@ jobs: - name: mingw-check <<: *job-linux-xl - - name: x86_64-gnu-llvm-9 + - name: x86_64-gnu-llvm-10 <<: *job-linux-xl - name: x86_64-gnu-tools @@ -412,7 +412,7 @@ jobs: - name: x86_64-gnu-distcheck <<: *job-linux-xl - - name: x86_64-gnu-llvm-9 + - name: x86_64-gnu-llvm-10 env: RUST_BACKTRACE: 1 <<: *job-linux-xl diff --git a/src/doc/book b/src/doc/book -Subproject fc2f690fc16592abbead2360cfc0a42f5df7805 +Subproject b54090a99ec7c4b46a5203a9c927fdbc311bb1f diff --git a/src/doc/embedded-book b/src/doc/embedded-book -Subproject f61685755fad7d3b88b4645adfbf461d500563a +Subproject d3f2ace94d51610cf3e3c265705bb8416d37f8e diff --git a/src/doc/reference b/src/doc/reference -Subproject d10a0af8dca25d9d548ca6a369fd66ad06acb3c +Subproject fd97729e2d82f8b08d68a31c9bfdf0c37a7fd54 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example -Subproject eead22c6c030fa4f3a167d1798658c341199e2a +Subproject 29d91f591c90dd18fdca6d23f1a9caf9c139d0d diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide -Subproject 67ebd4b55dba44edfc351621cef6e5e758169c5 +Subproject 0687daac28939c476df51778f5a1d1aff1a3fdd diff --git a/src/doc/rustc/src/targets/built-in.md b/src/doc/rustc/src/targets/built-in.md index c33b506cdae..344048ee4a1 100644 --- a/src/doc/rustc/src/targets/built-in.md +++ b/src/doc/rustc/src/targets/built-in.md @@ -12,4 +12,4 @@ library built by the official Rust distributions. Most targets will need a system linker, and possibly other things. [rustup]: https://github.com/rust-lang/rustup -[rustup-cross]: https://github.com/rust-lang/rustup#cross-compilation +[rustup-cross]: https://rust-lang.github.io/rustup/cross-compilation.html diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index 7d1845dc957..28b81a40265 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -88,26 +88,28 @@ Book][unstable-doc-cfg] and [its tracking issue][issue-doc-cfg]. [unstable-doc-cfg]: ../unstable-book/language-features/doc-cfg.html [issue-doc-cfg]: https://github.com/rust-lang/rust/issues/43781 -### Adding your trait to the "Important Traits" dialog - -Rustdoc keeps a list of a few traits that are believed to be "fundamental" to a given type when -implemented on it. These traits are intended to be the primary interface for their types, and are -often the only thing available to be documented on their types. For this reason, Rustdoc will track -when a given type implements one of these traits and call special attention to it when a function -returns one of these types. This is the "Important Traits" dialog, visible as a circle-i button next -to the function, which, when clicked, shows the dialog. - -In the standard library, the traits that qualify for inclusion are `Iterator`, `io::Read`, and -`io::Write`. However, rather than being implemented as a hard-coded list, these traits have a -special marker attribute on them: `#[doc(spotlight)]`. This means that you could apply this -attribute to your own trait to include it in the "Important Traits" dialog in documentation. - -The `#[doc(spotlight)]` attribute currently requires the `#![feature(doc_spotlight)]` feature gate. -For more information, see [its chapter in the Unstable Book][unstable-spotlight] and [its tracking -issue][issue-spotlight]. - -[unstable-spotlight]: ../unstable-book/language-features/doc-spotlight.html -[issue-spotlight]: https://github.com/rust-lang/rust/issues/45040 +### Adding your trait to the "Notable traits" dialog + +Rustdoc keeps a list of a few traits that are believed to be "fundamental" to +types that implement them. These traits are intended to be the primary interface +for their implementers, and are often most of the API available to be documented +on their types. For this reason, Rustdoc will track when a given type implements +one of these traits and call special attention to it when a function returns one +of these types. This is the "Notable traits" dialog, accessible as a circled `i` +button next to the function, which, when clicked, shows the dialog. + +In the standard library, some of the traits that are part of this list are +`Iterator`, `Future`, `io::Read`, and `io::Write`. However, rather than being +implemented as a hard-coded list, these traits have a special marker attribute +on them: `#[doc(notable_trait)]`. This means that you can apply this attribute +to your own trait to include it in the "Notable traits" dialog in documentation. + +The `#[doc(notable_trait)]` attribute currently requires the `#![feature(doc_notable_trait)]` +feature gate. For more information, see [its chapter in the Unstable Book][unstable-notable_trait] +and [its tracking issue][issue-notable_trait]. + +[unstable-notable_trait]: ../unstable-book/language-features/doc-notable-trait.html +[issue-notable_trait]: https://github.com/rust-lang/rust/issues/45040 ### Exclude certain dependencies from documentation diff --git a/src/doc/unstable-book/src/language-features/doc-notable-trait.md b/src/doc/unstable-book/src/language-features/doc-notable-trait.md new file mode 100644 index 00000000000..dc402ed4253 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/doc-notable-trait.md @@ -0,0 +1,33 @@ +# `doc_notable_trait` + +The tracking issue for this feature is: [#45040] + +The `doc_notable_trait` feature allows the use of the `#[doc(notable_trait)]` +attribute, which will display the trait in a "Notable traits" dialog for +functions returning types that implement the trait. For example, this attribute +is applied to the `Iterator`, `Future`, `io::Read`, and `io::Write` traits in +the standard library. + +You can do this on your own traits like so: + +``` +#![feature(doc_notable_trait)] + +#[doc(notable_trait)] +pub trait MyTrait {} + +pub struct MyStruct; +impl MyTrait for MyStruct {} + +/// The docs for this function will have a button that displays a dialog about +/// `MyStruct` implementing `MyTrait`. +pub fn my_fn() -> MyStruct { MyStruct } +``` + +This feature was originally implemented in PR [#45039]. + +See also its documentation in [the rustdoc book][rustdoc-book-notable_trait]. + +[#45040]: https://github.com/rust-lang/rust/issues/45040 +[#45039]: https://github.com/rust-lang/rust/pull/45039 +[rustdoc-book-notable_trait]: ../../rustdoc/unstable-features.html#adding-your-trait-to-the-notable-traits-dialog diff --git a/src/doc/unstable-book/src/language-features/doc-spotlight.md b/src/doc/unstable-book/src/language-features/doc-spotlight.md deleted file mode 100644 index 75eff163318..00000000000 --- a/src/doc/unstable-book/src/language-features/doc-spotlight.md +++ /dev/null @@ -1,30 +0,0 @@ -# `doc_spotlight` - -The tracking issue for this feature is: [#45040] - -The `doc_spotlight` feature allows the use of the `spotlight` parameter to the `#[doc]` attribute, -to "spotlight" a specific trait on the return values of functions. Adding a `#[doc(spotlight)]` -attribute to a trait definition will make rustdoc print extra information for functions which return -a type that implements that trait. For example, this attribute is applied to the `Iterator`, -`io::Read`, `io::Write`, and `Future` traits in the standard library. - -You can do this on your own traits, like this: - -``` -#![feature(doc_spotlight)] - -#[doc(spotlight)] -pub trait MyTrait {} - -pub struct MyStruct; -impl MyTrait for MyStruct {} - -/// The docs for this function will have an extra line about `MyStruct` implementing `MyTrait`, -/// without having to write that yourself! -pub fn my_fn() -> MyStruct { MyStruct } -``` - -This feature was originally implemented in PR [#45039]. - -[#45040]: https://github.com/rust-lang/rust/issues/45040 -[#45039]: https://github.com/rust-lang/rust/pull/45039 diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index 6e7164457ce..f7e08d10401 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -26,18 +26,16 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { { continue; } - self.cx.tcx.for_each_relevant_impl(trait_def_id, ty, |impl_def_id| { + // NOTE: doesn't use `for_each_relevant_impl` to avoid looking at anything besides blanket impls + let trait_impls = self.cx.tcx.trait_impls_of(trait_def_id); + for &impl_def_id in trait_impls.blanket_impls() { debug!( "get_blanket_impls: Considering impl for trait '{:?}' {:?}", trait_def_id, impl_def_id ); let trait_ref = self.cx.tcx.impl_trait_ref(impl_def_id).unwrap(); - let may_apply = self.cx.tcx.infer_ctxt().enter(|infcx| { - match trait_ref.self_ty().kind() { - ty::Param(_) => {} - _ => return false, - } - + let is_param = matches!(trait_ref.self_ty().kind(), ty::Param(_)); + let may_apply = is_param && self.cx.tcx.infer_ctxt().enter(|infcx| { let substs = infcx.fresh_substs_for_item(DUMMY_SP, item_def_id); let ty = ty.subst(infcx.tcx, substs); let param_env = param_env.subst(infcx.tcx, substs); @@ -90,7 +88,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { may_apply, trait_ref, ty ); if !may_apply { - return; + continue; } self.cx.generated_synthetics.insert((ty, trait_def_id)); @@ -131,7 +129,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { blanket_impl: Some(trait_ref.self_ty().clean(self.cx)), }), }); - }); + } } impls } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 0d32c14c3be..1e9a7d1b4b9 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -9,7 +9,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc_hir::Mutability; use rustc_metadata::creader::LoadedMacro; -use rustc_middle::ty; +use rustc_middle::ty::{self, TyCtxt}; use rustc_mir::const_eval::is_min_const_fn; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Symbol}; @@ -490,23 +490,19 @@ fn build_module( clean::Module { items, is_crate: false } } -crate fn print_inlined_const(cx: &DocContext<'_>, did: DefId) -> String { +crate fn print_inlined_const(tcx: TyCtxt<'_>, did: DefId) -> String { if let Some(did) = did.as_local() { - let hir_id = cx.tcx.hir().local_def_id_to_hir_id(did); - rustc_hir_pretty::id_to_string(&cx.tcx.hir(), hir_id) + let hir_id = tcx.hir().local_def_id_to_hir_id(did); + rustc_hir_pretty::id_to_string(&tcx.hir(), hir_id) } else { - cx.tcx.rendered_const(did) + tcx.rendered_const(did) } } -fn build_const(cx: &mut DocContext<'_>, did: DefId) -> clean::Constant { +fn build_const(cx: &mut DocContext<'_>, def_id: DefId) -> clean::Constant { clean::Constant { - type_: cx.tcx.type_of(did).clean(cx), - expr: print_inlined_const(cx, did), - value: clean::utils::print_evaluated_const(cx, did), - is_literal: did.as_local().map_or(false, |did| { - clean::utils::is_literal_expr(cx, cx.tcx.hir().local_def_id_to_hir_id(did)) - }), + type_: cx.tcx.type_of(def_id).clean(cx), + kind: clean::ConstantKind::Extern { def_id }, } } @@ -628,7 +624,7 @@ crate fn record_extern_trait(cx: &mut DocContext<'_>, did: DefId) { let trait_ = clean::TraitWithExtraInfo { trait_, - is_spotlight: clean::utils::has_doc_flag(cx.tcx.get_attrs(did), sym::spotlight), + is_spotlight: clean::utils::has_doc_flag(cx.tcx.get_attrs(did), sym::notable_trait), }; cx.external_traits.borrow_mut().insert(did, trait_); cx.active_extern_traits.remove(&did); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 84210276d35..217e899001e 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -129,7 +129,6 @@ impl Clean<ExternalCrate> for CrateNum { tcx.hir() .krate() .item - .module .item_ids .iter() .filter_map(|&id| { @@ -174,7 +173,6 @@ impl Clean<ExternalCrate> for CrateNum { tcx.hir() .krate() .item - .module .item_ids .iter() .filter_map(|&id| { @@ -354,7 +352,7 @@ impl Clean<Lifetime> for hir::Lifetime { match def { Some( rl::Region::EarlyBound(_, node_id, _) - | rl::Region::LateBound(_, node_id, _) + | rl::Region::LateBound(_, _, node_id, _) | rl::Region::Free(_, node_id), ) => { if let Some(lt) = cx.lt_substs.get(&node_id).cloned() { @@ -398,9 +396,7 @@ impl Clean<Constant> for hir::ConstArg { .tcx .type_of(cx.tcx.hir().body_owner_def_id(self.value.body).to_def_id()) .clean(cx), - expr: print_const_expr(cx.tcx, self.value.body), - value: None, - is_literal: is_literal_expr(cx, self.value.body.hir_id), + kind: ConstantKind::Anonymous { body: self.value.body }, } } } @@ -415,7 +411,7 @@ impl Clean<Option<Lifetime>> for ty::RegionKind { fn clean(&self, _cx: &mut DocContext<'_>) -> Option<Lifetime> { match *self { ty::ReStatic => Some(Lifetime::statik()), - ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name) }) => { + ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) => { Some(Lifetime(name)) } ty::ReEarlyBound(ref data) => Some(Lifetime(data.name)), @@ -1135,7 +1131,7 @@ impl Clean<Item> for ty::AssocItem { ty::AssocKind::Const => { let ty = tcx.type_of(self.def_id); let default = if self.defaultness.has_value() { - Some(inline::print_inlined_const(cx, self.def_id)) + Some(inline::print_inlined_const(tcx, self.def_id)) } else { None }; @@ -1745,11 +1741,10 @@ impl<'tcx> Clean<Type> for Ty<'tcx> { impl<'tcx> Clean<Constant> for ty::Const<'tcx> { fn clean(&self, cx: &mut DocContext<'_>) -> Constant { + // FIXME: instead of storing the stringified expression, store `self` directly instead. Constant { type_: self.ty.clean(cx), - expr: format!("{}", self), - value: None, - is_literal: false, + kind: ConstantKind::TyConst { expr: self.to_string() }, } } } @@ -1953,9 +1948,7 @@ impl Clean<Vec<Item>> for (&hir::Item<'_>, Option<Symbol>) { } ItemKind::Const(ty, body_id) => ConstantItem(Constant { type_: ty.clean(cx), - expr: print_const_expr(cx.tcx, body_id), - value: print_evaluated_const(cx, def_id), - is_literal: is_literal_expr(cx, body_id.hir_id), + kind: ConstantKind::Local { body: body_id, def_id }, }), ItemKind::OpaqueTy(ref ty) => OpaqueTyItem(OpaqueTy { bounds: ty.bounds.clean(cx), diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 142121b7346..4132e187c72 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -32,8 +32,9 @@ use rustc_target::spec::abi::Abi; use crate::clean::cfg::Cfg; use crate::clean::external_path; -use crate::clean::inline; +use crate::clean::inline::{self, print_inlined_const}; use crate::clean::types::Type::{QPath, ResolvedPath}; +use crate::clean::utils::{is_literal_expr, print_const_expr, print_evaluated_const}; use crate::clean::Clean; use crate::core::DocContext; use crate::formats::cache::Cache; @@ -1988,9 +1989,58 @@ crate struct Static { #[derive(Clone, PartialEq, Eq, Hash, Debug)] crate struct Constant { crate type_: Type, - crate expr: String, - crate value: Option<String>, - crate is_literal: bool, + crate kind: ConstantKind, +} + +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +crate enum ConstantKind { + /// This is the wrapper around `ty::Const` for a non-local constant. Because it doesn't have a + /// `BodyId`, we need to handle it on its own. + /// + /// Note that `ty::Const` includes generic parameters, and may not always be uniquely identified + /// by a DefId. So this field must be different from `Extern`. + TyConst { expr: String }, + /// A constant (expression) that's not an item or associated item. These are usually found + /// nested inside types (e.g., array lengths) or expressions (e.g., repeat counts), and also + /// used to define explicit discriminant values for enum variants. + Anonymous { body: BodyId }, + /// A constant from a different crate. + Extern { def_id: DefId }, + /// `const FOO: u32 = ...;` + Local { def_id: DefId, body: BodyId }, +} + +impl Constant { + crate fn expr(&self, tcx: TyCtxt<'_>) -> String { + match self.kind { + ConstantKind::TyConst { ref expr } => expr.clone(), + ConstantKind::Extern { def_id } => print_inlined_const(tcx, def_id), + ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => { + print_const_expr(tcx, body) + } + } + } + + crate fn value(&self, tcx: TyCtxt<'_>) -> Option<String> { + match self.kind { + ConstantKind::TyConst { .. } | ConstantKind::Anonymous { .. } => None, + ConstantKind::Extern { def_id } | ConstantKind::Local { def_id, .. } => { + print_evaluated_const(tcx, def_id) + } + } + } + + crate fn is_literal(&self, tcx: TyCtxt<'_>) -> bool { + match self.kind { + ConstantKind::TyConst { .. } => false, + ConstantKind::Extern { def_id } => def_id.as_local().map_or(false, |def_id| { + is_literal_expr(tcx, tcx.hir().local_def_id_to_hir_id(def_id)) + }), + ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => { + is_literal_expr(tcx, body.hir_id) + } + } + } } #[derive(Clone, Debug)] diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 582cbf69ed1..60cbe9f376f 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -97,7 +97,7 @@ fn external_generic_args( .iter() .filter_map(|kind| match kind.unpack() { GenericArgKind::Lifetime(lt) => match lt { - ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrAnon(_) }) => { + ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrAnon(_), .. }) => { Some(GenericArg::Lifetime(Lifetime::elided())) } _ => lt.clean(cx).map(GenericArg::Lifetime), @@ -301,7 +301,7 @@ crate fn print_const(cx: &DocContext<'_>, n: &'tcx ty::Const<'_>) -> String { let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def.did); print_const_expr(cx.tcx, cx.tcx.hir().body_owned_by(hir_id)) } else { - inline::print_inlined_const(cx, def.did) + inline::print_inlined_const(cx.tcx, def.did) }; if let Some(promoted) = promoted { s.push_str(&format!("::{:?}", promoted)) @@ -324,15 +324,15 @@ crate fn print_const(cx: &DocContext<'_>, n: &'tcx ty::Const<'_>) -> String { } } -crate fn print_evaluated_const(cx: &DocContext<'_>, def_id: DefId) -> Option<String> { - cx.tcx.const_eval_poly(def_id).ok().and_then(|val| { - let ty = cx.tcx.type_of(def_id); +crate fn print_evaluated_const(tcx: TyCtxt<'_>, def_id: DefId) -> Option<String> { + tcx.const_eval_poly(def_id).ok().and_then(|val| { + let ty = tcx.type_of(def_id); match (val, ty.kind()) { (_, &ty::Ref(..)) => None, (ConstValue::Scalar(_), &ty::Adt(_, _)) => None, (ConstValue::Scalar(_), _) => { - let const_ = ty::Const::from_value(cx.tcx, val, ty); - Some(print_const_with_custom_print_scalar(cx, const_)) + let const_ = ty::Const::from_value(tcx, val, ty); + Some(print_const_with_custom_print_scalar(tcx, const_)) } _ => None, } @@ -349,7 +349,7 @@ fn format_integer_with_underscore_sep(num: &str) -> String { .collect() } -fn print_const_with_custom_print_scalar(cx: &DocContext<'_>, ct: &'tcx ty::Const<'tcx>) -> String { +fn print_const_with_custom_print_scalar(tcx: TyCtxt<'_>, ct: &'tcx ty::Const<'tcx>) -> String { // Use a slightly different format for integer types which always shows the actual value. // For all other types, fallback to the original `pretty_print_const`. match (ct.val, ct.ty.kind()) { @@ -357,8 +357,8 @@ fn print_const_with_custom_print_scalar(cx: &DocContext<'_>, ct: &'tcx ty::Const format!("{}{}", format_integer_with_underscore_sep(&int.to_string()), ui.name_str()) } (ty::ConstKind::Value(ConstValue::Scalar(int)), ty::Int(i)) => { - let ty = cx.tcx.lift(ct.ty).unwrap(); - let size = cx.tcx.layout_of(ty::ParamEnv::empty().and(ty)).unwrap().size; + let ty = tcx.lift(ct.ty).unwrap(); + let size = tcx.layout_of(ty::ParamEnv::empty().and(ty)).unwrap().size; let data = int.assert_bits(size); let sign_extended_data = size.sign_extend(data) as i128; @@ -372,8 +372,8 @@ fn print_const_with_custom_print_scalar(cx: &DocContext<'_>, ct: &'tcx ty::Const } } -crate fn is_literal_expr(cx: &DocContext<'_>, hir_id: hir::HirId) -> bool { - if let hir::Node::Expr(expr) = cx.tcx.hir().get(hir_id) { +crate fn is_literal_expr(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool { + if let hir::Node::Expr(expr) = tcx.hir().get(hir_id) { if let hir::ExprKind::Lit(_) = &expr.kind { return true; } @@ -411,7 +411,7 @@ crate fn resolve_type(cx: &mut DocContext<'_>, path: Path, id: hir::HirId) -> Ty return Generic(kw::SelfUpper); } Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => { - return Generic(Symbol::intern(&format!("{:#}", path.print(&cx.cache)))); + return Generic(Symbol::intern(&format!("{:#}", path.print(&cx.cache, cx.tcx)))); } Res::SelfTy(..) | Res::Def(DefKind::TyParam | DefKind::AssocTy, _) => true, _ => false, diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index d9e97e02a14..3d0ef028902 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -141,7 +141,7 @@ crate fn run(options: Options) -> Result<(), ErrorReported> { hir_collector.visit_testable( "".to_string(), CRATE_HIR_ID, - krate.item.span, + krate.item.inner, |this| { intravisit::walk_crate(this, krate); }, diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index f9a663b38eb..01bceb1d910 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -227,7 +227,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { if let clean::TraitItem(ref t) = *item.kind { self.cache.traits.entry(item.def_id).or_insert_with(|| clean::TraitWithExtraInfo { trait_: t.clone(), - is_spotlight: item.attrs.has_doc_flag(sym::spotlight), + is_spotlight: item.attrs.has_doc_flag(sym::notable_trait), }); } diff --git a/src/librustdoc/formats/renderer.rs b/src/librustdoc/formats/renderer.rs index f0b390add73..ae97cd64fb5 100644 --- a/src/librustdoc/formats/renderer.rs +++ b/src/librustdoc/formats/renderer.rs @@ -13,6 +13,11 @@ crate trait FormatRenderer<'tcx>: Sized { /// Gives a description of the renderer. Used for performance profiling. fn descr() -> &'static str; + /// Whether to call `item` recursivly for modules + /// + /// This is true for html, and false for json. See #80664 + const RUN_ON_MODULE: bool; + /// Sets up any state required for the renderer. When this is called the cache has already been /// populated. fn init( @@ -73,7 +78,7 @@ crate fn run_format<'tcx, T: FormatRenderer<'tcx>>( let unknown = Symbol::intern("<unknown item>"); while let Some((mut cx, item)) = work.pop() { - if item.is_mod() { + if item.is_mod() && T::RUN_ON_MODULE { // modules are special because they add a namespace. We also need to // recurse into the items of the module as well. let name = item.name.as_ref().unwrap().to_string(); diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 60106f3b7ae..a004ee5054e 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -5,10 +5,10 @@ //! assume that HTML output is desired, although it may be possible to redesign //! them in the future to instead emit any format desired. -use std::borrow::Cow; use std::cell::Cell; use std::fmt; +use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_middle::ty::TyCtxt; @@ -111,31 +111,6 @@ impl Buffer { } } -/// Wrapper struct for properly emitting a function or method declaration. -crate struct Function<'a> { - /// The declaration to emit. - crate decl: &'a clean::FnDecl, - /// The length of the function header and name. In other words, the number of characters in the - /// function declaration up to but not including the parentheses. - /// - /// Used to determine line-wrapping. - crate header_len: usize, - /// The number of spaces to indent each successive line with, if line-wrapping is necessary. - crate indent: usize, - /// Whether the function is async or not. - crate asyncness: hir::IsAsync, -} - -/// Wrapper struct for emitting a where-clause from Generics. -crate struct WhereClause<'a> { - /// The Generics from which to emit a where-clause. - crate gens: &'a clean::Generics, - /// The number of spaces to indent each line with. - crate indent: usize, - /// Whether the where-clause needs to add a comma and newline after the last bound. - crate end_newline: bool, -} - fn comma_sep<T: fmt::Display>(items: impl Iterator<Item = T>) -> impl fmt::Display { display_fn(move |f| { for (i, item) in items.enumerate() { @@ -148,27 +123,32 @@ fn comma_sep<T: fmt::Display>(items: impl Iterator<Item = T>) -> impl fmt::Displ }) } -crate fn print_generic_bounds<'a>( +crate fn print_generic_bounds<'a, 'tcx: 'a>( bounds: &'a [clean::GenericBound], cache: &'a Cache, -) -> impl fmt::Display + 'a { + tcx: TyCtxt<'tcx>, +) -> impl fmt::Display + 'a + Captures<'tcx> { display_fn(move |f| { let mut bounds_dup = FxHashSet::default(); for (i, bound) in - bounds.iter().filter(|b| bounds_dup.insert(b.print(cache).to_string())).enumerate() + bounds.iter().filter(|b| bounds_dup.insert(b.print(cache, tcx).to_string())).enumerate() { if i > 0 { f.write_str(" + ")?; } - fmt::Display::fmt(&bound.print(cache), f)?; + fmt::Display::fmt(&bound.print(cache, tcx), f)?; } Ok(()) }) } impl clean::GenericParamDef { - crate fn print<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a { + crate fn print<'a, 'tcx: 'a>( + &'a self, + cache: &'a Cache, + tcx: TyCtxt<'tcx>, + ) -> impl fmt::Display + 'a + Captures<'tcx> { display_fn(move |f| match self.kind { clean::GenericParamDefKind::Lifetime => write!(f, "{}", self.name), clean::GenericParamDefKind::Type { ref bounds, ref default, .. } => { @@ -176,17 +156,17 @@ impl clean::GenericParamDef { if !bounds.is_empty() { if f.alternate() { - write!(f, ": {:#}", print_generic_bounds(bounds, cache))?; + write!(f, ": {:#}", print_generic_bounds(bounds, cache, tcx))?; } else { - write!(f, ": {}", print_generic_bounds(bounds, cache))?; + write!(f, ": {}", print_generic_bounds(bounds, cache, tcx))?; } } if let Some(ref ty) = default { if f.alternate() { - write!(f, " = {:#}", ty.print(cache))?; + write!(f, " = {:#}", ty.print(cache, tcx))?; } else { - write!(f, " = {}", ty.print(cache))?; + write!(f, " = {}", ty.print(cache, tcx))?; } } @@ -194,9 +174,9 @@ impl clean::GenericParamDef { } clean::GenericParamDefKind::Const { ref ty, .. } => { if f.alternate() { - write!(f, "const {}: {:#}", self.name, ty.print(cache)) + write!(f, "const {}: {:#}", self.name, ty.print(cache, tcx)) } else { - write!(f, "const {}: {}", self.name, ty.print(cache)) + write!(f, "const {}: {}", self.name, ty.print(cache, tcx)) } } }) @@ -204,7 +184,11 @@ impl clean::GenericParamDef { } impl clean::Generics { - crate fn print<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a { + crate fn print<'a, 'tcx: 'a>( + &'a self, + cache: &'a Cache, + tcx: TyCtxt<'tcx>, + ) -> impl fmt::Display + 'a + Captures<'tcx> { display_fn(move |f| { let real_params = self.params.iter().filter(|p| !p.is_synthetic_type_param()).collect::<Vec<_>>(); @@ -212,109 +196,115 @@ impl clean::Generics { return Ok(()); } if f.alternate() { - write!(f, "<{:#}>", comma_sep(real_params.iter().map(|g| g.print(cache)))) + write!(f, "<{:#}>", comma_sep(real_params.iter().map(|g| g.print(cache, tcx)))) } else { - write!(f, "<{}>", comma_sep(real_params.iter().map(|g| g.print(cache)))) + write!(f, "<{}>", comma_sep(real_params.iter().map(|g| g.print(cache, tcx)))) } }) } } -impl<'a> WhereClause<'a> { - crate fn print<'b>(&'b self, cache: &'b Cache) -> impl fmt::Display + 'b { - display_fn(move |f| { - let &WhereClause { gens, indent, end_newline } = self; - if gens.where_predicates.is_empty() { - return Ok(()); +/// * The Generics from which to emit a where-clause. +/// * The number of spaces to indent each line with. +/// * Whether the where-clause needs to add a comma and newline after the last bound. +crate fn print_where_clause<'a, 'tcx: 'a>( + gens: &'a clean::Generics, + cache: &'a Cache, + tcx: TyCtxt<'tcx>, + indent: usize, + end_newline: bool, +) -> impl fmt::Display + 'a + Captures<'tcx> { + display_fn(move |f| { + if gens.where_predicates.is_empty() { + return Ok(()); + } + let mut clause = String::new(); + if f.alternate() { + clause.push_str(" where"); + } else { + if end_newline { + clause.push_str(" <span class=\"where fmt-newline\">where"); + } else { + clause.push_str(" <span class=\"where\">where"); } - let mut clause = String::new(); + } + for (i, pred) in gens.where_predicates.iter().enumerate() { if f.alternate() { - clause.push_str(" where"); + clause.push(' '); } else { - if end_newline { - clause.push_str(" <span class=\"where fmt-newline\">where"); - } else { - clause.push_str(" <span class=\"where\">where"); - } + clause.push_str("<br>"); } - for (i, pred) in gens.where_predicates.iter().enumerate() { - if f.alternate() { - clause.push(' '); - } else { - clause.push_str("<br>"); - } - match pred { - clean::WherePredicate::BoundPredicate { ty, bounds } => { - let bounds = bounds; - if f.alternate() { - clause.push_str(&format!( - "{:#}: {:#}", - ty.print(cache), - print_generic_bounds(bounds, cache) - )); - } else { - clause.push_str(&format!( - "{}: {}", - ty.print(cache), - print_generic_bounds(bounds, cache) - )); - } - } - clean::WherePredicate::RegionPredicate { lifetime, bounds } => { + match pred { + clean::WherePredicate::BoundPredicate { ty, bounds } => { + let bounds = bounds; + if f.alternate() { + clause.push_str(&format!( + "{:#}: {:#}", + ty.print(cache, tcx), + print_generic_bounds(bounds, cache, tcx) + )); + } else { clause.push_str(&format!( "{}: {}", - lifetime.print(), - bounds - .iter() - .map(|b| b.print(cache).to_string()) - .collect::<Vec<_>>() - .join(" + ") + ty.print(cache, tcx), + print_generic_bounds(bounds, cache, tcx) )); } - clean::WherePredicate::EqPredicate { lhs, rhs } => { - if f.alternate() { - clause.push_str(&format!( - "{:#} == {:#}", - lhs.print(cache), - rhs.print(cache) - )); - } else { - clause.push_str(&format!( - "{} == {}", - lhs.print(cache), - rhs.print(cache) - )); - } + } + clean::WherePredicate::RegionPredicate { lifetime, bounds } => { + clause.push_str(&format!( + "{}: {}", + lifetime.print(), + bounds + .iter() + .map(|b| b.print(cache, tcx).to_string()) + .collect::<Vec<_>>() + .join(" + ") + )); + } + clean::WherePredicate::EqPredicate { lhs, rhs } => { + if f.alternate() { + clause.push_str(&format!( + "{:#} == {:#}", + lhs.print(cache, tcx), + rhs.print(cache, tcx), + )); + } else { + clause.push_str(&format!( + "{} == {}", + lhs.print(cache, tcx), + rhs.print(cache, tcx), + )); } } + } - if i < gens.where_predicates.len() - 1 || end_newline { - clause.push(','); - } + if i < gens.where_predicates.len() - 1 || end_newline { + clause.push(','); } + } - if end_newline { - // add a space so stripping <br> tags and breaking spaces still renders properly - if f.alternate() { - clause.push(' '); - } else { - clause.push_str(" "); - } + if end_newline { + // add a space so stripping <br> tags and breaking spaces still renders properly + if f.alternate() { + clause.push(' '); + } else { + clause.push_str(" "); } + } - if !f.alternate() { - clause.push_str("</span>"); - let padding = " ".repeat(indent + 4); - clause = clause.replace("<br>", &format!("<br>{}", padding)); - clause.insert_str(0, &" ".repeat(indent.saturating_sub(1))); - if !end_newline { - clause.insert_str(0, "<br>"); - } + if !f.alternate() { + clause.push_str("</span>"); + let padding = " ".repeat(indent + 4); + clause = clause.replace("<br>", &format!("<br>{}", padding)); + clause.insert_str(0, &" ".repeat(indent.saturating_sub(1))); + if !end_newline { + clause.insert_str(0, "<br>"); } - write!(f, "{}", clause) - }) - } + } + write!(f, "{}", clause) + }) } impl clean::Lifetime { @@ -324,46 +314,53 @@ impl clean::Lifetime { } impl clean::Constant { - crate fn print(&self) -> impl fmt::Display + '_ { - display_fn(move |f| { - if f.alternate() { - f.write_str(&self.expr) - } else { - write!(f, "{}", Escape(&self.expr)) - } - }) + crate fn print(&self, tcx: TyCtxt<'_>) -> impl fmt::Display + '_ { + let expr = self.expr(tcx); + display_fn( + move |f| { + if f.alternate() { f.write_str(&expr) } else { write!(f, "{}", Escape(&expr)) } + }, + ) } } impl clean::PolyTrait { - fn print<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a { + fn print<'a, 'tcx: 'a>( + &'a self, + cache: &'a Cache, + tcx: TyCtxt<'tcx>, + ) -> impl fmt::Display + 'a + Captures<'tcx> { display_fn(move |f| { if !self.generic_params.is_empty() { if f.alternate() { write!( f, "for<{:#}> ", - comma_sep(self.generic_params.iter().map(|g| g.print(cache))) + comma_sep(self.generic_params.iter().map(|g| g.print(cache, tcx))) )?; } else { write!( f, "for<{}> ", - comma_sep(self.generic_params.iter().map(|g| g.print(cache))) + comma_sep(self.generic_params.iter().map(|g| g.print(cache, tcx))) )?; } } if f.alternate() { - write!(f, "{:#}", self.trait_.print(cache)) + write!(f, "{:#}", self.trait_.print(cache, tcx)) } else { - write!(f, "{}", self.trait_.print(cache)) + write!(f, "{}", self.trait_.print(cache, tcx)) } }) } } impl clean::GenericBound { - crate fn print<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a { + crate fn print<'a, 'tcx: 'a>( + &'a self, + cache: &'a Cache, + tcx: TyCtxt<'tcx>, + ) -> impl fmt::Display + 'a + Captures<'tcx> { display_fn(move |f| match self { clean::GenericBound::Outlives(lt) => write!(f, "{}", lt.print()), clean::GenericBound::TraitBound(ty, modifier) => { @@ -373,9 +370,9 @@ impl clean::GenericBound { hir::TraitBoundModifier::MaybeConst => "?const", }; if f.alternate() { - write!(f, "{}{:#}", modifier_str, ty.print(cache)) + write!(f, "{}{:#}", modifier_str, ty.print(cache, tcx)) } else { - write!(f, "{}{}", modifier_str, ty.print(cache)) + write!(f, "{}{}", modifier_str, ty.print(cache, tcx)) } } }) @@ -383,7 +380,11 @@ impl clean::GenericBound { } impl clean::GenericArgs { - fn print<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a { + fn print<'a, 'tcx: 'a>( + &'a self, + cache: &'a Cache, + tcx: TyCtxt<'tcx>, + ) -> impl fmt::Display + 'a + Captures<'tcx> { display_fn(move |f| { match self { clean::GenericArgs::AngleBracketed { args, bindings } => { @@ -400,9 +401,9 @@ impl clean::GenericArgs { } comma = true; if f.alternate() { - write!(f, "{:#}", arg.print(cache))?; + write!(f, "{:#}", arg.print(cache, tcx))?; } else { - write!(f, "{}", arg.print(cache))?; + write!(f, "{}", arg.print(cache, tcx))?; } } for binding in bindings { @@ -411,9 +412,9 @@ impl clean::GenericArgs { } comma = true; if f.alternate() { - write!(f, "{:#}", binding.print(cache))?; + write!(f, "{:#}", binding.print(cache, tcx))?; } else { - write!(f, "{}", binding.print(cache))?; + write!(f, "{}", binding.print(cache, tcx))?; } } if f.alternate() { @@ -432,17 +433,17 @@ impl clean::GenericArgs { } comma = true; if f.alternate() { - write!(f, "{:#}", ty.print(cache))?; + write!(f, "{:#}", ty.print(cache, tcx))?; } else { - write!(f, "{}", ty.print(cache))?; + write!(f, "{}", ty.print(cache, tcx))?; } } f.write_str(")")?; if let Some(ref ty) = *output { if f.alternate() { - write!(f, " -> {:#}", ty.print(cache))?; + write!(f, " -> {:#}", ty.print(cache, tcx))?; } else { - write!(f, " -> {}", ty.print(cache))?; + write!(f, " -> {}", ty.print(cache, tcx))?; } } } @@ -453,19 +454,27 @@ impl clean::GenericArgs { } impl clean::PathSegment { - crate fn print<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a { + crate fn print<'a, 'tcx: 'a>( + &'a self, + cache: &'a Cache, + tcx: TyCtxt<'tcx>, + ) -> impl fmt::Display + 'a + Captures<'tcx> { display_fn(move |f| { if f.alternate() { - write!(f, "{}{:#}", self.name, self.args.print(cache)) + write!(f, "{}{:#}", self.name, self.args.print(cache, tcx)) } else { - write!(f, "{}{}", self.name, self.args.print(cache)) + write!(f, "{}{}", self.name, self.args.print(cache, tcx)) } }) } } impl clean::Path { - crate fn print<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a { + crate fn print<'a, 'tcx: 'a>( + &'a self, + cache: &'a Cache, + tcx: TyCtxt<'tcx>, + ) -> impl fmt::Display + 'a + Captures<'tcx> { display_fn(move |f| { if self.global { f.write_str("::")? @@ -476,9 +485,9 @@ impl clean::Path { f.write_str("::")? } if f.alternate() { - write!(f, "{:#}", seg.print(cache))?; + write!(f, "{:#}", seg.print(cache, tcx))?; } else { - write!(f, "{}", seg.print(cache))?; + write!(f, "{}", seg.print(cache, tcx))?; } } Ok(()) @@ -528,13 +537,14 @@ crate fn href(did: DefId, cache: &Cache) -> Option<(String, ItemType, Vec<String /// Used when rendering a `ResolvedPath` structure. This invokes the `path` /// rendering function with the necessary arguments for linking to a local path. -fn resolved_path( +fn resolved_path<'a, 'tcx: 'a>( w: &mut fmt::Formatter<'_>, did: DefId, path: &clean::Path, print_all: bool, use_absolute: bool, cache: &Cache, + tcx: TyCtxt<'tcx>, ) -> fmt::Result { let last = path.segments.last().unwrap(); @@ -544,7 +554,7 @@ fn resolved_path( } } if w.alternate() { - write!(w, "{}{:#}", &last.name, last.args.print(cache))?; + write!(w, "{}{:#}", &last.name, last.args.print(cache, tcx))?; } else { let path = if use_absolute { if let Some((_, _, fqp)) = href(did, cache) { @@ -559,7 +569,7 @@ fn resolved_path( } else { anchor(did, &*last.name.as_str(), cache).to_string() }; - write!(w, "{}{}", path, last.args.print(cache))?; + write!(w, "{}{}", path, last.args.print(cache, tcx))?; } Ok(()) } @@ -615,15 +625,16 @@ fn primitive_link( } /// Helper to render type parameters -fn tybounds<'a>( +fn tybounds<'a, 'tcx: 'a>( param_names: &'a Option<Vec<clean::GenericBound>>, cache: &'a Cache, -) -> impl fmt::Display + 'a { + tcx: TyCtxt<'tcx>, +) -> impl fmt::Display + 'a + Captures<'tcx> { display_fn(move |f| match *param_names { Some(ref params) => { for param in params { write!(f, " + ")?; - fmt::Display::fmt(¶m.print(cache), f)?; + fmt::Display::fmt(¶m.print(cache, tcx), f)?; } Ok(()) } @@ -654,6 +665,7 @@ fn fmt_type( f: &mut fmt::Formatter<'_>, use_absolute: bool, cache: &Cache, + tcx: TyCtxt<'_>, ) -> fmt::Result { debug!("fmt_type(t = {:?})", t); @@ -664,8 +676,8 @@ fn fmt_type( f.write_str("dyn ")?; } // Paths like `T::Output` and `Self::Output` should be rendered with all segments. - resolved_path(f, did, path, is_generic, use_absolute, cache)?; - fmt::Display::fmt(&tybounds(param_names, cache), f) + resolved_path(f, did, path, is_generic, use_absolute, cache, tcx)?; + fmt::Display::fmt(&tybounds(param_names, cache, tcx), f) } clean::Infer => write!(f, "_"), clean::Primitive(prim) => primitive_link(f, prim, prim.as_str(), cache), @@ -674,21 +686,21 @@ fn fmt_type( write!( f, "{:#}{}{:#}fn{:#}", - decl.print_hrtb_with_space(cache), + decl.print_hrtb_with_space(cache, tcx), decl.unsafety.print_with_space(), print_abi_with_space(decl.abi), - decl.decl.print(cache) + decl.decl.print(cache, tcx), ) } else { write!( f, "{}{}{}", - decl.print_hrtb_with_space(cache), + decl.print_hrtb_with_space(cache, tcx), decl.unsafety.print_with_space(), print_abi_with_space(decl.abi) )?; primitive_link(f, PrimitiveType::Fn, "fn", cache)?; - write!(f, "{}", decl.decl.print(cache)) + write!(f, "{}", decl.decl.print(cache, tcx)) } } clean::Tuple(ref typs) => { @@ -697,7 +709,7 @@ fn fmt_type( &[ref one] => { primitive_link(f, PrimitiveType::Tuple, "(", cache)?; // Carry `f.alternate()` into this display w/o branching manually. - fmt::Display::fmt(&one.print(cache), f)?; + fmt::Display::fmt(&one.print(cache, tcx), f)?; primitive_link(f, PrimitiveType::Tuple, ",)", cache) } many => { @@ -706,7 +718,7 @@ fn fmt_type( if i != 0 { write!(f, ", ")?; } - fmt::Display::fmt(&item.print(cache), f)?; + fmt::Display::fmt(&item.print(cache, tcx), f)?; } primitive_link(f, PrimitiveType::Tuple, ")", cache) } @@ -714,12 +726,12 @@ fn fmt_type( } clean::Slice(ref t) => { primitive_link(f, PrimitiveType::Slice, "[", cache)?; - fmt::Display::fmt(&t.print(cache), f)?; + fmt::Display::fmt(&t.print(cache, tcx), f)?; primitive_link(f, PrimitiveType::Slice, "]", cache) } clean::Array(ref t, ref n) => { primitive_link(f, PrimitiveType::Array, "[", cache)?; - fmt::Display::fmt(&t.print(cache), f)?; + fmt::Display::fmt(&t.print(cache, tcx), f)?; if f.alternate() { primitive_link(f, PrimitiveType::Array, &format!("; {}]", n), cache) } else { @@ -738,14 +750,14 @@ fn fmt_type( primitive_link( f, clean::PrimitiveType::RawPointer, - &format!("*{} {:#}", m, t.print(cache)), + &format!("*{} {:#}", m, t.print(cache, tcx)), cache, ) } else { primitive_link( f, clean::PrimitiveType::RawPointer, - &format!("*{} {}", m, t.print(cache)), + &format!("*{} {}", m, t.print(cache, tcx)), cache, ) } @@ -757,7 +769,7 @@ fn fmt_type( &format!("*{} ", m), cache, )?; - fmt::Display::fmt(&t.print(cache), f) + fmt::Display::fmt(&t.print(cache, tcx), f) } } } @@ -777,14 +789,14 @@ fn fmt_type( primitive_link( f, PrimitiveType::Slice, - &format!("{}{}{}[{:#}]", amp, lt, m, bt.print(cache)), + &format!("{}{}{}[{:#}]", amp, lt, m, bt.print(cache, tcx)), cache, ) } else { primitive_link( f, PrimitiveType::Slice, - &format!("{}{}{}[{}]", amp, lt, m, bt.print(cache)), + &format!("{}{}{}[{}]", amp, lt, m, bt.print(cache, tcx)), cache, ) } @@ -797,9 +809,9 @@ fn fmt_type( cache, )?; if f.alternate() { - write!(f, "{:#}", bt.print(cache))?; + write!(f, "{:#}", bt.print(cache, tcx))?; } else { - write!(f, "{}", bt.print(cache))?; + write!(f, "{}", bt.print(cache, tcx))?; } primitive_link(f, PrimitiveType::Slice, "]", cache) } @@ -807,7 +819,7 @@ fn fmt_type( } clean::ResolvedPath { param_names: Some(ref v), .. } if !v.is_empty() => { write!(f, "{}{}{}(", amp, lt, m)?; - fmt_type(&ty, f, use_absolute, cache)?; + fmt_type(&ty, f, use_absolute, cache, tcx)?; write!(f, ")") } clean::Generic(..) => { @@ -817,19 +829,19 @@ fn fmt_type( &format!("{}{}{}", amp, lt, m), cache, )?; - fmt_type(&ty, f, use_absolute, cache) + fmt_type(&ty, f, use_absolute, cache, tcx) } _ => { write!(f, "{}{}{}", amp, lt, m)?; - fmt_type(&ty, f, use_absolute, cache) + fmt_type(&ty, f, use_absolute, cache, tcx) } } } clean::ImplTrait(ref bounds) => { if f.alternate() { - write!(f, "impl {:#}", print_generic_bounds(bounds, cache)) + write!(f, "impl {:#}", print_generic_bounds(bounds, cache, tcx)) } else { - write!(f, "impl {}", print_generic_bounds(bounds, cache)) + write!(f, "impl {}", print_generic_bounds(bounds, cache, tcx)) } } clean::QPath { ref name, ref self_type, ref trait_ } => { @@ -841,15 +853,25 @@ fn fmt_type( }; if f.alternate() { if should_show_cast { - write!(f, "<{:#} as {:#}>::", self_type.print(cache), trait_.print(cache))? + write!( + f, + "<{:#} as {:#}>::", + self_type.print(cache, tcx), + trait_.print(cache, tcx) + )? } else { - write!(f, "{:#}::", self_type.print(cache))? + write!(f, "{:#}::", self_type.print(cache, tcx))? } } else { if should_show_cast { - write!(f, "<{} as {}>::", self_type.print(cache), trait_.print(cache))? + write!( + f, + "<{} as {}>::", + self_type.print(cache, tcx), + trait_.print(cache, tcx) + )? } else { - write!(f, "{}::", self_type.print(cache))? + write!(f, "{}::", self_type.print(cache, tcx))? } }; match *trait_ { @@ -890,52 +912,64 @@ fn fmt_type( } impl clean::Type { - crate fn print<'b, 'a: 'b>(&'a self, cache: &'b Cache) -> impl fmt::Display + 'b { - display_fn(move |f| fmt_type(self, f, false, cache)) + crate fn print<'b, 'a: 'b, 'tcx: 'a>( + &'a self, + cache: &'b Cache, + tcx: TyCtxt<'tcx>, + ) -> impl fmt::Display + 'b + Captures<'tcx> { + display_fn(move |f| fmt_type(self, f, false, cache, tcx)) } } impl clean::Impl { - crate fn print<'a>(&'a self, cache: &'a Cache, use_absolute: bool) -> impl fmt::Display + 'a { + crate fn print<'a, 'tcx: 'a>( + &'a self, + cache: &'a Cache, + use_absolute: bool, + tcx: TyCtxt<'tcx>, + ) -> impl fmt::Display + 'a + Captures<'tcx> { display_fn(move |f| { if f.alternate() { - write!(f, "impl{:#} ", self.generics.print(cache))?; + write!(f, "impl{:#} ", self.generics.print(cache, tcx))?; } else { - write!(f, "impl{} ", self.generics.print(cache))?; + write!(f, "impl{} ", self.generics.print(cache, tcx))?; } if let Some(ref ty) = self.trait_ { if self.negative_polarity { write!(f, "!")?; } - fmt::Display::fmt(&ty.print(cache), f)?; + fmt::Display::fmt(&ty.print(cache, tcx), f)?; write!(f, " for ")?; } if let Some(ref ty) = self.blanket_impl { - fmt_type(ty, f, use_absolute, cache)?; + fmt_type(ty, f, use_absolute, cache, tcx)?; } else { - fmt_type(&self.for_, f, use_absolute, cache)?; + fmt_type(&self.for_, f, use_absolute, cache, tcx)?; } - let where_clause = WhereClause { gens: &self.generics, indent: 0, end_newline: true }; - fmt::Display::fmt(&where_clause.print(cache), f)?; + fmt::Display::fmt(&print_where_clause(&self.generics, cache, tcx, 0, true), f)?; Ok(()) }) } } impl clean::Arguments { - crate fn print<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a { + crate fn print<'a, 'tcx: 'a>( + &'a self, + cache: &'a Cache, + tcx: TyCtxt<'tcx>, + ) -> impl fmt::Display + 'a + Captures<'tcx> { display_fn(move |f| { for (i, input) in self.values.iter().enumerate() { if !input.name.is_empty() { write!(f, "{}: ", input.name)?; } if f.alternate() { - write!(f, "{:#}", input.type_.print(cache))?; + write!(f, "{:#}", input.type_.print(cache, tcx))?; } else { - write!(f, "{}", input.type_.print(cache))?; + write!(f, "{}", input.type_.print(cache, tcx))?; } if i + 1 < self.values.len() { write!(f, ", ")?; @@ -947,21 +981,33 @@ impl clean::Arguments { } impl clean::FnRetTy { - crate fn print<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a { + crate fn print<'a, 'tcx: 'a>( + &'a self, + cache: &'a Cache, + tcx: TyCtxt<'tcx>, + ) -> impl fmt::Display + 'a + Captures<'tcx> { display_fn(move |f| match self { clean::Return(clean::Tuple(tys)) if tys.is_empty() => Ok(()), - clean::Return(ty) if f.alternate() => write!(f, " -> {:#}", ty.print(cache)), - clean::Return(ty) => write!(f, " -> {}", ty.print(cache)), + clean::Return(ty) if f.alternate() => write!(f, " -> {:#}", ty.print(cache, tcx)), + clean::Return(ty) => write!(f, " -> {}", ty.print(cache, tcx)), clean::DefaultReturn => Ok(()), }) } } impl clean::BareFunctionDecl { - fn print_hrtb_with_space<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a { + fn print_hrtb_with_space<'a, 'tcx: 'a>( + &'a self, + cache: &'a Cache, + tcx: TyCtxt<'tcx>, + ) -> impl fmt::Display + 'a + Captures<'tcx> { display_fn(move |f| { if !self.generic_params.is_empty() { - write!(f, "for<{}> ", comma_sep(self.generic_params.iter().map(|g| g.print(cache)))) + write!( + f, + "for<{}> ", + comma_sep(self.generic_params.iter().map(|g| g.print(cache, tcx))) + ) } else { Ok(()) } @@ -970,147 +1016,176 @@ impl clean::BareFunctionDecl { } impl clean::FnDecl { - crate fn print<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a { + crate fn print<'b, 'a: 'b, 'tcx: 'a>( + &'a self, + cache: &'b Cache, + tcx: TyCtxt<'tcx>, + ) -> impl fmt::Display + 'b + Captures<'tcx> { display_fn(move |f| { let ellipsis = if self.c_variadic { ", ..." } else { "" }; if f.alternate() { write!( f, "({args:#}{ellipsis}){arrow:#}", - args = self.inputs.print(cache), + args = self.inputs.print(cache, tcx), ellipsis = ellipsis, - arrow = self.output.print(cache) + arrow = self.output.print(cache, tcx) ) } else { write!( f, "({args}{ellipsis}){arrow}", - args = self.inputs.print(cache), + args = self.inputs.print(cache, tcx), ellipsis = ellipsis, - arrow = self.output.print(cache) + arrow = self.output.print(cache, tcx) ) } }) } -} -impl Function<'_> { - crate fn print<'b, 'a: 'b>(&'a self, cache: &'b Cache) -> impl fmt::Display + 'b { - display_fn(move |f| { - let &Function { decl, header_len, indent, asyncness } = self; - let amp = if f.alternate() { "&" } else { "&" }; - let mut args = String::new(); - let mut args_plain = String::new(); - for (i, input) in decl.inputs.values.iter().enumerate() { - if i == 0 { - args.push_str("<br>"); - } + /// * `header_len`: The length of the function header and name. In other words, the number of + /// characters in the function declaration up to but not including the parentheses. + /// <br>Used to determine line-wrapping. + /// * `indent`: The number of spaces to indent each successive line with, if line-wrapping is + /// necessary. + /// * `asyncness`: Whether the function is async or not. + crate fn full_print<'b, 'a: 'b, 'tcx: 'a>( + &'a self, + cache: &'b Cache, + tcx: TyCtxt<'tcx>, + header_len: usize, + indent: usize, + asyncness: hir::IsAsync, + ) -> impl fmt::Display + 'b + Captures<'tcx> { + display_fn(move |f| self.inner_full_print(cache, tcx, header_len, indent, asyncness, f)) + } - if let Some(selfty) = input.to_self() { - match selfty { - clean::SelfValue => { - args.push_str("self"); - args_plain.push_str("self"); - } - clean::SelfBorrowed(Some(ref lt), mtbl) => { - args.push_str(&format!( - "{}{} {}self", - amp, - lt.print(), - mtbl.print_with_space() - )); - args_plain.push_str(&format!( - "&{} {}self", - lt.print(), - mtbl.print_with_space() - )); - } - clean::SelfBorrowed(None, mtbl) => { - args.push_str(&format!("{}{}self", amp, mtbl.print_with_space())); - args_plain.push_str(&format!("&{}self", mtbl.print_with_space())); - } - clean::SelfExplicit(ref typ) => { - if f.alternate() { - args.push_str(&format!("self: {:#}", typ.print(cache))); - } else { - args.push_str(&format!("self: {}", typ.print(cache))); - } - args_plain.push_str(&format!("self: {:#}", typ.print(cache))); - } + fn inner_full_print( + &self, + cache: &Cache, + tcx: TyCtxt<'_>, + header_len: usize, + indent: usize, + asyncness: hir::IsAsync, + f: &mut fmt::Formatter<'_>, + ) -> fmt::Result { + let amp = if f.alternate() { "&" } else { "&" }; + let mut args = String::new(); + let mut args_plain = String::new(); + for (i, input) in self.inputs.values.iter().enumerate() { + if i == 0 { + args.push_str("<br>"); + } + + if let Some(selfty) = input.to_self() { + match selfty { + clean::SelfValue => { + args.push_str("self"); + args_plain.push_str("self"); } - } else { - if i > 0 { - args.push_str(" <br>"); - args_plain.push(' '); + clean::SelfBorrowed(Some(ref lt), mtbl) => { + args.push_str(&format!( + "{}{} {}self", + amp, + lt.print(), + mtbl.print_with_space() + )); + args_plain.push_str(&format!( + "&{} {}self", + lt.print(), + mtbl.print_with_space() + )); } - if !input.name.is_empty() { - args.push_str(&format!("{}: ", input.name)); - args_plain.push_str(&format!("{}: ", input.name)); + clean::SelfBorrowed(None, mtbl) => { + args.push_str(&format!("{}{}self", amp, mtbl.print_with_space())); + args_plain.push_str(&format!("&{}self", mtbl.print_with_space())); } - - if f.alternate() { - args.push_str(&format!("{:#}", input.type_.print(cache))); - } else { - args.push_str(&input.type_.print(cache).to_string()); + clean::SelfExplicit(ref typ) => { + if f.alternate() { + args.push_str(&format!("self: {:#}", typ.print(cache, tcx))); + } else { + args.push_str(&format!("self: {}", typ.print(cache, tcx))); + } + args_plain.push_str(&format!("self: {:#}", typ.print(cache, tcx))); } - args_plain.push_str(&format!("{:#}", input.type_.print(cache))); } - if i + 1 < decl.inputs.values.len() { - args.push(','); - args_plain.push(','); + } else { + if i > 0 { + args.push_str(" <br>"); + args_plain.push(' '); + } + if !input.name.is_empty() { + args.push_str(&format!("{}: ", input.name)); + args_plain.push_str(&format!("{}: ", input.name)); } - } - - let mut args_plain = format!("({})", args_plain); - if decl.c_variadic { - args.push_str(",<br> ..."); - args_plain.push_str(", ..."); + if f.alternate() { + args.push_str(&format!("{:#}", input.type_.print(cache, tcx))); + } else { + args.push_str(&input.type_.print(cache, tcx).to_string()); + } + args_plain.push_str(&format!("{:#}", input.type_.print(cache, tcx))); + } + if i + 1 < self.inputs.values.len() { + args.push(','); + args_plain.push(','); } + } - let output = if let hir::IsAsync::Async = asyncness { - Cow::Owned(decl.sugared_async_return_type()) - } else { - Cow::Borrowed(&decl.output) - }; + let mut args_plain = format!("({})", args_plain); - let arrow_plain = format!("{:#}", &output.print(cache)); - let arrow = if f.alternate() { - format!("{:#}", &output.print(cache)) - } else { - output.print(cache).to_string() - }; + if self.c_variadic { + args.push_str(",<br> ..."); + args_plain.push_str(", ..."); + } - let declaration_len = header_len + args_plain.len() + arrow_plain.len(); - let output = if declaration_len > 80 { - let full_pad = format!("<br>{}", " ".repeat(indent + 4)); - let close_pad = format!("<br>{}", " ".repeat(indent)); - format!( - "({args}{close}){arrow}", - args = args.replace("<br>", &full_pad), - close = close_pad, - arrow = arrow - ) + let arrow_plain; + let arrow = if let hir::IsAsync::Async = asyncness { + let output = self.sugared_async_return_type(); + arrow_plain = format!("{:#}", output.print(cache, tcx)); + if f.alternate() { + arrow_plain.clone() } else { - format!("({args}){arrow}", args = args.replace("<br>", ""), arrow = arrow) - }; - + format!("{}", output.print(cache, tcx)) + } + } else { + arrow_plain = format!("{:#}", self.output.print(cache, tcx)); if f.alternate() { - write!(f, "{}", output.replace("<br>", "\n")) + arrow_plain.clone() } else { - write!(f, "{}", output) + format!("{}", self.output.print(cache, tcx)) } - }) + }; + + let declaration_len = header_len + args_plain.len() + arrow_plain.len(); + let output = if declaration_len > 80 { + let full_pad = format!("<br>{}", " ".repeat(indent + 4)); + let close_pad = format!("<br>{}", " ".repeat(indent)); + format!( + "({args}{close}){arrow}", + args = args.replace("<br>", &full_pad), + close = close_pad, + arrow = arrow + ) + } else { + format!("({args}){arrow}", args = args.replace("<br>", ""), arrow = arrow) + }; + + if f.alternate() { + write!(f, "{}", output.replace("<br>", "\n")) + } else { + write!(f, "{}", output) + } } } impl clean::Visibility { - crate fn print_with_space<'tcx>( + crate fn print_with_space<'a, 'tcx: 'a>( self, tcx: TyCtxt<'tcx>, item_did: DefId, - cache: &Cache, - ) -> impl fmt::Display + 'tcx { + cache: &'a Cache, + ) -> impl fmt::Display + 'a + Captures<'tcx> { use rustc_span::symbol::kw; let to_print = match self { @@ -1202,20 +1277,24 @@ impl PrintWithSpace for hir::Mutability { } impl clean::Import { - crate fn print<'b, 'a: 'b>(&'a self, cache: &'b Cache) -> impl fmt::Display + 'b { + crate fn print<'b, 'a: 'b, 'tcx: 'a>( + &'a self, + cache: &'b Cache, + tcx: TyCtxt<'tcx>, + ) -> impl fmt::Display + 'b + Captures<'tcx> { display_fn(move |f| match self.kind { clean::ImportKind::Simple(name) => { if name == self.source.path.last() { - write!(f, "use {};", self.source.print(cache)) + write!(f, "use {};", self.source.print(cache, tcx)) } else { - write!(f, "use {} as {};", self.source.print(cache), name) + write!(f, "use {} as {};", self.source.print(cache, tcx), name) } } clean::ImportKind::Glob => { if self.source.path.segments.is_empty() { write!(f, "use *;") } else { - write!(f, "use {}::*;", self.source.print(cache)) + write!(f, "use {}::*;", self.source.print(cache, tcx)) } } }) @@ -1223,9 +1302,13 @@ impl clean::Import { } impl clean::ImportSource { - crate fn print<'b, 'a: 'b>(&'a self, cache: &'b Cache) -> impl fmt::Display + 'b { + crate fn print<'b, 'a: 'b, 'tcx: 'a>( + &'a self, + cache: &'b Cache, + tcx: TyCtxt<'tcx>, + ) -> impl fmt::Display + 'b + Captures<'tcx> { display_fn(move |f| match self.did { - Some(did) => resolved_path(f, did, &self.path, true, false, cache), + Some(did) => resolved_path(f, did, &self.path, true, false, cache, tcx), _ => { for seg in &self.path.segments[..self.path.segments.len() - 1] { write!(f, "{}::", seg.name)?; @@ -1243,23 +1326,27 @@ impl clean::ImportSource { } impl clean::TypeBinding { - crate fn print<'b, 'a: 'b>(&'a self, cache: &'b Cache) -> impl fmt::Display + 'b { + crate fn print<'b, 'a: 'b, 'tcx: 'a>( + &'a self, + cache: &'b Cache, + tcx: TyCtxt<'tcx>, + ) -> impl fmt::Display + 'b + Captures<'tcx> { display_fn(move |f| { f.write_str(&*self.name.as_str())?; match self.kind { clean::TypeBindingKind::Equality { ref ty } => { if f.alternate() { - write!(f, " = {:#}", ty.print(cache))?; + write!(f, " = {:#}", ty.print(cache, tcx))?; } else { - write!(f, " = {}", ty.print(cache))?; + write!(f, " = {}", ty.print(cache, tcx))?; } } clean::TypeBindingKind::Constraint { ref bounds } => { if !bounds.is_empty() { if f.alternate() { - write!(f, ": {:#}", print_generic_bounds(bounds, cache))?; + write!(f, ": {:#}", print_generic_bounds(bounds, cache, tcx))?; } else { - write!(f, ": {}", print_generic_bounds(bounds, cache))?; + write!(f, ": {}", print_generic_bounds(bounds, cache, tcx))?; } } } @@ -1284,11 +1371,15 @@ crate fn print_default_space<'a>(v: bool) -> &'a str { } impl clean::GenericArg { - crate fn print<'b, 'a: 'b>(&'a self, cache: &'b Cache) -> impl fmt::Display + 'b { + crate fn print<'b, 'a: 'b, 'tcx: 'a>( + &'a self, + cache: &'b Cache, + tcx: TyCtxt<'tcx>, + ) -> impl fmt::Display + 'b + Captures<'tcx> { display_fn(move |f| match self { clean::GenericArg::Lifetime(lt) => fmt::Display::fmt(<.print(), f), - clean::GenericArg::Type(ty) => fmt::Display::fmt(&ty.print(cache), f), - clean::GenericArg::Const(ct) => fmt::Display::fmt(&ct.print(), f), + clean::GenericArg::Type(ty) => fmt::Display::fmt(&ty.print(cache, tcx), f), + clean::GenericArg::Const(ct) => fmt::Display::fmt(&ct.print(tcx), f), }) } } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index b39f9f87892..cdccb1c8581 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -1162,6 +1162,7 @@ crate fn plain_text_summary(md: &str) -> String { s } +#[derive(Debug)] crate struct MarkdownLink { pub kind: LinkType, pub link: String, @@ -1354,6 +1355,7 @@ fn init_id_map() -> FxHashMap<String, usize> { map.insert("default-settings".to_owned(), 1); map.insert("rustdoc-vars".to_owned(), 1); map.insert("sidebar-vars".to_owned(), 1); + map.insert("copy-path".to_owned(), 1); // This is the list of IDs used by rustdoc sections. map.insert("fields".to_owned(), 1); map.insert("variants".to_owned(), 1); diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 17cedeb5a51..07c850a20a9 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -279,6 +279,8 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { "html" } + const RUN_ON_MODULE: bool = true; + fn init( mut krate: clean::Crate, options: RenderOptions, diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 05d30187aa8..07bd26a4c5e 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -67,8 +67,8 @@ use crate::formats::item_type::ItemType; use crate::formats::{AssocItemRender, FormatRenderer, Impl, RenderMode}; use crate::html::escape::Escape; use crate::html::format::{ - href, print_abi_with_space, print_default_space, print_generic_bounds, Buffer, Function, - PrintWithSpace, WhereClause, + href, print_abi_with_space, print_default_space, print_generic_bounds, print_where_clause, + Buffer, PrintWithSpace, }; use crate::html::layout; use crate::html::markdown::{self, ErrorCodes, Markdown, MarkdownHtml, MarkdownSummaryLine}; @@ -855,10 +855,12 @@ fn render_impls( traits: &[&&Impl], containing_item: &clean::Item, ) { + let cache = cx.cache(); + let tcx = cx.tcx(); let mut impls = traits .iter() .map(|i| { - let did = i.trait_did_full(cx.cache()).unwrap(); + let did = i.trait_did_full(cache).unwrap(); let assoc_link = AssocItemLink::GotoSource(did, &i.inner_impl().provided_trait_methods); let mut buffer = if w.is_for_html() { Buffer::html() } else { Buffer::new() }; render_impl( @@ -868,8 +870,8 @@ fn render_impls( containing_item, assoc_link, RenderMode::Normal, - containing_item.stable_since(cx.tcx()).as_deref(), - containing_item.const_stable_since(cx.tcx()).as_deref(), + containing_item.stable_since(tcx).as_deref(), + containing_item.const_stable_since(tcx).as_deref(), true, None, false, @@ -911,14 +913,16 @@ fn assoc_const( extra: &str, cx: &Context<'_>, ) { + let cache = cx.cache(); + let tcx = cx.tcx(); write!( w, "{}{}const <a href=\"{}\" class=\"constant\"><b>{}</b></a>: {}", extra, - it.visibility.print_with_space(cx.tcx(), it.def_id, cx.cache()), - naive_assoc_href(it, link, cx.cache()), + it.visibility.print_with_space(tcx, it.def_id, cache), + naive_assoc_href(it, link, cache), it.name.as_ref().unwrap(), - ty.print(cx.cache()) + ty.print(cache, tcx) ); } @@ -930,6 +934,7 @@ fn assoc_type( link: AssocItemLink<'_>, extra: &str, cache: &Cache, + tcx: TyCtxt<'_>, ) { write!( w, @@ -939,10 +944,10 @@ fn assoc_type( it.name.as_ref().unwrap() ); if !bounds.is_empty() { - write!(w, ": {}", print_generic_bounds(bounds, cache)) + write!(w, ": {}", print_generic_bounds(bounds, cache, tcx)) } if let Some(default) = default { - write!(w, " = {}", default.print(cache)) + write!(w, " = {}", default.print(cache, tcx)) } } @@ -992,6 +997,8 @@ fn render_assoc_item( parent: ItemType, cx: &Context<'_>, ) { + let cache = cx.cache(); + let tcx = cx.tcx(); let name = meth.name.as_ref().unwrap(); let anchor = format!("#{}.{}", meth.type_(), name); let href = match link { @@ -1006,18 +1013,17 @@ fn render_assoc_item( ItemType::TyMethod }; - href(did, cx.cache()).map(|p| format!("{}#{}.{}", p.0, ty, name)).unwrap_or(anchor) + href(did, cache).map(|p| format!("{}#{}.{}", p.0, ty, name)).unwrap_or(anchor) } }; - let tcx = cx.tcx(); - let vis = meth.visibility.print_with_space(tcx, meth.def_id, cx.cache()).to_string(); + let vis = meth.visibility.print_with_space(tcx, meth.def_id, cache).to_string(); let constness = header.constness.print_with_space(); let asyncness = header.asyncness.print_with_space(); let unsafety = header.unsafety.print_with_space(); let defaultness = print_default_space(meth.is_default()); let abi = print_abi_with_space(header.abi).to_string(); // NOTE: `{:#}` does not print HTML formatting, `{}` does. So `g.print` can't be reused between the length calculation and `write!`. - let generics_len = format!("{:#}", g.print(cx.cache())).len(); + let generics_len = format!("{:#}", g.print(cache, tcx)).len(); let mut header_len = "fn ".len() + vis.len() + constness.len() @@ -1049,11 +1055,10 @@ fn render_assoc_item( abi, href = href, name = name, - generics = g.print(cx.cache()), - decl = Function { decl: d, header_len, indent, asyncness: header.asyncness } - .print(cx.cache()), - spotlight = spotlight_decl(&d, cx.cache()), - where_clause = WhereClause { gens: g, indent, end_newline }.print(cx.cache()) + generics = g.print(cache, tcx), + decl = d.full_print(cache, tcx, header_len, indent, header.asyncness), + spotlight = spotlight_decl(&d, cache, tcx), + where_clause = print_where_clause(g, cache, tcx, indent, end_newline), ) } match *item.kind { @@ -1081,6 +1086,7 @@ fn render_assoc_item( link, if parent == ItemType::Trait { " " } else { "" }, cx.cache(), + cx.tcx(), ), _ => panic!("render_assoc_item called on non-associated-item"), } @@ -1155,6 +1161,8 @@ fn render_assoc_items( Some(v) => v, None => return, }; + let tcx = cx.tcx(); + let cache = cx.cache(); let (non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| i.inner_impl().trait_.is_none()); if !non_trait.is_empty() { let render_mode = match what { @@ -1169,12 +1177,10 @@ fn render_assoc_items( AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => { let id = cx.derive_id(small_url_encode(format!( "deref-methods-{:#}", - type_.print(cx.cache()) + type_.print(cache, tcx) ))); - debug!("Adding {} to deref id map", type_.print(cx.cache())); - cx.deref_id_map - .borrow_mut() - .insert(type_.def_id_full(cx.cache()).unwrap(), id.clone()); + debug!("Adding {} to deref id map", type_.print(cache, tcx)); + cx.deref_id_map.borrow_mut().insert(type_.def_id_full(cache).unwrap(), id.clone()); write!( w, "<h2 id=\"{id}\" class=\"small-section-header\">\ @@ -1182,8 +1188,8 @@ fn render_assoc_items( <a href=\"#{id}\" class=\"anchor\"></a>\ </h2>", id = id, - trait_ = trait_.print(cx.cache()), - type_ = type_.print(cx.cache()), + trait_ = trait_.print(cache, tcx), + type_ = type_.print(cache, tcx), ); RenderMode::ForDeref { mut_: deref_mut_ } } @@ -1196,8 +1202,8 @@ fn render_assoc_items( containing_item, AssocItemLink::Anchor(None), render_mode, - containing_item.stable_since(cx.tcx()).as_deref(), - containing_item.const_stable_since(cx.tcx()).as_deref(), + containing_item.stable_since(tcx).as_deref(), + containing_item.const_stable_since(tcx).as_deref(), true, None, false, @@ -1209,11 +1215,11 @@ fn render_assoc_items( if !traits.is_empty() { let deref_impl = traits .iter() - .find(|t| t.inner_impl().trait_.def_id_full(cx.cache()) == cx.cache.deref_trait_did); + .find(|t| t.inner_impl().trait_.def_id_full(cache) == cx.cache.deref_trait_did); if let Some(impl_) = deref_impl { - let has_deref_mut = traits.iter().any(|t| { - t.inner_impl().trait_.def_id_full(cx.cache()) == cx.cache.deref_mut_trait_did - }); + let has_deref_mut = traits + .iter() + .any(|t| t.inner_impl().trait_.def_id_full(cache) == cx.cache.deref_mut_trait_did); render_deref_methods(w, cx, impl_, containing_item, has_deref_mut); } @@ -1335,7 +1341,7 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool, cache: &Cache) -> bo } } -fn spotlight_decl(decl: &clean::FnDecl, cache: &Cache) -> String { +fn spotlight_decl(decl: &clean::FnDecl, cache: &Cache, tcx: TyCtxt<'_>) -> String { let mut out = Buffer::html(); let mut trait_ = String::new(); @@ -1351,16 +1357,16 @@ fn spotlight_decl(decl: &clean::FnDecl, cache: &Cache) -> String { &mut out, "<h3 class=\"notable\">Notable traits for {}</h3>\ <code class=\"content\">", - impl_.for_.print(cache) + impl_.for_.print(cache, tcx) ); - trait_.push_str(&impl_.for_.print(cache).to_string()); + trait_.push_str(&impl_.for_.print(cache, tcx).to_string()); } //use the "where" class here to make it small write!( &mut out, "<span class=\"where fmt-newline\">{}</span>", - impl_.print(cache, false) + impl_.print(cache, false, tcx) ); let t_did = impl_.trait_.def_id_full(cache).unwrap(); for it in &impl_.items { @@ -1374,6 +1380,7 @@ fn spotlight_decl(decl: &clean::FnDecl, cache: &Cache) -> String { AssocItemLink::GotoSource(t_did, &FxHashSet::default()), "", cache, + tcx, ); out.push_str(";</span>"); } @@ -1413,15 +1420,17 @@ fn render_impl( aliases: &[String], ) { let traits = &cx.cache.traits; - let trait_ = i.trait_did_full(cx.cache()).map(|did| &traits[&did]); + let tcx = cx.tcx(); + let cache = cx.cache(); + let trait_ = i.trait_did_full(cache).map(|did| &traits[&did]); if render_mode == RenderMode::Normal { let id = cx.derive_id(match i.inner_impl().trait_ { Some(ref t) => { if is_on_foreign_type { - get_id_for_impl_on_foreign_type(&i.inner_impl().for_, t, cx.cache()) + get_id_for_impl_on_foreign_type(&i.inner_impl().for_, t, cache, tcx) } else { - format!("impl-{}", small_url_encode(format!("{:#}", t.print(cx.cache())))) + format!("impl-{}", small_url_encode(format!("{:#}", t.print(cache, tcx)))) } } None => "impl".to_string(), @@ -1433,7 +1442,7 @@ fn render_impl( }; if let Some(use_absolute) = use_absolute { write!(w, "<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">", id, aliases); - write!(w, "{}", i.inner_impl().print(cx.cache(), use_absolute)); + write!(w, "{}", i.inner_impl().print(cache, use_absolute, tcx)); if show_def_docs { for it in &i.inner_impl().items { if let clean::TypedefItem(ref tydef, _) = *it.kind { @@ -1445,7 +1454,8 @@ fn render_impl( Some(&tydef.type_), AssocItemLink::Anchor(None), "", - cx.cache(), + cache, + tcx, ); w.write_str(";</span>"); } @@ -1458,14 +1468,14 @@ fn render_impl( "<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">{}</code>", id, aliases, - i.inner_impl().print(cx.cache(), false) + i.inner_impl().print(cache, false, tcx) ); } write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id); render_stability_since_raw( w, - i.impl_item.stable_since(cx.tcx()).as_deref(), - i.impl_item.const_stable_since(cx.tcx()).as_deref(), + i.impl_item.stable_since(tcx).as_deref(), + i.impl_item.const_stable_since(tcx).as_deref(), outer_version, outer_const_version, ); @@ -1511,6 +1521,7 @@ fn render_impl( ) { let item_type = item.type_(); let name = item.name.as_ref().unwrap(); + let tcx = cx.tcx(); let render_method_item = match render_mode { RenderMode::Normal => true, @@ -1538,8 +1549,8 @@ fn render_impl( w.write_str("</code>"); render_stability_since_raw( w, - item.stable_since(cx.tcx()).as_deref(), - item.const_stable_since(cx.tcx()).as_deref(), + item.stable_since(tcx).as_deref(), + item.const_stable_since(tcx).as_deref(), outer_version, outer_const_version, ); @@ -1558,6 +1569,7 @@ fn render_impl( link.anchor(&id), "", cx.cache(), + tcx, ); w.write_str("</code></h4>"); } @@ -1568,8 +1580,8 @@ fn render_impl( w.write_str("</code>"); render_stability_since_raw( w, - item.stable_since(cx.tcx()).as_deref(), - item.const_stable_since(cx.tcx()).as_deref(), + item.stable_since(tcx).as_deref(), + item.const_stable_since(tcx).as_deref(), outer_version, outer_const_version, ); @@ -1579,7 +1591,16 @@ fn render_impl( clean::AssocTypeItem(ref bounds, ref default) => { let id = cx.derive_id(format!("{}.{}", item_type, name)); write!(w, "<h4 id=\"{}\" class=\"{}{}\"><code>", id, item_type, extra_class); - assoc_type(w, item, bounds, default.as_ref(), link.anchor(&id), "", cx.cache()); + assoc_type( + w, + item, + bounds, + default.as_ref(), + link.anchor(&id), + "", + cx.cache(), + tcx, + ); w.write_str("</code></h4>"); } clean::StrippedItem(..) => return, @@ -1882,6 +1903,8 @@ fn small_url_encode(s: String) -> String { fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) { if let Some(v) = cx.cache.impls.get(&it.def_id) { let mut used_links = FxHashSet::default(); + let tcx = cx.tcx(); + let cache = cx.cache(); { let used_links_bor = &mut used_links; @@ -1911,7 +1934,7 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) { if let Some(impl_) = v .iter() .filter(|i| i.inner_impl().trait_.is_some()) - .find(|i| i.inner_impl().trait_.def_id_full(cx.cache()) == cx.cache.deref_trait_did) + .find(|i| i.inner_impl().trait_.def_id_full(cache) == cx.cache.deref_trait_did) { sidebar_deref_methods(cx, out, impl_, v); } @@ -1922,9 +1945,9 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) { .iter() .filter_map(|it| { if let Some(ref i) = it.inner_impl().trait_ { - let i_display = format!("{:#}", i.print(cx.cache())); + let i_display = format!("{:#}", i.print(cache, tcx)); let out = Escape(&i_display); - let encoded = small_url_encode(format!("{:#}", i.print(cx.cache()))); + let encoded = small_url_encode(format!("{:#}", i.print(cache, tcx))); let generated = format!( "<a href=\"#impl-{}\">{}{}</a>", encoded, @@ -1988,6 +2011,7 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) { fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &Vec<Impl>) { let c = cx.cache(); + let tcx = cx.tcx(); debug!("found Deref: {:?}", impl_); if let Some((target, real_target)) = @@ -2000,8 +2024,8 @@ fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &V }) { debug!("found target, real_target: {:?} {:?}", target, real_target); - if let Some(did) = target.def_id_full(cx.cache()) { - if let Some(type_did) = impl_.inner_impl().for_.def_id_full(cx.cache()) { + if let Some(did) = target.def_id_full(c) { + if let Some(type_did) = impl_.inner_impl().for_.def_id_full(c) { // `impl Deref<Target = S> for S` if did == type_did { // Avoid infinite cycles @@ -2012,9 +2036,9 @@ fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &V let deref_mut = v .iter() .filter(|i| i.inner_impl().trait_.is_some()) - .any(|i| i.inner_impl().trait_.def_id_full(cx.cache()) == c.deref_mut_trait_did); + .any(|i| i.inner_impl().trait_.def_id_full(c) == c.deref_mut_trait_did); let inner_impl = target - .def_id_full(cx.cache()) + .def_id_full(c) .or_else(|| { target.primitive_type().and_then(|prim| c.primitive_locations.get(&prim).cloned()) }) @@ -2030,14 +2054,17 @@ fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &V if !ret.is_empty() { let deref_id_map = cx.deref_id_map.borrow(); let id = deref_id_map - .get(&real_target.def_id_full(cx.cache()).unwrap()) + .get(&real_target.def_id_full(c).unwrap()) .expect("Deref section without derived id"); write!( out, "<a class=\"sidebar-title\" href=\"#{}\">Methods from {}<Target={}></a>", id, - Escape(&format!("{:#}", impl_.inner_impl().trait_.as_ref().unwrap().print(c))), - Escape(&format!("{:#}", real_target.print(c))), + Escape(&format!( + "{:#}", + impl_.inner_impl().trait_.as_ref().unwrap().print(c, tcx) + )), + Escape(&format!("{:#}", real_target.print(c, tcx))), ); // We want links' order to be reproducible so we don't use unstable sort. ret.sort(); @@ -2050,12 +2077,12 @@ fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &V } // Recurse into any further impls that might exist for `target` - if let Some(target_did) = target.def_id_full(cx.cache()) { + if let Some(target_did) = target.def_id_full(c) { if let Some(target_impls) = c.impls.get(&target_did) { if let Some(target_deref_impl) = target_impls .iter() .filter(|i| i.inner_impl().trait_.is_some()) - .find(|i| i.inner_impl().trait_.def_id_full(cx.cache()) == c.deref_trait_did) + .find(|i| i.inner_impl().trait_.def_id_full(c) == c.deref_trait_did) { sidebar_deref_methods(cx, out, target_deref_impl, target_impls); } @@ -2094,17 +2121,26 @@ fn get_id_for_impl_on_foreign_type( for_: &clean::Type, trait_: &clean::Type, cache: &Cache, + tcx: TyCtxt<'_>, ) -> String { - small_url_encode(format!("impl-{:#}-for-{:#}", trait_.print(cache), for_.print(cache))) + small_url_encode(format!( + "impl-{:#}-for-{:#}", + trait_.print(cache, tcx), + for_.print(cache, tcx) + )) } -fn extract_for_impl_name(item: &clean::Item, cache: &Cache) -> Option<(String, String)> { +fn extract_for_impl_name( + item: &clean::Item, + cache: &Cache, + tcx: TyCtxt<'_>, +) -> Option<(String, String)> { match *item.kind { clean::ItemKind::ImplItem(ref i) => { if let Some(ref trait_) = i.trait_ { Some(( - format!("{:#}", i.for_.print(cache)), - get_id_for_impl_on_foreign_type(&i.for_, trait_, cache), + format!("{:#}", i.for_.print(cache, tcx)), + get_id_for_impl_on_foreign_type(&i.for_, trait_, cache, tcx), )) } else { None @@ -2184,15 +2220,17 @@ fn sidebar_trait(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, t: &clean ); if let Some(implementors) = cx.cache.implementors.get(&it.def_id) { + let cache = cx.cache(); + let tcx = cx.tcx(); let mut res = implementors .iter() .filter(|i| { i.inner_impl() .for_ - .def_id_full(cx.cache()) + .def_id_full(cache) .map_or(false, |d| !cx.cache.paths.contains_key(&d)) }) - .filter_map(|i| extract_for_impl_name(&i.impl_item, cx.cache())) + .filter_map(|i| extract_for_impl_name(&i.impl_item, cache, tcx)) .collect::<Vec<_>>(); if !res.is_empty() { diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index c3c4c4952b3..25314f87eb5 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -19,7 +19,7 @@ use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; use crate::formats::{AssocItemRender, FormatRenderer, Impl, RenderMode}; use crate::html::escape::Escape; -use crate::html::format::{print_abi_with_space, Buffer, Function, PrintWithSpace, WhereClause}; +use crate::html::format::{print_abi_with_space, print_where_clause, Buffer, PrintWithSpace}; use crate::html::highlight; use crate::html::markdown::MarkdownSummaryLine; @@ -73,6 +73,7 @@ pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer) } } write!(buf, "<a class=\"{}\" href=\"\">{}</a>", item.type_(), item.name.as_ref().unwrap()); + write!(buf, "<button id=\"copy-path\" onclick=\"copy_path(this)\">⎘</button>"); buf.write_str("</span>"); // in-band buf.write_str("<span class=\"out-of-band\">"); @@ -266,7 +267,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl w, "<tr><td><code>{}{}</code></td></tr>", myitem.visibility.print_with_space(cx.tcx(), myitem.def_id, cx.cache()), - import.print(cx.cache()) + import.print(cx.cache(), cx.tcx()), ); } @@ -372,7 +373,7 @@ fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean:: f.header.unsafety.print_with_space(), print_abi_with_space(f.header.abi), it.name.as_ref().unwrap(), - f.generics.print(cx.cache()) + f.generics.print(cx.cache(), cx.tcx()) ) .len(); w.write_str("<pre class=\"rust fn\">"); @@ -387,18 +388,16 @@ fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean:: unsafety = f.header.unsafety.print_with_space(), abi = print_abi_with_space(f.header.abi), name = it.name.as_ref().unwrap(), - generics = f.generics.print(cx.cache()), - where_clause = - WhereClause { gens: &f.generics, indent: 0, end_newline: true }.print(cx.cache()), - decl = Function { decl: &f.decl, header_len, indent: 0, asyncness: f.header.asyncness } - .print(cx.cache()), - spotlight = spotlight_decl(&f.decl, cx.cache()), + generics = f.generics.print(cx.cache(), cx.tcx()), + where_clause = print_where_clause(&f.generics, cx.cache(), cx.tcx(), 0, true), + decl = f.decl.full_print(cx.cache(), cx.tcx(), header_len, 0, f.header.asyncness), + spotlight = spotlight_decl(&f.decl, cx.cache(), cx.tcx()), ); document(w, cx, it, None) } fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Trait) { - let bounds = bounds(&t.bounds, false, cx.cache()); + let bounds = bounds(&t.bounds, false, cx.cache(), cx.tcx()); let types = t.items.iter().filter(|m| m.is_associated_type()).collect::<Vec<_>>(); let consts = t.items.iter().filter(|m| m.is_associated_const()).collect::<Vec<_>>(); let required = t.items.iter().filter(|m| m.is_ty_method()).collect::<Vec<_>>(); @@ -415,13 +414,12 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra t.unsafety.print_with_space(), if t.is_auto { "auto " } else { "" }, it.name.as_ref().unwrap(), - t.generics.print(cx.cache()), + t.generics.print(cx.cache(), cx.tcx()), bounds ); if !t.generics.where_predicates.is_empty() { - let where_ = WhereClause { gens: &t.generics, indent: 0, end_newline: true }; - write!(w, "{}", where_.print(cx.cache())); + write!(w, "{}", print_where_clause(&t.generics, cx.cache(), cx.tcx(), 0, true)); } else { w.write_str(" "); } @@ -594,8 +592,8 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra let (mut synthetic, mut concrete): (Vec<&&Impl>, Vec<&&Impl>) = local.iter().partition(|i| i.inner_impl().synthetic); - synthetic.sort_by(|a, b| compare_impl(a, b, cx.cache())); - concrete.sort_by(|a, b| compare_impl(a, b, cx.cache())); + synthetic.sort_by(|a, b| compare_impl(a, b, cx.cache(), cx.tcx())); + concrete.sort_by(|a, b| compare_impl(a, b, cx.cache(), cx.tcx())); if !foreign.is_empty() { write_small_section_header(w, "foreign-impls", "Implementations on Foreign Types", ""); @@ -700,9 +698,9 @@ fn item_trait_alias(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clea w, "trait {}{}{} = {};</pre>", it.name.as_ref().unwrap(), - t.generics.print(cx.cache()), - WhereClause { gens: &t.generics, indent: 0, end_newline: true }.print(cx.cache()), - bounds(&t.bounds, true, cx.cache()) + t.generics.print(cx.cache(), cx.tcx()), + print_where_clause(&t.generics, cx.cache(), cx.tcx(), 0, true), + bounds(&t.bounds, true, cx.cache(), cx.tcx()) ); document(w, cx, it, None); @@ -721,10 +719,9 @@ fn item_opaque_ty(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean: w, "type {}{}{where_clause} = impl {bounds};</pre>", it.name.as_ref().unwrap(), - t.generics.print(cx.cache()), - where_clause = - WhereClause { gens: &t.generics, indent: 0, end_newline: true }.print(cx.cache()), - bounds = bounds(&t.bounds, false, cx.cache()) + t.generics.print(cx.cache(), cx.tcx()), + where_clause = print_where_clause(&t.generics, cx.cache(), cx.tcx(), 0, true), + bounds = bounds(&t.bounds, false, cx.cache(), cx.tcx()), ); document(w, cx, it, None); @@ -743,10 +740,9 @@ fn item_typedef(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::T w, "type {}{}{where_clause} = {type_};</pre>", it.name.as_ref().unwrap(), - t.generics.print(cx.cache()), - where_clause = - WhereClause { gens: &t.generics, indent: 0, end_newline: true }.print(cx.cache()), - type_ = t.type_.print(cx.cache()) + t.generics.print(cx.cache(), cx.tcx()), + where_clause = print_where_clause(&t.generics, cx.cache(), cx.tcx(), 0, true), + type_ = t.type_.print(cx.cache(), cx.tcx()), ); document(w, cx, it, None); @@ -793,7 +789,7 @@ fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni id = id, name = name, shortty = ItemType::StructField, - ty = ty.print(cx.cache()) + ty = ty.print(cx.cache(), cx.tcx()), ); if let Some(stability_class) = field.stability_class(cx.tcx()) { write!(w, "<span class=\"stab {stab}\"></span>", stab = stability_class); @@ -813,8 +809,8 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum "{}enum {}{}{}", it.visibility.print_with_space(cx.tcx(), it.def_id, cx.cache()), it.name.as_ref().unwrap(), - e.generics.print(cx.cache()), - WhereClause { gens: &e.generics, indent: 0, end_newline: true }.print(cx.cache()) + e.generics.print(cx.cache(), cx.tcx()), + print_where_clause(&e.generics, cx.cache(), cx.tcx(), 0, true), ); if e.variants.is_empty() && !e.variants_stripped { w.write_str(" {}"); @@ -832,7 +828,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum if i > 0 { w.write_str(", ") } - write!(w, "{}", ty.print(cx.cache())); + write!(w, "{}", ty.print(cx.cache(), cx.tcx())); } w.write_str(")"); } @@ -879,7 +875,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum if i > 0 { w.write_str(", "); } - write!(w, "{}", ty.print(cx.cache())); + write!(w, "{}", ty.print(cx.cache(), cx.tcx())); } w.write_str(")"); } @@ -916,7 +912,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum </span>", id = id, f = field.name.as_ref().unwrap(), - t = ty.print(cx.cache()) + t = ty.print(cx.cache(), cx.tcx()) ); document(w, cx, field, Some(variant)); } @@ -987,19 +983,22 @@ fn item_constant(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, c: &clean:: "{vis}const {name}: {typ}", vis = it.visibility.print_with_space(cx.tcx(), it.def_id, cx.cache()), name = it.name.as_ref().unwrap(), - typ = c.type_.print(cx.cache()), + typ = c.type_.print(cx.cache(), cx.tcx()), ); - if c.value.is_some() || c.is_literal { - write!(w, " = {expr};", expr = Escape(&c.expr)); + let value = c.value(cx.tcx()); + let is_literal = c.is_literal(cx.tcx()); + let expr = c.expr(cx.tcx()); + if value.is_some() || is_literal { + write!(w, " = {expr};", expr = Escape(&expr)); } else { w.write_str(";"); } - if let Some(value) = &c.value { - if !c.is_literal { + if !is_literal { + if let Some(value) = &value { let value_lowercase = value.to_lowercase(); - let expr_lowercase = c.expr.to_lowercase(); + let expr_lowercase = expr.to_lowercase(); if value_lowercase != expr_lowercase && value_lowercase.trim_end_matches("i32") != expr_lowercase @@ -1054,7 +1053,7 @@ fn item_struct(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St item_type = ItemType::StructField, id = id, name = field.name.as_ref().unwrap(), - ty = ty.print(cx.cache()) + ty = ty.print(cx.cache(), cx.tcx()) ); document(w, cx, field, Some(it)); } @@ -1072,7 +1071,7 @@ fn item_static(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St vis = it.visibility.print_with_space(cx.tcx(), it.def_id, cx.cache()), mutability = s.mutability.print_with_space(), name = it.name.as_ref().unwrap(), - typ = s.type_.print(cx.cache()) + typ = s.type_.print(cx.cache(), cx.tcx()) ); document(w, cx, it, None) } @@ -1147,7 +1146,12 @@ pub(super) fn item_path(ty: ItemType, name: &str) -> String { } } -fn bounds(t_bounds: &[clean::GenericBound], trait_alias: bool, cache: &Cache) -> String { +fn bounds( + t_bounds: &[clean::GenericBound], + trait_alias: bool, + cache: &Cache, + tcx: TyCtxt<'_>, +) -> String { let mut bounds = String::new(); if !t_bounds.is_empty() { if !trait_alias { @@ -1157,7 +1161,7 @@ fn bounds(t_bounds: &[clean::GenericBound], trait_alias: bool, cache: &Cache) -> if i > 0 { bounds.push_str(" + "); } - bounds.push_str(&p.print(cache).to_string()); + bounds.push_str(&p.print(cache, tcx).to_string()); } } bounds @@ -1187,9 +1191,14 @@ fn render_stability_since( ) } -fn compare_impl<'a, 'b>(lhs: &'a &&Impl, rhs: &'b &&Impl, cache: &Cache) -> Ordering { - let lhs = format!("{}", lhs.inner_impl().print(cache, false)); - let rhs = format!("{}", rhs.inner_impl().print(cache, false)); +fn compare_impl<'a, 'b>( + lhs: &'a &&Impl, + rhs: &'b &&Impl, + cache: &Cache, + tcx: TyCtxt<'_>, +) -> Ordering { + let lhs = format!("{}", lhs.inner_impl().print(cache, false, tcx)); + let rhs = format!("{}", rhs.inner_impl().print(cache, false, tcx)); // lhs and rhs are formatted as HTML, which may be unnecessary compare_names(&lhs, &rhs) @@ -1247,8 +1256,8 @@ fn render_union( it.name.as_ref().unwrap() ); if let Some(g) = g { - write!(w, "{}", g.print(cx.cache())); - write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: true }.print(cx.cache())); + write!(w, "{}", g.print(cx.cache(), cx.tcx())); + write!(w, "{}", print_where_clause(&g, cx.cache(), cx.tcx(), 0, true)); } write!(w, " {{\n{}", tab); @@ -1259,7 +1268,7 @@ fn render_union( " {}{}: {},\n{}", field.visibility.print_with_space(cx.tcx(), field.def_id, cx.cache()), field.name.as_ref().unwrap(), - ty.print(cx.cache()), + ty.print(cx.cache(), cx.tcx()), tab ); } @@ -1289,16 +1298,12 @@ fn render_struct( it.name.as_ref().unwrap() ); if let Some(g) = g { - write!(w, "{}", g.print(cx.cache())) + write!(w, "{}", g.print(cx.cache(), cx.tcx())) } match ty { CtorKind::Fictive => { if let Some(g) = g { - write!( - w, - "{}", - WhereClause { gens: g, indent: 0, end_newline: true }.print(cx.cache()) - ) + write!(w, "{}", print_where_clause(g, cx.cache(), cx.tcx(), 0, true),) } let mut has_visible_fields = false; w.write_str(" {"); @@ -1310,7 +1315,7 @@ fn render_struct( tab, field.visibility.print_with_space(cx.tcx(), field.def_id, cx.cache()), field.name.as_ref().unwrap(), - ty.print(cx.cache()) + ty.print(cx.cache(), cx.tcx()), ); has_visible_fields = true; } @@ -1341,7 +1346,7 @@ fn render_struct( w, "{}{}", field.visibility.print_with_space(cx.tcx(), field.def_id, cx.cache()), - ty.print(cx.cache()) + ty.print(cx.cache(), cx.tcx()), ) } _ => unreachable!(), @@ -1349,22 +1354,14 @@ fn render_struct( } w.write_str(")"); if let Some(g) = g { - write!( - w, - "{}", - WhereClause { gens: g, indent: 0, end_newline: false }.print(cx.cache()) - ) + write!(w, "{}", print_where_clause(g, cx.cache(), cx.tcx(), 0, false),) } w.write_str(";"); } CtorKind::Const => { // Needed for PhantomData. if let Some(g) = g { - write!( - w, - "{}", - WhereClause { gens: g, indent: 0, end_newline: false }.print(cx.cache()) - ) + write!(w, "{}", print_where_clause(g, cx.cache(), cx.tcx(), 0, false),) } w.write_str(";"); } diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index b2f2283c177..59dc4ef9449 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -500,7 +500,7 @@ pub(super) fn write_shared( None } else { Some(Implementor { - text: imp.inner_impl().print(cx.cache(), false).to_string(), + text: imp.inner_impl().print(cx.cache(), false, cx.tcx()).to_string(), synthetic: imp.inner_impl().synthetic, types: collect_paths_for_type(imp.inner_impl().for_.clone(), cx.cache()), }) diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index 1b6a82fed11..001c8b09044 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -54,12 +54,10 @@ impl DocFolder for SourceCollector<'_, '_> { self.scx.include_sources = match self.emit_source(&filename) { Ok(()) => true, Err(e) => { - println!( - "warning: source code was requested to be rendered, \ - but processing `{}` had an error: {}", - filename, e + self.scx.tcx.sess.span_err( + item.span.inner(), + &format!("failed to render source code for `{}`: {}", filename, e), ); - println!(" skipping rendering of source code"); false } }; diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index da2952bbebd..f2e62ee7b6b 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -3061,3 +3061,28 @@ function hideThemeButtonState() { window.onhashchange = onHashChange; setupSearchLoader(); }()); + +function copy_path(but) { + var parent = but.parentElement; + var path = []; + + onEach(parent.childNodes, function(child) { + if (child.tagName === 'A') { + path.push(child.textContent); + } + }); + + var el = document.createElement('textarea'); + el.value = 'use ' + path.join('::') + ';'; + el.setAttribute('readonly', ''); + // To not make it appear on the screen. + el.style.position = 'absolute'; + el.style.left = '-9999px'; + + document.body.appendChild(el); + el.select(); + document.execCommand('copy'); + document.body.removeChild(el); + + but.textContent = '✓'; +} diff --git a/src/librustdoc/html/static/noscript.css b/src/librustdoc/html/static/noscript.css index c9fed989ec0..4d3332877c0 100644 --- a/src/librustdoc/html/static/noscript.css +++ b/src/librustdoc/html/static/noscript.css @@ -33,3 +33,8 @@ rules. /* Since there is no toggle (the "[-]") when JS is disabled, no need for this margin either. */ margin-left: 0 !important; } + +#copy-path { + /* It requires JS to work so no need to display it in this case. */ + display: none; +} diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 6c90fd7c9ee..07dfb7f5cf0 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -424,7 +424,9 @@ nav.sub { text-overflow: ellipsis; margin: 0; } -.docblock-short code { +/* Wrap non-pre code blocks (`text`) but not (```text```). */ +.docblock > :not(pre) > code, +.docblock-short > :not(pre) > code { white-space: pre-wrap; } @@ -1316,20 +1318,29 @@ h4 > .notable-traits { outline: none; } +#theme-picker, #settings-menu, .help-button, #copy-path { + padding: 4px; + width: 27px; + height: 29px; + border: 1px solid; + border-radius: 3px; + cursor: pointer; +} + .help-button { right: 30px; font-family: "Fira Sans", Arial, sans-serif; text-align: center; font-size: 17px; + padding-top: 2px; } -#theme-picker, #settings-menu, .help-button { - padding: 4px; - width: 27px; - height: 29px; - border: 1px solid; - border-radius: 3px; - cursor: pointer; +#copy-path { + height: 30px; + font-size: 18px; + margin-left: 10px; + padding: 0 6px; + width: 28px; } #theme-choices { diff --git a/src/librustdoc/html/static/themes/ayu.css b/src/librustdoc/html/static/themes/ayu.css index 7374aee71f8..b24f4035ca8 100644 --- a/src/librustdoc/html/static/themes/ayu.css +++ b/src/librustdoc/html/static/themes/ayu.css @@ -498,7 +498,7 @@ kbd { box-shadow-color: #c6cbd1; } -#theme-picker, #settings-menu, .help-button { +#theme-picker, #settings-menu, .help-button, #copy-path { border-color: #5c6773; background-color: #0f1419; color: #fff; @@ -510,7 +510,8 @@ kbd { #theme-picker:hover, #theme-picker:focus, #settings-menu:hover, #settings-menu:focus, -.help-button:hover, .help-button:focus { +.help-button:hover, .help-button:focus, +#copy-path:hover, #copy-path:focus { border-color: #e0e0e0; } diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css index cf2d28bb43f..e863ed03f51 100644 --- a/src/librustdoc/html/static/themes/dark.css +++ b/src/librustdoc/html/static/themes/dark.css @@ -388,7 +388,7 @@ kbd { box-shadow-color: #c6cbd1; } -#theme-picker, #settings-menu, .help-button { +#theme-picker, #settings-menu, .help-button, #copy-path { border-color: #e0e0e0; background: #f0f0f0; color: #000; @@ -396,7 +396,8 @@ kbd { #theme-picker:hover, #theme-picker:focus, #settings-menu:hover, #settings-menu:focus, -.help-button:hover, .help-button:focus { +.help-button:hover, .help-button:focus, +#copy-path:hover, #copy-path:focus { border-color: #ffb900; } diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css index 7bf6793809c..9335dd96d29 100644 --- a/src/librustdoc/html/static/themes/light.css +++ b/src/librustdoc/html/static/themes/light.css @@ -380,14 +380,15 @@ kbd { box-shadow-color: #c6cbd1; } -#theme-picker, #settings-menu, .help-button { +#theme-picker, #settings-menu, .help-button, #copy-path { border-color: #e0e0e0; background-color: #fff; } #theme-picker:hover, #theme-picker:focus, #settings-menu:hover, #settings-menu:focus, -.help-button:hover, .help-button:focus { +.help-button:hover, .help-button:focus, +#copy-path:hover, #copy-path:focus { border-color: #717171; } diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 073209c2468..c470dc57005 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -27,7 +27,7 @@ impl JsonRenderer<'_> { let clean::Item { span, name, attrs, kind, visibility, def_id } = item; let inner = match *kind { clean::StrippedItem(_) => return None, - x => from_clean_item_kind(x, self.tcx, &name), + kind => from_clean_item_kind(kind, self.tcx, &name), }; Some(Item { id: from_def_id(def_id), @@ -87,59 +87,78 @@ impl JsonRenderer<'_> { } } +crate trait FromWithTcx<T> { + fn from_tcx(f: T, tcx: TyCtxt<'_>) -> Self; +} + +crate trait IntoWithTcx<T> { + fn into_tcx(self, tcx: TyCtxt<'_>) -> T; +} + +impl<T, U> IntoWithTcx<U> for T +where + U: FromWithTcx<T>, +{ + fn into_tcx(self, tcx: TyCtxt<'_>) -> U { + U::from_tcx(self, tcx) + } +} + crate fn from_deprecation(deprecation: rustc_attr::Deprecation) -> Deprecation { #[rustfmt::skip] let rustc_attr::Deprecation { since, note, is_since_rustc_version: _, suggestion: _ } = deprecation; Deprecation { since: since.map(|s| s.to_string()), note: note.map(|s| s.to_string()) } } -impl From<clean::GenericArgs> for GenericArgs { - fn from(args: clean::GenericArgs) -> Self { +impl FromWithTcx<clean::GenericArgs> for GenericArgs { + fn from_tcx(args: clean::GenericArgs, tcx: TyCtxt<'_>) -> Self { use clean::GenericArgs::*; match args { AngleBracketed { args, bindings } => GenericArgs::AngleBracketed { - args: args.into_iter().map(Into::into).collect(), - bindings: bindings.into_iter().map(Into::into).collect(), + args: args.into_iter().map(|a| a.into_tcx(tcx)).collect(), + bindings: bindings.into_iter().map(|a| a.into_tcx(tcx)).collect(), }, Parenthesized { inputs, output } => GenericArgs::Parenthesized { - inputs: inputs.into_iter().map(Into::into).collect(), - output: output.map(Into::into), + inputs: inputs.into_iter().map(|a| a.into_tcx(tcx)).collect(), + output: output.map(|a| a.into_tcx(tcx)), }, } } } -impl From<clean::GenericArg> for GenericArg { - fn from(arg: clean::GenericArg) -> Self { +impl FromWithTcx<clean::GenericArg> for GenericArg { + fn from_tcx(arg: clean::GenericArg, tcx: TyCtxt<'_>) -> Self { use clean::GenericArg::*; match arg { Lifetime(l) => GenericArg::Lifetime(l.0.to_string()), - Type(t) => GenericArg::Type(t.into()), - Const(c) => GenericArg::Const(c.into()), + Type(t) => GenericArg::Type(t.into_tcx(tcx)), + Const(c) => GenericArg::Const(c.into_tcx(tcx)), } } } -impl From<clean::Constant> for Constant { - fn from(constant: clean::Constant) -> Self { - let clean::Constant { type_, expr, value, is_literal } = constant; - Constant { type_: type_.into(), expr, value, is_literal } +impl FromWithTcx<clean::Constant> for Constant { + fn from_tcx(constant: clean::Constant, tcx: TyCtxt<'_>) -> Self { + let expr = constant.expr(tcx); + let value = constant.value(tcx); + let is_literal = constant.is_literal(tcx); + Constant { type_: constant.type_.into_tcx(tcx), expr, value, is_literal } } } -impl From<clean::TypeBinding> for TypeBinding { - fn from(binding: clean::TypeBinding) -> Self { - TypeBinding { name: binding.name.to_string(), binding: binding.kind.into() } +impl FromWithTcx<clean::TypeBinding> for TypeBinding { + fn from_tcx(binding: clean::TypeBinding, tcx: TyCtxt<'_>) -> Self { + TypeBinding { name: binding.name.to_string(), binding: binding.kind.into_tcx(tcx) } } } -impl From<clean::TypeBindingKind> for TypeBindingKind { - fn from(kind: clean::TypeBindingKind) -> Self { +impl FromWithTcx<clean::TypeBindingKind> for TypeBindingKind { + fn from_tcx(kind: clean::TypeBindingKind, tcx: TyCtxt<'_>) -> Self { use clean::TypeBindingKind::*; match kind { - Equality { ty } => TypeBindingKind::Equality(ty.into()), + Equality { ty } => TypeBindingKind::Equality(ty.into_tcx(tcx)), Constraint { bounds } => { - TypeBindingKind::Constraint(bounds.into_iter().map(Into::into).collect()) + TypeBindingKind::Constraint(bounds.into_iter().map(|a| a.into_tcx(tcx)).collect()) } } } @@ -152,34 +171,35 @@ crate fn from_def_id(did: DefId) -> Id { fn from_clean_item_kind(item: clean::ItemKind, tcx: TyCtxt<'_>, name: &Option<Symbol>) -> ItemEnum { use clean::ItemKind::*; match item { - ModuleItem(m) => ItemEnum::Module(m.into()), - ImportItem(i) => ItemEnum::Import(i.into()), - StructItem(s) => ItemEnum::Struct(s.into()), - UnionItem(u) => ItemEnum::Union(u.into()), - StructFieldItem(f) => ItemEnum::StructField(f.into()), - EnumItem(e) => ItemEnum::Enum(e.into()), - VariantItem(v) => ItemEnum::Variant(v.into()), - FunctionItem(f) => ItemEnum::Function(f.into()), - ForeignFunctionItem(f) => ItemEnum::Function(f.into()), - TraitItem(t) => ItemEnum::Trait(t.into()), - TraitAliasItem(t) => ItemEnum::TraitAlias(t.into()), - MethodItem(m, _) => ItemEnum::Method(from_function_method(m, true)), - TyMethodItem(m) => ItemEnum::Method(from_function_method(m, false)), - ImplItem(i) => ItemEnum::Impl(i.into()), - StaticItem(s) => ItemEnum::Static(from_clean_static(s, tcx)), - ForeignStaticItem(s) => ItemEnum::Static(from_clean_static(s, tcx)), + ModuleItem(m) => ItemEnum::Module(m.into_tcx(tcx)), + ImportItem(i) => ItemEnum::Import(i.into_tcx(tcx)), + StructItem(s) => ItemEnum::Struct(s.into_tcx(tcx)), + UnionItem(u) => ItemEnum::Union(u.into_tcx(tcx)), + StructFieldItem(f) => ItemEnum::StructField(f.into_tcx(tcx)), + EnumItem(e) => ItemEnum::Enum(e.into_tcx(tcx)), + VariantItem(v) => ItemEnum::Variant(v.into_tcx(tcx)), + FunctionItem(f) => ItemEnum::Function(f.into_tcx(tcx)), + ForeignFunctionItem(f) => ItemEnum::Function(f.into_tcx(tcx)), + TraitItem(t) => ItemEnum::Trait(t.into_tcx(tcx)), + TraitAliasItem(t) => ItemEnum::TraitAlias(t.into_tcx(tcx)), + MethodItem(m, _) => ItemEnum::Method(from_function_method(m, true, tcx)), + TyMethodItem(m) => ItemEnum::Method(from_function_method(m, false, tcx)), + ImplItem(i) => ItemEnum::Impl(i.into_tcx(tcx)), + StaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)), + ForeignStaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)), ForeignTypeItem => ItemEnum::ForeignType, - TypedefItem(t, _) => ItemEnum::Typedef(t.into()), - OpaqueTyItem(t) => ItemEnum::OpaqueTy(t.into()), - ConstantItem(c) => ItemEnum::Constant(c.into()), + TypedefItem(t, _) => ItemEnum::Typedef(t.into_tcx(tcx)), + OpaqueTyItem(t) => ItemEnum::OpaqueTy(t.into_tcx(tcx)), + ConstantItem(c) => ItemEnum::Constant(c.into_tcx(tcx)), MacroItem(m) => ItemEnum::Macro(m.source), - ProcMacroItem(m) => ItemEnum::ProcMacro(m.into()), - AssocConstItem(t, s) => ItemEnum::AssocConst { type_: t.into(), default: s }, + ProcMacroItem(m) => ItemEnum::ProcMacro(m.into_tcx(tcx)), + AssocConstItem(t, s) => ItemEnum::AssocConst { type_: t.into_tcx(tcx), default: s }, AssocTypeItem(g, t) => ItemEnum::AssocType { - bounds: g.into_iter().map(Into::into).collect(), - default: t.map(Into::into), + bounds: g.into_iter().map(|x| x.into_tcx(tcx)).collect(), + default: t.map(|x| x.into_tcx(tcx)), }, - StrippedItem(inner) => from_clean_item_kind(*inner, tcx, name), + // `convert_item` early returns `None` for striped items + StrippedItem(_) => unreachable!(), PrimitiveItem(_) | KeywordItem(_) => { panic!("{:?} is not supported for JSON output", item) } @@ -190,18 +210,18 @@ fn from_clean_item_kind(item: clean::ItemKind, tcx: TyCtxt<'_>, name: &Option<Sy } } -impl From<clean::Module> for Module { - fn from(module: clean::Module) -> Self { +impl FromWithTcx<clean::Module> for Module { + fn from_tcx(module: clean::Module, _tcx: TyCtxt<'_>) -> Self { Module { is_crate: module.is_crate, items: ids(module.items) } } } -impl From<clean::Struct> for Struct { - fn from(struct_: clean::Struct) -> Self { +impl FromWithTcx<clean::Struct> for Struct { + fn from_tcx(struct_: clean::Struct, tcx: TyCtxt<'_>) -> Self { let clean::Struct { struct_type, generics, fields, fields_stripped } = struct_; Struct { struct_type: from_ctor_kind(struct_type), - generics: generics.into(), + generics: generics.into_tcx(tcx), fields_stripped, fields: ids(fields), impls: Vec::new(), // Added in JsonRenderer::item @@ -209,11 +229,11 @@ impl From<clean::Struct> for Struct { } } -impl From<clean::Union> for Union { - fn from(struct_: clean::Union) -> Self { +impl FromWithTcx<clean::Union> for Union { + fn from_tcx(struct_: clean::Union, tcx: TyCtxt<'_>) -> Self { let clean::Union { generics, fields, fields_stripped } = struct_; Union { - generics: generics.into(), + generics: generics.into_tcx(tcx), fields_stripped, fields: ids(fields), impls: Vec::new(), // Added in JsonRenderer::item @@ -247,74 +267,81 @@ crate fn from_fn_header(header: &rustc_hir::FnHeader) -> HashSet<Qualifiers> { v } -impl From<clean::Function> for Function { - fn from(function: clean::Function) -> Self { +impl FromWithTcx<clean::Function> for Function { + fn from_tcx(function: clean::Function, tcx: TyCtxt<'_>) -> Self { let clean::Function { decl, generics, header } = function; Function { - decl: decl.into(), - generics: generics.into(), + decl: decl.into_tcx(tcx), + generics: generics.into_tcx(tcx), header: from_fn_header(&header), abi: header.abi.to_string(), } } } -impl From<clean::Generics> for Generics { - fn from(generics: clean::Generics) -> Self { +impl FromWithTcx<clean::Generics> for Generics { + fn from_tcx(generics: clean::Generics, tcx: TyCtxt<'_>) -> Self { Generics { - params: generics.params.into_iter().map(Into::into).collect(), - where_predicates: generics.where_predicates.into_iter().map(Into::into).collect(), + params: generics.params.into_iter().map(|x| x.into_tcx(tcx)).collect(), + where_predicates: generics + .where_predicates + .into_iter() + .map(|x| x.into_tcx(tcx)) + .collect(), } } } -impl From<clean::GenericParamDef> for GenericParamDef { - fn from(generic_param: clean::GenericParamDef) -> Self { - GenericParamDef { name: generic_param.name.to_string(), kind: generic_param.kind.into() } +impl FromWithTcx<clean::GenericParamDef> for GenericParamDef { + fn from_tcx(generic_param: clean::GenericParamDef, tcx: TyCtxt<'_>) -> Self { + GenericParamDef { + name: generic_param.name.to_string(), + kind: generic_param.kind.into_tcx(tcx), + } } } -impl From<clean::GenericParamDefKind> for GenericParamDefKind { - fn from(kind: clean::GenericParamDefKind) -> Self { +impl FromWithTcx<clean::GenericParamDefKind> for GenericParamDefKind { + fn from_tcx(kind: clean::GenericParamDefKind, tcx: TyCtxt<'_>) -> Self { use clean::GenericParamDefKind::*; match kind { Lifetime => GenericParamDefKind::Lifetime, Type { did: _, bounds, default, synthetic: _ } => GenericParamDefKind::Type { - bounds: bounds.into_iter().map(Into::into).collect(), - default: default.map(Into::into), + bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(), + default: default.map(|x| x.into_tcx(tcx)), }, - Const { did: _, ty } => GenericParamDefKind::Const(ty.into()), + Const { did: _, ty } => GenericParamDefKind::Const(ty.into_tcx(tcx)), } } } -impl From<clean::WherePredicate> for WherePredicate { - fn from(predicate: clean::WherePredicate) -> Self { +impl FromWithTcx<clean::WherePredicate> for WherePredicate { + fn from_tcx(predicate: clean::WherePredicate, tcx: TyCtxt<'_>) -> Self { use clean::WherePredicate::*; match predicate { BoundPredicate { ty, bounds } => WherePredicate::BoundPredicate { - ty: ty.into(), - bounds: bounds.into_iter().map(Into::into).collect(), + ty: ty.into_tcx(tcx), + bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(), }, RegionPredicate { lifetime, bounds } => WherePredicate::RegionPredicate { lifetime: lifetime.0.to_string(), - bounds: bounds.into_iter().map(Into::into).collect(), + bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(), }, EqPredicate { lhs, rhs } => { - WherePredicate::EqPredicate { lhs: lhs.into(), rhs: rhs.into() } + WherePredicate::EqPredicate { lhs: lhs.into_tcx(tcx), rhs: rhs.into_tcx(tcx) } } } } } -impl From<clean::GenericBound> for GenericBound { - fn from(bound: clean::GenericBound) -> Self { +impl FromWithTcx<clean::GenericBound> for GenericBound { + fn from_tcx(bound: clean::GenericBound, tcx: TyCtxt<'_>) -> Self { use clean::GenericBound::*; match bound { TraitBound(clean::PolyTrait { trait_, generic_params }, modifier) => { GenericBound::TraitBound { - trait_: trait_.into(), - generic_params: generic_params.into_iter().map(Into::into).collect(), + trait_: trait_.into_tcx(tcx), + generic_params: generic_params.into_iter().map(|x| x.into_tcx(tcx)).collect(), modifier: from_trait_bound_modifier(modifier), } } @@ -332,47 +359,47 @@ crate fn from_trait_bound_modifier(modifier: rustc_hir::TraitBoundModifier) -> T } } -impl From<clean::Type> for Type { - fn from(ty: clean::Type) -> Self { +impl FromWithTcx<clean::Type> for Type { + fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self { use clean::Type::*; match ty { ResolvedPath { path, param_names, did, is_generic: _ } => Type::ResolvedPath { name: path.whole_name(), id: from_def_id(did), - args: path.segments.last().map(|args| Box::new(args.clone().args.into())), + args: path.segments.last().map(|args| Box::new(args.clone().args.into_tcx(tcx))), param_names: param_names - .map(|v| v.into_iter().map(Into::into).collect()) + .map(|v| v.into_iter().map(|x| x.into_tcx(tcx)).collect()) .unwrap_or_default(), }, Generic(s) => Type::Generic(s.to_string()), Primitive(p) => Type::Primitive(p.as_str().to_string()), - BareFunction(f) => Type::FunctionPointer(Box::new((*f).into())), - Tuple(t) => Type::Tuple(t.into_iter().map(Into::into).collect()), - Slice(t) => Type::Slice(Box::new((*t).into())), - Array(t, s) => Type::Array { type_: Box::new((*t).into()), len: s }, - ImplTrait(g) => Type::ImplTrait(g.into_iter().map(Into::into).collect()), + BareFunction(f) => Type::FunctionPointer(Box::new((*f).into_tcx(tcx))), + Tuple(t) => Type::Tuple(t.into_iter().map(|x| x.into_tcx(tcx)).collect()), + Slice(t) => Type::Slice(Box::new((*t).into_tcx(tcx))), + Array(t, s) => Type::Array { type_: Box::new((*t).into_tcx(tcx)), len: s }, + ImplTrait(g) => Type::ImplTrait(g.into_iter().map(|x| x.into_tcx(tcx)).collect()), Never => Type::Never, Infer => Type::Infer, RawPointer(mutability, type_) => Type::RawPointer { mutable: mutability == ast::Mutability::Mut, - type_: Box::new((*type_).into()), + type_: Box::new((*type_).into_tcx(tcx)), }, BorrowedRef { lifetime, mutability, type_ } => Type::BorrowedRef { lifetime: lifetime.map(|l| l.0.to_string()), mutable: mutability == ast::Mutability::Mut, - type_: Box::new((*type_).into()), + type_: Box::new((*type_).into_tcx(tcx)), }, QPath { name, self_type, trait_ } => Type::QualifiedPath { name: name.to_string(), - self_type: Box::new((*self_type).into()), - trait_: Box::new((*trait_).into()), + self_type: Box::new((*self_type).into_tcx(tcx)), + trait_: Box::new((*trait_).into_tcx(tcx)), }, } } } -impl From<clean::BareFunctionDecl> for FunctionPointer { - fn from(bare_decl: clean::BareFunctionDecl) -> Self { +impl FromWithTcx<clean::BareFunctionDecl> for FunctionPointer { + fn from_tcx(bare_decl: clean::BareFunctionDecl, tcx: TyCtxt<'_>) -> Self { let clean::BareFunctionDecl { unsafety, generic_params, decl, abi } = bare_decl; FunctionPointer { header: if let rustc_hir::Unsafety::Unsafe = unsafety { @@ -382,24 +409,24 @@ impl From<clean::BareFunctionDecl> for FunctionPointer { } else { HashSet::new() }, - generic_params: generic_params.into_iter().map(Into::into).collect(), - decl: decl.into(), + generic_params: generic_params.into_iter().map(|x| x.into_tcx(tcx)).collect(), + decl: decl.into_tcx(tcx), abi: abi.to_string(), } } } -impl From<clean::FnDecl> for FnDecl { - fn from(decl: clean::FnDecl) -> Self { +impl FromWithTcx<clean::FnDecl> for FnDecl { + fn from_tcx(decl: clean::FnDecl, tcx: TyCtxt<'_>) -> Self { let clean::FnDecl { inputs, output, c_variadic, attrs: _ } = decl; FnDecl { inputs: inputs .values .into_iter() - .map(|arg| (arg.name.to_string(), arg.type_.into())) + .map(|arg| (arg.name.to_string(), arg.type_.into_tcx(tcx))) .collect(), output: match output { - clean::FnRetTy::Return(t) => Some(t.into()), + clean::FnRetTy::Return(t) => Some(t.into_tcx(tcx)), clean::FnRetTy::DefaultReturn => None, }, c_variadic, @@ -407,22 +434,22 @@ impl From<clean::FnDecl> for FnDecl { } } -impl From<clean::Trait> for Trait { - fn from(trait_: clean::Trait) -> Self { +impl FromWithTcx<clean::Trait> for Trait { + fn from_tcx(trait_: clean::Trait, tcx: TyCtxt<'_>) -> Self { let clean::Trait { unsafety, items, generics, bounds, is_auto } = trait_; Trait { is_auto, is_unsafe: unsafety == rustc_hir::Unsafety::Unsafe, items: ids(items), - generics: generics.into(), - bounds: bounds.into_iter().map(Into::into).collect(), + generics: generics.into_tcx(tcx), + bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(), implementors: Vec::new(), // Added in JsonRenderer::item } } } -impl From<clean::Impl> for Impl { - fn from(impl_: clean::Impl) -> Self { +impl FromWithTcx<clean::Impl> for Impl { + fn from_tcx(impl_: clean::Impl, tcx: TyCtxt<'_>) -> Self { let clean::Impl { unsafety, generics, @@ -436,37 +463,41 @@ impl From<clean::Impl> for Impl { } = impl_; Impl { is_unsafe: unsafety == rustc_hir::Unsafety::Unsafe, - generics: generics.into(), + generics: generics.into_tcx(tcx), provided_trait_methods: provided_trait_methods .into_iter() .map(|x| x.to_string()) .collect(), - trait_: trait_.map(Into::into), - for_: for_.into(), + trait_: trait_.map(|x| x.into_tcx(tcx)), + for_: for_.into_tcx(tcx), items: ids(items), negative: negative_polarity, synthetic, - blanket_impl: blanket_impl.map(Into::into), + blanket_impl: blanket_impl.map(|x| x.into_tcx(tcx)), } } } -crate fn from_function_method(function: clean::Function, has_body: bool) -> Method { +crate fn from_function_method( + function: clean::Function, + has_body: bool, + tcx: TyCtxt<'_>, +) -> Method { let clean::Function { header, decl, generics } = function; Method { - decl: decl.into(), - generics: generics.into(), + decl: decl.into_tcx(tcx), + generics: generics.into_tcx(tcx), header: from_fn_header(&header), abi: header.abi.to_string(), has_body, } } -impl From<clean::Enum> for Enum { - fn from(enum_: clean::Enum) -> Self { +impl FromWithTcx<clean::Enum> for Enum { + fn from_tcx(enum_: clean::Enum, tcx: TyCtxt<'_>) -> Self { let clean::Enum { variants, generics, variants_stripped } = enum_; Enum { - generics: generics.into(), + generics: generics.into_tcx(tcx), variants_stripped, variants: ids(variants), impls: Vec::new(), // Added in JsonRenderer::item @@ -474,8 +505,8 @@ impl From<clean::Enum> for Enum { } } -impl From<clean::VariantStruct> for Struct { - fn from(struct_: clean::VariantStruct) -> Self { +impl FromWithTcx<clean::VariantStruct> for Struct { + fn from_tcx(struct_: clean::VariantStruct, _tcx: TyCtxt<'_>) -> Self { let clean::VariantStruct { struct_type, fields, fields_stripped } = struct_; Struct { struct_type: from_ctor_kind(struct_type), @@ -487,19 +518,19 @@ impl From<clean::VariantStruct> for Struct { } } -impl From<clean::Variant> for Variant { - fn from(variant: clean::Variant) -> Self { +impl FromWithTcx<clean::Variant> for Variant { + fn from_tcx(variant: clean::Variant, tcx: TyCtxt<'_>) -> Self { use clean::Variant::*; match variant { CLike => Variant::Plain, - Tuple(t) => Variant::Tuple(t.into_iter().map(Into::into).collect()), + Tuple(t) => Variant::Tuple(t.into_iter().map(|x| x.into_tcx(tcx)).collect()), Struct(s) => Variant::Struct(ids(s.fields)), } } } -impl From<clean::Import> for Import { - fn from(import: clean::Import) -> Self { +impl FromWithTcx<clean::Import> for Import { + fn from_tcx(import: clean::Import, _tcx: TyCtxt<'_>) -> Self { use clean::ImportKind::*; match import.kind { Simple(s) => Import { @@ -518,8 +549,8 @@ impl From<clean::Import> for Import { } } -impl From<clean::ProcMacro> for ProcMacro { - fn from(mac: clean::ProcMacro) -> Self { +impl FromWithTcx<clean::ProcMacro> for ProcMacro { + fn from_tcx(mac: clean::ProcMacro, _tcx: TyCtxt<'_>) -> Self { ProcMacro { kind: from_macro_kind(mac.kind), helpers: mac.helpers.iter().map(|x| x.to_string()).collect(), @@ -536,41 +567,43 @@ crate fn from_macro_kind(kind: rustc_span::hygiene::MacroKind) -> MacroKind { } } -impl From<clean::Typedef> for Typedef { - fn from(typedef: clean::Typedef) -> Self { +impl FromWithTcx<clean::Typedef> for Typedef { + fn from_tcx(typedef: clean::Typedef, tcx: TyCtxt<'_>) -> Self { let clean::Typedef { type_, generics, item_type: _ } = typedef; - Typedef { type_: type_.into(), generics: generics.into() } + Typedef { type_: type_.into_tcx(tcx), generics: generics.into_tcx(tcx) } } } -impl From<clean::OpaqueTy> for OpaqueTy { - fn from(opaque: clean::OpaqueTy) -> Self { +impl FromWithTcx<clean::OpaqueTy> for OpaqueTy { + fn from_tcx(opaque: clean::OpaqueTy, tcx: TyCtxt<'_>) -> Self { OpaqueTy { - bounds: opaque.bounds.into_iter().map(Into::into).collect(), - generics: opaque.generics.into(), + bounds: opaque.bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(), + generics: opaque.generics.into_tcx(tcx), } } } -fn from_clean_static(stat: clean::Static, tcx: TyCtxt<'_>) -> Static { - Static { - type_: stat.type_.into(), - mutable: stat.mutability == ast::Mutability::Mut, - expr: stat.expr.map(|e| print_const_expr(tcx, e)).unwrap_or_default(), +impl FromWithTcx<clean::Static> for Static { + fn from_tcx(stat: clean::Static, tcx: TyCtxt<'_>) -> Self { + Static { + type_: stat.type_.into_tcx(tcx), + mutable: stat.mutability == ast::Mutability::Mut, + expr: stat.expr.map(|e| print_const_expr(tcx, e)).unwrap_or_default(), + } } } -impl From<clean::TraitAlias> for TraitAlias { - fn from(alias: clean::TraitAlias) -> Self { +impl FromWithTcx<clean::TraitAlias> for TraitAlias { + fn from_tcx(alias: clean::TraitAlias, tcx: TyCtxt<'_>) -> Self { TraitAlias { - generics: alias.generics.into(), - params: alias.bounds.into_iter().map(Into::into).collect(), + generics: alias.generics.into_tcx(tcx), + params: alias.bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(), } } } -impl From<ItemType> for ItemKind { - fn from(kind: ItemType) -> Self { +impl FromWithTcx<ItemType> for ItemKind { + fn from_tcx(kind: ItemType, _tcx: TyCtxt<'_>) -> Self { use ItemType::*; match kind { Module => ItemKind::Module, diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index a4cdad69865..db3a0c5ceb1 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -24,7 +24,7 @@ use crate::error::Error; use crate::formats::cache::Cache; use crate::formats::FormatRenderer; use crate::html::render::cache::ExternalLocation; -use crate::json::conversions::from_def_id; +use crate::json::conversions::{from_def_id, IntoWithTcx}; #[derive(Clone)] crate struct JsonRenderer<'tcx> { @@ -108,7 +108,7 @@ impl JsonRenderer<'tcx> { .last() .map(Clone::clone), visibility: types::Visibility::Public, - inner: types::ItemEnum::Trait(trait_item.clone().into()), + inner: types::ItemEnum::Trait(trait_item.clone().into_tcx(self.tcx)), span: None, docs: Default::default(), links: Default::default(), @@ -129,6 +129,8 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { "json" } + const RUN_ON_MODULE: bool = false; + fn init( krate: clean::Crate, options: RenderOptions, @@ -169,8 +171,10 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { e.impls = self.get_impls(id) } let removed = self.index.borrow_mut().insert(from_def_id(id), new_item.clone()); + // FIXME(adotinthevoid): Currently, the index is duplicated. This is a sanity check - // to make sure the items are unique. + // to make sure the items are unique. The main place this happens is when an item, is + // reexported in more than one place. See `rustdoc-json/reexport/in_root_and_mod` if let Some(old_item) = removed { assert_eq!(old_item, new_item); } @@ -225,7 +229,11 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { .map(|(k, (path, kind))| { ( from_def_id(k), - types::ItemSummary { crate_id: k.krate.as_u32(), path, kind: kind.into() }, + types::ItemSummary { + crate_id: k.krate.as_u32(), + path, + kind: kind.into_tcx(self.tcx), + }, ) }) .collect(), diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index a2f8eb3772e..ad269413ac6 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -216,8 +216,8 @@ impl<'a, 'b> fold::DocFolder for CoverageCalculator<'a, 'b> { if let Some(ref tr) = impl_.trait_ { debug!( "impl {:#} for {:#} in {}", - tr.print(&self.ctx.cache), - impl_.for_.print(&self.ctx.cache), + tr.print(&self.ctx.cache, self.ctx.tcx), + impl_.for_.print(&self.ctx.cache, self.ctx.tcx), filename, ); @@ -228,7 +228,11 @@ impl<'a, 'b> fold::DocFolder for CoverageCalculator<'a, 'b> { // inherent impls *can* be documented, and those docs show up, but in most // cases it doesn't make sense, as all methods on a type are in one single // impl block - debug!("impl {:#} in {}", impl_.for_.print(&self.ctx.cache), filename); + debug!( + "impl {:#} in {}", + impl_.for_.print(&self.ctx.cache, self.ctx.tcx), + filename + ); } } _ => { diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 499931f7e96..55978ca551b 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -950,6 +950,7 @@ impl LinkCollector<'_, '_> { } let link = ori_link.link.replace("`", ""); + let no_backticks_range = range_between_backticks(&ori_link); let parts = link.split('#').collect::<Vec<_>>(); let (link, extra_fragment) = if parts.len() > 2 { // A valid link can't have multiple #'s @@ -973,10 +974,15 @@ impl LinkCollector<'_, '_> { }; // Parse and strip the disambiguator from the link, if present. - let (mut path_str, disambiguator) = if let Ok((d, path)) = Disambiguator::from_str(&link) { - (path.trim(), Some(d)) - } else { - (link.trim(), None) + let (mut path_str, disambiguator) = match Disambiguator::from_str(&link) { + Ok(Some((d, path))) => (path.trim(), Some(d)), + Ok(None) => (link.trim(), None), + Err((err_msg, relative_range)) => { + let disambiguator_range = (no_backticks_range.start + relative_range.start) + ..(no_backticks_range.start + relative_range.end); + disambiguator_error(self.cx, &item, dox, disambiguator_range, &err_msg); + return None; + } }; if path_str.contains(|ch: char| !(ch.is_alphanumeric() || ":_<>, !*&;".contains(ch))) { @@ -1488,6 +1494,27 @@ impl LinkCollector<'_, '_> { } } +/// Get the section of a link between the backticks, +/// or the whole link if there aren't any backticks. +/// +/// For example: +/// +/// ```text +/// [`Foo`] +/// ^^^ +/// ``` +fn range_between_backticks(ori_link: &MarkdownLink) -> Range<usize> { + let after_first_backtick_group = ori_link.link.bytes().position(|b| b != b'`').unwrap_or(0); + let before_second_backtick_group = ori_link + .link + .bytes() + .skip(after_first_backtick_group) + .position(|b| b == b'`') + .unwrap_or(ori_link.link.len()); + (ori_link.range.start + after_first_backtick_group) + ..(ori_link.range.start + before_second_backtick_group) +} + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] /// Disambiguators for a link. enum Disambiguator { @@ -1514,27 +1541,14 @@ impl Disambiguator { } } - /// Given a link, parse and return `(disambiguator, path_str)` - fn from_str(link: &str) -> Result<(Self, &str), ()> { + /// Given a link, parse and return `(disambiguator, path_str)`. + /// + /// This returns `Ok(Some(...))` if a disambiguator was found, + /// `Ok(None)` if no disambiguator was found, or `Err(...)` + /// if there was a problem with the disambiguator. + fn from_str(link: &str) -> Result<Option<(Self, &str)>, (String, Range<usize>)> { use Disambiguator::{Kind, Namespace as NS, Primitive}; - let find_suffix = || { - let suffixes = [ - ("!()", DefKind::Macro(MacroKind::Bang)), - ("()", DefKind::Fn), - ("!", DefKind::Macro(MacroKind::Bang)), - ]; - for &(suffix, kind) in &suffixes { - if let Some(link) = link.strip_suffix(suffix) { - // Avoid turning `!` or `()` into an empty string - if !link.is_empty() { - return Ok((Kind(kind), link)); - } - } - } - Err(()) - }; - if let Some(idx) = link.find('@') { let (prefix, rest) = link.split_at(idx); let d = match prefix { @@ -1551,11 +1565,24 @@ impl Disambiguator { "value" => NS(Namespace::ValueNS), "macro" => NS(Namespace::MacroNS), "prim" | "primitive" => Primitive, - _ => return find_suffix(), + _ => return Err((format!("unknown disambiguator `{}`", prefix), 0..idx)), }; - Ok((d, &rest[1..])) + Ok(Some((d, &rest[1..]))) } else { - find_suffix() + let suffixes = [ + ("!()", DefKind::Macro(MacroKind::Bang)), + ("()", DefKind::Fn), + ("!", DefKind::Macro(MacroKind::Bang)), + ]; + for &(suffix, kind) in &suffixes { + if let Some(link) = link.strip_suffix(suffix) { + // Avoid turning `!` or `()` into an empty string + if !link.is_empty() { + return Ok(Some((Kind(kind), link))); + } + } + } + Ok(None) } } @@ -1979,6 +2006,17 @@ fn anchor_failure( }); } +/// Report an error in the link disambiguator. +fn disambiguator_error( + cx: &DocContext<'_>, + item: &Item, + dox: &str, + link_range: Range<usize>, + msg: &str, +) { + report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, item, dox, &link_range, |_diag, _sp| {}); +} + /// Report an ambiguity error, where there were multiple possible resolutions. fn ambiguity_error( cx: &DocContext<'_>, diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 17a66d1788e..ca30d8f0d46 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -72,10 +72,10 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { crate fn visit(mut self, krate: &'tcx hir::Crate<'_>) -> Module<'tcx> { let mut top_level_module = self.visit_mod_contents( - krate.item.span, + krate.item.inner, &Spanned { span: rustc_span::DUMMY_SP, node: hir::VisibilityKind::Public }, hir::CRATE_HIR_ID, - &krate.item.module, + &krate.item, self.cx.tcx.crate_name, ); top_level_module.is_crate = true; diff --git a/src/llvm-project b/src/llvm-project -Subproject c3a26cbf6e73f2c5f8d03cee1f151d90a266ef3 +Subproject 0abbcc04d8375661a0637896b9ae5dc37a99dc7 diff --git a/src/test/assembly/asm/aarch64-modifiers.rs b/src/test/assembly/asm/aarch64-modifiers.rs index 150997ee807..d4a44b17392 100644 --- a/src/test/assembly/asm/aarch64-modifiers.rs +++ b/src/test/assembly/asm/aarch64-modifiers.rs @@ -1,4 +1,4 @@ -// no-system-llvm +// min-llvm-version: 10.0.1 // assembly-output: emit-asm // compile-flags: -O // compile-flags: --target aarch64-unknown-linux-gnu diff --git a/src/test/assembly/asm/aarch64-types.rs b/src/test/assembly/asm/aarch64-types.rs index 8dd1f3c873f..aa25562d323 100644 --- a/src/test/assembly/asm/aarch64-types.rs +++ b/src/test/assembly/asm/aarch64-types.rs @@ -1,4 +1,4 @@ -// no-system-llvm +// min-llvm-version: 10.0.1 // assembly-output: emit-asm // compile-flags: --target aarch64-unknown-linux-gnu // needs-llvm-components: aarch64 diff --git a/src/test/assembly/asm/arm-modifiers.rs b/src/test/assembly/asm/arm-modifiers.rs index ad4ab63f265..bb6cc1c9873 100644 --- a/src/test/assembly/asm/arm-modifiers.rs +++ b/src/test/assembly/asm/arm-modifiers.rs @@ -1,4 +1,4 @@ -// no-system-llvm +// min-llvm-version: 10.0.1 // assembly-output: emit-asm // compile-flags: -O // compile-flags: --target armv7-unknown-linux-gnueabihf diff --git a/src/test/assembly/asm/arm-types.rs b/src/test/assembly/asm/arm-types.rs index 09901a7a39c..b16fde571af 100644 --- a/src/test/assembly/asm/arm-types.rs +++ b/src/test/assembly/asm/arm-types.rs @@ -1,4 +1,4 @@ -// no-system-llvm +// min-llvm-version: 10.0.1 // assembly-output: emit-asm // compile-flags: --target armv7-unknown-linux-gnueabihf // compile-flags: -C target-feature=+neon diff --git a/src/test/assembly/asm/hexagon-types.rs b/src/test/assembly/asm/hexagon-types.rs index 95135a3e5dd..40352cdb4cd 100644 --- a/src/test/assembly/asm/hexagon-types.rs +++ b/src/test/assembly/asm/hexagon-types.rs @@ -1,4 +1,4 @@ -// no-system-llvm +// min-llvm-version: 10.0.1 // assembly-output: emit-asm // compile-flags: --target hexagon-unknown-linux-musl // needs-llvm-components: hexagon diff --git a/src/test/assembly/asm/mips-types.rs b/src/test/assembly/asm/mips-types.rs index 04e840dc166..60cfebdd992 100644 --- a/src/test/assembly/asm/mips-types.rs +++ b/src/test/assembly/asm/mips-types.rs @@ -1,4 +1,4 @@ -// no-system-llvm +// min-llvm-version: 10.0.1 // revisions: mips32 mips64 // assembly-output: emit-asm //[mips32] compile-flags: --target mips-unknown-linux-gnu diff --git a/src/test/assembly/asm/nvptx-types.rs b/src/test/assembly/asm/nvptx-types.rs index 77fd5141357..75b6371fb70 100644 --- a/src/test/assembly/asm/nvptx-types.rs +++ b/src/test/assembly/asm/nvptx-types.rs @@ -1,4 +1,4 @@ -// no-system-llvm +// min-llvm-version: 10.0.1 // assembly-output: emit-asm // compile-flags: --target nvptx64-nvidia-cuda // compile-flags: --crate-type cdylib diff --git a/src/test/assembly/asm/riscv-types.rs b/src/test/assembly/asm/riscv-types.rs index 47518cdcf16..1ba73fcac9d 100644 --- a/src/test/assembly/asm/riscv-types.rs +++ b/src/test/assembly/asm/riscv-types.rs @@ -1,4 +1,4 @@ -// no-system-llvm +// min-llvm-version: 10.0.1 // revisions: riscv64 riscv32 // assembly-output: emit-asm //[riscv64] compile-flags: --target riscv64imac-unknown-none-elf diff --git a/src/test/assembly/asm/wasm-types.rs b/src/test/assembly/asm/wasm-types.rs index 94ca526222a..a071a850c22 100644 --- a/src/test/assembly/asm/wasm-types.rs +++ b/src/test/assembly/asm/wasm-types.rs @@ -1,4 +1,4 @@ -// no-system-llvm +// min-llvm-version: 10.0.1 // assembly-output: emit-asm // compile-flags: --target wasm32-unknown-unknown // compile-flags: --crate-type cdylib diff --git a/src/test/assembly/asm/x86-modifiers.rs b/src/test/assembly/asm/x86-modifiers.rs index e538167cd46..da2dc51d69e 100644 --- a/src/test/assembly/asm/x86-modifiers.rs +++ b/src/test/assembly/asm/x86-modifiers.rs @@ -1,4 +1,4 @@ -// no-system-llvm +// min-llvm-version: 10.0.1 // revisions: x86_64 i686 // assembly-output: emit-asm // compile-flags: -O diff --git a/src/test/assembly/asm/x86-types.rs b/src/test/assembly/asm/x86-types.rs index f636f1f5296..e0190d3bdae 100644 --- a/src/test/assembly/asm/x86-types.rs +++ b/src/test/assembly/asm/x86-types.rs @@ -1,4 +1,4 @@ -// no-system-llvm +// min-llvm-version: 10.0.1 // revisions: x86_64 i686 // assembly-output: emit-asm //[x86_64] compile-flags: --target x86_64-unknown-linux-gnu diff --git a/src/test/codegen/alloc-optimisation.rs b/src/test/codegen/alloc-optimisation.rs index c3ffaeb9547..5b27f3f4545 100644 --- a/src/test/codegen/alloc-optimisation.rs +++ b/src/test/codegen/alloc-optimisation.rs @@ -1,5 +1,5 @@ // -// no-system-llvm +// min-llvm-version: 10.0.1 // compile-flags: -O #![crate_type="lib"] diff --git a/src/test/codegen/binary-search-index-no-bound-check.rs b/src/test/codegen/binary-search-index-no-bound-check.rs new file mode 100644 index 00000000000..110d1d55626 --- /dev/null +++ b/src/test/codegen/binary-search-index-no-bound-check.rs @@ -0,0 +1,19 @@ +// min-llvm-version: 11.0.0 +// compile-flags: -O +// ignore-debug: the debug assertions get in the way +#![crate_type = "lib"] + +// Make sure no bounds checks are emitted when slicing or indexing +// with an index from `binary_search`. + +// CHECK-LABEL: @binary_search_index_no_bounds_check +#[no_mangle] +pub fn binary_search_index_no_bounds_check(s: &[u8]) -> u8 { + // CHECK-NOT: panic + // CHECK-NOT: slice_index_len_fail + if let Ok(idx) = s.binary_search(&b'\\') { + s[idx] + } else { + 42 + } +} diff --git a/src/test/codegen/issue-83623-SIMD-PartialEq.rs b/src/test/codegen/issue-83623-SIMD-PartialEq.rs new file mode 100644 index 00000000000..b22b7f52402 --- /dev/null +++ b/src/test/codegen/issue-83623-SIMD-PartialEq.rs @@ -0,0 +1,46 @@ +// This test checks that jumps generated by logical operators can be optimized away + +// compile-flags: -Copt-level=3 +// only-64bit + +#![crate_type="lib"] + +pub struct Blueprint { + pub fuel_tank_size: u32, + pub payload: u32, + pub wheel_diameter: u32, + pub wheel_width: u32, + pub storage: u32, +} + +// && chains should not prevent SIMD optimizations for primitives +impl PartialEq for Blueprint{ + fn eq(&self, other: &Self)->bool{ + // CHECK-NOT: call{{.*}}bcmp + // CHECK-NOT: call{{.*}}memcmp + // CHECK-NOT: br {{.*}} + self.fuel_tank_size == other.fuel_tank_size + && self.payload == other.payload + && self.wheel_diameter == other.wheel_diameter + && self.wheel_width == other.wheel_width + && self.storage == other.storage + } +} + +#[derive(PartialEq)] +pub struct Blueprint2 { + pub fuel_tank_size: u32, + pub payload: u32, + pub wheel_diameter: u32, + pub wheel_width: u32, + pub storage: u32, +} + +// Derived PartialEq should not generate jumps and should use SIMD +#[no_mangle] +pub fn partial_eq_should_not_jump(a: &Blueprint2, b:&Blueprint2)->bool{ + // CHECK-NOT: call{{.*}}bcmp + // CHECK-NOT: call{{.*}}memcmp + // CHECK-NOT: br {{.*}} + a==b +} diff --git a/src/test/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs b/src/test/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs index 56466a78d5a..ae13d91ddeb 100644 --- a/src/test/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs +++ b/src/test/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs @@ -1,6 +1,5 @@ // ignore-tidy-linelength // compile-flags: -C no-prepopulate-passes -// min-llvm-version 8.0 #![crate_type = "lib"] diff --git a/src/test/incremental/hashes/function_interfaces.rs b/src/test/incremental/hashes/function_interfaces.rs index ed67b2dcb04..c8530c70f78 100644 --- a/src/test/incremental/hashes/function_interfaces.rs +++ b/src/test/incremental/hashes/function_interfaces.rs @@ -118,7 +118,7 @@ pub fn type_parameter<T>() {} pub fn lifetime_parameter() {} #[cfg(not(cfail1))] -#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_nodes, generics_of")] +#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_nodes, generics_of,fn_sig")] #[rustc_clean(cfg = "cfail3")] pub fn lifetime_parameter<'a>() {} @@ -150,7 +150,7 @@ pub fn lifetime_bound<'a, T>() {} #[cfg(not(cfail1))] #[rustc_clean( cfg = "cfail2", - except = "hir_owner, hir_owner_nodes, generics_of, type_of, predicates_of" + except = "hir_owner, hir_owner_nodes, generics_of, type_of, predicates_of,fn_sig" )] #[rustc_clean(cfg = "cfail3")] pub fn lifetime_bound<'a, T: 'a>() {} @@ -183,7 +183,7 @@ pub fn second_lifetime_bound<'a, 'b, T: 'a>() {} #[cfg(not(cfail1))] #[rustc_clean( cfg = "cfail2", - except = "hir_owner, hir_owner_nodes, generics_of, type_of, predicates_of" + except = "hir_owner, hir_owner_nodes, generics_of, type_of, predicates_of,fn_sig" )] #[rustc_clean(cfg = "cfail3")] pub fn second_lifetime_bound<'a, 'b, T: 'a + 'b>() {} diff --git a/src/test/incremental/hashes/inherent_impls.rs b/src/test/incremental/hashes/inherent_impls.rs index ae8f2ace217..ee7b258cec4 100644 --- a/src/test/incremental/hashes/inherent_impls.rs +++ b/src/test/incremental/hashes/inherent_impls.rs @@ -312,7 +312,7 @@ impl Foo { // if we lower generics before the body, then the `HirId` for // things in the body will be affected. So if you start to see // `typeck` appear dirty, that might be the cause. -nmatsakis - #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] + #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,fn_sig")] #[rustc_clean(cfg="cfail3")] pub fn add_lifetime_parameter_to_method<'a>(&self) { } } @@ -360,7 +360,7 @@ impl Foo { impl Foo { #[rustc_clean( cfg="cfail2", - except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of" + except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of,fn_sig" )] #[rustc_clean(cfg="cfail3")] pub fn add_lifetime_bound_to_lifetime_param_of_method<'a, 'b: 'a>(&self) { } @@ -388,7 +388,7 @@ impl Foo { // body will be affected. So if you start to see `typeck` // appear dirty, that might be the cause. -nmatsakis #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of,\ - type_of")] + type_of,fn_sig")] #[rustc_clean(cfg="cfail3")] pub fn add_lifetime_bound_to_type_param_of_method<'a, T: 'a>(&self) { } } diff --git a/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff b/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff index 4e990dd6b70..2566d745ecd 100644 --- a/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff +++ b/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff @@ -22,7 +22,7 @@ - // + ty: &i32 - // + val: Value(Scalar(alloc0)) + // + ty: &[&i32; 1] -+ // + val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:6 ~ const_promotion_extern_static[317d]::BAR), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) ++ // + val: Unevaluated(BAR, [], Some(promoted[0])) // mir::Constant - // + span: $DIR/const-promotion-extern-static.rs:9:33: 9:34 - // + literal: Const { ty: &i32, val: Value(Scalar(alloc0)) } diff --git a/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff b/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff index 0a9a3f3c2c5..093e228a0ce 100644 --- a/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff +++ b/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff @@ -24,7 +24,7 @@ - // + ty: *const i32 - // + val: Value(Scalar(alloc2)) + // + ty: &[&i32; 1] -+ // + val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:7 ~ const_promotion_extern_static[317d]::FOO), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) ++ // + val: Unevaluated(FOO, [], Some(promoted[0])) // mir::Constant - // + span: $DIR/const-promotion-extern-static.rs:13:42: 13:43 - // + literal: Const { ty: *const i32, val: Value(Scalar(alloc2)) } diff --git a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff index 0535b45aa9f..0517e7fac40 100644 --- a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff +++ b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff @@ -28,7 +28,7 @@ _9 = const main::promoted[0]; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 // ty::Const // + ty: &[i32; 3] - // + val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) + // + val: Unevaluated(main, [], Some(promoted[0])) // mir::Constant // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 // + literal: Const { ty: &[i32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } diff --git a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff index 0535b45aa9f..0517e7fac40 100644 --- a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff +++ b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff @@ -28,7 +28,7 @@ _9 = const main::promoted[0]; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 // ty::Const // + ty: &[i32; 3] - // + val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) + // + val: Unevaluated(main, [], Some(promoted[0])) // mir::Constant // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 // + literal: Const { ty: &[i32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } diff --git a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff index 81e6937b1b3..28c80b346e7 100644 --- a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff @@ -19,7 +19,7 @@ _3 = const FOO; // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:16 // ty::Const // + ty: &i32 - // + val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:5 ~ const_prop_fails_gracefully[317d]::main::FOO), const_param_did: None }, substs: [], promoted: None }) + // + val: Unevaluated(FOO, [], None) // mir::Constant // + span: $DIR/const_prop_fails_gracefully.rs:7:13: 7:16 // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:5 ~ const_prop_fails_gracefully[317d]::main::FOO), const_param_did: None }, substs: [], promoted: None }) } diff --git a/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff b/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff index 9126b9953ed..ae77443e019 100644 --- a/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff @@ -14,7 +14,7 @@ _4 = const main::promoted[0]; // scope 0 at $DIR/ref_deref.rs:5:6: 5:10 // ty::Const // + ty: &i32 - // + val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) + // + val: Unevaluated(main, [], Some(promoted[0])) // mir::Constant // + span: $DIR/ref_deref.rs:5:6: 5:10 // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } diff --git a/src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff b/src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff index e1c8085b31b..402a28f3f9f 100644 --- a/src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff +++ b/src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff @@ -17,7 +17,7 @@ + _4 = const main::promoted[0]; // scope 0 at $DIR/ref_deref.rs:5:6: 5:10 + // ty::Const + // + ty: &i32 -+ // + val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) ++ // + val: Unevaluated(main, [], Some(promoted[0])) + // mir::Constant + // + span: $DIR/ref_deref.rs:5:6: 5:10 + // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } diff --git a/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff b/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff index ce1720698c7..b97d7d1be15 100644 --- a/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff @@ -14,7 +14,7 @@ _4 = const main::promoted[0]; // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17 // ty::Const // + ty: &(i32, i32) - // + val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) + // + val: Unevaluated(main, [], Some(promoted[0])) // mir::Constant // + span: $DIR/ref_deref_project.rs:5:6: 5:17 // + literal: Const { ty: &(i32, i32), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } diff --git a/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff b/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff index 93ba9de8202..48ede27112c 100644 --- a/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff +++ b/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff @@ -17,7 +17,7 @@ + _4 = const main::promoted[0]; // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17 + // ty::Const + // + ty: &(i32, i32) -+ // + val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) ++ // + val: Unevaluated(main, [], Some(promoted[0])) + // mir::Constant + // + span: $DIR/ref_deref_project.rs:5:6: 5:17 + // + literal: Const { ty: &(i32, i32), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } diff --git a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff index 610e3c25573..27791852d6d 100644 --- a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff +++ b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff @@ -21,7 +21,7 @@ _9 = const main::promoted[0]; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 // ty::Const // + ty: &[u32; 3] - // + val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ slice_len[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) + // + val: Unevaluated(main, [], Some(promoted[0])) // mir::Constant // + span: $DIR/slice_len.rs:5:6: 5:19 // + literal: Const { ty: &[u32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ slice_len[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } diff --git a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff index 610e3c25573..27791852d6d 100644 --- a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff +++ b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff @@ -21,7 +21,7 @@ _9 = const main::promoted[0]; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 // ty::Const // + ty: &[u32; 3] - // + val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ slice_len[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) + // + val: Unevaluated(main, [], Some(promoted[0])) // mir::Constant // + span: $DIR/slice_len.rs:5:6: 5:19 // + literal: Const { ty: &[u32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ slice_len[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } diff --git a/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff b/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff index caa02abf019..3a50ed224b5 100644 --- a/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff +++ b/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff @@ -51,7 +51,7 @@ } bb2: { - discriminant(_6) = 2; // scope 1 at $DIR/funky_arms.rs:21:17: 21:41 + discriminant(_6) = 1; // scope 1 at $DIR/funky_arms.rs:21:17: 21:41 goto -> bb4; // scope 1 at $DIR/funky_arms.rs:19:16: 22:6 } diff --git a/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir b/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir index 0b5dc2b20fc..1aabee83be6 100644 --- a/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir @@ -35,7 +35,7 @@ fn bar() -> bool { _10 = const bar::promoted[1]; // scope 1 at $DIR/inline-retag.rs:12:7: 12:9 // ty::Const // + ty: &i32 - // + val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:4 ~ inline_retag[317d]::bar), const_param_did: None }, substs: [], promoted: Some(promoted[1]) }) + // + val: Unevaluated(bar, [], Some(promoted[1])) // mir::Constant // + span: $DIR/inline-retag.rs:12:7: 12:9 // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:4 ~ inline_retag[317d]::bar), const_param_did: None }, substs: [], promoted: Some(promoted[1]) }) } @@ -49,7 +49,7 @@ fn bar() -> bool { _9 = const bar::promoted[0]; // scope 1 at $DIR/inline-retag.rs:12:11: 12:14 // ty::Const // + ty: &i32 - // + val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:4 ~ inline_retag[317d]::bar), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) + // + val: Unevaluated(bar, [], Some(promoted[0])) // mir::Constant // + span: $DIR/inline-retag.rs:12:11: 12:14 // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:4 ~ inline_retag[317d]::bar), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } diff --git a/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff b/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff index 1ba56016776..95a8ef997fa 100644 --- a/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff +++ b/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff @@ -63,7 +63,7 @@ _20 = const main::promoted[0]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // ty::Const // + ty: &i32 - // + val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) + // + val: Unevaluated(main, [], Some(promoted[0])) // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } diff --git a/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff b/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff index 1ba56016776..95a8ef997fa 100644 --- a/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff +++ b/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff @@ -63,7 +63,7 @@ _20 = const main::promoted[0]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // ty::Const // + ty: &i32 - // + val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) + // + val: Unevaluated(main, [], Some(promoted[0])) // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } diff --git a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff index 245f0e9d000..261eb3b27ea 100644 --- a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff +++ b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff @@ -84,7 +84,7 @@ _28 = const main::promoted[0]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // ty::Const // + ty: &i32 - // + val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) + // + val: Unevaluated(main, [], Some(promoted[0])) // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } diff --git a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff index 245f0e9d000..261eb3b27ea 100644 --- a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff +++ b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff @@ -84,7 +84,7 @@ _28 = const main::promoted[0]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // ty::Const // + ty: &i32 - // + val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) + // + val: Unevaluated(main, [], Some(promoted[0])) // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } diff --git a/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff index 83650d837b0..a37df4da9ae 100644 --- a/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff +++ b/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff @@ -47,7 +47,7 @@ _19 = const discriminant::<T>::promoted[2]; // scope 0 at $DIR/lower_intrinsics.rs:70:42: 70:44 // ty::Const // + ty: &i32 - // + val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:27 ~ lower_intrinsics[8787]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[2]) }) + // + val: Unevaluated(discriminant, [T], Some(promoted[2])) // mir::Constant // + span: $DIR/lower_intrinsics.rs:70:42: 70:44 // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:27 ~ lower_intrinsics[8787]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[2]) }) } @@ -71,7 +71,7 @@ _18 = const discriminant::<T>::promoted[1]; // scope 0 at $DIR/lower_intrinsics.rs:71:42: 71:45 // ty::Const // + ty: &() - // + val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:27 ~ lower_intrinsics[8787]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[1]) }) + // + val: Unevaluated(discriminant, [T], Some(promoted[1])) // mir::Constant // + span: $DIR/lower_intrinsics.rs:71:42: 71:45 // + literal: Const { ty: &(), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:27 ~ lower_intrinsics[8787]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[1]) }) } @@ -95,7 +95,7 @@ _17 = const discriminant::<T>::promoted[0]; // scope 0 at $DIR/lower_intrinsics.rs:72:42: 72:47 // ty::Const // + ty: &E - // + val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:27 ~ lower_intrinsics[8787]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[0]) }) + // + val: Unevaluated(discriminant, [T], Some(promoted[0])) // mir::Constant // + span: $DIR/lower_intrinsics.rs:72:42: 72:47 // + literal: Const { ty: &E, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:27 ~ lower_intrinsics[8787]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[0]) }) } diff --git a/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir b/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir index 242138754c5..1921b935941 100644 --- a/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir +++ b/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir @@ -54,7 +54,7 @@ fn full_tested_match() -> () { _11 = const full_tested_match::promoted[0]; // scope 0 at $DIR/match_false_edges.rs:16:14: 16:15 // ty::Const // + ty: &std::option::Option<i32> - // + val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:5 ~ match_false_edges[317d]::full_tested_match), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) + // + val: Unevaluated(full_tested_match, [], Some(promoted[0])) // mir::Constant // + span: $DIR/match_false_edges.rs:16:14: 16:15 // + literal: Const { ty: &std::option::Option<i32>, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:5 ~ match_false_edges[317d]::full_tested_match), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } diff --git a/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir index d25f98db9f6..894f64c7767 100644 --- a/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir +++ b/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir @@ -149,7 +149,7 @@ fn main() -> () { _27 = const main::promoted[0]; // scope 7 at $DIR/retag.rs:47:21: 47:23 // ty::Const // + ty: &i32 - // + val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:13 ~ retag[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) + // + val: Unevaluated(main, [], Some(promoted[0])) // mir::Constant // + span: $DIR/retag.rs:47:21: 47:23 // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:13 ~ retag[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } diff --git a/src/test/run-make-fulldeps/coverage-llvmir/Makefile b/src/test/run-make-fulldeps/coverage-llvmir/Makefile index 86af7e41ae1..7d9121ee2f8 100644 --- a/src/test/run-make-fulldeps/coverage-llvmir/Makefile +++ b/src/test/run-make-fulldeps/coverage-llvmir/Makefile @@ -17,7 +17,7 @@ else COMDAT_IF_SUPPORTED=, comdat endif -DEFINE_INTERNAL=define hidden +DEFINE_INTERNAL=define internal ifdef IS_WINDOWS LLVM_FILECHECK_OPTIONS=\ diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generics.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generics.txt index 6f28c089093..7b38ffb87cb 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generics.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generics.txt @@ -29,12 +29,12 @@ 18| 2| println!("BOOM times {}!!!", self.strength); 19| 2| } ------------------ - | <generics::Firework<f64> as core::ops::drop::Drop>::drop: + | <generics::Firework<i32> as core::ops::drop::Drop>::drop: | 17| 1| fn drop(&mut self) { | 18| 1| println!("BOOM times {}!!!", self.strength); | 19| 1| } ------------------ - | <generics::Firework<i32> as core::ops::drop::Drop>::drop: + | <generics::Firework<f64> as core::ops::drop::Drop>::drop: | 17| 1| fn drop(&mut self) { | 18| 1| println!("BOOM times {}!!!", self.strength); | 19| 1| } diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt index 380869d62a8..cdcbd8fca94 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt @@ -36,12 +36,12 @@ 22| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); 23| 2|} ------------------ - | used_crate::used_only_from_this_lib_crate_generic_function::<alloc::vec::Vec<i32>>: + | used_crate::used_only_from_this_lib_crate_generic_function::<&str>: | 21| 1|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) { | 22| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); | 23| 1|} ------------------ - | used_crate::used_only_from_this_lib_crate_generic_function::<&str>: + | used_crate::used_only_from_this_lib_crate_generic_function::<alloc::vec::Vec<i32>>: | 21| 1|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) { | 22| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); | 23| 1|} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_inline_crate.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_inline_crate.txt index 0853dc9c014..cc98956e307 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_inline_crate.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_inline_crate.txt @@ -30,29 +30,12 @@ ^0 29| 1| use_this_lib_crate(); 30| 1|} - ------------------ - | used_inline_crate::used_inline_function: - | 20| 1|pub fn used_inline_function() { - | 21| | // Initialize test constants in a way that cannot be determined at compile time, to ensure - | 22| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - | 23| | // dependent conditions. - | 24| 1| let is_true = std::env::args().len() == 1; - | 25| 1| let mut countdown = 0; - | 26| 1| if is_true { - | 27| 1| countdown = 10; - | 28| 1| } - | ^0 - | 29| 1| use_this_lib_crate(); - | 30| 1|} - ------------------ - | Unexecuted instantiation: used_inline_crate::used_inline_function - ------------------ - 31| |// Expect for above function: - 32| |// - 33| |// | Unexecuted instantiation: used_crate::used_only_from_bin_crate_generic_function::<_> - 34| |// - 35| |// With `#[inline(always)]` this function is instantiated twice, in both the library crate (which - 36| |// does not use it) and the `uses_inline_crate` binary (which does use/call it). + 31| | + 32| | + 33| | + 34| | + 35| | + 36| | 37| | 38| |#[inline(always)] 39| 2|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) { diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.conditions/conditions.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.conditions/conditions.main.-------.InstrumentCoverage.0.html index 0aa6fe65686..3d1b737ec2d 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.conditions/conditions.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.conditions/conditions.main.-------.InstrumentCoverage.0.html @@ -83,7 +83,7 @@ For revisions in Pull Requests (PR): 5:13-7:6: @1[1]: _2 = const ()"> }<span class="annotation">⦉@1</span></span></span><span><span class="code even" style="--layer: 1" title="7:6-7:6: @2[0]: _2 = const ()"><span class="annotation">@2⦊</span>‸<span class="annotation">⦉@2</span></span></span><span class="code" style="--layer: 0"></span></span> <span class="line"><span class="code" style="--layer: 0"></span></span> <span class="line"><span class="code" style="--layer: 0"> const B: u32 = 100;</span></span> -<span class="line"><span class="code" style="--layer: 0"> let </span><span><span class="code odd" style="--layer: 1" title="10:9-10:10: @21[1]: FakeRead(ForLet, _4)"><span class="annotation">@21⦊</span>x<span class="annotation">⦉@21</span></span></span><span class="code" style="--layer: 0"> = if </span><span><span class="code even" style="--layer: 1" title="10:16-10:25: @3[5]: _6 = _1 +<span class="line"><span class="code" style="--layer: 0"> let </span><span><span class="code odd" style="--layer: 1" title="10:9-10:10: @19[1]: FakeRead(ForLet, _4)"><span class="annotation">@19⦊</span>x<span class="annotation">⦉@19</span></span></span><span class="code" style="--layer: 0"> = if </span><span><span class="code even" style="--layer: 1" title="10:16-10:25: @3[5]: _6 = _1 10:16-10:29: @3[6]: _5 = Gt(move _6, const 7_u32)"><span class="annotation">@3⦊</span>countdown > 7<span class="annotation">⦉@3</span></span></span><span class="code" style="--layer: 0"> {</span></span> <span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="11:9-11:23: @4[0]: _7 = CheckedSub(_1, const 4_u32) 11:9-11:23: @6[0]: _1 = move (_7.0: u32) @@ -94,214 +94,214 @@ For revisions in Pull Requests (PR): <span class="line"><span class="code" style="--layer: 0"> } else if </span><span><span class="code even" style="--layer: 1" title="13:15-13:24: @5[2]: _9 = _1 13:15-13:28: @5[3]: _8 = Gt(move _9, const 2_u32)"><span class="annotation">@5⦊</span>countdown > 2<span class="annotation">⦉@5</span></span></span><span class="code" style="--layer: 0"> {</span></span> <span class="line"><span class="code" style="--layer: 0"> if </span><span><span class="code odd" style="--layer: 1" title="14:12-14:21: @7[5]: _14 = _1 -14:12-14:25: @7[6]: _13 = Lt(move _14, const 1_u32)"><span class="annotation">@7⦊</span>countdown < 1<span class="annotation">⦉@7</span></span></span><span class="code" style="--layer: 0"> || </span><span><span class="code even" style="--layer: 1" title="14:29-14:38: @15[2]: _16 = _1 -14:29-14:42: @15[3]: _15 = Gt(move _16, const 5_u32)"><span class="annotation">@15⦊</span>countdown > 5<span class="annotation">⦉@15</span></span></span><span class="code" style="--layer: 0"> || </span><span><span class="code odd" style="--layer: 1" title="14:46-14:55: @11[2]: _18 = _1 -14:46-14:60: @11[3]: _17 = Ne(move _18, const 9_u32)"><span class="annotation">@11⦊</span>countdown != 9<span class="annotation">⦉@11</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="15:13-15:26: @17[0]: _1 = const 0_u32 -14:61-16:10: @17[1]: _10 = const ()"><span class="annotation">@17⦊</span>{</span></span> -<span class="line"><span class="code even" style="--layer: 1" title="15:13-15:26: @17[0]: _1 = const 0_u32 -14:61-16:10: @17[1]: _10 = const ()"> countdown = 0;</span></span> -<span class="line"><span class="code even" style="--layer: 1" title="15:13-15:26: @17[0]: _1 = const 0_u32 -14:61-16:10: @17[1]: _10 = const ()"> }<span class="annotation">⦉@17</span></span></span><span><span class="code odd" style="--layer: 1" title="16:10-16:10: @18[0]: _10 = const ()"><span class="annotation">@18⦊</span>‸<span class="annotation">⦉@18</span></span></span><span class="code" style="--layer: 0"></span></span> -<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="17:9-17:23: @19[2]: _19 = CheckedSub(_1, const 5_u32) -17:9-17:23: @20[0]: _1 = move (_19.0: u32) -18:9-18:18: @20[1]: _4 = _1"><span class="annotation">@19,20⦊</span>countdown -= 5;</span></span> -<span class="line"><span class="code even" style="--layer: 1" title="17:9-17:23: @19[2]: _19 = CheckedSub(_1, const 5_u32) -17:9-17:23: @20[0]: _1 = move (_19.0: u32) -18:9-18:18: @20[1]: _4 = _1"> countdown<span class="annotation">⦉@19,20</span></span></span><span class="code" style="--layer: 0"></span></span> +14:12-14:25: @7[6]: _13 = Lt(move _14, const 1_u32)"><span class="annotation">@7⦊</span>countdown < 1<span class="annotation">⦉@7</span></span></span><span class="code" style="--layer: 0"> || </span><span><span class="code even" style="--layer: 1" title="14:29-14:38: @13[2]: _16 = _1 +14:29-14:42: @13[3]: _15 = Gt(move _16, const 5_u32)"><span class="annotation">@13⦊</span>countdown > 5<span class="annotation">⦉@13</span></span></span><span class="code" style="--layer: 0"> || </span><span><span class="code odd" style="--layer: 1" title="14:46-14:55: @10[2]: _18 = _1 +14:46-14:60: @10[3]: _17 = Ne(move _18, const 9_u32)"><span class="annotation">@10⦊</span>countdown != 9<span class="annotation">⦉@10</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="15:13-15:26: @15[0]: _1 = const 0_u32 +14:61-16:10: @15[1]: _10 = const ()"><span class="annotation">@15⦊</span>{</span></span> +<span class="line"><span class="code even" style="--layer: 1" title="15:13-15:26: @15[0]: _1 = const 0_u32 +14:61-16:10: @15[1]: _10 = const ()"> countdown = 0;</span></span> +<span class="line"><span class="code even" style="--layer: 1" title="15:13-15:26: @15[0]: _1 = const 0_u32 +14:61-16:10: @15[1]: _10 = const ()"> }<span class="annotation">⦉@15</span></span></span><span><span class="code odd" style="--layer: 1" title="16:10-16:10: @16[0]: _10 = const ()"><span class="annotation">@16⦊</span>‸<span class="annotation">⦉@16</span></span></span><span class="code" style="--layer: 0"></span></span> +<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="17:9-17:23: @17[2]: _19 = CheckedSub(_1, const 5_u32) +17:9-17:23: @18[0]: _1 = move (_19.0: u32) +18:9-18:18: @18[1]: _4 = _1"><span class="annotation">@17,18⦊</span>countdown -= 5;</span></span> +<span class="line"><span class="code even" style="--layer: 1" title="17:9-17:23: @17[2]: _19 = CheckedSub(_1, const 5_u32) +17:9-17:23: @18[0]: _1 = move (_19.0: u32) +18:9-18:18: @18[1]: _4 = _1"> countdown<span class="annotation">⦉@17,18</span></span></span><span class="code" style="--layer: 0"></span></span> <span class="line"><span class="code" style="--layer: 0"> } else {</span></span> <span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="20:9-20:15: @8[0]: _0 = const ()"><span class="annotation">@8⦊</span>return<span class="annotation">⦉@8</span></span></span><span class="code" style="--layer: 0">;</span></span> <span class="line"><span class="code" style="--layer: 0"> };</span></span> <span class="line"><span class="code" style="--layer: 0"></span></span> -<span class="line"><span class="code" style="--layer: 0"> let </span><span><span class="code even" style="--layer: 1" title="23:25-23:26: @21[3]: _21 = const 0_i32 -23:9-23:22: @21[4]: FakeRead(ForLet, _21) -24:8-24:12: @21[7]: _23 = const true"><span class="annotation">@21⦊</span>mut countdown = 0;</span></span> -<span class="line"><span class="code even" style="--layer: 1" title="23:25-23:26: @21[3]: _21 = const 0_i32 -23:9-23:22: @21[4]: FakeRead(ForLet, _21) -24:8-24:12: @21[7]: _23 = const true"> if true<span class="annotation">⦉@21</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="25:9-25:23: @22[0]: _21 = const 10_i32 -24:13-26:6: @22[1]: _22 = const ()"><span class="annotation">@22⦊</span>{</span></span> -<span class="line"><span class="code odd" style="--layer: 1" title="25:9-25:23: @22[0]: _21 = const 10_i32 -24:13-26:6: @22[1]: _22 = const ()"> countdown = 10;</span></span> -<span class="line"><span class="code odd" style="--layer: 1" title="25:9-25:23: @22[0]: _21 = const 10_i32 -24:13-26:6: @22[1]: _22 = const ()"> }<span class="annotation">⦉@22</span></span></span><span><span class="code even" style="--layer: 1" title="26:6-26:6: @23[0]: _22 = const ()"><span class="annotation">@23⦊</span>‸<span class="annotation">⦉@23</span></span></span><span class="code" style="--layer: 0"></span></span> +<span class="line"><span class="code" style="--layer: 0"> let </span><span><span class="code even" style="--layer: 1" title="23:25-23:26: @19[3]: _21 = const 0_i32 +23:9-23:22: @19[4]: FakeRead(ForLet, _21) +24:8-24:12: @19[7]: _23 = const true"><span class="annotation">@19⦊</span>mut countdown = 0;</span></span> +<span class="line"><span class="code even" style="--layer: 1" title="23:25-23:26: @19[3]: _21 = const 0_i32 +23:9-23:22: @19[4]: FakeRead(ForLet, _21) +24:8-24:12: @19[7]: _23 = const true"> if true<span class="annotation">⦉@19</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="25:9-25:23: @20[0]: _21 = const 10_i32 +24:13-26:6: @20[1]: _22 = const ()"><span class="annotation">@20⦊</span>{</span></span> +<span class="line"><span class="code odd" style="--layer: 1" title="25:9-25:23: @20[0]: _21 = const 10_i32 +24:13-26:6: @20[1]: _22 = const ()"> countdown = 10;</span></span> +<span class="line"><span class="code odd" style="--layer: 1" title="25:9-25:23: @20[0]: _21 = const 10_i32 +24:13-26:6: @20[1]: _22 = const ()"> }<span class="annotation">⦉@20</span></span></span><span><span class="code even" style="--layer: 1" title="26:6-26:6: @21[0]: _22 = const ()"><span class="annotation">@21⦊</span>‸<span class="annotation">⦉@21</span></span></span><span class="code" style="--layer: 0"></span></span> <span class="line"><span class="code" style="--layer: 0"></span></span> -<span class="line"><span class="code" style="--layer: 0"> if </span><span><span class="code odd" style="--layer: 1" title="28:8-28:17: @24[5]: _26 = _21 -28:8-28:21: @24[6]: _25 = Gt(move _26, const 7_i32)"><span class="annotation">@24⦊</span>countdown > 7<span class="annotation">⦉@24</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="29:9-29:23: @25[0]: _27 = CheckedSub(_21, const 4_i32) -29:9-29:23: @27[0]: _21 = move (_27.0: i32) -28:22-30:6: @27[1]: _24 = const ()"><span class="annotation">@25,27⦊</span>{</span></span> -<span class="line"><span class="code even" style="--layer: 1" title="29:9-29:23: @25[0]: _27 = CheckedSub(_21, const 4_i32) -29:9-29:23: @27[0]: _21 = move (_27.0: i32) -28:22-30:6: @27[1]: _24 = const ()"> countdown -= 4;</span></span> -<span class="line"><span class="code even" style="--layer: 1" title="29:9-29:23: @25[0]: _27 = CheckedSub(_21, const 4_i32) -29:9-29:23: @27[0]: _21 = move (_27.0: i32) -28:22-30:6: @27[1]: _24 = const ()"> }<span class="annotation">⦉@25,27</span></span></span><span class="code" style="--layer: 0"> else if </span><span><span class="code odd" style="--layer: 1" title="30:15-30:24: @26[2]: _29 = _21 -30:15-30:28: @26[3]: _28 = Gt(move _29, const 2_i32)"><span class="annotation">@26⦊</span>countdown > 2<span class="annotation">⦉@26</span></span></span><span class="code" style="--layer: 0"> {</span></span> -<span class="line"><span class="code" style="--layer: 0"> if </span><span><span class="code even" style="--layer: 1" title="31:12-31:21: @28[5]: _34 = _21 -31:12-31:25: @28[6]: _33 = Lt(move _34, const 1_i32)"><span class="annotation">@28⦊</span>countdown < 1<span class="annotation">⦉@28</span></span></span><span class="code" style="--layer: 0"> || </span><span><span class="code odd" style="--layer: 1" title="31:29-31:38: @36[2]: _36 = _21 -31:29-31:42: @36[3]: _35 = Gt(move _36, const 5_i32)"><span class="annotation">@36⦊</span>countdown > 5<span class="annotation">⦉@36</span></span></span><span class="code" style="--layer: 0"> || </span><span><span class="code even" style="--layer: 1" title="31:46-31:55: @32[2]: _38 = _21 -31:46-31:60: @32[3]: _37 = Ne(move _38, const 9_i32)"><span class="annotation">@32⦊</span>countdown != 9<span class="annotation">⦉@32</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="32:13-32:26: @38[0]: _21 = const 0_i32 -31:61-33:10: @38[1]: _30 = const ()"><span class="annotation">@38⦊</span>{</span></span> -<span class="line"><span class="code odd" style="--layer: 1" title="32:13-32:26: @38[0]: _21 = const 0_i32 -31:61-33:10: @38[1]: _30 = const ()"> countdown = 0;</span></span> -<span class="line"><span class="code odd" style="--layer: 1" title="32:13-32:26: @38[0]: _21 = const 0_i32 -31:61-33:10: @38[1]: _30 = const ()"> }<span class="annotation">⦉@38</span></span></span><span><span class="code even" style="--layer: 1" title="33:10-33:10: @39[0]: _30 = const ()"><span class="annotation">@39⦊</span>‸<span class="annotation">⦉@39</span></span></span><span class="code" style="--layer: 0"></span></span> -<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="34:9-34:23: @40[2]: _39 = CheckedSub(_21, const 5_i32) -34:9-34:23: @41[0]: _21 = move (_39.0: i32)"><span class="annotation">@40,41⦊</span>countdown -= 5<span class="annotation">⦉@40,41</span></span></span><span class="code" style="--layer: 0">;</span></span> +<span class="line"><span class="code" style="--layer: 0"> if </span><span><span class="code odd" style="--layer: 1" title="28:8-28:17: @22[5]: _26 = _21 +28:8-28:21: @22[6]: _25 = Gt(move _26, const 7_i32)"><span class="annotation">@22⦊</span>countdown > 7<span class="annotation">⦉@22</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="29:9-29:23: @23[0]: _27 = CheckedSub(_21, const 4_i32) +29:9-29:23: @25[0]: _21 = move (_27.0: i32) +28:22-30:6: @25[1]: _24 = const ()"><span class="annotation">@23,25⦊</span>{</span></span> +<span class="line"><span class="code even" style="--layer: 1" title="29:9-29:23: @23[0]: _27 = CheckedSub(_21, const 4_i32) +29:9-29:23: @25[0]: _21 = move (_27.0: i32) +28:22-30:6: @25[1]: _24 = const ()"> countdown -= 4;</span></span> +<span class="line"><span class="code even" style="--layer: 1" title="29:9-29:23: @23[0]: _27 = CheckedSub(_21, const 4_i32) +29:9-29:23: @25[0]: _21 = move (_27.0: i32) +28:22-30:6: @25[1]: _24 = const ()"> }<span class="annotation">⦉@23,25</span></span></span><span class="code" style="--layer: 0"> else if </span><span><span class="code odd" style="--layer: 1" title="30:15-30:24: @24[2]: _29 = _21 +30:15-30:28: @24[3]: _28 = Gt(move _29, const 2_i32)"><span class="annotation">@24⦊</span>countdown > 2<span class="annotation">⦉@24</span></span></span><span class="code" style="--layer: 0"> {</span></span> +<span class="line"><span class="code" style="--layer: 0"> if </span><span><span class="code even" style="--layer: 1" title="31:12-31:21: @26[5]: _34 = _21 +31:12-31:25: @26[6]: _33 = Lt(move _34, const 1_i32)"><span class="annotation">@26⦊</span>countdown < 1<span class="annotation">⦉@26</span></span></span><span class="code" style="--layer: 0"> || </span><span><span class="code odd" style="--layer: 1" title="31:29-31:38: @32[2]: _36 = _21 +31:29-31:42: @32[3]: _35 = Gt(move _36, const 5_i32)"><span class="annotation">@32⦊</span>countdown > 5<span class="annotation">⦉@32</span></span></span><span class="code" style="--layer: 0"> || </span><span><span class="code even" style="--layer: 1" title="31:46-31:55: @29[2]: _38 = _21 +31:46-31:60: @29[3]: _37 = Ne(move _38, const 9_i32)"><span class="annotation">@29⦊</span>countdown != 9<span class="annotation">⦉@29</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="32:13-32:26: @34[0]: _21 = const 0_i32 +31:61-33:10: @34[1]: _30 = const ()"><span class="annotation">@34⦊</span>{</span></span> +<span class="line"><span class="code odd" style="--layer: 1" title="32:13-32:26: @34[0]: _21 = const 0_i32 +31:61-33:10: @34[1]: _30 = const ()"> countdown = 0;</span></span> +<span class="line"><span class="code odd" style="--layer: 1" title="32:13-32:26: @34[0]: _21 = const 0_i32 +31:61-33:10: @34[1]: _30 = const ()"> }<span class="annotation">⦉@34</span></span></span><span><span class="code even" style="--layer: 1" title="33:10-33:10: @35[0]: _30 = const ()"><span class="annotation">@35⦊</span>‸<span class="annotation">⦉@35</span></span></span><span class="code" style="--layer: 0"></span></span> +<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="34:9-34:23: @36[2]: _39 = CheckedSub(_21, const 5_i32) +34:9-34:23: @37[0]: _21 = move (_39.0: i32)"><span class="annotation">@36,37⦊</span>countdown -= 5<span class="annotation">⦉@36,37</span></span></span><span class="code" style="--layer: 0">;</span></span> <span class="line"><span class="code" style="--layer: 0"> } else {</span></span> -<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="36:9-36:15: @29[0]: _0 = const ()"><span class="annotation">@29⦊</span>return<span class="annotation">⦉@29</span></span></span><span class="code" style="--layer: 0">;</span></span> +<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="36:9-36:15: @27[0]: _0 = const ()"><span class="annotation">@27⦊</span>return<span class="annotation">⦉@27</span></span></span><span class="code" style="--layer: 0">;</span></span> <span class="line"><span class="code" style="--layer: 0"> }</span></span> <span class="line"><span class="code" style="--layer: 0"></span></span> -<span class="line"><span class="code" style="--layer: 0"> if </span><span><span class="code odd" style="--layer: 1" title="39:8-39:12: @42[4]: _42 = const true"><span class="annotation">@42⦊</span>true<span class="annotation">⦉@42</span></span></span><span class="code" style="--layer: 0"> {</span></span> -<span class="line"><span class="code" style="--layer: 0"> let </span><span><span class="code even" style="--layer: 1" title="40:29-40:30: @43[1]: _43 = const 0_i32 -40:13-40:26: @43[2]: FakeRead(ForLet, _43) -41:12-41:16: @43[5]: _45 = const true"><span class="annotation">@43⦊</span>mut countdown = 0;</span></span> -<span class="line"><span class="code even" style="--layer: 1" title="40:29-40:30: @43[1]: _43 = const 0_i32 -40:13-40:26: @43[2]: FakeRead(ForLet, _43) -41:12-41:16: @43[5]: _45 = const true"> if true<span class="annotation">⦉@43</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="42:13-42:27: @45[0]: _43 = const 10_i32 -41:17-43:10: @45[1]: _44 = const ()"><span class="annotation">@45⦊</span>{</span></span> -<span class="line"><span class="code odd" style="--layer: 1" title="42:13-42:27: @45[0]: _43 = const 10_i32 -41:17-43:10: @45[1]: _44 = const ()"> countdown = 10;</span></span> -<span class="line"><span class="code odd" style="--layer: 1" title="42:13-42:27: @45[0]: _43 = const 10_i32 -41:17-43:10: @45[1]: _44 = const ()"> }<span class="annotation">⦉@45</span></span></span><span><span class="code even" style="--layer: 1" title="43:10-43:10: @46[0]: _44 = const ()"><span class="annotation">@46⦊</span>‸<span class="annotation">⦉@46</span></span></span><span class="code" style="--layer: 0"></span></span> +<span class="line"><span class="code" style="--layer: 0"> if </span><span><span class="code odd" style="--layer: 1" title="39:8-39:12: @38[4]: _42 = const true"><span class="annotation">@38⦊</span>true<span class="annotation">⦉@38</span></span></span><span class="code" style="--layer: 0"> {</span></span> +<span class="line"><span class="code" style="--layer: 0"> let </span><span><span class="code even" style="--layer: 1" title="40:29-40:30: @39[1]: _43 = const 0_i32 +40:13-40:26: @39[2]: FakeRead(ForLet, _43) +41:12-41:16: @39[5]: _45 = const true"><span class="annotation">@39⦊</span>mut countdown = 0;</span></span> +<span class="line"><span class="code even" style="--layer: 1" title="40:29-40:30: @39[1]: _43 = const 0_i32 +40:13-40:26: @39[2]: FakeRead(ForLet, _43) +41:12-41:16: @39[5]: _45 = const true"> if true<span class="annotation">⦉@39</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="42:13-42:27: @41[0]: _43 = const 10_i32 +41:17-43:10: @41[1]: _44 = const ()"><span class="annotation">@41⦊</span>{</span></span> +<span class="line"><span class="code odd" style="--layer: 1" title="42:13-42:27: @41[0]: _43 = const 10_i32 +41:17-43:10: @41[1]: _44 = const ()"> countdown = 10;</span></span> +<span class="line"><span class="code odd" style="--layer: 1" title="42:13-42:27: @41[0]: _43 = const 10_i32 +41:17-43:10: @41[1]: _44 = const ()"> }<span class="annotation">⦉@41</span></span></span><span><span class="code even" style="--layer: 1" title="43:10-43:10: @42[0]: _44 = const ()"><span class="annotation">@42⦊</span>‸<span class="annotation">⦉@42</span></span></span><span class="code" style="--layer: 0"></span></span> <span class="line"><span class="code" style="--layer: 0"></span></span> -<span class="line"><span class="code" style="--layer: 0"> if </span><span><span class="code odd" style="--layer: 1" title="45:12-45:21: @47[4]: _47 = _43 -45:12-45:25: @47[5]: _46 = Gt(move _47, const 7_i32)"><span class="annotation">@47⦊</span>countdown > 7<span class="annotation">⦉@47</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="46:13-46:27: @48[0]: _48 = CheckedSub(_43, const 4_i32) -46:13-46:27: @50[0]: _43 = move (_48.0: i32) -45:26-47:10: @50[1]: _41 = const ()"><span class="annotation">@48,50⦊</span>{</span></span> -<span class="line"><span class="code even" style="--layer: 1" title="46:13-46:27: @48[0]: _48 = CheckedSub(_43, const 4_i32) -46:13-46:27: @50[0]: _43 = move (_48.0: i32) -45:26-47:10: @50[1]: _41 = const ()"> countdown -= 4;</span></span> -<span class="line"><span class="code even" style="--layer: 1" title="46:13-46:27: @48[0]: _48 = CheckedSub(_43, const 4_i32) -46:13-46:27: @50[0]: _43 = move (_48.0: i32) -45:26-47:10: @50[1]: _41 = const ()"> }<span class="annotation">⦉@48,50</span></span></span><span class="code" style="--layer: 0"></span></span> -<span class="line"><span class="code" style="--layer: 0"> else if </span><span><span class="code odd" style="--layer: 1" title="48:17-48:26: @49[2]: _50 = _43 -48:17-48:30: @49[3]: _49 = Gt(move _50, const 2_i32)"><span class="annotation">@49⦊</span>countdown > 2<span class="annotation">⦉@49</span></span></span><span class="code" style="--layer: 0"> {</span></span> -<span class="line"><span class="code" style="--layer: 0"> if </span><span><span class="code even" style="--layer: 1" title="49:16-49:25: @51[5]: _55 = _43 -49:16-49:29: @51[6]: _54 = Lt(move _55, const 1_i32)"><span class="annotation">@51⦊</span>countdown < 1<span class="annotation">⦉@51</span></span></span><span class="code" style="--layer: 0"> || </span><span><span class="code odd" style="--layer: 1" title="49:33-49:42: @59[2]: _57 = _43 -49:33-49:46: @59[3]: _56 = Gt(move _57, const 5_i32)"><span class="annotation">@59⦊</span>countdown > 5<span class="annotation">⦉@59</span></span></span><span class="code" style="--layer: 0"> || </span><span><span class="code even" style="--layer: 1" title="49:50-49:59: @55[2]: _59 = _43 -49:50-49:64: @55[3]: _58 = Ne(move _59, const 9_i32)"><span class="annotation">@55⦊</span>countdown != 9<span class="annotation">⦉@55</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="50:17-50:30: @61[0]: _43 = const 0_i32 -49:65-51:14: @61[1]: _51 = const ()"><span class="annotation">@61⦊</span>{</span></span> -<span class="line"><span class="code odd" style="--layer: 1" title="50:17-50:30: @61[0]: _43 = const 0_i32 -49:65-51:14: @61[1]: _51 = const ()"> countdown = 0;</span></span> -<span class="line"><span class="code odd" style="--layer: 1" title="50:17-50:30: @61[0]: _43 = const 0_i32 -49:65-51:14: @61[1]: _51 = const ()"> }<span class="annotation">⦉@61</span></span></span><span><span class="code even" style="--layer: 1" title="51:14-51:14: @62[0]: _51 = const ()"><span class="annotation">@62⦊</span>‸<span class="annotation">⦉@62</span></span></span><span class="code" style="--layer: 0"></span></span> -<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="52:13-52:27: @63[2]: _60 = CheckedSub(_43, const 5_i32) -52:13-52:27: @64[0]: _43 = move (_60.0: i32)"><span class="annotation">@63,64⦊</span>countdown -= 5<span class="annotation">⦉@63,64</span></span></span><span class="code" style="--layer: 0">;</span></span> +<span class="line"><span class="code" style="--layer: 0"> if </span><span><span class="code odd" style="--layer: 1" title="45:12-45:21: @43[4]: _47 = _43 +45:12-45:25: @43[5]: _46 = Gt(move _47, const 7_i32)"><span class="annotation">@43⦊</span>countdown > 7<span class="annotation">⦉@43</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="46:13-46:27: @44[0]: _48 = CheckedSub(_43, const 4_i32) +46:13-46:27: @46[0]: _43 = move (_48.0: i32) +45:26-47:10: @46[1]: _41 = const ()"><span class="annotation">@44,46⦊</span>{</span></span> +<span class="line"><span class="code even" style="--layer: 1" title="46:13-46:27: @44[0]: _48 = CheckedSub(_43, const 4_i32) +46:13-46:27: @46[0]: _43 = move (_48.0: i32) +45:26-47:10: @46[1]: _41 = const ()"> countdown -= 4;</span></span> +<span class="line"><span class="code even" style="--layer: 1" title="46:13-46:27: @44[0]: _48 = CheckedSub(_43, const 4_i32) +46:13-46:27: @46[0]: _43 = move (_48.0: i32) +45:26-47:10: @46[1]: _41 = const ()"> }<span class="annotation">⦉@44,46</span></span></span><span class="code" style="--layer: 0"></span></span> +<span class="line"><span class="code" style="--layer: 0"> else if </span><span><span class="code odd" style="--layer: 1" title="48:17-48:26: @45[2]: _50 = _43 +48:17-48:30: @45[3]: _49 = Gt(move _50, const 2_i32)"><span class="annotation">@45⦊</span>countdown > 2<span class="annotation">⦉@45</span></span></span><span class="code" style="--layer: 0"> {</span></span> +<span class="line"><span class="code" style="--layer: 0"> if </span><span><span class="code even" style="--layer: 1" title="49:16-49:25: @47[5]: _55 = _43 +49:16-49:29: @47[6]: _54 = Lt(move _55, const 1_i32)"><span class="annotation">@47⦊</span>countdown < 1<span class="annotation">⦉@47</span></span></span><span class="code" style="--layer: 0"> || </span><span><span class="code odd" style="--layer: 1" title="49:33-49:42: @53[2]: _57 = _43 +49:33-49:46: @53[3]: _56 = Gt(move _57, const 5_i32)"><span class="annotation">@53⦊</span>countdown > 5<span class="annotation">⦉@53</span></span></span><span class="code" style="--layer: 0"> || </span><span><span class="code even" style="--layer: 1" title="49:50-49:59: @50[2]: _59 = _43 +49:50-49:64: @50[3]: _58 = Ne(move _59, const 9_i32)"><span class="annotation">@50⦊</span>countdown != 9<span class="annotation">⦉@50</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="50:17-50:30: @55[0]: _43 = const 0_i32 +49:65-51:14: @55[1]: _51 = const ()"><span class="annotation">@55⦊</span>{</span></span> +<span class="line"><span class="code odd" style="--layer: 1" title="50:17-50:30: @55[0]: _43 = const 0_i32 +49:65-51:14: @55[1]: _51 = const ()"> countdown = 0;</span></span> +<span class="line"><span class="code odd" style="--layer: 1" title="50:17-50:30: @55[0]: _43 = const 0_i32 +49:65-51:14: @55[1]: _51 = const ()"> }<span class="annotation">⦉@55</span></span></span><span><span class="code even" style="--layer: 1" title="51:14-51:14: @56[0]: _51 = const ()"><span class="annotation">@56⦊</span>‸<span class="annotation">⦉@56</span></span></span><span class="code" style="--layer: 0"></span></span> +<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="52:13-52:27: @57[2]: _60 = CheckedSub(_43, const 5_i32) +52:13-52:27: @58[0]: _43 = move (_60.0: i32)"><span class="annotation">@57,58⦊</span>countdown -= 5<span class="annotation">⦉@57,58</span></span></span><span class="code" style="--layer: 0">;</span></span> <span class="line"><span class="code" style="--layer: 0"> } else {</span></span> -<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="54:13-54:19: @52[0]: _0 = const ()"><span class="annotation">@52⦊</span>return<span class="annotation">⦉@52</span></span></span><span class="code" style="--layer: 0">;</span></span> +<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="54:13-54:19: @48[0]: _0 = const ()"><span class="annotation">@48⦊</span>return<span class="annotation">⦉@48</span></span></span><span class="code" style="--layer: 0">;</span></span> <span class="line"><span class="code" style="--layer: 0"> }</span></span> -<span class="line"><span class="code" style="--layer: 0"> }</span><span><span class="code odd" style="--layer: 1" title="56:6-56:6: @44[0]: _41 = const ()"><span class="annotation">@44⦊</span>‸<span class="annotation">⦉@44</span></span></span><span class="code" style="--layer: 0"> // Note: closing brace shows uncovered (vs. `0` for implicit else) because condition literal</span></span> +<span class="line"><span class="code" style="--layer: 0"> }</span><span><span class="code odd" style="--layer: 1" title="56:6-56:6: @40[0]: _41 = const ()"><span class="annotation">@40⦊</span>‸<span class="annotation">⦉@40</span></span></span><span class="code" style="--layer: 0"> // Note: closing brace shows uncovered (vs. `0` for implicit else) because condition literal</span></span> <span class="line"><span class="code" style="--layer: 0"> // `true` was const-evaluated. The compiler knows the `if` block will be executed.</span></span> <span class="line"><span class="code" style="--layer: 0"></span></span> -<span class="line"><span class="code" style="--layer: 0"> let </span><span><span class="code even" style="--layer: 1" title="59:25-59:26: @66[3]: _62 = const 0_i32 -59:9-59:22: @66[4]: FakeRead(ForLet, _62) -60:8-60:12: @66[7]: _64 = const true"><span class="annotation">@66⦊</span>mut countdown = 0;</span></span> -<span class="line"><span class="code even" style="--layer: 1" title="59:25-59:26: @66[3]: _62 = const 0_i32 -59:9-59:22: @66[4]: FakeRead(ForLet, _62) -60:8-60:12: @66[7]: _64 = const true"> if true<span class="annotation">⦉@66</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="61:9-61:22: @67[0]: _62 = const 1_i32 -60:13-62:6: @67[1]: _63 = const ()"><span class="annotation">@67⦊</span>{</span></span> -<span class="line"><span class="code odd" style="--layer: 1" title="61:9-61:22: @67[0]: _62 = const 1_i32 -60:13-62:6: @67[1]: _63 = const ()"> countdown = 1;</span></span> -<span class="line"><span class="code odd" style="--layer: 1" title="61:9-61:22: @67[0]: _62 = const 1_i32 -60:13-62:6: @67[1]: _63 = const ()"> }<span class="annotation">⦉@67</span></span></span><span><span class="code even" style="--layer: 1" title="62:6-62:6: @68[0]: _63 = const ()"><span class="annotation">@68⦊</span>‸<span class="annotation">⦉@68</span></span></span><span class="code" style="--layer: 0"></span></span> +<span class="line"><span class="code" style="--layer: 0"> let </span><span><span class="code even" style="--layer: 1" title="59:25-59:26: @60[3]: _62 = const 0_i32 +59:9-59:22: @60[4]: FakeRead(ForLet, _62) +60:8-60:12: @60[7]: _64 = const true"><span class="annotation">@60⦊</span>mut countdown = 0;</span></span> +<span class="line"><span class="code even" style="--layer: 1" title="59:25-59:26: @60[3]: _62 = const 0_i32 +59:9-59:22: @60[4]: FakeRead(ForLet, _62) +60:8-60:12: @60[7]: _64 = const true"> if true<span class="annotation">⦉@60</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="61:9-61:22: @61[0]: _62 = const 1_i32 +60:13-62:6: @61[1]: _63 = const ()"><span class="annotation">@61⦊</span>{</span></span> +<span class="line"><span class="code odd" style="--layer: 1" title="61:9-61:22: @61[0]: _62 = const 1_i32 +60:13-62:6: @61[1]: _63 = const ()"> countdown = 1;</span></span> +<span class="line"><span class="code odd" style="--layer: 1" title="61:9-61:22: @61[0]: _62 = const 1_i32 +60:13-62:6: @61[1]: _63 = const ()"> }<span class="annotation">⦉@61</span></span></span><span><span class="code even" style="--layer: 1" title="62:6-62:6: @62[0]: _63 = const ()"><span class="annotation">@62⦊</span>‸<span class="annotation">⦉@62</span></span></span><span class="code" style="--layer: 0"></span></span> <span class="line"><span class="code" style="--layer: 0"></span></span> -<span class="line"><span class="code" style="--layer: 0"> let </span><span><span class="code odd" style="--layer: 1" title="64:9-64:10: @89[1]: FakeRead(ForLet, _65)"><span class="annotation">@89⦊</span>z<span class="annotation">⦉@89</span></span></span><span class="code" style="--layer: 0"> = if </span><span><span class="code even" style="--layer: 1" title="64:16-64:25: @69[5]: _67 = _62 -64:16-64:29: @69[6]: _66 = Gt(move _67, const 7_i32)"><span class="annotation">@69⦊</span>countdown > 7<span class="annotation">⦉@69</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="65:9-65:23: @70[0]: _68 = CheckedSub(_62, const 4_i32) -65:9-65:23: @72[0]: _62 = move (_68.0: i32) -64:30-66:6: @72[1]: _65 = const ()"><span class="annotation">@70,72⦊</span>{</span></span> -<span class="line"><span class="code odd" style="--layer: 1" title="65:9-65:23: @70[0]: _68 = CheckedSub(_62, const 4_i32) -65:9-65:23: @72[0]: _62 = move (_68.0: i32) -64:30-66:6: @72[1]: _65 = const ()"> countdown -= 4;</span></span> -<span class="line"><span class="code odd" style="--layer: 1" title="65:9-65:23: @70[0]: _68 = CheckedSub(_62, const 4_i32) -65:9-65:23: @72[0]: _62 = move (_68.0: i32) -64:30-66:6: @72[1]: _65 = const ()"> }<span class="annotation">⦉@70,72</span></span></span><span class="code" style="--layer: 0"> else if </span><span><span class="code even" style="--layer: 1" title="66:15-66:24: @71[2]: _70 = _62 -66:15-66:28: @71[3]: _69 = Gt(move _70, const 2_i32)"><span class="annotation">@71⦊</span>countdown > 2<span class="annotation">⦉@71</span></span></span><span class="code" style="--layer: 0"> {</span></span> -<span class="line"><span class="code" style="--layer: 0"> if </span><span><span class="code odd" style="--layer: 1" title="67:12-67:21: @73[5]: _75 = _62 -67:12-67:25: @73[6]: _74 = Lt(move _75, const 1_i32)"><span class="annotation">@73⦊</span>countdown < 1<span class="annotation">⦉@73</span></span></span><span class="code" style="--layer: 0"> || </span><span><span class="code even" style="--layer: 1" title="67:29-67:38: @81[2]: _77 = _62 -67:29-67:42: @81[3]: _76 = Gt(move _77, const 5_i32)"><span class="annotation">@81⦊</span>countdown > 5<span class="annotation">⦉@81</span></span></span><span class="code" style="--layer: 0"> || </span><span><span class="code odd" style="--layer: 1" title="67:46-67:55: @77[2]: _79 = _62 -67:46-67:60: @77[3]: _78 = Ne(move _79, const 9_i32)"><span class="annotation">@77⦊</span>countdown != 9<span class="annotation">⦉@77</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="68:13-68:26: @83[0]: _62 = const 0_i32 -67:61-69:10: @83[1]: _71 = const ()"><span class="annotation">@83⦊</span>{</span></span> -<span class="line"><span class="code even" style="--layer: 1" title="68:13-68:26: @83[0]: _62 = const 0_i32 -67:61-69:10: @83[1]: _71 = const ()"> countdown = 0;</span></span> -<span class="line"><span class="code even" style="--layer: 1" title="68:13-68:26: @83[0]: _62 = const 0_i32 -67:61-69:10: @83[1]: _71 = const ()"> }<span class="annotation">⦉@83</span></span></span><span><span class="code odd" style="--layer: 1" title="69:10-69:10: @84[0]: _71 = const ()"><span class="annotation">@84⦊</span>‸<span class="annotation">⦉@84</span></span></span><span class="code" style="--layer: 0"></span></span> -<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="70:9-70:23: @85[2]: _80 = CheckedSub(_62, const 5_i32) -70:9-70:23: @86[0]: _62 = move (_80.0: i32)"><span class="annotation">@85,86⦊</span>countdown -= 5<span class="annotation">⦉@85,86</span></span></span><span class="code" style="--layer: 0">;</span></span> +<span class="line"><span class="code" style="--layer: 0"> let </span><span><span class="code odd" style="--layer: 1" title="64:9-64:10: @81[1]: FakeRead(ForLet, _65)"><span class="annotation">@81⦊</span>z<span class="annotation">⦉@81</span></span></span><span class="code" style="--layer: 0"> = if </span><span><span class="code even" style="--layer: 1" title="64:16-64:25: @63[5]: _67 = _62 +64:16-64:29: @63[6]: _66 = Gt(move _67, const 7_i32)"><span class="annotation">@63⦊</span>countdown > 7<span class="annotation">⦉@63</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="65:9-65:23: @64[0]: _68 = CheckedSub(_62, const 4_i32) +65:9-65:23: @66[0]: _62 = move (_68.0: i32) +64:30-66:6: @66[1]: _65 = const ()"><span class="annotation">@64,66⦊</span>{</span></span> +<span class="line"><span class="code odd" style="--layer: 1" title="65:9-65:23: @64[0]: _68 = CheckedSub(_62, const 4_i32) +65:9-65:23: @66[0]: _62 = move (_68.0: i32) +64:30-66:6: @66[1]: _65 = const ()"> countdown -= 4;</span></span> +<span class="line"><span class="code odd" style="--layer: 1" title="65:9-65:23: @64[0]: _68 = CheckedSub(_62, const 4_i32) +65:9-65:23: @66[0]: _62 = move (_68.0: i32) +64:30-66:6: @66[1]: _65 = const ()"> }<span class="annotation">⦉@64,66</span></span></span><span class="code" style="--layer: 0"> else if </span><span><span class="code even" style="--layer: 1" title="66:15-66:24: @65[2]: _70 = _62 +66:15-66:28: @65[3]: _69 = Gt(move _70, const 2_i32)"><span class="annotation">@65⦊</span>countdown > 2<span class="annotation">⦉@65</span></span></span><span class="code" style="--layer: 0"> {</span></span> +<span class="line"><span class="code" style="--layer: 0"> if </span><span><span class="code odd" style="--layer: 1" title="67:12-67:21: @67[5]: _75 = _62 +67:12-67:25: @67[6]: _74 = Lt(move _75, const 1_i32)"><span class="annotation">@67⦊</span>countdown < 1<span class="annotation">⦉@67</span></span></span><span class="code" style="--layer: 0"> || </span><span><span class="code even" style="--layer: 1" title="67:29-67:38: @73[2]: _77 = _62 +67:29-67:42: @73[3]: _76 = Gt(move _77, const 5_i32)"><span class="annotation">@73⦊</span>countdown > 5<span class="annotation">⦉@73</span></span></span><span class="code" style="--layer: 0"> || </span><span><span class="code odd" style="--layer: 1" title="67:46-67:55: @70[2]: _79 = _62 +67:46-67:60: @70[3]: _78 = Ne(move _79, const 9_i32)"><span class="annotation">@70⦊</span>countdown != 9<span class="annotation">⦉@70</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="68:13-68:26: @75[0]: _62 = const 0_i32 +67:61-69:10: @75[1]: _71 = const ()"><span class="annotation">@75⦊</span>{</span></span> +<span class="line"><span class="code even" style="--layer: 1" title="68:13-68:26: @75[0]: _62 = const 0_i32 +67:61-69:10: @75[1]: _71 = const ()"> countdown = 0;</span></span> +<span class="line"><span class="code even" style="--layer: 1" title="68:13-68:26: @75[0]: _62 = const 0_i32 +67:61-69:10: @75[1]: _71 = const ()"> }<span class="annotation">⦉@75</span></span></span><span><span class="code odd" style="--layer: 1" title="69:10-69:10: @76[0]: _71 = const ()"><span class="annotation">@76⦊</span>‸<span class="annotation">⦉@76</span></span></span><span class="code" style="--layer: 0"></span></span> +<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="70:9-70:23: @77[2]: _80 = CheckedSub(_62, const 5_i32) +70:9-70:23: @78[0]: _62 = move (_80.0: i32)"><span class="annotation">@77,78⦊</span>countdown -= 5<span class="annotation">⦉@77,78</span></span></span><span class="code" style="--layer: 0">;</span></span> <span class="line"><span class="code" style="--layer: 0"> } else {</span></span> -<span class="line"><span class="code" style="--layer: 0"> let </span><span><span class="code odd" style="--layer: 1" title="72:35-72:44: @74[1]: _82 = _62 -72:13-72:32: @74[2]: FakeRead(ForLet, _82) -73:18-73:27: @74[9]: _113 = const main::promoted[1] -73:18-73:27: @74[10]: _88 = &(*_113) -73:18-73:27: @74[11]: _87 = &(*_88) -73:18-73:27: @74[12]: _86 = move _87 as &[&str] (Pointer(Unsize)) -73:9-73:29: @74[18]: _94 = () -73:9-73:29: @74[19]: FakeRead(ForMatchedPlace, _94) -73:9-73:29: @74[20]: _112 = const main::promoted[0] -73:9-73:29: @74[21]: _92 = &(*_112) -73:9-73:29: @74[22]: _91 = &(*_92) -73:9-73:29: @74[23]: _90 = move _91 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) -73:9-73:29: @74.Call: _85 = std::fmt::Arguments::new_v1(move _86, move _90) -> [return: bb87, unwind: bb112] -73:9-73:29: @87.Call: _84 = std::io::_print(move _85) -> [return: bb88, unwind: bb112] -73:9-73:29: @88[5]: _83 = const () -74:9-74:15: @88[7]: _0 = const ()"><span class="annotation">@74,87,88⦊</span>should_be_reachable = countdown;</span></span> -<span class="line"><span class="code odd" style="--layer: 1" title="72:35-72:44: @74[1]: _82 = _62 -72:13-72:32: @74[2]: FakeRead(ForLet, _82) -73:18-73:27: @74[9]: _113 = const main::promoted[1] -73:18-73:27: @74[10]: _88 = &(*_113) -73:18-73:27: @74[11]: _87 = &(*_88) -73:18-73:27: @74[12]: _86 = move _87 as &[&str] (Pointer(Unsize)) -73:9-73:29: @74[18]: _94 = () -73:9-73:29: @74[19]: FakeRead(ForMatchedPlace, _94) -73:9-73:29: @74[20]: _112 = const main::promoted[0] -73:9-73:29: @74[21]: _92 = &(*_112) -73:9-73:29: @74[22]: _91 = &(*_92) -73:9-73:29: @74[23]: _90 = move _91 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) -73:9-73:29: @74.Call: _85 = std::fmt::Arguments::new_v1(move _86, move _90) -> [return: bb87, unwind: bb112] -73:9-73:29: @87.Call: _84 = std::io::_print(move _85) -> [return: bb88, unwind: bb112] -73:9-73:29: @88[5]: _83 = const () -74:9-74:15: @88[7]: _0 = const ()"> println!("reached");</span></span> -<span class="line"><span class="code odd" style="--layer: 1" title="72:35-72:44: @74[1]: _82 = _62 -72:13-72:32: @74[2]: FakeRead(ForLet, _82) -73:18-73:27: @74[9]: _113 = const main::promoted[1] -73:18-73:27: @74[10]: _88 = &(*_113) -73:18-73:27: @74[11]: _87 = &(*_88) -73:18-73:27: @74[12]: _86 = move _87 as &[&str] (Pointer(Unsize)) -73:9-73:29: @74[18]: _94 = () -73:9-73:29: @74[19]: FakeRead(ForMatchedPlace, _94) -73:9-73:29: @74[20]: _112 = const main::promoted[0] -73:9-73:29: @74[21]: _92 = &(*_112) -73:9-73:29: @74[22]: _91 = &(*_92) -73:9-73:29: @74[23]: _90 = move _91 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) -73:9-73:29: @74.Call: _85 = std::fmt::Arguments::new_v1(move _86, move _90) -> [return: bb87, unwind: bb112] -73:9-73:29: @87.Call: _84 = std::io::_print(move _85) -> [return: bb88, unwind: bb112] -73:9-73:29: @88[5]: _83 = const () -74:9-74:15: @88[7]: _0 = const ()"> return<span class="annotation">⦉@74,87,88</span></span></span><span class="code" style="--layer: 0">;</span></span> +<span class="line"><span class="code" style="--layer: 0"> let </span><span><span class="code odd" style="--layer: 1" title="72:35-72:44: @68[1]: _82 = _62 +72:13-72:32: @68[2]: FakeRead(ForLet, _82) +73:18-73:27: @68[9]: _113 = const main::promoted[1] +73:18-73:27: @68[10]: _88 = &(*_113) +73:18-73:27: @68[11]: _87 = &(*_88) +73:18-73:27: @68[12]: _86 = move _87 as &[&str] (Pointer(Unsize)) +73:9-73:29: @68[18]: _94 = () +73:9-73:29: @68[19]: FakeRead(ForMatchedPlace, _94) +73:9-73:29: @68[20]: _112 = const main::promoted[0] +73:9-73:29: @68[21]: _92 = &(*_112) +73:9-73:29: @68[22]: _91 = &(*_92) +73:9-73:29: @68[23]: _90 = move _91 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +73:9-73:29: @68.Call: _85 = std::fmt::Arguments::new_v1(move _86, move _90) -> [return: bb79, unwind: bb102] +73:9-73:29: @79.Call: _84 = std::io::_print(move _85) -> [return: bb80, unwind: bb102] +73:9-73:29: @80[5]: _83 = const () +74:9-74:15: @80[7]: _0 = const ()"><span class="annotation">@68,79,80⦊</span>should_be_reachable = countdown;</span></span> +<span class="line"><span class="code odd" style="--layer: 1" title="72:35-72:44: @68[1]: _82 = _62 +72:13-72:32: @68[2]: FakeRead(ForLet, _82) +73:18-73:27: @68[9]: _113 = const main::promoted[1] +73:18-73:27: @68[10]: _88 = &(*_113) +73:18-73:27: @68[11]: _87 = &(*_88) +73:18-73:27: @68[12]: _86 = move _87 as &[&str] (Pointer(Unsize)) +73:9-73:29: @68[18]: _94 = () +73:9-73:29: @68[19]: FakeRead(ForMatchedPlace, _94) +73:9-73:29: @68[20]: _112 = const main::promoted[0] +73:9-73:29: @68[21]: _92 = &(*_112) +73:9-73:29: @68[22]: _91 = &(*_92) +73:9-73:29: @68[23]: _90 = move _91 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +73:9-73:29: @68.Call: _85 = std::fmt::Arguments::new_v1(move _86, move _90) -> [return: bb79, unwind: bb102] +73:9-73:29: @79.Call: _84 = std::io::_print(move _85) -> [return: bb80, unwind: bb102] +73:9-73:29: @80[5]: _83 = const () +74:9-74:15: @80[7]: _0 = const ()"> println!("reached");</span></span> +<span class="line"><span class="code odd" style="--layer: 1" title="72:35-72:44: @68[1]: _82 = _62 +72:13-72:32: @68[2]: FakeRead(ForLet, _82) +73:18-73:27: @68[9]: _113 = const main::promoted[1] +73:18-73:27: @68[10]: _88 = &(*_113) +73:18-73:27: @68[11]: _87 = &(*_88) +73:18-73:27: @68[12]: _86 = move _87 as &[&str] (Pointer(Unsize)) +73:9-73:29: @68[18]: _94 = () +73:9-73:29: @68[19]: FakeRead(ForMatchedPlace, _94) +73:9-73:29: @68[20]: _112 = const main::promoted[0] +73:9-73:29: @68[21]: _92 = &(*_112) +73:9-73:29: @68[22]: _91 = &(*_92) +73:9-73:29: @68[23]: _90 = move _91 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +73:9-73:29: @68.Call: _85 = std::fmt::Arguments::new_v1(move _86, move _90) -> [return: bb79, unwind: bb102] +73:9-73:29: @79.Call: _84 = std::io::_print(move _85) -> [return: bb80, unwind: bb102] +73:9-73:29: @80[5]: _83 = const () +74:9-74:15: @80[7]: _0 = const ()"> return<span class="annotation">⦉@68,79,80</span></span></span><span class="code" style="--layer: 0">;</span></span> <span class="line"><span class="code" style="--layer: 0"> };</span></span> <span class="line"><span class="code" style="--layer: 0"></span></span> -<span class="line"><span class="code" style="--layer: 0"> let </span><span><span class="code even" style="--layer: 1" title="77:9-77:10: @107[1]: FakeRead(ForLet, _95)"><span class="annotation">@107⦊</span>w<span class="annotation">⦉@107</span></span></span><span class="code" style="--layer: 0"> = if </span><span><span class="code odd" style="--layer: 1" title="77:16-77:25: @89[5]: _97 = _62 -77:16-77:29: @89[6]: _96 = Gt(move _97, const 7_i32)"><span class="annotation">@89⦊</span>countdown > 7<span class="annotation">⦉@89</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="78:9-78:23: @90[0]: _98 = CheckedSub(_62, const 4_i32) -78:9-78:23: @92[0]: _62 = move (_98.0: i32) -77:30-79:6: @92[1]: _95 = const ()"><span class="annotation">@90,92⦊</span>{</span></span> -<span class="line"><span class="code even" style="--layer: 1" title="78:9-78:23: @90[0]: _98 = CheckedSub(_62, const 4_i32) -78:9-78:23: @92[0]: _62 = move (_98.0: i32) -77:30-79:6: @92[1]: _95 = const ()"> countdown -= 4;</span></span> -<span class="line"><span class="code even" style="--layer: 1" title="78:9-78:23: @90[0]: _98 = CheckedSub(_62, const 4_i32) -78:9-78:23: @92[0]: _62 = move (_98.0: i32) -77:30-79:6: @92[1]: _95 = const ()"> }<span class="annotation">⦉@90,92</span></span></span><span class="code" style="--layer: 0"> else if </span><span><span class="code odd" style="--layer: 1" title="79:15-79:24: @91[2]: _100 = _62 -79:15-79:28: @91[3]: _99 = Gt(move _100, const 2_i32)"><span class="annotation">@91⦊</span>countdown > 2<span class="annotation">⦉@91</span></span></span><span class="code" style="--layer: 0"> {</span></span> -<span class="line"><span class="code" style="--layer: 0"> if </span><span><span class="code even" style="--layer: 1" title="80:12-80:21: @93[5]: _105 = _62 -80:12-80:25: @93[6]: _104 = Lt(move _105, const 1_i32)"><span class="annotation">@93⦊</span>countdown < 1<span class="annotation">⦉@93</span></span></span><span class="code" style="--layer: 0"> || </span><span><span class="code odd" style="--layer: 1" title="80:29-80:38: @101[2]: _107 = _62 -80:29-80:42: @101[3]: _106 = Gt(move _107, const 5_i32)"><span class="annotation">@101⦊</span>countdown > 5<span class="annotation">⦉@101</span></span></span><span class="code" style="--layer: 0"> || </span><span><span class="code even" style="--layer: 1" title="80:46-80:55: @97[2]: _109 = _62 -80:46-80:60: @97[3]: _108 = Ne(move _109, const 9_i32)"><span class="annotation">@97⦊</span>countdown != 9<span class="annotation">⦉@97</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="81:13-81:26: @103[0]: _62 = const 0_i32 -80:61-82:10: @103[1]: _101 = const ()"><span class="annotation">@103⦊</span>{</span></span> -<span class="line"><span class="code odd" style="--layer: 1" title="81:13-81:26: @103[0]: _62 = const 0_i32 -80:61-82:10: @103[1]: _101 = const ()"> countdown = 0;</span></span> -<span class="line"><span class="code odd" style="--layer: 1" title="81:13-81:26: @103[0]: _62 = const 0_i32 -80:61-82:10: @103[1]: _101 = const ()"> }<span class="annotation">⦉@103</span></span></span><span><span class="code even" style="--layer: 1" title="82:10-82:10: @104[0]: _101 = const ()"><span class="annotation">@104⦊</span>‸<span class="annotation">⦉@104</span></span></span><span class="code" style="--layer: 0"></span></span> -<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="83:9-83:23: @105[2]: _110 = CheckedSub(_62, const 5_i32) -83:9-83:23: @106[0]: _62 = move (_110.0: i32)"><span class="annotation">@105,106⦊</span>countdown -= 5<span class="annotation">⦉@105,106</span></span></span><span class="code" style="--layer: 0">;</span></span> +<span class="line"><span class="code" style="--layer: 0"> let </span><span><span class="code even" style="--layer: 1" title="77:9-77:10: @97[1]: FakeRead(ForLet, _95)"><span class="annotation">@97⦊</span>w<span class="annotation">⦉@97</span></span></span><span class="code" style="--layer: 0"> = if </span><span><span class="code odd" style="--layer: 1" title="77:16-77:25: @81[5]: _97 = _62 +77:16-77:29: @81[6]: _96 = Gt(move _97, const 7_i32)"><span class="annotation">@81⦊</span>countdown > 7<span class="annotation">⦉@81</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="78:9-78:23: @82[0]: _98 = CheckedSub(_62, const 4_i32) +78:9-78:23: @84[0]: _62 = move (_98.0: i32) +77:30-79:6: @84[1]: _95 = const ()"><span class="annotation">@82,84⦊</span>{</span></span> +<span class="line"><span class="code even" style="--layer: 1" title="78:9-78:23: @82[0]: _98 = CheckedSub(_62, const 4_i32) +78:9-78:23: @84[0]: _62 = move (_98.0: i32) +77:30-79:6: @84[1]: _95 = const ()"> countdown -= 4;</span></span> +<span class="line"><span class="code even" style="--layer: 1" title="78:9-78:23: @82[0]: _98 = CheckedSub(_62, const 4_i32) +78:9-78:23: @84[0]: _62 = move (_98.0: i32) +77:30-79:6: @84[1]: _95 = const ()"> }<span class="annotation">⦉@82,84</span></span></span><span class="code" style="--layer: 0"> else if </span><span><span class="code odd" style="--layer: 1" title="79:15-79:24: @83[2]: _100 = _62 +79:15-79:28: @83[3]: _99 = Gt(move _100, const 2_i32)"><span class="annotation">@83⦊</span>countdown > 2<span class="annotation">⦉@83</span></span></span><span class="code" style="--layer: 0"> {</span></span> +<span class="line"><span class="code" style="--layer: 0"> if </span><span><span class="code even" style="--layer: 1" title="80:12-80:21: @85[5]: _105 = _62 +80:12-80:25: @85[6]: _104 = Lt(move _105, const 1_i32)"><span class="annotation">@85⦊</span>countdown < 1<span class="annotation">⦉@85</span></span></span><span class="code" style="--layer: 0"> || </span><span><span class="code odd" style="--layer: 1" title="80:29-80:38: @91[2]: _107 = _62 +80:29-80:42: @91[3]: _106 = Gt(move _107, const 5_i32)"><span class="annotation">@91⦊</span>countdown > 5<span class="annotation">⦉@91</span></span></span><span class="code" style="--layer: 0"> || </span><span><span class="code even" style="--layer: 1" title="80:46-80:55: @88[2]: _109 = _62 +80:46-80:60: @88[3]: _108 = Ne(move _109, const 9_i32)"><span class="annotation">@88⦊</span>countdown != 9<span class="annotation">⦉@88</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="81:13-81:26: @93[0]: _62 = const 0_i32 +80:61-82:10: @93[1]: _101 = const ()"><span class="annotation">@93⦊</span>{</span></span> +<span class="line"><span class="code odd" style="--layer: 1" title="81:13-81:26: @93[0]: _62 = const 0_i32 +80:61-82:10: @93[1]: _101 = const ()"> countdown = 0;</span></span> +<span class="line"><span class="code odd" style="--layer: 1" title="81:13-81:26: @93[0]: _62 = const 0_i32 +80:61-82:10: @93[1]: _101 = const ()"> }<span class="annotation">⦉@93</span></span></span><span><span class="code even" style="--layer: 1" title="82:10-82:10: @94[0]: _101 = const ()"><span class="annotation">@94⦊</span>‸<span class="annotation">⦉@94</span></span></span><span class="code" style="--layer: 0"></span></span> +<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="83:9-83:23: @95[2]: _110 = CheckedSub(_62, const 5_i32) +83:9-83:23: @96[0]: _62 = move (_110.0: i32)"><span class="annotation">@95,96⦊</span>countdown -= 5<span class="annotation">⦉@95,96</span></span></span><span class="code" style="--layer: 0">;</span></span> <span class="line"><span class="code" style="--layer: 0"> } else {</span></span> -<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="85:9-85:15: @94[0]: _0 = const ()"><span class="annotation">@94⦊</span>return<span class="annotation">⦉@94</span></span></span><span class="code" style="--layer: 0">;</span></span> +<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="85:9-85:15: @86[0]: _0 = const ()"><span class="annotation">@86⦊</span>return<span class="annotation">⦉@86</span></span></span><span class="code" style="--layer: 0">;</span></span> <span class="line"><span class="code" style="--layer: 0"> };</span></span> -<span class="line"><span class="code" style="--layer: 0">}</span><span><span class="code odd" style="--layer: 1" title="87:2-87:2: @111.Return: return"><span class="annotation">@111⦊</span>‸<span class="annotation">⦉@111</span></span></span></span></div> +<span class="line"><span class="code" style="--layer: 0">}</span><span><span class="code odd" style="--layer: 1" title="87:2-87:2: @101.Return: return"><span class="annotation">@101⦊</span>‸<span class="annotation">⦉@101</span></span></span></span></div> </body> </html> diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.lazy_boolean/lazy_boolean.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.lazy_boolean/lazy_boolean.main.-------.InstrumentCoverage.0.html index 358e2e2bbba..a6f8d500065 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.lazy_boolean/lazy_boolean.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.lazy_boolean/lazy_boolean.main.-------.InstrumentCoverage.0.html @@ -69,9 +69,9 @@ For revisions in Pull Requests (PR): </style> </head> <body> -<div class="code" style="counter-reset: line 2"><span class="line"><span><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = std::env::args() -> [return: bb1, unwind: bb36] +<div class="code" style="counter-reset: line 2"><span class="line"><span><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = std::env::args() -> [return: bb1, unwind: bb32] 7:19-7:35: @1[0]: _3 = &_4 -7:19-7:41: @1.Call: _2 = <std::env::Args as std::iter::ExactSizeIterator>::len(move _3) -> [return: bb2, unwind: bb35] +7:19-7:41: @1.Call: _2 = <std::env::Args as std::iter::ExactSizeIterator>::len(move _3) -> [return: bb2, unwind: bb31] 7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize) 7:9-7:16: @2[3]: FakeRead(ForLet, _1) 9:33-9:42: @3[2]: _8 = (const 0_i32, const 0_i32, const 0_i32) @@ -79,9 +79,9 @@ For revisions in Pull Requests (PR): 9:17-9:22: @3[6]: _6 = (_8.1: i32) 9:24-9:29: @3[8]: _7 = (_8.2: i32) 10:8-10:15: @3[12]: _10 = _1"><span class="annotation">@0,1,2,3⦊</span>fn main() {</span></span> -<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = std::env::args() -> [return: bb1, unwind: bb36] +<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = std::env::args() -> [return: bb1, unwind: bb32] 7:19-7:35: @1[0]: _3 = &_4 -7:19-7:41: @1.Call: _2 = <std::env::Args as std::iter::ExactSizeIterator>::len(move _3) -> [return: bb2, unwind: bb35] +7:19-7:41: @1.Call: _2 = <std::env::Args as std::iter::ExactSizeIterator>::len(move _3) -> [return: bb2, unwind: bb31] 7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize) 7:9-7:16: @2[3]: FakeRead(ForLet, _1) 9:33-9:42: @3[2]: _8 = (const 0_i32, const 0_i32, const 0_i32) @@ -89,9 +89,9 @@ For revisions in Pull Requests (PR): 9:17-9:22: @3[6]: _6 = (_8.1: i32) 9:24-9:29: @3[8]: _7 = (_8.2: i32) 10:8-10:15: @3[12]: _10 = _1"> // Initialize test constants in a way that cannot be determined at compile time, to ensure</span></span> -<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = std::env::args() -> [return: bb1, unwind: bb36] +<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = std::env::args() -> [return: bb1, unwind: bb32] 7:19-7:35: @1[0]: _3 = &_4 -7:19-7:41: @1.Call: _2 = <std::env::Args as std::iter::ExactSizeIterator>::len(move _3) -> [return: bb2, unwind: bb35] +7:19-7:41: @1.Call: _2 = <std::env::Args as std::iter::ExactSizeIterator>::len(move _3) -> [return: bb2, unwind: bb31] 7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize) 7:9-7:16: @2[3]: FakeRead(ForLet, _1) 9:33-9:42: @3[2]: _8 = (const 0_i32, const 0_i32, const 0_i32) @@ -99,9 +99,9 @@ For revisions in Pull Requests (PR): 9:17-9:22: @3[6]: _6 = (_8.1: i32) 9:24-9:29: @3[8]: _7 = (_8.2: i32) 10:8-10:15: @3[12]: _10 = _1"> // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from</span></span> -<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = std::env::args() -> [return: bb1, unwind: bb36] +<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = std::env::args() -> [return: bb1, unwind: bb32] 7:19-7:35: @1[0]: _3 = &_4 -7:19-7:41: @1.Call: _2 = <std::env::Args as std::iter::ExactSizeIterator>::len(move _3) -> [return: bb2, unwind: bb35] +7:19-7:41: @1.Call: _2 = <std::env::Args as std::iter::ExactSizeIterator>::len(move _3) -> [return: bb2, unwind: bb31] 7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize) 7:9-7:16: @2[3]: FakeRead(ForLet, _1) 9:33-9:42: @3[2]: _8 = (const 0_i32, const 0_i32, const 0_i32) @@ -109,9 +109,9 @@ For revisions in Pull Requests (PR): 9:17-9:22: @3[6]: _6 = (_8.1: i32) 9:24-9:29: @3[8]: _7 = (_8.2: i32) 10:8-10:15: @3[12]: _10 = _1"> // dependent conditions.</span></span> -<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = std::env::args() -> [return: bb1, unwind: bb36] +<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = std::env::args() -> [return: bb1, unwind: bb32] 7:19-7:35: @1[0]: _3 = &_4 -7:19-7:41: @1.Call: _2 = <std::env::Args as std::iter::ExactSizeIterator>::len(move _3) -> [return: bb2, unwind: bb35] +7:19-7:41: @1.Call: _2 = <std::env::Args as std::iter::ExactSizeIterator>::len(move _3) -> [return: bb2, unwind: bb31] 7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize) 7:9-7:16: @2[3]: FakeRead(ForLet, _1) 9:33-9:42: @3[2]: _8 = (const 0_i32, const 0_i32, const 0_i32) @@ -119,9 +119,9 @@ For revisions in Pull Requests (PR): 9:17-9:22: @3[6]: _6 = (_8.1: i32) 9:24-9:29: @3[8]: _7 = (_8.2: i32) 10:8-10:15: @3[12]: _10 = _1"> let is_true = std::env::args().len() == 1;</span></span> -<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = std::env::args() -> [return: bb1, unwind: bb36] +<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = std::env::args() -> [return: bb1, unwind: bb32] 7:19-7:35: @1[0]: _3 = &_4 -7:19-7:41: @1.Call: _2 = <std::env::Args as std::iter::ExactSizeIterator>::len(move _3) -> [return: bb2, unwind: bb35] +7:19-7:41: @1.Call: _2 = <std::env::Args as std::iter::ExactSizeIterator>::len(move _3) -> [return: bb2, unwind: bb31] 7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize) 7:9-7:16: @2[3]: FakeRead(ForLet, _1) 9:33-9:42: @3[2]: _8 = (const 0_i32, const 0_i32, const 0_i32) @@ -129,9 +129,9 @@ For revisions in Pull Requests (PR): 9:17-9:22: @3[6]: _6 = (_8.1: i32) 9:24-9:29: @3[8]: _7 = (_8.2: i32) 10:8-10:15: @3[12]: _10 = _1"></span></span> -<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = std::env::args() -> [return: bb1, unwind: bb36] +<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = std::env::args() -> [return: bb1, unwind: bb32] 7:19-7:35: @1[0]: _3 = &_4 -7:19-7:41: @1.Call: _2 = <std::env::Args as std::iter::ExactSizeIterator>::len(move _3) -> [return: bb2, unwind: bb35] +7:19-7:41: @1.Call: _2 = <std::env::Args as std::iter::ExactSizeIterator>::len(move _3) -> [return: bb2, unwind: bb31] 7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize) 7:9-7:16: @2[3]: FakeRead(ForLet, _1) 9:33-9:42: @3[2]: _8 = (const 0_i32, const 0_i32, const 0_i32) @@ -139,9 +139,9 @@ For revisions in Pull Requests (PR): 9:17-9:22: @3[6]: _6 = (_8.1: i32) 9:24-9:29: @3[8]: _7 = (_8.2: i32) 10:8-10:15: @3[12]: _10 = _1"> let (mut a, mut b, mut c) = (0, 0, 0);</span></span> -<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = std::env::args() -> [return: bb1, unwind: bb36] +<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = std::env::args() -> [return: bb1, unwind: bb32] 7:19-7:35: @1[0]: _3 = &_4 -7:19-7:41: @1.Call: _2 = <std::env::Args as std::iter::ExactSizeIterator>::len(move _3) -> [return: bb2, unwind: bb35] +7:19-7:41: @1.Call: _2 = <std::env::Args as std::iter::ExactSizeIterator>::len(move _3) -> [return: bb2, unwind: bb31] 7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize) 7:9-7:16: @2[3]: FakeRead(ForLet, _1) 9:33-9:42: @3[2]: _8 = (const 0_i32, const 0_i32, const 0_i32) @@ -169,91 +169,91 @@ For revisions in Pull Requests (PR): 13:9-13:16: @4[2]: _7 = const 100_i32 10:16-14:6: @4[3]: _9 = const ()"> }<span class="annotation">⦉@4</span></span></span><span><span class="code even" style="--layer: 1" title="14:6-14:6: @5[0]: _9 = const ()"><span class="annotation">@5⦊</span>‸<span class="annotation">⦉@5</span></span></span><span class="code" style="--layer: 0"></span></span> <span class="line"><span class="code" style="--layer: 0"> let</span></span> -<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="16:9-16:17: @10[2]: FakeRead(ForLet, _11)"><span class="annotation">@10⦊</span>somebool<span class="annotation">⦉@10</span></span></span><span class="code" style="--layer: 0"></span></span> +<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="16:9-16:17: @9[2]: FakeRead(ForLet, _11)"><span class="annotation">@9⦊</span>somebool<span class="annotation">⦉@9</span></span></span><span class="code" style="--layer: 0"></span></span> <span class="line"><span class="code" style="--layer: 0"> =</span></span> <span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="18:13-18:14: @6[5]: _13 = _5 18:17-18:18: @6[7]: _14 = _6 18:13-18:18: @6[8]: _12 = Lt(move _13, move _14)"><span class="annotation">@6⦊</span>a < b<span class="annotation">⦉@6</span></span></span><span class="code" style="--layer: 0"></span></span> <span class="line"><span class="code" style="--layer: 0"> ||</span></span> -<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="20:13-20:14: @9[2]: _16 = _6 -20:17-20:18: @9[4]: _17 = _7 -20:13-20:18: @9[5]: _15 = Lt(move _16, move _17)"><span class="annotation">@9⦊</span>b < c<span class="annotation">⦉@9</span></span></span><span class="code" style="--layer: 0"></span></span> +<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="20:13-20:14: @8[2]: _16 = _6 +20:17-20:18: @8[4]: _17 = _7 +20:13-20:18: @8[5]: _15 = Lt(move _16, move _17)"><span class="annotation">@8⦊</span>b < c<span class="annotation">⦉@8</span></span></span><span class="code" style="--layer: 0"></span></span> <span class="line"><span class="code" style="--layer: 0"> ;</span></span> <span class="line"><span class="code" style="--layer: 0"> let</span></span> -<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="23:9-23:17: @14[2]: FakeRead(ForLet, _18)"><span class="annotation">@14⦊</span>somebool<span class="annotation">⦉@14</span></span></span><span class="code" style="--layer: 0"></span></span> +<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="23:9-23:17: @12[2]: FakeRead(ForLet, _18)"><span class="annotation">@12⦊</span>somebool<span class="annotation">⦉@12</span></span></span><span class="code" style="--layer: 0"></span></span> <span class="line"><span class="code" style="--layer: 0"> =</span></span> -<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="25:13-25:14: @10[6]: _20 = _6 -25:17-25:18: @10[8]: _21 = _5 -25:13-25:18: @10[9]: _19 = Lt(move _20, move _21)"><span class="annotation">@10⦊</span>b < a<span class="annotation">⦉@10</span></span></span><span class="code" style="--layer: 0"></span></span> +<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="25:13-25:14: @9[6]: _20 = _6 +25:17-25:18: @9[8]: _21 = _5 +25:13-25:18: @9[9]: _19 = Lt(move _20, move _21)"><span class="annotation">@9⦊</span>b < a<span class="annotation">⦉@9</span></span></span><span class="code" style="--layer: 0"></span></span> <span class="line"><span class="code" style="--layer: 0"> ||</span></span> -<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="27:13-27:14: @13[2]: _23 = _6 -27:17-27:18: @13[4]: _24 = _7 -27:13-27:18: @13[5]: _22 = Lt(move _23, move _24)"><span class="annotation">@13⦊</span>b < c<span class="annotation">⦉@13</span></span></span><span class="code" style="--layer: 0"></span></span> +<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="27:13-27:14: @11[2]: _23 = _6 +27:17-27:18: @11[4]: _24 = _7 +27:13-27:18: @11[5]: _22 = Lt(move _23, move _24)"><span class="annotation">@11⦊</span>b < c<span class="annotation">⦉@11</span></span></span><span class="code" style="--layer: 0"></span></span> <span class="line"><span class="code" style="--layer: 0"> ;</span></span> -<span class="line"><span class="code" style="--layer: 0"> let </span><span><span class="code odd" style="--layer: 1" title="29:9-29:17: @18[2]: FakeRead(ForLet, _25)"><span class="annotation">@18⦊</span>somebool<span class="annotation">⦉@18</span></span></span><span class="code" style="--layer: 0"> = </span><span><span class="code even" style="--layer: 1" title="29:20-29:21: @14[6]: _27 = _5 -29:24-29:25: @14[8]: _28 = _6 -29:20-29:25: @14[9]: _26 = Lt(move _27, move _28)"><span class="annotation">@14⦊</span>a < b<span class="annotation">⦉@14</span></span></span><span class="code" style="--layer: 0"> && </span><span><span class="code odd" style="--layer: 1" title="29:29-29:30: @17[2]: _30 = _6 -29:33-29:34: @17[4]: _31 = _7 -29:29-29:34: @17[5]: _29 = Lt(move _30, move _31)"><span class="annotation">@17⦊</span>b < c<span class="annotation">⦉@17</span></span></span><span class="code" style="--layer: 0">;</span></span> -<span class="line"><span class="code" style="--layer: 0"> let </span><span><span class="code even" style="--layer: 1" title="30:9-30:17: @22[2]: FakeRead(ForLet, _32)"><span class="annotation">@22⦊</span>somebool<span class="annotation">⦉@22</span></span></span><span class="code" style="--layer: 0"> = </span><span><span class="code odd" style="--layer: 1" title="30:20-30:21: @18[6]: _34 = _6 -30:24-30:25: @18[8]: _35 = _5 -30:20-30:25: @18[9]: _33 = Lt(move _34, move _35)"><span class="annotation">@18⦊</span>b < a<span class="annotation">⦉@18</span></span></span><span class="code" style="--layer: 0"> && </span><span><span class="code even" style="--layer: 1" title="30:29-30:30: @21[2]: _37 = _6 -30:33-30:34: @21[4]: _38 = _7 -30:29-30:34: @21[5]: _36 = Lt(move _37, move _38)"><span class="annotation">@21⦊</span>b < c<span class="annotation">⦉@21</span></span></span><span class="code" style="--layer: 0">;</span></span> +<span class="line"><span class="code" style="--layer: 0"> let </span><span><span class="code odd" style="--layer: 1" title="29:9-29:17: @15[2]: FakeRead(ForLet, _25)"><span class="annotation">@15⦊</span>somebool<span class="annotation">⦉@15</span></span></span><span class="code" style="--layer: 0"> = </span><span><span class="code even" style="--layer: 1" title="29:20-29:21: @12[6]: _27 = _5 +29:24-29:25: @12[8]: _28 = _6 +29:20-29:25: @12[9]: _26 = Lt(move _27, move _28)"><span class="annotation">@12⦊</span>a < b<span class="annotation">⦉@12</span></span></span><span class="code" style="--layer: 0"> && </span><span><span class="code odd" style="--layer: 1" title="29:29-29:30: @14[2]: _30 = _6 +29:33-29:34: @14[4]: _31 = _7 +29:29-29:34: @14[5]: _29 = Lt(move _30, move _31)"><span class="annotation">@14⦊</span>b < c<span class="annotation">⦉@14</span></span></span><span class="code" style="--layer: 0">;</span></span> +<span class="line"><span class="code" style="--layer: 0"> let </span><span><span class="code even" style="--layer: 1" title="30:9-30:17: @18[2]: FakeRead(ForLet, _32)"><span class="annotation">@18⦊</span>somebool<span class="annotation">⦉@18</span></span></span><span class="code" style="--layer: 0"> = </span><span><span class="code odd" style="--layer: 1" title="30:20-30:21: @15[6]: _34 = _6 +30:24-30:25: @15[8]: _35 = _5 +30:20-30:25: @15[9]: _33 = Lt(move _34, move _35)"><span class="annotation">@15⦊</span>b < a<span class="annotation">⦉@15</span></span></span><span class="code" style="--layer: 0"> && </span><span><span class="code even" style="--layer: 1" title="30:29-30:30: @17[2]: _37 = _6 +30:33-30:34: @17[4]: _38 = _7 +30:29-30:34: @17[5]: _36 = Lt(move _37, move _38)"><span class="annotation">@17⦊</span>b < c<span class="annotation">⦉@17</span></span></span><span class="code" style="--layer: 0">;</span></span> <span class="line"><span class="code" style="--layer: 0"></span></span> <span class="line"><span class="code" style="--layer: 0"> if</span></span> -<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="34:9-34:16: @22[6]: _41 = _1 -33:9-34:16: @22[7]: _40 = Not(move _41)"><span class="annotation">@22⦊</span>!</span></span> -<span class="line"><span class="code odd" style="--layer: 1" title="34:9-34:16: @22[6]: _41 = _1 -33:9-34:16: @22[7]: _40 = Not(move _41)"> is_true<span class="annotation">⦉@22</span></span></span><span class="code" style="--layer: 0"></span></span> -<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="36:9-36:14: @23[0]: _5 = const 2_i32 -35:5-38:6: @23[1]: _39 = const ()"><span class="annotation">@23⦊</span>{</span></span> -<span class="line"><span class="code even" style="--layer: 1" title="36:9-36:14: @23[0]: _5 = const 2_i32 -35:5-38:6: @23[1]: _39 = const ()"> a = 2</span></span> -<span class="line"><span class="code even" style="--layer: 1" title="36:9-36:14: @23[0]: _5 = const 2_i32 -35:5-38:6: @23[1]: _39 = const ()"> ;</span></span> -<span class="line"><span class="code even" style="--layer: 1" title="36:9-36:14: @23[0]: _5 = const 2_i32 -35:5-38:6: @23[1]: _39 = const ()"> }<span class="annotation">⦉@23</span></span></span><span><span class="code odd" style="--layer: 1" title="38:6-38:6: @24[0]: _39 = const ()"><span class="annotation">@24⦊</span>‸<span class="annotation">⦉@24</span></span></span><span class="code" style="--layer: 0"></span></span> +<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="34:9-34:16: @18[6]: _41 = _1 +33:9-34:16: @18[7]: _40 = Not(move _41)"><span class="annotation">@18⦊</span>!</span></span> +<span class="line"><span class="code odd" style="--layer: 1" title="34:9-34:16: @18[6]: _41 = _1 +33:9-34:16: @18[7]: _40 = Not(move _41)"> is_true<span class="annotation">⦉@18</span></span></span><span class="code" style="--layer: 0"></span></span> +<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="36:9-36:14: @19[0]: _5 = const 2_i32 +35:5-38:6: @19[1]: _39 = const ()"><span class="annotation">@19⦊</span>{</span></span> +<span class="line"><span class="code even" style="--layer: 1" title="36:9-36:14: @19[0]: _5 = const 2_i32 +35:5-38:6: @19[1]: _39 = const ()"> a = 2</span></span> +<span class="line"><span class="code even" style="--layer: 1" title="36:9-36:14: @19[0]: _5 = const 2_i32 +35:5-38:6: @19[1]: _39 = const ()"> ;</span></span> +<span class="line"><span class="code even" style="--layer: 1" title="36:9-36:14: @19[0]: _5 = const 2_i32 +35:5-38:6: @19[1]: _39 = const ()"> }<span class="annotation">⦉@19</span></span></span><span><span class="code odd" style="--layer: 1" title="38:6-38:6: @20[0]: _39 = const ()"><span class="annotation">@20⦊</span>‸<span class="annotation">⦉@20</span></span></span><span class="code" style="--layer: 0"></span></span> <span class="line"><span class="code" style="--layer: 0"></span></span> <span class="line"><span class="code" style="--layer: 0"> if</span></span> -<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="41:9-41:16: @25[4]: _43 = _1"><span class="annotation">@25⦊</span>is_true<span class="annotation">⦉@25</span></span></span><span class="code" style="--layer: 0"></span></span> -<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="43:9-43:15: @26[0]: _6 = const 30_i32 -42:5-45:6: @26[1]: _42 = const ()"><span class="annotation">@26⦊</span>{</span></span> -<span class="line"><span class="code odd" style="--layer: 1" title="43:9-43:15: @26[0]: _6 = const 30_i32 -42:5-45:6: @26[1]: _42 = const ()"> b = 30</span></span> -<span class="line"><span class="code odd" style="--layer: 1" title="43:9-43:15: @26[0]: _6 = const 30_i32 -42:5-45:6: @26[1]: _42 = const ()"> ;</span></span> -<span class="line"><span class="code odd" style="--layer: 1" title="43:9-43:15: @26[0]: _6 = const 30_i32 -42:5-45:6: @26[1]: _42 = const ()"> }<span class="annotation">⦉@26</span></span></span><span class="code" style="--layer: 0"></span></span> +<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="41:9-41:16: @21[4]: _43 = _1"><span class="annotation">@21⦊</span>is_true<span class="annotation">⦉@21</span></span></span><span class="code" style="--layer: 0"></span></span> +<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="43:9-43:15: @22[0]: _6 = const 30_i32 +42:5-45:6: @22[1]: _42 = const ()"><span class="annotation">@22⦊</span>{</span></span> +<span class="line"><span class="code odd" style="--layer: 1" title="43:9-43:15: @22[0]: _6 = const 30_i32 +42:5-45:6: @22[1]: _42 = const ()"> b = 30</span></span> +<span class="line"><span class="code odd" style="--layer: 1" title="43:9-43:15: @22[0]: _6 = const 30_i32 +42:5-45:6: @22[1]: _42 = const ()"> ;</span></span> +<span class="line"><span class="code odd" style="--layer: 1" title="43:9-43:15: @22[0]: _6 = const 30_i32 +42:5-45:6: @22[1]: _42 = const ()"> }<span class="annotation">⦉@22</span></span></span><span class="code" style="--layer: 0"></span></span> <span class="line"><span class="code" style="--layer: 0"> else</span></span> -<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="48:9-48:16: @27[0]: _7 = const 400_i32 -47:5-50:6: @27[1]: _42 = const ()"><span class="annotation">@27⦊</span>{</span></span> -<span class="line"><span class="code even" style="--layer: 1" title="48:9-48:16: @27[0]: _7 = const 400_i32 -47:5-50:6: @27[1]: _42 = const ()"> c = 400</span></span> -<span class="line"><span class="code even" style="--layer: 1" title="48:9-48:16: @27[0]: _7 = const 400_i32 -47:5-50:6: @27[1]: _42 = const ()"> ;</span></span> -<span class="line"><span class="code even" style="--layer: 1" title="48:9-48:16: @27[0]: _7 = const 400_i32 -47:5-50:6: @27[1]: _42 = const ()"> }<span class="annotation">⦉@27</span></span></span><span class="code" style="--layer: 0"></span></span> +<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="48:9-48:16: @23[0]: _7 = const 400_i32 +47:5-50:6: @23[1]: _42 = const ()"><span class="annotation">@23⦊</span>{</span></span> +<span class="line"><span class="code even" style="--layer: 1" title="48:9-48:16: @23[0]: _7 = const 400_i32 +47:5-50:6: @23[1]: _42 = const ()"> c = 400</span></span> +<span class="line"><span class="code even" style="--layer: 1" title="48:9-48:16: @23[0]: _7 = const 400_i32 +47:5-50:6: @23[1]: _42 = const ()"> ;</span></span> +<span class="line"><span class="code even" style="--layer: 1" title="48:9-48:16: @23[0]: _7 = const 400_i32 +47:5-50:6: @23[1]: _42 = const ()"> }<span class="annotation">⦉@23</span></span></span><span class="code" style="--layer: 0"></span></span> <span class="line"><span class="code" style="--layer: 0"></span></span> -<span class="line"><span class="code" style="--layer: 0"> if </span><span><span class="code odd" style="--layer: 1" title="52:9-52:16: @28[5]: _46 = _1 -52:8-52:16: @28[6]: _45 = Not(move _46)"><span class="annotation">@28⦊</span>!is_true<span class="annotation">⦉@28</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="53:9-53:14: @29[0]: _5 = const 2_i32 -52:17-54:6: @29[1]: _44 = const ()"><span class="annotation">@29⦊</span>{</span></span> -<span class="line"><span class="code even" style="--layer: 1" title="53:9-53:14: @29[0]: _5 = const 2_i32 -52:17-54:6: @29[1]: _44 = const ()"> a = 2;</span></span> -<span class="line"><span class="code even" style="--layer: 1" title="53:9-53:14: @29[0]: _5 = const 2_i32 -52:17-54:6: @29[1]: _44 = const ()"> }<span class="annotation">⦉@29</span></span></span><span><span class="code odd" style="--layer: 1" title="54:6-54:6: @30[0]: _44 = const ()"><span class="annotation">@30⦊</span>‸<span class="annotation">⦉@30</span></span></span><span class="code" style="--layer: 0"></span></span> +<span class="line"><span class="code" style="--layer: 0"> if </span><span><span class="code odd" style="--layer: 1" title="52:9-52:16: @24[5]: _46 = _1 +52:8-52:16: @24[6]: _45 = Not(move _46)"><span class="annotation">@24⦊</span>!is_true<span class="annotation">⦉@24</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="53:9-53:14: @25[0]: _5 = const 2_i32 +52:17-54:6: @25[1]: _44 = const ()"><span class="annotation">@25⦊</span>{</span></span> +<span class="line"><span class="code even" style="--layer: 1" title="53:9-53:14: @25[0]: _5 = const 2_i32 +52:17-54:6: @25[1]: _44 = const ()"> a = 2;</span></span> +<span class="line"><span class="code even" style="--layer: 1" title="53:9-53:14: @25[0]: _5 = const 2_i32 +52:17-54:6: @25[1]: _44 = const ()"> }<span class="annotation">⦉@25</span></span></span><span><span class="code odd" style="--layer: 1" title="54:6-54:6: @26[0]: _44 = const ()"><span class="annotation">@26⦊</span>‸<span class="annotation">⦉@26</span></span></span><span class="code" style="--layer: 0"></span></span> <span class="line"><span class="code" style="--layer: 0"></span></span> -<span class="line"><span class="code" style="--layer: 0"> if </span><span><span class="code even" style="--layer: 1" title="56:8-56:15: @31[3]: _47 = _1"><span class="annotation">@31⦊</span>is_true<span class="annotation">⦉@31</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="57:9-57:15: @32[0]: _6 = const 30_i32 -56:16-58:6: @32[1]: _0 = const ()"><span class="annotation">@32⦊</span>{</span></span> -<span class="line"><span class="code odd" style="--layer: 1" title="57:9-57:15: @32[0]: _6 = const 30_i32 -56:16-58:6: @32[1]: _0 = const ()"> b = 30;</span></span> -<span class="line"><span class="code odd" style="--layer: 1" title="57:9-57:15: @32[0]: _6 = const 30_i32 -56:16-58:6: @32[1]: _0 = const ()"> }<span class="annotation">⦉@32</span></span></span><span class="code" style="--layer: 0"> else </span><span><span class="code even" style="--layer: 1" title="59:9-59:16: @33[0]: _7 = const 400_i32 -58:12-60:6: @33[1]: _0 = const ()"><span class="annotation">@33⦊</span>{</span></span> -<span class="line"><span class="code even" style="--layer: 1" title="59:9-59:16: @33[0]: _7 = const 400_i32 -58:12-60:6: @33[1]: _0 = const ()"> c = 400;</span></span> -<span class="line"><span class="code even" style="--layer: 1" title="59:9-59:16: @33[0]: _7 = const 400_i32 -58:12-60:6: @33[1]: _0 = const ()"> }<span class="annotation">⦉@33</span></span></span><span class="code" style="--layer: 0"></span></span> -<span class="line"><span class="code" style="--layer: 0">}</span><span><span class="code odd" style="--layer: 1" title="61:2-61:2: @34.Return: return"><span class="annotation">@34⦊</span>‸<span class="annotation">⦉@34</span></span></span></span></div> +<span class="line"><span class="code" style="--layer: 0"> if </span><span><span class="code even" style="--layer: 1" title="56:8-56:15: @27[3]: _47 = _1"><span class="annotation">@27⦊</span>is_true<span class="annotation">⦉@27</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="57:9-57:15: @28[0]: _6 = const 30_i32 +56:16-58:6: @28[1]: _0 = const ()"><span class="annotation">@28⦊</span>{</span></span> +<span class="line"><span class="code odd" style="--layer: 1" title="57:9-57:15: @28[0]: _6 = const 30_i32 +56:16-58:6: @28[1]: _0 = const ()"> b = 30;</span></span> +<span class="line"><span class="code odd" style="--layer: 1" title="57:9-57:15: @28[0]: _6 = const 30_i32 +56:16-58:6: @28[1]: _0 = const ()"> }<span class="annotation">⦉@28</span></span></span><span class="code" style="--layer: 0"> else </span><span><span class="code even" style="--layer: 1" title="59:9-59:16: @29[0]: _7 = const 400_i32 +58:12-60:6: @29[1]: _0 = const ()"><span class="annotation">@29⦊</span>{</span></span> +<span class="line"><span class="code even" style="--layer: 1" title="59:9-59:16: @29[0]: _7 = const 400_i32 +58:12-60:6: @29[1]: _0 = const ()"> c = 400;</span></span> +<span class="line"><span class="code even" style="--layer: 1" title="59:9-59:16: @29[0]: _7 = const 400_i32 +58:12-60:6: @29[1]: _0 = const ()"> }<span class="annotation">⦉@29</span></span></span><span class="code" style="--layer: 0"></span></span> +<span class="line"><span class="code" style="--layer: 0">}</span><span><span class="code odd" style="--layer: 1" title="61:2-61:2: @30.Return: return"><span class="annotation">@30⦊</span>‸<span class="annotation">⦉@30</span></span></span></span></div> </body> </html> diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#6}-eq.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#6}-eq.-------.InstrumentCoverage.0.html index 2e128181c5e..9858b270d7e 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#6}-eq.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#6}-eq.-------.InstrumentCoverage.0.html @@ -69,6 +69,6 @@ For revisions in Pull Requests (PR): </style> </head> <body> -<div class="code" style="counter-reset: line 3"><span class="line"> <span><span class="code even" style="--layer: 1"><span class="annotation">@0⦊</span>‸<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0">PartialEq</span><span><span class="code odd" style="--layer: 1" title="4:33-4:33: @4.Return: return"><span class="annotation">@4⦊</span>‸<span class="annotation">⦉@4</span></span></span></span></div> +<div class="code" style="counter-reset: line 3"><span class="line"> <span><span class="code even" style="--layer: 1"><span class="annotation">@0⦊</span>‸<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0">PartialEq</span><span><span class="code odd" style="--layer: 1" title="4:33-4:33: @3.Return: return"><span class="annotation">@3⦊</span>‸<span class="annotation">⦉@3</span></span></span></span></div> </body> </html> diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#6}-ne.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#6}-ne.-------.InstrumentCoverage.0.html index 637b1c62086..bf94e5cbf73 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#6}-ne.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#6}-ne.-------.InstrumentCoverage.0.html @@ -69,6 +69,6 @@ For revisions in Pull Requests (PR): </style> </head> <body> -<div class="code" style="counter-reset: line 3"><span class="line"> <span><span class="code even" style="--layer: 1"><span class="annotation">@0⦊</span>‸<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0">PartialEq</span><span><span class="code odd" style="--layer: 1" title="4:33-4:33: @4.Return: return"><span class="annotation">@4⦊</span>‸<span class="annotation">⦉@4</span></span></span></span></div> +<div class="code" style="counter-reset: line 3"><span class="line"> <span><span class="code even" style="--layer: 1"><span class="annotation">@0⦊</span>‸<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0">PartialEq</span><span><span class="code odd" style="--layer: 1" title="4:33-4:33: @3.Return: return"><span class="annotation">@3⦊</span>‸<span class="annotation">⦉@3</span></span></span></span></div> </body> </html> diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.unused/unused.foo.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.unused/unused.foo.-------.InstrumentCoverage.0.html index 45fec46f55c..ef431a356c2 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.unused/unused.foo.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.unused/unused.foo.-------.InstrumentCoverage.0.html @@ -77,11 +77,11 @@ For revisions in Pull Requests (PR): 3:11-3:17: @2[3]: _4 = Lt(move _5, const 10_i32) 3:11-3:17: @2[5]: FakeRead(ForMatchedPlace, _4)"><span class="annotation">@1,2⦊</span>i < 10<span class="annotation">⦉@1,2</span></span></span><span class="code" style="--layer: 0"> {</span></span> <span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="4:9-4:10: @5[3]: _8 = _2 -4:9-4:15: @5[4]: _7 = Ne(move _8, const 0_i32)"><span class="annotation">@3,5⦊</span>i != 0<span class="annotation">⦉@3,5</span></span></span><span class="code" style="--layer: 0"> || </span><span><span class="code odd" style="--layer: 1" title="4:19-4:20: @8[2]: _10 = _2 -4:19-4:25: @8[3]: _9 = Ne(move _10, const 0_i32)"><span class="annotation">@8⦊</span>i != 0<span class="annotation">⦉@8</span></span></span><span class="code" style="--layer: 0">;</span></span> -<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="5:9-5:15: @9[3]: _11 = CheckedAdd(_2, const 1_i32) -5:9-5:15: @10[0]: _2 = move (_11.0: i32)"><span class="annotation">@9,10⦊</span>i += 1<span class="annotation">⦉@9,10</span></span></span><span class="code" style="--layer: 0">;</span></span> +4:9-4:15: @5[4]: _7 = Ne(move _8, const 0_i32)"><span class="annotation">@3,5⦊</span>i != 0<span class="annotation">⦉@3,5</span></span></span><span class="code" style="--layer: 0"> || </span><span><span class="code odd" style="--layer: 1" title="4:19-4:20: @7[2]: _10 = _2 +4:19-4:25: @7[3]: _9 = Ne(move _10, const 0_i32)"><span class="annotation">@7⦊</span>i != 0<span class="annotation">⦉@7</span></span></span><span class="code" style="--layer: 0">;</span></span> +<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="5:9-5:15: @8[3]: _11 = CheckedAdd(_2, const 1_i32) +5:9-5:15: @9[0]: _2 = move (_11.0: i32)"><span class="annotation">@8,9⦊</span>i += 1<span class="annotation">⦉@8,9</span></span></span><span class="code" style="--layer: 0">;</span></span> <span class="line"><span class="code" style="--layer: 0"> }</span></span> -<span class="line"><span class="code" style="--layer: 0">}</span><span><span class="code odd" style="--layer: 1" title="7:2-7:2: @11.Return: return"><span class="annotation">@4,11⦊</span>‸<span class="annotation">⦉@4,11</span></span></span></span></div> +<span class="line"><span class="code" style="--layer: 0">}</span><span><span class="code odd" style="--layer: 1" title="7:2-7:2: @10.Return: return"><span class="annotation">@4,10⦊</span>‸<span class="annotation">⦉@4,10</span></span></span></span></div> </body> </html> diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.unused/unused.unused_template_func.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.unused/unused.unused_template_func.-------.InstrumentCoverage.0.html index 9b32bcb47f6..be4f5efc5db 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.unused/unused.unused_template_func.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.unused/unused.unused_template_func.-------.InstrumentCoverage.0.html @@ -77,11 +77,11 @@ For revisions in Pull Requests (PR): 11:11-11:17: @2[3]: _4 = Lt(move _5, const 10_i32) 11:11-11:17: @2[5]: FakeRead(ForMatchedPlace, _4)"><span class="annotation">@1,2⦊</span>i < 10<span class="annotation">⦉@1,2</span></span></span><span class="code" style="--layer: 0"> {</span></span> <span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="12:9-12:10: @5[3]: _8 = _2 -12:9-12:15: @5[4]: _7 = Ne(move _8, const 0_i32)"><span class="annotation">@3,5⦊</span>i != 0<span class="annotation">⦉@3,5</span></span></span><span class="code" style="--layer: 0"> || </span><span><span class="code odd" style="--layer: 1" title="12:19-12:20: @8[2]: _10 = _2 -12:19-12:25: @8[3]: _9 = Ne(move _10, const 0_i32)"><span class="annotation">@8⦊</span>i != 0<span class="annotation">⦉@8</span></span></span><span class="code" style="--layer: 0">;</span></span> -<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="13:9-13:15: @9[3]: _11 = CheckedAdd(_2, const 1_i32) -13:9-13:15: @10[0]: _2 = move (_11.0: i32)"><span class="annotation">@9,10⦊</span>i += 1<span class="annotation">⦉@9,10</span></span></span><span class="code" style="--layer: 0">;</span></span> +12:9-12:15: @5[4]: _7 = Ne(move _8, const 0_i32)"><span class="annotation">@3,5⦊</span>i != 0<span class="annotation">⦉@3,5</span></span></span><span class="code" style="--layer: 0"> || </span><span><span class="code odd" style="--layer: 1" title="12:19-12:20: @7[2]: _10 = _2 +12:19-12:25: @7[3]: _9 = Ne(move _10, const 0_i32)"><span class="annotation">@7⦊</span>i != 0<span class="annotation">⦉@7</span></span></span><span class="code" style="--layer: 0">;</span></span> +<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="13:9-13:15: @8[3]: _11 = CheckedAdd(_2, const 1_i32) +13:9-13:15: @9[0]: _2 = move (_11.0: i32)"><span class="annotation">@8,9⦊</span>i += 1<span class="annotation">⦉@8,9</span></span></span><span class="code" style="--layer: 0">;</span></span> <span class="line"><span class="code" style="--layer: 0"> }</span></span> -<span class="line"><span class="code" style="--layer: 0">}</span><span><span class="code odd" style="--layer: 1" title="15:2-15:2: @11.Return: return"><span class="annotation">@4,11⦊</span>‸<span class="annotation">⦉@4,11</span></span></span></span></div> +<span class="line"><span class="code" style="--layer: 0">}</span><span><span class="code odd" style="--layer: 1" title="15:2-15:2: @10.Return: return"><span class="annotation">@4,10⦊</span>‸<span class="annotation">⦉@4,10</span></span></span></span></div> </body> </html> diff --git a/src/test/run-make-fulldeps/coverage/lib/used_inline_crate.rs b/src/test/run-make-fulldeps/coverage/lib/used_inline_crate.rs index f4c3dd46f76..4a052756d4e 100644 --- a/src/test/run-make-fulldeps/coverage/lib/used_inline_crate.rs +++ b/src/test/run-make-fulldeps/coverage/lib/used_inline_crate.rs @@ -28,12 +28,12 @@ pub fn used_inline_function() { } use_this_lib_crate(); } -// Expect for above function: -// -// | Unexecuted instantiation: used_crate::used_only_from_bin_crate_generic_function::<_> -// -// With `#[inline(always)]` this function is instantiated twice, in both the library crate (which -// does not use it) and the `uses_inline_crate` binary (which does use/call it). + + + + + + #[inline(always)] pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) { diff --git a/src/test/run-make-fulldeps/issue-83045/Makefile b/src/test/run-make-fulldeps/issue-83045/Makefile new file mode 100644 index 00000000000..34853cb1d31 --- /dev/null +++ b/src/test/run-make-fulldeps/issue-83045/Makefile @@ -0,0 +1,33 @@ +include ../../run-make-fulldeps/tools.mk + +# This test case creates a situation where the crate loader would run +# into an ICE when confronted with an invalid setup where it cannot +# find the dependency of a direct dependency. +# +# The test case makes sure that the compiler produces the expected +# error message but does not ICE immediately after. +# +# See https://github.com/rust-lang/rust/issues/83045 + +# This is a platform-independent issue, no need to waste time testing +# everywhere. +# only-x86_64 +# only-linux + +# NOTE: We use BARE_RUSTC below so that the compiler can't find liba.rlib +# If we used RUSTC the additional '-L TMPDIR' option would allow rustc to +# actually find the crate. +# +# We check that we get the expected error message +# But that we do not get an ICE + +all: + $(RUSTC) --crate-name=a --crate-type=rlib a.rs --verbose + $(RUSTC) --crate-name=b --crate-type=rlib --extern a=$(TMPDIR)/liba.rlib b.rs --verbose + $(BARE_RUSTC) --out-dir $(TMPDIR) \ + --extern b=$(TMPDIR)/libb.rlib \ + --crate-type=rlib \ + --edition=2018 \ + c.rs 2>&1 | tee $(TMPDIR)/output.txt || exit 0 + $(CGREP) E0463 < $(TMPDIR)/output.txt + $(CGREP) -v "internal compiler error" < $(TMPDIR)/output.txt diff --git a/src/test/run-make-fulldeps/issue-83045/a.rs b/src/test/run-make-fulldeps/issue-83045/a.rs new file mode 100644 index 00000000000..66d9f758e9d --- /dev/null +++ b/src/test/run-make-fulldeps/issue-83045/a.rs @@ -0,0 +1 @@ +// empty on purpose diff --git a/src/test/run-make-fulldeps/issue-83045/b.rs b/src/test/run-make-fulldeps/issue-83045/b.rs new file mode 100644 index 00000000000..f4876cfa457 --- /dev/null +++ b/src/test/run-make-fulldeps/issue-83045/b.rs @@ -0,0 +1 @@ +extern crate a; diff --git a/src/test/run-make-fulldeps/issue-83045/c.rs b/src/test/run-make-fulldeps/issue-83045/c.rs new file mode 100644 index 00000000000..e0c4525499e --- /dev/null +++ b/src/test/run-make-fulldeps/issue-83045/c.rs @@ -0,0 +1 @@ +use b as _; diff --git a/src/test/run-make/incr-prev-body-beyond-eof/Makefile b/src/test/run-make/incr-prev-body-beyond-eof/Makefile index 49a7ee5f900..24eea3acaea 100644 --- a/src/test/run-make/incr-prev-body-beyond-eof/Makefile +++ b/src/test/run-make/incr-prev-body-beyond-eof/Makefile @@ -1,7 +1,7 @@ -include ../../run-make-fulldeps/tools.mk +# ignore-none no-std is not supported +# ignore-nvptx64-nvidia-cuda FIXME: can't find crate for `std` -# FIXME https://github.com/rust-lang/rust/issues/78911 -# ignore-32bit wrong/no cross compiler and sometimes we pass wrong gcc args (-m64) +include ../../run-make-fulldeps/tools.mk # Tests that we don't ICE during incremental compilation after modifying a # function span such that its previous end line exceeds the number of lines @@ -14,6 +14,6 @@ all: mkdir $(SRC) mkdir $(INCR) cp a.rs $(SRC)/main.rs - $(RUSTC) -C incremental=$(INCR) $(SRC)/main.rs + $(RUSTC) -C incremental=$(INCR) $(SRC)/main.rs --target $(TARGET) cp b.rs $(SRC)/main.rs - $(RUSTC) -C incremental=$(INCR) $(SRC)/main.rs + $(RUSTC) -C incremental=$(INCR) $(SRC)/main.rs --target $(TARGET) diff --git a/src/test/run-make/issue-36710/Makefile b/src/test/run-make/issue-36710/Makefile index b0e8451ff5d..b5270ad2ba9 100644 --- a/src/test/run-make/issue-36710/Makefile +++ b/src/test/run-make/issue-36710/Makefile @@ -1,13 +1,20 @@ -include ../../run-make-fulldeps/tools.mk +# ignore-riscv64 $(call RUN,foo) expects to run the target executable natively +# so it won't work with remote-test-server +# ignore-arm Another build using remote-test-server +# ignore-none no-std is not supported +# ignore-wasm32 FIXME: don't attempt to compile C++ to WASM +# ignore-wasm64 FIXME: don't attempt to compile C++ to WASM +# ignore-nvptx64-nvidia-cuda FIXME: can't find crate for `std` +# ignore-musl FIXME: this makefile needs teaching how to use a musl toolchain +# (see dist-i586-gnu-i586-i686-musl Dockerfile) -# FIXME https://github.com/rust-lang/rust/issues/78911 -# ignore-32bit wrong/no cross compiler and sometimes we pass wrong gcc args (-m64) +include ../../run-make-fulldeps/tools.mk all: foo $(call RUN,foo) foo: foo.rs $(call NATIVE_STATICLIB,foo) - $(RUSTC) $< -lfoo $(EXTRARSCXXFLAGS) + $(RUSTC) $< -lfoo $(EXTRARSCXXFLAGS) --target $(TARGET) $(TMPDIR)/libfoo.o: foo.cpp $(call COMPILE_OBJ_CXX,$@,$<) diff --git a/src/test/run-make/issue-83112-incr-test-moved-file/Makefile b/src/test/run-make/issue-83112-incr-test-moved-file/Makefile index 76ecaba0f6a..2f796e5b2fc 100644 --- a/src/test/run-make/issue-83112-incr-test-moved-file/Makefile +++ b/src/test/run-make/issue-83112-incr-test-moved-file/Makefile @@ -1,7 +1,7 @@ include ../../run-make-fulldeps/tools.mk -# FIXME https://github.com/rust-lang/rust/issues/78911 -# ignore-32bit wrong/no cross compiler and sometimes we pass wrong gcc args (-m64) +# ignore-none no-std is not supported +# ignore-nvptx64-nvidia-cuda FIXME: can't find crate for 'std' # Regression test for issue #83112 # The generated test harness code contains spans with a dummy location, @@ -20,6 +20,6 @@ all: mkdir $(SRC)/mydir mkdir $(INCR) cp main.rs $(SRC)/main.rs - $(RUSTC) --test -C incremental=$(INCR) $(SRC)/main.rs + $(RUSTC) --test -C incremental=$(INCR) $(SRC)/main.rs --target $(TARGET) mv $(SRC)/main.rs $(SRC)/mydir/main.rs - $(RUSTC) --test -C incremental=$(INCR) $(SRC)/mydir/main.rs + $(RUSTC) --test -C incremental=$(INCR) $(SRC)/mydir/main.rs --target $(TARGET) diff --git a/src/test/rustdoc-gui/search-tab-selection-if-current-is-empty.goml b/src/test/rustdoc-gui/search-tab-selection-if-current-is-empty.goml new file mode 100644 index 00000000000..a4df102d245 --- /dev/null +++ b/src/test/rustdoc-gui/search-tab-selection-if-current-is-empty.goml @@ -0,0 +1,21 @@ +goto: file://|DOC_PATH|/index.html +write: (".search-input", "Foo") +// Waiting for the search results to appear... +wait-for: "#titles" +assert: ("#titles > button:nth-of-type(1)", "class", "selected") + +// To go back to the original "state" +goto: file://|DOC_PATH|/index.html +write: (".search-input", "-> String") +// Waiting for the search results to appear... +wait-for: "#titles" +// With this search, only the last tab shouldn't be empty so it should be selected. +assert: ("#titles > button:nth-of-type(3)", "class", "selected") + +// To go back to the original "state" +goto: file://|DOC_PATH|/index.html +write: (".search-input", "-> Something") +// Waiting for the search results to appear... +wait-for: "#titles" +// With this search, all the tabs are empty so the first one should remain selected. +assert: ("#titles > button:nth-of-type(1)", "class", "selected") diff --git a/src/test/rustdoc-json/reexport/in_root_and_mod.rs b/src/test/rustdoc-json/reexport/in_root_and_mod.rs new file mode 100644 index 00000000000..e3cecbdd7ff --- /dev/null +++ b/src/test/rustdoc-json/reexport/in_root_and_mod.rs @@ -0,0 +1,15 @@ +#![feature(no_core)] +#![no_core] + +mod foo { + // @set foo_id = in_root_and_mod.json "$.index[*][?(@.name=='Foo')].id" + pub struct Foo; +} + +// @has - "$.index[*][?(@.name=='in_root_and_mod')].inner.items[*]" $foo_id +pub use foo::Foo; + +pub mod bar { + // @has - "$.index[*][?(@.name=='bar')].inner.items[*]" $foo_id + pub use crate::foo::Foo; +} diff --git a/src/test/rustdoc-json/reexport/in_root_and_mod_pub.rs b/src/test/rustdoc-json/reexport/in_root_and_mod_pub.rs new file mode 100644 index 00000000000..2daadf7620c --- /dev/null +++ b/src/test/rustdoc-json/reexport/in_root_and_mod_pub.rs @@ -0,0 +1,20 @@ +#![feature(no_core)] +#![no_core] + +pub mod foo { + // @set bar_id = in_root_and_mod_pub.json "$.index[*][?(@.name=='Bar')].id" + // @has - "$.index[*][?(@.name=='foo')].inner.items[*]" $bar_id + pub struct Bar; +} + +// @set root_import_id = - "$.index[*][?(@.inner.source=='foo::Bar')].id" +// @is - "$.index[*][?(@.inner.source=='foo::Bar')].inner.id" $bar_id +// @has - "$.index[*][?(@.name=='in_root_and_mod_pub')].inner.items[*]" $root_import_id +pub use foo::Bar; + +pub mod baz { + // @set baz_import_id = - "$.index[*][?(@.inner.source=='crate::foo::Bar')].id" + // @is - "$.index[*][?(@.inner.source=='crate::foo::Bar')].inner.id" $bar_id + // @has - "$.index[*][?(@.name=='baz')].inner.items[*]" $baz_import_id + pub use crate::foo::Bar; +} diff --git a/src/test/rustdoc-json/reexport/rename_private.rs b/src/test/rustdoc-json/reexport/rename_private.rs new file mode 100644 index 00000000000..fb8296f2337 --- /dev/null +++ b/src/test/rustdoc-json/reexport/rename_private.rs @@ -0,0 +1,14 @@ +// edition:2018 + +#![no_core] +#![feature(no_core)] +// @!has rename_private.json "$.index[*][?(@.name=='inner')]" +mod inner { + // @!has - "$.index[*][?(@.name=='Public')]" + pub struct Public; +} + +// @set newname_id = - "$.index[*][?(@.name=='NewName')].id" +// @is - "$.index[*][?(@.name=='NewName')].kind" \"struct\" +// @has - "$.index[*][?(@.name=='rename_private')].inner.items[*]" $newname_id +pub use inner::Public as NewName; diff --git a/src/test/rustdoc-ui/check-doc-alias-attr.stderr b/src/test/rustdoc-ui/check-doc-alias-attr.stderr index f99d69dc101..250568be333 100644 --- a/src/test/rustdoc-ui/check-doc-alias-attr.stderr +++ b/src/test/rustdoc-ui/check-doc-alias-attr.stderr @@ -10,7 +10,7 @@ error: doc alias attribute expects a string `#[doc(alias = "a")]` or a list of s LL | #[doc(alias = 0)] | ^^^^^^^^^ -error: '\"' character isn't allowed in `#[doc(alias = "...")]` +error: '"' character isn't allowed in `#[doc(alias = "...")]` --> $DIR/check-doc-alias-attr.rs:9:15 | LL | #[doc(alias = "\"")] @@ -60,7 +60,7 @@ error: `#[doc(alias("a"))]` expects string literals LL | #[doc(alias(0))] | ^ -error: '\"' character isn't allowed in `#[doc(alias("..."))]` +error: '"' character isn't allowed in `#[doc(alias("..."))]` --> $DIR/check-doc-alias-attr.rs:20:13 | LL | #[doc(alias("\""))] diff --git a/src/test/rustdoc-ui/doc-spotlight.fixed b/src/test/rustdoc-ui/doc-spotlight.fixed new file mode 100644 index 00000000000..6c90aace689 --- /dev/null +++ b/src/test/rustdoc-ui/doc-spotlight.fixed @@ -0,0 +1,10 @@ +// ignore-tidy-linelength +// check-pass +// run-rustfix + +#![feature(doc_notable_trait)] + +#[doc(notable_trait)] +//~^ WARN unknown `doc` attribute `spotlight` +//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +trait MyTrait {} diff --git a/src/test/rustdoc-ui/doc-spotlight.rs b/src/test/rustdoc-ui/doc-spotlight.rs new file mode 100644 index 00000000000..7cea553c4b0 --- /dev/null +++ b/src/test/rustdoc-ui/doc-spotlight.rs @@ -0,0 +1,10 @@ +// ignore-tidy-linelength +// check-pass +// run-rustfix + +#![feature(doc_notable_trait)] + +#[doc(spotlight)] +//~^ WARN unknown `doc` attribute `spotlight` +//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +trait MyTrait {} diff --git a/src/test/rustdoc-ui/doc-spotlight.stderr b/src/test/rustdoc-ui/doc-spotlight.stderr new file mode 100644 index 00000000000..e79cdc3d77a --- /dev/null +++ b/src/test/rustdoc-ui/doc-spotlight.stderr @@ -0,0 +1,14 @@ +warning: unknown `doc` attribute `spotlight` + --> $DIR/doc-spotlight.rs:7:7 + | +LL | #[doc(spotlight)] + | ^^^^^^^^^ help: use `notable_trait` instead + | + = note: `#[warn(invalid_doc_attributes)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730> + = note: `doc(spotlight)` was renamed to `doc(notable_trait)` + = note: `doc(spotlight)` is now a no-op + +warning: 1 warning emitted + diff --git a/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.rs b/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.rs new file mode 100644 index 00000000000..925fc515a3e --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.rs @@ -0,0 +1,13 @@ +#![deny(warnings)] + +//! Linking to [foo@banana] and [`bar@banana!()`]. +//~^ ERROR unknown disambiguator `foo` +//~| ERROR unknown disambiguator `bar` +//! And to [no disambiguator](@nectarine) and [another](@apricot!()). +//~^ ERROR unknown disambiguator `` +//~| ERROR unknown disambiguator `` +//! And with weird backticks: [``foo@hello``] [foo`@`hello]. +//~^ ERROR unknown disambiguator `foo` +//~| ERROR unknown disambiguator `foo` + +fn main() {} diff --git a/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.stderr b/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.stderr new file mode 100644 index 00000000000..195aaca32a2 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.stderr @@ -0,0 +1,45 @@ +error: unknown disambiguator `foo` + --> $DIR/unknown-disambiguator.rs:3:17 + | +LL | //! Linking to [foo@banana] and [`bar@banana!()`]. + | ^^^ + | +note: the lint level is defined here + --> $DIR/unknown-disambiguator.rs:1:9 + | +LL | #![deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(rustdoc::broken_intra_doc_links)]` implied by `#[deny(warnings)]` + +error: unknown disambiguator `bar` + --> $DIR/unknown-disambiguator.rs:3:35 + | +LL | //! Linking to [foo@banana] and [`bar@banana!()`]. + | ^^^ + +error: unknown disambiguator `foo` + --> $DIR/unknown-disambiguator.rs:9:34 + | +LL | //! And with weird backticks: [``foo@hello``] [foo`@`hello]. + | ^^^ + +error: unknown disambiguator `foo` + --> $DIR/unknown-disambiguator.rs:9:48 + | +LL | //! And with weird backticks: [``foo@hello``] [foo`@`hello]. + | ^^^ + +error: unknown disambiguator `` + --> $DIR/unknown-disambiguator.rs:6:31 + | +LL | //! And to [no disambiguator](@nectarine) and [another](@apricot!()). + | ^ + +error: unknown disambiguator `` + --> $DIR/unknown-disambiguator.rs:6:57 + | +LL | //! And to [no disambiguator](@nectarine) and [another](@apricot!()). + | ^ + +error: aborting due to 6 previous errors + diff --git a/src/test/rustdoc/doc-spotlight.rs b/src/test/rustdoc/doc-notable_trait.rs index ddd46c3c215..58a24b855d6 100644 --- a/src/test/rustdoc/doc-spotlight.rs +++ b/src/test/rustdoc/doc-notable_trait.rs @@ -1,4 +1,4 @@ -#![feature(doc_spotlight)] +#![feature(doc_notable_trait)] pub struct Wrapper<T> { inner: T, @@ -6,9 +6,9 @@ pub struct Wrapper<T> { impl<T: SomeTrait> SomeTrait for Wrapper<T> {} -#[doc(spotlight)] +#[doc(notable_trait)] pub trait SomeTrait { - // @has doc_spotlight/trait.SomeTrait.html + // @has doc_notable_trait/trait.SomeTrait.html // @has - '//code[@class="content"]' 'impl<T: SomeTrait> SomeTrait for Wrapper<T>' fn wrap_me(self) -> Wrapper<Self> where Self: Sized { Wrapper { @@ -21,7 +21,7 @@ pub struct SomeStruct; impl SomeTrait for SomeStruct {} impl SomeStruct { - // @has doc_spotlight/struct.SomeStruct.html + // @has doc_notable_trait/struct.SomeStruct.html // @has - '//code[@class="content"]' 'impl SomeTrait for SomeStruct' // @has - '//code[@class="content"]' 'impl<T: SomeTrait> SomeTrait for Wrapper<T>' pub fn new() -> SomeStruct { @@ -29,7 +29,7 @@ impl SomeStruct { } } -// @has doc_spotlight/fn.bare_fn.html +// @has doc_notable_trait/fn.bare_fn.html // @has - '//code[@class="content"]' 'impl SomeTrait for SomeStruct' pub fn bare_fn() -> SomeStruct { SomeStruct diff --git a/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs b/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs index 8b1a3887f15..51cea4f6ba9 100644 --- a/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs +++ b/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs @@ -33,7 +33,7 @@ macro_rules! fake_lint_pass { if !cx.sess().contains_name(attrs, $attr) { cx.lint(CRATE_NOT_OKAY, |lint| { let msg = format!("crate is not marked with #![{}]", $attr); - lint.build(&msg).set_span(krate.item.span).emit() + lint.build(&msg).set_span(krate.item.inner).emit() }); } )* diff --git a/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs b/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs index c9269d2b9ba..ef5353e6d8c 100644 --- a/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs +++ b/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs @@ -31,7 +31,7 @@ impl<'tcx> LateLintPass<'tcx> for Pass { if !cx.sess().contains_name(attrs, Symbol::intern("crate_okay")) { cx.lint(CRATE_NOT_OKAY, |lint| { lint.build("crate is not marked with #![crate_okay]") - .set_span(krate.item.span) + .set_span(krate.item.inner) .emit() }); } diff --git a/src/test/ui/asm/const.rs b/src/test/ui/asm/const.rs index e08da24f44a..22bc790713d 100644 --- a/src/test/ui/asm/const.rs +++ b/src/test/ui/asm/const.rs @@ -1,4 +1,4 @@ -// no-system-llvm +// min-llvm-version: 10.0.1 // only-x86_64 // run-pass diff --git a/src/test/ui/asm/inline-syntax.arm.stderr b/src/test/ui/asm/inline-syntax.arm.stderr index 78b85dfde33..56e6572fc67 100644 --- a/src/test/ui/asm/inline-syntax.arm.stderr +++ b/src/test/ui/asm/inline-syntax.arm.stderr @@ -1,14 +1,74 @@ -error: att syntax is the default syntax on this target, and trying to use this directive may cause issues - --> $DIR/inline-syntax.rs:23:15 +error: unknown directive + --> $DIR/inline-syntax.rs:22:15 + | +LL | asm!(".intel_syntax noprefix", "nop"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:2 + | +LL | .intel_syntax noprefix + | ^ + +error: unknown directive + --> $DIR/inline-syntax.rs:25:15 + | +LL | asm!(".intel_syntax aaa noprefix", "nop"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:2 + | +LL | .intel_syntax aaa noprefix + | ^ + +error: unknown directive + --> $DIR/inline-syntax.rs:28:15 | LL | asm!(".att_syntax noprefix", "nop"); - | ^^^^^^^^^^^^^^^^^^^^ help: remove this assembler directive + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:2 + | +LL | .att_syntax noprefix + | ^ -error: att syntax is the default syntax on this target, and trying to use this directive may cause issues - --> $DIR/inline-syntax.rs:26:15 +error: unknown directive + --> $DIR/inline-syntax.rs:31:15 | LL | asm!(".att_syntax bbb noprefix", "nop"); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this assembler directive + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:2 + | +LL | .att_syntax bbb noprefix + | ^ + +error: unknown directive + --> $DIR/inline-syntax.rs:34:15 + | +LL | asm!(".intel_syntax noprefix; nop"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:2 + | +LL | .intel_syntax noprefix; nop + | ^ + +error: unknown directive + --> $DIR/inline-syntax.rs:40:13 + | +LL | .intel_syntax noprefix + | ^ + | +note: instantiated into assembly here + --> <inline asm>:2:13 + | +LL | .intel_syntax noprefix + | ^ -error: aborting due to 2 previous errors +error: aborting due to 6 previous errors diff --git a/src/test/ui/asm/inline-syntax.rs b/src/test/ui/asm/inline-syntax.rs index 9048282456e..78dde5a58e1 100644 --- a/src/test/ui/asm/inline-syntax.rs +++ b/src/test/ui/asm/inline-syntax.rs @@ -1,9 +1,12 @@ // needs-llvm-components: arm // revisions: x86_64 arm //[x86_64] compile-flags: --target x86_64-unknown-linux-gnu +//[x86_64] check-pass //[arm] compile-flags: --target armv7-unknown-linux-gnueabihf +//[arm] build-fail #![feature(no_core, lang_items, rustc_attrs)] +#![crate_type = "rlib"] #![no_core] #[rustc_builtin_macro] @@ -14,26 +17,30 @@ macro_rules! asm { #[lang = "sized"] trait Sized {} -fn main() { +pub fn main() { unsafe { asm!(".intel_syntax noprefix", "nop"); - //[x86_64]~^ ERROR intel syntax is the default syntax on this target + //[x86_64]~^ WARN avoid using `.intel_syntax` + //[arm]~^^ ERROR unknown directive asm!(".intel_syntax aaa noprefix", "nop"); - //[x86_64]~^ ERROR intel syntax is the default syntax on this target + //[x86_64]~^ WARN avoid using `.intel_syntax` + //[arm]~^^ ERROR unknown directive asm!(".att_syntax noprefix", "nop"); - //[x86_64]~^ ERROR using the .att_syntax directive may cause issues - //[arm]~^^ att syntax is the default syntax on this target + //[x86_64]~^ WARN avoid using `.att_syntax` + //[arm]~^^ ERROR unknown directive asm!(".att_syntax bbb noprefix", "nop"); - //[x86_64]~^ ERROR using the .att_syntax directive may cause issues - //[arm]~^^ att syntax is the default syntax on this target + //[x86_64]~^ WARN avoid using `.att_syntax` + //[arm]~^^ ERROR unknown directive asm!(".intel_syntax noprefix; nop"); - //[x86_64]~^ ERROR intel syntax is the default syntax on this target + //[x86_64]~^ WARN avoid using `.intel_syntax` + //[arm]~^^ ERROR unknown directive asm!( r" .intel_syntax noprefix nop" ); - //[x86_64]~^^^ ERROR intel syntax is the default syntax on this target + //[x86_64]~^^^ WARN avoid using `.intel_syntax` + //[arm]~^^^^ ERROR unknown directive } } diff --git a/src/test/ui/asm/inline-syntax.x86_64.stderr b/src/test/ui/asm/inline-syntax.x86_64.stderr index 826657c98e1..5c03d3a002c 100644 --- a/src/test/ui/asm/inline-syntax.x86_64.stderr +++ b/src/test/ui/asm/inline-syntax.x86_64.stderr @@ -1,50 +1,40 @@ -error: intel syntax is the default syntax on this target, and trying to use this directive may cause issues - --> $DIR/inline-syntax.rs:19:15 +warning: avoid using `.intel_syntax`, Intel syntax is the default + --> $DIR/inline-syntax.rs:22:15 | LL | asm!(".intel_syntax noprefix", "nop"); - | ^^^^^^^^^^^^^^^^^^^^^^ help: remove this assembler directive + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(bad_asm_style)]` on by default -error: intel syntax is the default syntax on this target, and trying to use this directive may cause issues - --> $DIR/inline-syntax.rs:21:15 +warning: avoid using `.intel_syntax`, Intel syntax is the default + --> $DIR/inline-syntax.rs:25:15 | LL | asm!(".intel_syntax aaa noprefix", "nop"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this assembler directive + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: using the .att_syntax directive may cause issues, use the att_syntax option instead - --> $DIR/inline-syntax.rs:23:15 +warning: avoid using `.att_syntax`, prefer using `options(att_syntax)` instead + --> $DIR/inline-syntax.rs:28:15 | LL | asm!(".att_syntax noprefix", "nop"); | ^^^^^^^^^^^^^^^^^^^^ - | -help: remove the assembler directive and replace it with options(att_syntax) - | -LL | asm!("", "nop", options(att_syntax)); - | -- ^^^^^^^^^^^^^^^^^^^^^ -error: using the .att_syntax directive may cause issues, use the att_syntax option instead - --> $DIR/inline-syntax.rs:26:15 +warning: avoid using `.att_syntax`, prefer using `options(att_syntax)` instead + --> $DIR/inline-syntax.rs:31:15 | LL | asm!(".att_syntax bbb noprefix", "nop"); | ^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: remove the assembler directive and replace it with options(att_syntax) - | -LL | asm!("", "nop", options(att_syntax)); - | -- ^^^^^^^^^^^^^^^^^^^^^ -error: intel syntax is the default syntax on this target, and trying to use this directive may cause issues - --> $DIR/inline-syntax.rs:29:15 +warning: avoid using `.intel_syntax`, Intel syntax is the default + --> $DIR/inline-syntax.rs:34:15 | LL | asm!(".intel_syntax noprefix; nop"); - | ^^^^^^^^^^^^^^^^^^^^^^ help: remove this assembler directive + | ^^^^^^^^^^^^^^^^^^^^^^ -error: intel syntax is the default syntax on this target, and trying to use this directive may cause issues - --> $DIR/inline-syntax.rs:34:14 +warning: avoid using `.intel_syntax`, Intel syntax is the default + --> $DIR/inline-syntax.rs:40:13 | -LL | .intel_syntax noprefix - | ______________^ -LL | | nop" - | |_ help: remove this assembler directive +LL | .intel_syntax noprefix + | ^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 6 previous errors +warning: 6 warnings emitted diff --git a/src/test/ui/asm/srcloc.rs b/src/test/ui/asm/srcloc.rs index 1477e3dd566..ed8cefc58b7 100644 --- a/src/test/ui/asm/srcloc.rs +++ b/src/test/ui/asm/srcloc.rs @@ -1,7 +1,7 @@ -// no-system-llvm +// min-llvm-version: 10.0.1 // only-x86_64 // build-fail - +// compile-flags: -Ccodegen-units=1 #![feature(asm)] // Checks that inline asm errors are mapped to the correct line in the source code. diff --git a/src/test/ui/asm/sym.rs b/src/test/ui/asm/sym.rs index 9931697e412..634ef010e6f 100644 --- a/src/test/ui/asm/sym.rs +++ b/src/test/ui/asm/sym.rs @@ -1,4 +1,4 @@ -// no-system-llvm +// min-llvm-version: 10.0.1 // only-x86_64 // only-linux // run-pass @@ -76,5 +76,5 @@ fn main() { std::thread::spawn(|| { assert_eq!(static_addr!(S1), &S1 as *const u32); assert_eq!(static_tls_addr!(S2), &S2 as *const u32); - }); + }).join().unwrap(); } diff --git a/src/test/ui/associated-type-bounds/hrtb.rs b/src/test/ui/associated-type-bounds/hrtb.rs new file mode 100644 index 00000000000..7ab3836493b --- /dev/null +++ b/src/test/ui/associated-type-bounds/hrtb.rs @@ -0,0 +1,65 @@ +// check-pass + +#![feature(associated_type_bounds)] + +trait A<'a> {} +trait B<'b> {} +fn foo<T>() +where + for<'a> T: A<'a> + 'a, +{ +} +trait C<'c>: for<'a> A<'a> + for<'b> B<'b> { + type As; +} +struct D<T> +where + T: for<'c> C<'c, As: A<'c>>, +{ + t: std::marker::PhantomData<T>, +} + +trait E<'e> { + type As; +} +trait F<'f>: for<'a> A<'a> + for<'e> E<'e> {} +struct G<T> +where + for<'f> T: F<'f, As: E<'f>> + 'f, +{ + t: std::marker::PhantomData<T>, +} + +trait I<'a, 'b, 'c> { + type As; +} +trait H<'d, 'e>: for<'f> I<'d, 'f, 'e> + 'd {} +fn foo2<T>() +where + T: for<'g> H<'g, 'g, As: for<'h> H<'h, 'g> + 'g>, +{ +} + +fn foo3<T>() +where + T: for<'i> H<'i, 'i, As: for<'j> H<'j, 'i, As: for<'k> I<'i, 'k, 'j> + 'j> + 'i>, +{ +} +fn foo4<T>() +where + T: for<'l, 'i> H<'l, 'i, As: for<'j> H<'j, 'i, As: for<'k> I<'l, 'k, 'j> + 'j> + 'i>, +{ +} + +struct X<'x, 'y> { + x: std::marker::PhantomData<&'x ()>, + y: std::marker::PhantomData<&'y ()>, +} + +fn foo5<T>() +where + T: for<'l, 'i> H<'l, 'i, As: for<'j> H<'j, 'i, As: for<'k> H<'j, 'k, As = X<'j, 'k>> + 'j> + 'i> +{ +} + +fn main() {} diff --git a/src/test/ui/associated-types/impl-trait-return-missing-constraint.stderr b/src/test/ui/associated-types/impl-trait-return-missing-constraint.stderr index b0e9e33a6c3..89e05b61fc9 100644 --- a/src/test/ui/associated-types/impl-trait-return-missing-constraint.stderr +++ b/src/test/ui/associated-types/impl-trait-return-missing-constraint.stderr @@ -2,13 +2,13 @@ error[E0271]: type mismatch resolving `<impl Bar as Foo>::Item == i32` --> $DIR/impl-trait-return-missing-constraint.rs:25:13 | LL | fn bar() -> impl Bar { - | -------- the expected opaque type + | -------- the found opaque type ... LL | fn baz() -> impl Bar<Item = i32> { - | ^^^^^^^^^^^^^^^^^^^^ expected associated type, found `i32` + | ^^^^^^^^^^^^^^^^^^^^ expected `i32`, found associated type | - = note: expected associated type `<impl Bar as Foo>::Item` - found type `i32` + = note: expected type `i32` + found associated type `<impl Bar as Foo>::Item` help: consider constraining the associated type `<impl Bar as Foo>::Item` to `i32` | LL | fn bar() -> impl Bar<Item = i32> { diff --git a/src/test/ui/associated-types/issue-44153.stderr b/src/test/ui/associated-types/issue-44153.stderr index 8ef71087958..cafc8ec52ca 100644 --- a/src/test/ui/associated-types/issue-44153.stderr +++ b/src/test/ui/associated-types/issue-44153.stderr @@ -5,7 +5,7 @@ LL | fn visit() {} | ---------- required by `Visit::visit` ... LL | <() as Visit>::visit(); - | ^^^^^^^^^^^^^^^^^^^^ expected `()`, found `&()` + | ^^^^^^^^^^^^^^^^^^^^ expected `&()`, found `()` | = note: required because of the requirements on the impl of `Visit` for `()` diff --git a/src/test/ui/async-await/issues/issue-64964.rs b/src/test/ui/async-await/issues/issue-64964.rs index 11f6cb6af9c..5313d1715c4 100644 --- a/src/test/ui/async-await/issues/issue-64964.rs +++ b/src/test/ui/async-await/issues/issue-64964.rs @@ -1,5 +1,5 @@ // check-pass -// compile-flags: -Z query-dep-graph +// compile-flags: -Z query-dep-graph -C incremental=tmp/issue-64964 // edition:2018 // Regression test for ICE related to `await`ing in a method + incr. comp. (#64964) diff --git a/src/test/ui/async-await/pin-needed-to-poll.rs b/src/test/ui/async-await/pin-needed-to-poll.rs new file mode 100644 index 00000000000..0d1fe684f60 --- /dev/null +++ b/src/test/ui/async-await/pin-needed-to-poll.rs @@ -0,0 +1,47 @@ +use std::{ + future::Future, + pin::Pin, + task::{Context, Poll}, +}; + +struct Sleep; + +impl Future for Sleep { + type Output = (); + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { + Poll::Ready(()) + } +} + +impl Drop for Sleep { + fn drop(&mut self) {} +} + +fn sleep() -> Sleep { + Sleep +} + + +struct MyFuture { + sleep: Sleep, +} + +impl MyFuture { + fn new() -> Self { + Self { + sleep: sleep(), + } + } +} + +impl Future for MyFuture { + type Output = (); + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { + self.sleep.poll(cx) + //~^ ERROR no method named `poll` found for struct `Sleep` in the current scope + } +} + +fn main() {} diff --git a/src/test/ui/async-await/pin-needed-to-poll.stderr b/src/test/ui/async-await/pin-needed-to-poll.stderr new file mode 100644 index 00000000000..0756a4d59c1 --- /dev/null +++ b/src/test/ui/async-await/pin-needed-to-poll.stderr @@ -0,0 +1,22 @@ +error[E0599]: no method named `poll` found for struct `Sleep` in the current scope + --> $DIR/pin-needed-to-poll.rs:42:20 + | +LL | struct Sleep; + | ------------- method `poll` not found for this +... +LL | self.sleep.poll(cx) + | ^^^^ method not found in `Sleep` + | + ::: $SRC_DIR/core/src/future/future.rs:LL:COL + | +LL | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>; + | ---- the method is available for `Pin<&mut Sleep>` here + | +help: consider wrapping the receiver expression with the appropriate type + | +LL | Pin::new(&mut self.sleep).poll(cx) + | ^^^^^^^^^^^^^ ^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/binding/issue-53114-safety-checks.rs b/src/test/ui/binding/issue-53114-safety-checks.rs index 28adb7571a9..ca4f0efd239 100644 --- a/src/test/ui/binding/issue-53114-safety-checks.rs +++ b/src/test/ui/binding/issue-53114-safety-checks.rs @@ -20,13 +20,13 @@ fn let_wild_gets_unsafe_field() { let u1 = U { a: I(0) }; let u2 = U { a: I(1) }; let p = P { a: &2, b: &3 }; - let _ = &p.b; //~ WARN E0133 + let _ = &p.b; //~ WARN reference to packed field //~^ WARN will become a hard error let _ = u1.a; // #53114: should eventually signal error as well let _ = &u2.a; //~ ERROR [E0133] // variation on above with `_` in substructure - let (_,) = (&p.b,); //~ WARN E0133 + let (_,) = (&p.b,); //~ WARN reference to packed field //~^ WARN will become a hard error let (_,) = (u1.a,); //~ ERROR [E0133] let (_,) = (&u2.a,); //~ ERROR [E0133] @@ -36,13 +36,13 @@ fn match_unsafe_field_to_wild() { let u1 = U { a: I(0) }; let u2 = U { a: I(1) }; let p = P { a: &2, b: &3 }; - match &p.b { _ => { } } //~ WARN E0133 + match &p.b { _ => { } } //~ WARN reference to packed field //~^ WARN will become a hard error match u1.a { _ => { } } //~ ERROR [E0133] match &u2.a { _ => { } } //~ ERROR [E0133] // variation on above with `_` in substructure - match (&p.b,) { (_,) => { } } //~ WARN E0133 + match (&p.b,) { (_,) => { } } //~ WARN reference to packed field //~^ WARN will become a hard error match (u1.a,) { (_,) => { } } //~ ERROR [E0133] match (&u2.a,) { (_,) => { } } //~ ERROR [E0133] diff --git a/src/test/ui/binding/issue-53114-safety-checks.stderr b/src/test/ui/binding/issue-53114-safety-checks.stderr index d4b8dfbade5..9e7deea4524 100644 --- a/src/test/ui/binding/issue-53114-safety-checks.stderr +++ b/src/test/ui/binding/issue-53114-safety-checks.stderr @@ -1,13 +1,43 @@ -warning: borrow of packed field is unsafe and requires unsafe function or block (error E0133) +warning: reference to packed field is unaligned --> $DIR/issue-53114-safety-checks.rs:23:13 | LL | let _ = &p.b; | ^^^^ | - = note: `#[warn(safe_packed_borrows)]` on by default + = note: `#[warn(unaligned_references)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #46043 <https://github.com/rust-lang/rust/issues/46043> - = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior + = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> + = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + +warning: reference to packed field is unaligned + --> $DIR/issue-53114-safety-checks.rs:29:17 + | +LL | let (_,) = (&p.b,); + | ^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> + = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + +warning: reference to packed field is unaligned + --> $DIR/issue-53114-safety-checks.rs:39:11 + | +LL | match &p.b { _ => { } } + | ^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> + = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + +warning: reference to packed field is unaligned + --> $DIR/issue-53114-safety-checks.rs:45:12 + | +LL | match (&p.b,) { (_,) => { } } + | ^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> + = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) error[E0133]: access to union field is unsafe and requires unsafe function or block --> $DIR/issue-53114-safety-checks.rs:26:13 @@ -17,16 +47,6 @@ LL | let _ = &u2.a; | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior -warning: borrow of packed field is unsafe and requires unsafe function or block (error E0133) - --> $DIR/issue-53114-safety-checks.rs:29:17 - | -LL | let (_,) = (&p.b,); - | ^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #46043 <https://github.com/rust-lang/rust/issues/46043> - = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior - error[E0133]: access to union field is unsafe and requires unsafe function or block --> $DIR/issue-53114-safety-checks.rs:31:17 | @@ -43,16 +63,6 @@ LL | let (_,) = (&u2.a,); | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior -warning: borrow of packed field is unsafe and requires unsafe function or block (error E0133) - --> $DIR/issue-53114-safety-checks.rs:39:11 - | -LL | match &p.b { _ => { } } - | ^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #46043 <https://github.com/rust-lang/rust/issues/46043> - = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior - error[E0133]: access to union field is unsafe and requires unsafe function or block --> $DIR/issue-53114-safety-checks.rs:41:11 | @@ -69,16 +79,6 @@ LL | match &u2.a { _ => { } } | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior -warning: borrow of packed field is unsafe and requires unsafe function or block (error E0133) - --> $DIR/issue-53114-safety-checks.rs:45:12 - | -LL | match (&p.b,) { (_,) => { } } - | ^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #46043 <https://github.com/rust-lang/rust/issues/46043> - = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior - error[E0133]: access to union field is unsafe and requires unsafe function or block --> $DIR/issue-53114-safety-checks.rs:47:12 | diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/repr_packed.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/repr_packed.rs index 6fce2951505..82ec60a2e79 100644 --- a/src/test/ui/closures/2229_closure_analysis/diagnostics/repr_packed.rs +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/repr_packed.rs @@ -23,7 +23,7 @@ fn test_missing_unsafe_warning_on_repr_packed() { let c = || { println!("{}", foo.x); - //~^ WARNING: borrow of packed field is unsafe and requires unsafe function or block + //~^ WARNING: reference to packed field is unaligned //~| WARNING: this was previously accepted by the compiler but is being phased out let _z = foo.x; }; diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/repr_packed.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/repr_packed.stderr index 440b2c54c0a..e8cc164be87 100644 --- a/src/test/ui/closures/2229_closure_analysis/diagnostics/repr_packed.stderr +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/repr_packed.stderr @@ -7,16 +7,16 @@ LL | #![feature(capture_disjoint_fields)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information -warning: borrow of packed field is unsafe and requires unsafe function or block (error E0133) +warning: reference to packed field is unaligned --> $DIR/repr_packed.rs:25:24 | LL | println!("{}", foo.x); | ^^^^^ | - = note: `#[warn(safe_packed_borrows)]` on by default + = note: `#[warn(unaligned_references)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #46043 <https://github.com/rust-lang/rust/issues/46043> - = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior + = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> + = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) warning: 2 warnings emitted diff --git a/src/test/ui/command/command-setgroups.rs b/src/test/ui/command/command-setgroups.rs index 2067314f740..aff67f91bba 100644 --- a/src/test/ui/command/command-setgroups.rs +++ b/src/test/ui/command/command-setgroups.rs @@ -1,6 +1,5 @@ // run-pass // ignore-windows - this is a unix-specific test -// ignore-cloudabi // ignore-emscripten // ignore-sgx // ignore-musl - returns dummy result for _SC_NGROUPS_MAX diff --git a/src/test/ui/const-generics/defaults/complex-unord-param.rs b/src/test/ui/const-generics/defaults/complex-unord-param.rs index 82b3627d22f..d24e403e017 100644 --- a/src/test/ui/const-generics/defaults/complex-unord-param.rs +++ b/src/test/ui/const-generics/defaults/complex-unord-param.rs @@ -6,16 +6,16 @@ #![allow(dead_code)] struct NestedArrays<'a, const N: usize, A: 'a, const M: usize, T:'a =u32> { - //[min]~^ ERROR type parameters must be declared prior to const parameters - args: &'a [&'a [T; M]; N], - specifier: A, + //[min]~^ ERROR type parameters must be declared prior to const parameters + args: &'a [&'a [T; M]; N], + specifier: A, } fn main() { - let array = [1, 2, 3]; - let nest = [&array]; - let _ = NestedArrays { - args: &nest, - specifier: true, - }; + let array = [1, 2, 3]; + let nest = [&array]; + let _ = NestedArrays { + args: &nest, + specifier: true, + }; } diff --git a/src/test/ui/const-generics/defaults/default-annotation.rs b/src/test/ui/const-generics/defaults/default-annotation.rs index e6e8d732bee..3febb7cffbf 100644 --- a/src/test/ui/const-generics/defaults/default-annotation.rs +++ b/src/test/ui/const-generics/defaults/default-annotation.rs @@ -13,8 +13,8 @@ pub struct ConstDefaultUnstable<const N: usize = 3>; #[stable(feature = "const_default_unstable", since="none")] pub struct ConstDefaultStable<const N: usize = { - #[stable(feature = "const_default_unstable_val", since="none")] - 3 + #[stable(feature = "const_default_unstable_val", since="none")] + 3 }>; fn main() {} diff --git a/src/test/ui/const-generics/defaults/mismatch.rs b/src/test/ui/const-generics/defaults/mismatch.rs index bf578468bb6..d85b756f538 100644 --- a/src/test/ui/const-generics/defaults/mismatch.rs +++ b/src/test/ui/const-generics/defaults/mismatch.rs @@ -8,16 +8,16 @@ pub struct Example3<const N: usize=13, T=u32>(T); pub struct Example4<const N: usize=13, const M: usize=4>; fn main() { - let e: Example::<13> = (); - //~^ Error: mismatched types - let e: Example2::<u32, 13> = (); - //~^ Error: mismatched types - let e: Example3::<13, u32> = (); - //~^ Error: mismatched types - let e: Example3::<7> = (); - //~^ Error: mismatched types - // FIXME(const_generics_defaults): There should be a note for the error below, but it is - // missing. - let e: Example4::<7> = (); - //~^ Error: mismatched types + let e: Example::<13> = (); + //~^ Error: mismatched types + let e: Example2::<u32, 13> = (); + //~^ Error: mismatched types + let e: Example3::<13, u32> = (); + //~^ Error: mismatched types + let e: Example3::<7> = (); + //~^ Error: mismatched types + // FIXME(const_generics_defaults): There should be a note for the error below, but it is + // missing. + let e: Example4::<7> = (); + //~^ Error: mismatched types } diff --git a/src/test/ui/const-generics/defaults/mismatch.stderr b/src/test/ui/const-generics/defaults/mismatch.stderr index c66eb4cd645..ff72c71c40f 100644 --- a/src/test/ui/const-generics/defaults/mismatch.stderr +++ b/src/test/ui/const-generics/defaults/mismatch.stderr @@ -1,51 +1,51 @@ error[E0308]: mismatched types - --> $DIR/mismatch.rs:11:26 + --> $DIR/mismatch.rs:11:28 | -LL | let e: Example::<13> = (); - | ------------- ^^ expected struct `Example`, found `()` - | | - | expected due to this +LL | let e: Example::<13> = (); + | ------------- ^^ expected struct `Example`, found `()` + | | + | expected due to this error[E0308]: mismatched types - --> $DIR/mismatch.rs:13:32 + --> $DIR/mismatch.rs:13:34 | -LL | let e: Example2::<u32, 13> = (); - | ------------------- ^^ expected struct `Example2`, found `()` - | | - | expected due to this +LL | let e: Example2::<u32, 13> = (); + | ------------------- ^^ expected struct `Example2`, found `()` + | | + | expected due to this | = note: expected struct `Example2` found unit type `()` error[E0308]: mismatched types - --> $DIR/mismatch.rs:15:32 + --> $DIR/mismatch.rs:15:34 | -LL | let e: Example3::<13, u32> = (); - | ------------------- ^^ expected struct `Example3`, found `()` - | | - | expected due to this +LL | let e: Example3::<13, u32> = (); + | ------------------- ^^ expected struct `Example3`, found `()` + | | + | expected due to this | = note: expected struct `Example3` found unit type `()` error[E0308]: mismatched types - --> $DIR/mismatch.rs:17:26 + --> $DIR/mismatch.rs:17:28 | -LL | let e: Example3::<7> = (); - | ------------- ^^ expected struct `Example3`, found `()` - | | - | expected due to this +LL | let e: Example3::<7> = (); + | ------------- ^^ expected struct `Example3`, found `()` + | | + | expected due to this | = note: expected struct `Example3<7_usize>` found unit type `()` error[E0308]: mismatched types - --> $DIR/mismatch.rs:21:26 + --> $DIR/mismatch.rs:21:28 | -LL | let e: Example4::<7> = (); - | ------------- ^^ expected struct `Example4`, found `()` - | | - | expected due to this +LL | let e: Example4::<7> = (); + | ------------- ^^ expected struct `Example4`, found `()` + | | + | expected due to this error: aborting due to 5 previous errors diff --git a/src/test/ui/const-generics/defaults/needs-feature.rs b/src/test/ui/const-generics/defaults/needs-feature.rs index 7eb7764a644..b58dee0712a 100644 --- a/src/test/ui/const-generics/defaults/needs-feature.rs +++ b/src/test/ui/const-generics/defaults/needs-feature.rs @@ -10,5 +10,5 @@ struct A<const N: usize, T=u32>(T); //[min]~^ ERROR type parameters must be declared prior fn main() { - let _: A<3> = A(0); + let _: A<3> = A(0); } diff --git a/src/test/ui/const-generics/defaults/repr-c-issue-82792.rs b/src/test/ui/const-generics/defaults/repr-c-issue-82792.rs new file mode 100644 index 00000000000..18ecf467299 --- /dev/null +++ b/src/test/ui/const-generics/defaults/repr-c-issue-82792.rs @@ -0,0 +1,14 @@ +// Regression test for #82792. + +// run-pass + +#![feature(const_generics_defaults)] +#![allow(incomplete_features)] + +#[repr(C)] +pub struct Loaf<T: Sized, const N: usize = 1usize> { + head: [T; N], + slice: [T], +} + +fn main() {} diff --git a/src/test/ui/const-generics/defaults/simple-defaults.rs b/src/test/ui/const-generics/defaults/simple-defaults.rs index 1f1b6c2260d..cb66c7769bb 100644 --- a/src/test/ui/const-generics/defaults/simple-defaults.rs +++ b/src/test/ui/const-generics/defaults/simple-defaults.rs @@ -6,12 +6,12 @@ #![allow(dead_code)] struct FixedOutput<'a, const N: usize, T=u32> { - //[min]~^ ERROR type parameters must be declared prior to const parameters - out: &'a [T; N], + //[min]~^ ERROR type parameters must be declared prior to const parameters + out: &'a [T; N], } trait FixedOutputter { - fn out(&self) -> FixedOutput<'_, 10>; + fn out(&self) -> FixedOutput<'_, 10>; } fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-56445.full.stderr b/src/test/ui/const-generics/issues/issue-56445-1.full.stderr index 61fba92c196..8416d64e1c2 100644 --- a/src/test/ui/const-generics/issues/issue-56445.full.stderr +++ b/src/test/ui/const-generics/issues/issue-56445-1.full.stderr @@ -1,5 +1,5 @@ warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-56445.rs:3:27 + --> $DIR/issue-56445-1.rs:3:27 | LL | #![cfg_attr(full, feature(const_generics))] | ^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | #![cfg_attr(full, feature(const_generics))] = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information error[E0771]: use of non-static lifetime `'a` in const generic - --> $DIR/issue-56445.rs:8:26 + --> $DIR/issue-56445-1.rs:8:26 | LL | struct Bug<'a, const S: &'a str>(PhantomData<&'a ()>); | ^^ diff --git a/src/test/ui/const-generics/issues/issue-56445.min.stderr b/src/test/ui/const-generics/issues/issue-56445-1.min.stderr index 80702dd4bc3..f7056f27cb3 100644 --- a/src/test/ui/const-generics/issues/issue-56445.min.stderr +++ b/src/test/ui/const-generics/issues/issue-56445-1.min.stderr @@ -1,5 +1,5 @@ error[E0771]: use of non-static lifetime `'a` in const generic - --> $DIR/issue-56445.rs:8:26 + --> $DIR/issue-56445-1.rs:8:26 | LL | struct Bug<'a, const S: &'a str>(PhantomData<&'a ()>); | ^^ diff --git a/src/test/ui/const-generics/issues/issue-56445.rs b/src/test/ui/const-generics/issues/issue-56445-1.rs index bc9e1dee853..bc9e1dee853 100644 --- a/src/test/ui/const-generics/issues/issue-56445.rs +++ b/src/test/ui/const-generics/issues/issue-56445-1.rs diff --git a/src/test/ui/const-generics/issues/issue-56445-2.rs b/src/test/ui/const-generics/issues/issue-56445-2.rs new file mode 100644 index 00000000000..e078c8487c7 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-56445-2.rs @@ -0,0 +1,11 @@ +// Regression test for https://github.com/rust-lang/rust/issues/56445#issuecomment-502095133 +struct OnDiskDirEntry<'a> { _s: &'a usize } + +impl<'a> OnDiskDirEntry<'a> { + const LFN_FRAGMENT_LEN: usize = 2; + + fn lfn_contents(&self) -> [char; Self::LFN_FRAGMENT_LEN] { loop { } } + //~^ ERROR: generic `Self` types are currently not permitted in anonymous constants +} + +fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-56445-2.stderr b/src/test/ui/const-generics/issues/issue-56445-2.stderr new file mode 100644 index 00000000000..770c80cbbd3 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-56445-2.stderr @@ -0,0 +1,14 @@ +error: generic `Self` types are currently not permitted in anonymous constants + --> $DIR/issue-56445-2.rs:7:38 + | +LL | fn lfn_contents(&self) -> [char; Self::LFN_FRAGMENT_LEN] { loop { } } + | ^^^^ + | +note: not a concrete type + --> $DIR/issue-56445-2.rs:4:10 + | +LL | impl<'a> OnDiskDirEntry<'a> { + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-56445-3.rs b/src/test/ui/const-generics/issues/issue-56445-3.rs new file mode 100644 index 00000000000..c29df14586e --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-56445-3.rs @@ -0,0 +1,12 @@ +// Regression test for https://github.com/rust-lang/rust/issues/56445#issuecomment-524494170 +pub struct Memory<'rom> { + rom: &'rom [u8], + ram: [u8; Self::SIZE], + //~^ ERROR: generic `Self` types are currently not permitted in anonymous constants +} + +impl<'rom> Memory<'rom> { + pub const SIZE: usize = 0x8000; +} + +fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-56445-3.stderr b/src/test/ui/const-generics/issues/issue-56445-3.stderr new file mode 100644 index 00000000000..f1c49eecfb5 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-56445-3.stderr @@ -0,0 +1,8 @@ +error: generic `Self` types are currently not permitted in anonymous constants + --> $DIR/issue-56445-3.rs:4:15 + | +LL | ram: [u8; Self::SIZE], + | ^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-69654-run-pass.rs b/src/test/ui/const-generics/issues/issue-69654-run-pass.rs index bbfd2183b06..45318ca68fc 100644 --- a/src/test/ui/const-generics/issues/issue-69654-run-pass.rs +++ b/src/test/ui/const-generics/issues/issue-69654-run-pass.rs @@ -1,4 +1,3 @@ -// run-pass #![feature(const_generics)] #![allow(incomplete_features, unused_braces)] @@ -15,4 +14,5 @@ where fn main() { Foo::foo(); + //~^ ERROR the function or associated item } diff --git a/src/test/ui/const-generics/issues/issue-69654-run-pass.stderr b/src/test/ui/const-generics/issues/issue-69654-run-pass.stderr new file mode 100644 index 00000000000..a82a60696b3 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-69654-run-pass.stderr @@ -0,0 +1,15 @@ +error[E0599]: the function or associated item `foo` exists for struct `Foo<{_: usize}>`, but its trait bounds were not satisfied + --> $DIR/issue-69654-run-pass.rs:16:10 + | +LL | struct Foo<const N: usize> {} + | -------------------------- function or associated item `foo` not found for this +... +LL | Foo::foo(); + | ^^^ function or associated item cannot be called on `Foo<{_: usize}>` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `[u8; _]: Bar<[(); _]>` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/const-generics/issues/issue-69654.rs b/src/test/ui/const-generics/issues/issue-69654.rs index 7e775999ebd..b1214b12a14 100644 --- a/src/test/ui/const-generics/issues/issue-69654.rs +++ b/src/test/ui/const-generics/issues/issue-69654.rs @@ -15,4 +15,5 @@ where fn main() { Foo::foo(); + //~^ ERROR the function or associated item } diff --git a/src/test/ui/const-generics/issues/issue-69654.stderr b/src/test/ui/const-generics/issues/issue-69654.stderr index 70af7bf25d8..0ce7640f685 100644 --- a/src/test/ui/const-generics/issues/issue-69654.stderr +++ b/src/test/ui/const-generics/issues/issue-69654.stderr @@ -4,6 +4,19 @@ error[E0423]: expected value, found type parameter `T` LL | impl<T> Bar<T> for [u8; T] {} | ^ not a value -error: aborting due to previous error +error[E0599]: the function or associated item `foo` exists for struct `Foo<{_: usize}>`, but its trait bounds were not satisfied + --> $DIR/issue-69654.rs:17:10 + | +LL | struct Foo<const N: usize> {} + | -------------------------- function or associated item `foo` not found for this +... +LL | Foo::foo(); + | ^^^ function or associated item cannot be called on `Foo<{_: usize}>` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `[u8; _]: Bar<[(); _]>` + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0423`. +Some errors have detailed explanations: E0423, E0599. +For more information about an error, try `rustc --explain E0423`. diff --git a/src/test/ui/const-generics/occurs-check/unused-substs-1.rs b/src/test/ui/const-generics/occurs-check/unused-substs-1.rs index f56687ecd93..6ded9f13bc4 100644 --- a/src/test/ui/const-generics/occurs-check/unused-substs-1.rs +++ b/src/test/ui/const-generics/occurs-check/unused-substs-1.rs @@ -1,4 +1,3 @@ -// build-pass #![feature(const_generics)] #![allow(incomplete_features)] @@ -10,5 +9,5 @@ where A<N>: Bar<N>; fn main() { - let _ = A; + let _ = A; //~ERROR the trait bound } diff --git a/src/test/ui/const-generics/occurs-check/unused-substs-1.stderr b/src/test/ui/const-generics/occurs-check/unused-substs-1.stderr new file mode 100644 index 00000000000..6830288acc0 --- /dev/null +++ b/src/test/ui/const-generics/occurs-check/unused-substs-1.stderr @@ -0,0 +1,17 @@ +error[E0277]: the trait bound `A<{_: usize}>: Bar<{_: usize}>` is not satisfied + --> $DIR/unused-substs-1.rs:12:13 + | +LL | / struct A<const N: usize> +LL | | where +LL | | A<N>: Bar<N>; + | |_________________- required by `A` +... +LL | let _ = A; + | ^ the trait `Bar<{_: usize}>` is not implemented for `A<{_: usize}>` + | + = help: the following implementations were found: + <A<7_usize> as Bar<N>> + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/const-generics/occurs-check/unused-substs-2.rs b/src/test/ui/const-generics/occurs-check/unused-substs-2.rs index 12444ec5312..2d00141fbf7 100644 --- a/src/test/ui/const-generics/occurs-check/unused-substs-2.rs +++ b/src/test/ui/const-generics/occurs-check/unused-substs-2.rs @@ -1,4 +1,3 @@ -// check-pass #![feature(const_generics)] #![allow(incomplete_features)] @@ -24,4 +23,6 @@ fn main() { // `t` is `ty::Infer(TyVar(_#1t))` // `foo` contains `ty::Infer(TyVar(_#1t))` in its substs t = foo; + //~^ ERROR mismatched types + //~| NOTE cyclic type } diff --git a/src/test/ui/const-generics/occurs-check/unused-substs-2.stderr b/src/test/ui/const-generics/occurs-check/unused-substs-2.stderr new file mode 100644 index 00000000000..9532fc21a31 --- /dev/null +++ b/src/test/ui/const-generics/occurs-check/unused-substs-2.stderr @@ -0,0 +1,9 @@ +error[E0308]: mismatched types + --> $DIR/unused-substs-2.rs:25:9 + | +LL | t = foo; + | ^^^ cyclic type of infinite size + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/occurs-check/unused-substs-3.rs b/src/test/ui/const-generics/occurs-check/unused-substs-3.rs index 187e27382fc..2e306f8c4c8 100644 --- a/src/test/ui/const-generics/occurs-check/unused-substs-3.rs +++ b/src/test/ui/const-generics/occurs-check/unused-substs-3.rs @@ -1,4 +1,3 @@ -// check-pass #![feature(const_generics)] #![allow(incomplete_features)] @@ -15,4 +14,6 @@ fn main() { // `t` is `ty::Infer(TyVar(_#1t))` // `foo` contains `ty::Infer(TyVar(_#1t))` in its substs t = foo; + //~^ ERROR mismatched types + //~| NOTE cyclic type } diff --git a/src/test/ui/const-generics/occurs-check/unused-substs-3.stderr b/src/test/ui/const-generics/occurs-check/unused-substs-3.stderr new file mode 100644 index 00000000000..2551d68f974 --- /dev/null +++ b/src/test/ui/const-generics/occurs-check/unused-substs-3.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/unused-substs-3.rs:16:9 + | +LL | t = foo; + | ^^^ + | | + | cyclic type of infinite size + | help: try using a conversion method: `foo.to_vec()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/occurs-check/unused-substs-4.rs b/src/test/ui/const-generics/occurs-check/unused-substs-4.rs index 8e42ceb6d70..9c7f5ab91ed 100644 --- a/src/test/ui/const-generics/occurs-check/unused-substs-4.rs +++ b/src/test/ui/const-generics/occurs-check/unused-substs-4.rs @@ -1,4 +1,3 @@ -// build-pass #![feature(const_generics)] #![allow(incomplete_features)] @@ -8,5 +7,5 @@ fn bind<const N: usize>(value: [u8; N]) -> [u8; 3 + 4] { fn main() { let mut arr = Default::default(); - arr = bind(arr); + arr = bind(arr); //~ ERROR mismatched type } diff --git a/src/test/ui/const-generics/occurs-check/unused-substs-4.stderr b/src/test/ui/const-generics/occurs-check/unused-substs-4.stderr new file mode 100644 index 00000000000..5685eedbdec --- /dev/null +++ b/src/test/ui/const-generics/occurs-check/unused-substs-4.stderr @@ -0,0 +1,9 @@ +error[E0308]: mismatched types + --> $DIR/unused-substs-4.rs:10:11 + | +LL | arr = bind(arr); + | ^^^^^^^^^ encountered a self-referencing constant + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/consts/const-eval/conditional_array_execution.rs b/src/test/ui/consts/const-eval/conditional_array_execution.rs index 9b99a685b63..bd517e568ea 100644 --- a/src/test/ui/consts/const-eval/conditional_array_execution.rs +++ b/src/test/ui/consts/const-eval/conditional_array_execution.rs @@ -10,7 +10,7 @@ const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; fn main() { println!("{}", FOO); - //~^ ERROR + //~^ ERROR evaluation of constant value failed //~| WARN erroneous constant used [const_err] //~| WARN this was previously accepted by the compiler but is being phased out } diff --git a/src/test/ui/consts/const-eval/const-eval-query-stack.stderr b/src/test/ui/consts/const-eval/const-eval-query-stack.stderr index 6a205ce9787..e6fecef9fb3 100644 --- a/src/test/ui/consts/const-eval/const-eval-query-stack.stderr +++ b/src/test/ui/consts/const-eval/const-eval-query-stack.stderr @@ -20,7 +20,7 @@ error[E0080]: evaluation of constant value failed LL | let x: &'static i32 = &X; | ^ referenced constant has errors query stack during panic: -#0 [normalize_generic_arg_after_erasing_regions] normalizing `main::promoted[1]` +#0 [normalize_mir_const_after_erasing_regions] normalizing `main::promoted[1]` #1 [optimized_mir] optimizing MIR for `main` #2 [collect_and_partition_mono_items] collect_and_partition_mono_items end of query stack diff --git a/src/test/ui/consts/const-eval/issue-44578.rs b/src/test/ui/consts/const-eval/issue-44578.rs index 79f1301a2f9..a88e2197048 100644 --- a/src/test/ui/consts/const-eval/issue-44578.rs +++ b/src/test/ui/consts/const-eval/issue-44578.rs @@ -25,5 +25,5 @@ impl Foo for u16 { fn main() { println!("{}", <Bar<u16, u8> as Foo>::AMT); - //~^ ERROR evaluation of constant value failed [E0080] + //~^ ERROR evaluation of constant value failed } diff --git a/src/test/ui/copy-a-resource.stderr b/src/test/ui/copy-a-resource.stderr index 36cf57bd3c5..79095452f9d 100644 --- a/src/test/ui/copy-a-resource.stderr +++ b/src/test/ui/copy-a-resource.stderr @@ -6,14 +6,6 @@ LL | struct Foo { ... LL | let _y = x.clone(); | ^^^^^ method not found in `Foo` - | - ::: $SRC_DIR/core/src/clone.rs:LL:COL - | -LL | fn clone(&self) -> Self; - | ----- - | | - | the method is available for `Arc<Foo>` here - | the method is available for `Rc<Foo>` here | = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `clone`, perhaps you need to implement it: diff --git a/src/test/ui/dep-graph/dep-graph-assoc-type-codegen.rs b/src/test/ui/dep-graph/dep-graph-assoc-type-codegen.rs index 0d11d933af0..a0ee3ad31e6 100644 --- a/src/test/ui/dep-graph/dep-graph-assoc-type-codegen.rs +++ b/src/test/ui/dep-graph/dep-graph-assoc-type-codegen.rs @@ -1,7 +1,7 @@ // Test that when a trait impl changes, fns whose body uses that trait // must also be recompiled. -// compile-flags: -Z query-dep-graph +// compile-flags: -Z query-dep-graph -C incremental=tmp/dep-graph-assoc-type-codegen #![feature(rustc_attrs)] #![allow(warnings)] diff --git a/src/test/ui/dep-graph/dep-graph-caller-callee.rs b/src/test/ui/dep-graph/dep-graph-caller-callee.rs index b12c635d2e7..c95ea53650b 100644 --- a/src/test/ui/dep-graph/dep-graph-caller-callee.rs +++ b/src/test/ui/dep-graph/dep-graph-caller-callee.rs @@ -1,7 +1,7 @@ // Test that immediate callers have to change when callee changes, but // not callers' callers. -// compile-flags: -Z query-dep-graph +// compile-flags: -Z query-dep-graph -C incremental=tmp/dep-graph-caller-callee #![feature(rustc_attrs)] #![allow(dead_code)] diff --git a/src/test/ui/dep-graph/dep-graph-struct-signature.rs b/src/test/ui/dep-graph/dep-graph-struct-signature.rs index 7ef6fac48c3..50a670b8772 100644 --- a/src/test/ui/dep-graph/dep-graph-struct-signature.rs +++ b/src/test/ui/dep-graph/dep-graph-struct-signature.rs @@ -1,7 +1,7 @@ // Test cases where a changing struct appears in the signature of fns // and methods. -// compile-flags: -Z query-dep-graph +// compile-flags: -Z query-dep-graph -C incremental=tmp/dep-graph-struct-signature #![feature(rustc_attrs)] #![allow(dead_code)] diff --git a/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.rs b/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.rs index 1b3bf5a3933..c0a6617316b 100644 --- a/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.rs +++ b/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.rs @@ -1,7 +1,7 @@ // Test that adding an impl to a trait `Foo` DOES affect functions // that only use `Bar` if they have methods in common. -// compile-flags: -Z query-dep-graph +// compile-flags: -Z query-dep-graph -C incremental=tmp/dep-graph-trait-impl-two-traits-same-method #![feature(rustc_attrs)] #![allow(dead_code)] diff --git a/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits.rs b/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits.rs index ebfe8ccc3df..56e9762ddb2 100644 --- a/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits.rs +++ b/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits.rs @@ -1,7 +1,7 @@ // Test that adding an impl to a trait `Foo` does not affect functions // that only use `Bar`, so long as they do not have methods in common. -// compile-flags: -Z query-dep-graph +// compile-flags: -Z query-dep-graph -C incremental=tmp/dep-graph-trait-impl-two-traits #![feature(rustc_attrs)] #![allow(warnings)] diff --git a/src/test/ui/dep-graph/dep-graph-trait-impl.rs b/src/test/ui/dep-graph/dep-graph-trait-impl.rs index 9dd201e2a1f..3bbe3e745ca 100644 --- a/src/test/ui/dep-graph/dep-graph-trait-impl.rs +++ b/src/test/ui/dep-graph/dep-graph-trait-impl.rs @@ -1,7 +1,7 @@ // Test that when a trait impl changes, fns whose body uses that trait // must also be recompiled. -// compile-flags: -Z query-dep-graph +// compile-flags: -Z query-dep-graph -C incremental=tmp/dep-graph-trait-impl #![feature(rustc_attrs)] #![allow(warnings)] diff --git a/src/test/ui/dep-graph/dep-graph-type-alias.rs b/src/test/ui/dep-graph/dep-graph-type-alias.rs index c9151ce79c5..5c5e24693a4 100644 --- a/src/test/ui/dep-graph/dep-graph-type-alias.rs +++ b/src/test/ui/dep-graph/dep-graph-type-alias.rs @@ -1,6 +1,6 @@ // Test that changing what a `type` points to does not go unnoticed. -// compile-flags: -Z query-dep-graph +// compile-flags: -Z query-dep-graph -C incremental=tmp/dep-graph-type-alias #![feature(rustc_attrs)] #![allow(dead_code)] diff --git a/src/test/ui/dep-graph/dep-graph-variance-alias.rs b/src/test/ui/dep-graph/dep-graph-variance-alias.rs index 927ea559778..6cc1f44104a 100644 --- a/src/test/ui/dep-graph/dep-graph-variance-alias.rs +++ b/src/test/ui/dep-graph/dep-graph-variance-alias.rs @@ -1,7 +1,7 @@ // Test that changing what a `type` points to does not go unnoticed // by the variance analysis. -// compile-flags: -Z query-dep-graph +// compile-flags: -Z query-dep-graph -C incremental=tmp/dep-graph-variance-alias #![feature(rustc_attrs)] #![allow(dead_code)] diff --git a/src/test/ui/derives/derive-assoc-type-not-impl.stderr b/src/test/ui/derives/derive-assoc-type-not-impl.stderr index ffee7004f8f..fd993d0f9d8 100644 --- a/src/test/ui/derives/derive-assoc-type-not-impl.stderr +++ b/src/test/ui/derives/derive-assoc-type-not-impl.stderr @@ -12,14 +12,6 @@ LL | struct NotClone; ... LL | Bar::<NotClone> { x: 1 }.clone(); | ^^^^^ method cannot be called on `Bar<NotClone>` due to unsatisfied trait bounds - | - ::: $SRC_DIR/core/src/clone.rs:LL:COL - | -LL | fn clone(&self) -> Self; - | ----- - | | - | the method is available for `Arc<Bar<NotClone>>` here - | the method is available for `Rc<Bar<NotClone>>` here | = note: the following trait bounds were not satisfied: `NotClone: Clone` diff --git a/src/test/ui/derives/deriving-with-repr-packed.rs b/src/test/ui/derives/deriving-with-repr-packed.rs index d354cef66bc..b78eeaa9055 100644 --- a/src/test/ui/derives/deriving-with-repr-packed.rs +++ b/src/test/ui/derives/deriving-with-repr-packed.rs @@ -1,4 +1,4 @@ -#![deny(safe_packed_borrows)] +#![deny(unaligned_references)] // check that derive on a packed struct with non-Copy fields // correctly. This can't be made to work perfectly because diff --git a/src/test/ui/derives/deriving-with-repr-packed.stderr b/src/test/ui/derives/deriving-with-repr-packed.stderr index d739257c8de..3caa563a085 100644 --- a/src/test/ui/derives/deriving-with-repr-packed.stderr +++ b/src/test/ui/derives/deriving-with-repr-packed.stderr @@ -7,10 +7,10 @@ LL | #[derive(Copy, Clone, PartialEq, Eq)] note: the lint level is defined here --> $DIR/deriving-with-repr-packed.rs:1:9 | -LL | #![deny(safe_packed_borrows)] - | ^^^^^^^^^^^^^^^^^^^ +LL | #![deny(unaligned_references)] + | ^^^^^^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #46043 <https://github.com/rust-lang/rust/issues/46043> + = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) error: `#[derive]` can't be used on a `#[repr(packed)]` struct with type or const parameters (error E0133) @@ -20,7 +20,7 @@ LL | #[derive(Copy, Clone, PartialEq, Eq)] | ^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #46043 <https://github.com/rust-lang/rust/issues/46043> + = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) error: `#[derive]` can't be used on a `#[repr(packed)]` struct that does not derive Copy (error E0133) @@ -30,7 +30,7 @@ LL | #[derive(PartialEq, Eq)] | ^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #46043 <https://github.com/rust-lang/rust/issues/46043> + = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) error: `#[derive]` can't be used on a `#[repr(packed)]` struct that does not derive Copy (error E0133) @@ -40,7 +40,7 @@ LL | #[derive(PartialEq)] | ^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #46043 <https://github.com/rust-lang/rust/issues/46043> + = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 4 previous errors diff --git a/src/test/ui/error-codes/E0106.stderr b/src/test/ui/error-codes/E0106.stderr index ac70e887626..b961fc8aeeb 100644 --- a/src/test/ui/error-codes/E0106.stderr +++ b/src/test/ui/error-codes/E0106.stderr @@ -24,17 +24,6 @@ LL | B(&'a bool), | error[E0106]: missing lifetime specifier - --> $DIR/E0106.rs:10:14 - | -LL | type MyStr = &str; - | ^ expected named lifetime parameter - | -help: consider introducing a named lifetime parameter - | -LL | type MyStr<'a> = &'a str; - | ^^^^ ^^^ - -error[E0106]: missing lifetime specifier --> $DIR/E0106.rs:17:10 | LL | baz: Baz, @@ -61,6 +50,17 @@ LL | LL | buzz: Buzz<'a, 'a>, | +error[E0106]: missing lifetime specifier + --> $DIR/E0106.rs:10:14 + | +LL | type MyStr = &str; + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL | type MyStr<'a> = &'a str; + | ^^^^ ^^^ + error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/feature-gates/feature-gate-doc_notable_trait.rs b/src/test/ui/feature-gates/feature-gate-doc_notable_trait.rs new file mode 100644 index 00000000000..7f3392eadad --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-doc_notable_trait.rs @@ -0,0 +1,4 @@ +#[doc(notable_trait)] //~ ERROR: `#[doc(notable_trait)]` is experimental +trait SomeTrait {} + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-doc_notable_trait.stderr b/src/test/ui/feature-gates/feature-gate-doc_notable_trait.stderr new file mode 100644 index 00000000000..1f9bef40c4e --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-doc_notable_trait.stderr @@ -0,0 +1,12 @@ +error[E0658]: `#[doc(notable_trait)]` is experimental + --> $DIR/feature-gate-doc_notable_trait.rs:1:1 + | +LL | #[doc(notable_trait)] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #45040 <https://github.com/rust-lang/rust/issues/45040> for more information + = help: add `#![feature(doc_notable_trait)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-doc_spotlight.rs b/src/test/ui/feature-gates/feature-gate-doc_spotlight.rs deleted file mode 100644 index 452b45b3445..00000000000 --- a/src/test/ui/feature-gates/feature-gate-doc_spotlight.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[doc(spotlight)] //~ ERROR: `#[doc(spotlight)]` is experimental -trait SomeTrait {} - -fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-doc_spotlight.stderr b/src/test/ui/feature-gates/feature-gate-doc_spotlight.stderr deleted file mode 100644 index 010d74054a4..00000000000 --- a/src/test/ui/feature-gates/feature-gate-doc_spotlight.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0658]: `#[doc(spotlight)]` is experimental - --> $DIR/feature-gate-doc_spotlight.rs:1:1 - | -LL | #[doc(spotlight)] - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #45040 <https://github.com/rust-lang/rust/issues/45040> for more information - = help: add `#![feature(doc_spotlight)]` to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-in_band_lifetimes.stderr b/src/test/ui/feature-gates/feature-gate-in_band_lifetimes.stderr index 0f0406b8e17..497b8a429e0 100644 --- a/src/test/ui/feature-gates/feature-gate-in_band_lifetimes.stderr +++ b/src/test/ui/feature-gates/feature-gate-in_band_lifetimes.stderr @@ -1,3 +1,87 @@ +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/feature-gate-in_band_lifetimes.rs:50:14 + | +LL | impl MyTrait<'a> for Y<&'a u8> { + | - ^^ undeclared lifetime + | | + | help: consider introducing lifetime `'a` here: `<'a>` + | + = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes + +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/feature-gate-in_band_lifetimes.rs:50:25 + | +LL | impl MyTrait<'a> for Y<&'a u8> { + | - ^^ undeclared lifetime + | | + | help: consider introducing lifetime `'a` here: `<'a>` + | + = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes + +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/feature-gate-in_band_lifetimes.rs:53:31 + | +LL | fn my_lifetime(&self) -> &'a u8 { self.0 } + | ^^ undeclared lifetime + | + = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes +help: consider introducing lifetime `'a` here + | +LL | impl<'a> MyTrait<'a> for Y<&'a u8> { + | ^^^^ +help: consider introducing lifetime `'a` here + | +LL | fn my_lifetime<'a>(&self) -> &'a u8 { self.0 } + | ^^^^ + +error[E0261]: use of undeclared lifetime name `'b` + --> $DIR/feature-gate-in_band_lifetimes.rs:55:27 + | +LL | fn any_lifetime() -> &'b u8 { &0 } + | ^^ undeclared lifetime + | + = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes +help: consider introducing lifetime `'b` here + | +LL | impl<'b> MyTrait<'a> for Y<&'a u8> { + | ^^^^ +help: consider introducing lifetime `'b` here + | +LL | fn any_lifetime<'b>() -> &'b u8 { &0 } + | ^^^^ + +error[E0261]: use of undeclared lifetime name `'b` + --> $DIR/feature-gate-in_band_lifetimes.rs:57:27 + | +LL | fn borrowed_lifetime(&'b self) -> &'b u8 { &*self.0 } + | ^^ undeclared lifetime + | + = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes +help: consider introducing lifetime `'b` here + | +LL | impl<'b> MyTrait<'a> for Y<&'a u8> { + | ^^^^ +help: consider introducing lifetime `'b` here + | +LL | fn borrowed_lifetime<'b>(&'b self) -> &'b u8 { &*self.0 } + | ^^^^ + +error[E0261]: use of undeclared lifetime name `'b` + --> $DIR/feature-gate-in_band_lifetimes.rs:57:40 + | +LL | fn borrowed_lifetime(&'b self) -> &'b u8 { &*self.0 } + | ^^ undeclared lifetime + | + = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes +help: consider introducing lifetime `'b` here + | +LL | impl<'b> MyTrait<'a> for Y<&'a u8> { + | ^^^^ +help: consider introducing lifetime `'b` here + | +LL | fn borrowed_lifetime<'b>(&'b self) -> &'b u8 { &*self.0 } + | ^^^^ + error[E0261]: use of undeclared lifetime name `'x` --> $DIR/feature-gate-in_band_lifetimes.rs:3:12 | @@ -142,90 +226,6 @@ help: consider introducing lifetime `'b` here LL | fn borrowed_lifetime<'b>(&'b self) -> &'b u8; | ^^^^ -error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/feature-gate-in_band_lifetimes.rs:50:14 - | -LL | impl MyTrait<'a> for Y<&'a u8> { - | - ^^ undeclared lifetime - | | - | help: consider introducing lifetime `'a` here: `<'a>` - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes - -error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/feature-gate-in_band_lifetimes.rs:50:25 - | -LL | impl MyTrait<'a> for Y<&'a u8> { - | - ^^ undeclared lifetime - | | - | help: consider introducing lifetime `'a` here: `<'a>` - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes - -error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/feature-gate-in_band_lifetimes.rs:53:31 - | -LL | fn my_lifetime(&self) -> &'a u8 { self.0 } - | ^^ undeclared lifetime - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes -help: consider introducing lifetime `'a` here - | -LL | impl<'a> MyTrait<'a> for Y<&'a u8> { - | ^^^^ -help: consider introducing lifetime `'a` here - | -LL | fn my_lifetime<'a>(&self) -> &'a u8 { self.0 } - | ^^^^ - -error[E0261]: use of undeclared lifetime name `'b` - --> $DIR/feature-gate-in_band_lifetimes.rs:55:27 - | -LL | fn any_lifetime() -> &'b u8 { &0 } - | ^^ undeclared lifetime - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes -help: consider introducing lifetime `'b` here - | -LL | impl<'b> MyTrait<'a> for Y<&'a u8> { - | ^^^^ -help: consider introducing lifetime `'b` here - | -LL | fn any_lifetime<'b>() -> &'b u8 { &0 } - | ^^^^ - -error[E0261]: use of undeclared lifetime name `'b` - --> $DIR/feature-gate-in_band_lifetimes.rs:57:27 - | -LL | fn borrowed_lifetime(&'b self) -> &'b u8 { &*self.0 } - | ^^ undeclared lifetime - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes -help: consider introducing lifetime `'b` here - | -LL | impl<'b> MyTrait<'a> for Y<&'a u8> { - | ^^^^ -help: consider introducing lifetime `'b` here - | -LL | fn borrowed_lifetime<'b>(&'b self) -> &'b u8 { &*self.0 } - | ^^^^ - -error[E0261]: use of undeclared lifetime name `'b` - --> $DIR/feature-gate-in_band_lifetimes.rs:57:40 - | -LL | fn borrowed_lifetime(&'b self) -> &'b u8 { &*self.0 } - | ^^ undeclared lifetime - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes -help: consider introducing lifetime `'b` here - | -LL | impl<'b> MyTrait<'a> for Y<&'a u8> { - | ^^^^ -help: consider introducing lifetime `'b` here - | -LL | fn borrowed_lifetime<'b>(&'b self) -> &'b u8 { &*self.0 } - | ^^^^ - error: aborting due to 17 previous errors For more information about this error, try `rustc --explain E0261`. diff --git a/src/test/ui/generator/type-mismatch-signature-deduction.stderr b/src/test/ui/generator/type-mismatch-signature-deduction.stderr index 30e23ea8f65..3f1f33a3b12 100644 --- a/src/test/ui/generator/type-mismatch-signature-deduction.stderr +++ b/src/test/ui/generator/type-mismatch-signature-deduction.stderr @@ -16,10 +16,10 @@ error[E0271]: type mismatch resolving `<[generator@$DIR/type-mismatch-signature- --> $DIR/type-mismatch-signature-deduction.rs:5:13 | LL | fn foo() -> impl Generator<Return = i32> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `Result`, found `i32` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found enum `Result` | - = note: expected enum `Result<{integer}, _>` - found type `i32` + = note: expected type `i32` + found enum `Result<{integer}, _>` error: aborting due to 2 previous errors diff --git a/src/test/ui/generic-associated-types/shadowing.stderr b/src/test/ui/generic-associated-types/shadowing.stderr index 95cebbb8681..d45ef83873a 100644 --- a/src/test/ui/generic-associated-types/shadowing.stderr +++ b/src/test/ui/generic-associated-types/shadowing.stderr @@ -15,14 +15,6 @@ LL | type Bar<T> = i32; | ^ already used error[E0496]: lifetime name `'a` shadows a lifetime name that is already in scope - --> $DIR/shadowing.rs:5:14 - | -LL | trait Shadow<'a> { - | -- first declared here -LL | type Bar<'a>; - | ^^ lifetime `'a` already in scope - -error[E0496]: lifetime name `'a` shadows a lifetime name that is already in scope --> $DIR/shadowing.rs:14:14 | LL | impl<'a> NoShadow<'a> for &'a u32 { @@ -30,6 +22,14 @@ LL | impl<'a> NoShadow<'a> for &'a u32 { LL | type Bar<'a> = i32; | ^^ lifetime `'a` already in scope +error[E0496]: lifetime name `'a` shadows a lifetime name that is already in scope + --> $DIR/shadowing.rs:5:14 + | +LL | trait Shadow<'a> { + | -- first declared here +LL | type Bar<'a>; + | ^^ lifetime `'a` already in scope + error: aborting due to 4 previous errors Some errors have detailed explanations: E0403, E0496. diff --git a/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr b/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr index 1106a067822..ce853d4d36d 100644 --- a/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr +++ b/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr @@ -5,6 +5,17 @@ LL | fn should_error<T>() where T : Into<&u32> {} | ^ explicit lifetime name needed here error[E0106]: missing lifetime specifier + --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:13:17 + | +LL | fn bar<'b, L: X<&'b Nested<i32>>>(){} + | ^ expected named lifetime parameter + | +help: consider using the `'b` lifetime + | +LL | fn bar<'b, L: X<'b, &'b Nested<i32>>>(){} + | ^^^ + +error[E0106]: missing lifetime specifier --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:9:21 | LL | fn foo<'b, L: X<&'b Nested<K>>>(); @@ -22,17 +33,6 @@ help: consider using one of the available lifetimes here LL | fn foo<'b, L: X<'lifetime, &'b Nested<K>>>(); | ^^^^^^^^^^ -error[E0106]: missing lifetime specifier - --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:13:17 - | -LL | fn bar<'b, L: X<&'b Nested<i32>>>(){} - | ^ expected named lifetime parameter - | -help: consider using the `'b` lifetime - | -LL | fn bar<'b, L: X<'b, &'b Nested<i32>>>(){} - | ^^^ - error: aborting due to 3 previous errors Some errors have detailed explanations: E0106, E0637. diff --git a/src/test/ui/generics/wrong-number-of-args.stderr b/src/test/ui/generics/wrong-number-of-args.stderr index 73bd76aa5fa..94fdd355d48 100644 --- a/src/test/ui/generics/wrong-number-of-args.stderr +++ b/src/test/ui/generics/wrong-number-of-args.stderr @@ -1,36 +1,3 @@ -error[E0106]: missing lifetime specifier - --> $DIR/wrong-number-of-args.rs:44:14 - | -LL | type A = Ty; - | ^^ expected named lifetime parameter - | -help: consider introducing a named lifetime parameter - | -LL | type A<'a> = Ty<'a>; - | ^^^^ ^^^^^^ - -error[E0106]: missing lifetime specifier - --> $DIR/wrong-number-of-args.rs:54:17 - | -LL | type C = Ty<usize>; - | ^ expected named lifetime parameter - | -help: consider introducing a named lifetime parameter - | -LL | type C<'a> = Ty<'a, usize>; - | ^^^^ ^^^ - -error[E0106]: missing lifetime specifier - --> $DIR/wrong-number-of-args.rs:100:22 - | -LL | type B = Box<dyn GenericLifetime>; - | ^^^^^^^^^^^^^^^ expected named lifetime parameter - | -help: consider introducing a named lifetime parameter - | -LL | type B<'a> = Box<dyn GenericLifetime<'a>>; - | ^^^^ ^^^^^^^^^^^^^^^^^^^ - error[E0107]: this struct takes 0 lifetime arguments but 1 lifetime argument was supplied --> $DIR/wrong-number-of-args.rs:6:14 | @@ -165,6 +132,17 @@ help: use angle brackets to add missing type argument LL | type A = Ty<T>; | ^^^ +error[E0106]: missing lifetime specifier + --> $DIR/wrong-number-of-args.rs:44:14 + | +LL | type A = Ty; + | ^^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL | type A<'a> = Ty<'a>; + | ^^^^ ^^^^^^ + error[E0107]: this struct takes 1 type argument but 0 type arguments were supplied --> $DIR/wrong-number-of-args.rs:50:14 | @@ -181,6 +159,17 @@ help: add missing type argument LL | type B = Ty<'static, T>; | ^^^ +error[E0106]: missing lifetime specifier + --> $DIR/wrong-number-of-args.rs:54:17 + | +LL | type C = Ty<usize>; + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL | type C<'a> = Ty<'a, usize>; + | ^^^^ ^^^ + error[E0107]: missing generics for struct `type_and_type_and_type::Ty` --> $DIR/wrong-number-of-args.rs:64:14 | @@ -243,6 +232,17 @@ note: trait defined here, with 0 type parameters LL | trait NonGeneric { | ^^^^^^^^^^ +error[E0106]: missing lifetime specifier + --> $DIR/wrong-number-of-args.rs:100:22 + | +LL | type B = Box<dyn GenericLifetime>; + | ^^^^^^^^^^^^^^^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL | type B<'a> = Box<dyn GenericLifetime<'a>>; + | ^^^^ ^^^^^^^^^^^^^^^^^^^ + error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied --> $DIR/wrong-number-of-args.rs:104:22 | diff --git a/src/test/ui/hrtb/complex.rs b/src/test/ui/hrtb/complex.rs new file mode 100644 index 00000000000..8cdfe247e02 --- /dev/null +++ b/src/test/ui/hrtb/complex.rs @@ -0,0 +1,28 @@ +// check-pass + +trait A<'a> {} +trait B<'b> {} +fn foo<T>() where for<'a> T: A<'a> + 'a {} +trait C<'c>: for<'a> A<'a> + for<'b> B<'b> { + type As; +} +struct D<T> where T: for<'c> C<'c, As=&'c ()> { + t: std::marker::PhantomData<T>, +} +trait E<'e, 'g> { + type As; +} +trait F<'f>: for<'a> A<'a> + for<'e> E<'e, 'f> {} +struct G<T> where T: for<'f> F<'f, As=&'f ()> { + t: std::marker::PhantomData<T>, +} +trait H<'a, 'b> { + type As; +} +trait I<'a>: for<'b> H<'a, 'b> {} + +struct J<T> where T: for<'i> I<'i, As=&'i ()> { + t: std::marker::PhantomData<T>, +} + +fn main() {} diff --git a/src/test/ui/impl-trait/bound-normalization-fail.stderr b/src/test/ui/impl-trait/bound-normalization-fail.stderr index a7d06c71663..6958cd97a4a 100644 --- a/src/test/ui/impl-trait/bound-normalization-fail.stderr +++ b/src/test/ui/impl-trait/bound-normalization-fail.stderr @@ -11,10 +11,10 @@ error[E0271]: type mismatch resolving `<Foo<()> as FooLike>::Output == <T as imp --> $DIR/bound-normalization-fail.rs:27:32 | LL | fn foo_fail<T: Trait>() -> impl FooLike<Output=T::Assoc> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected associated type, found `()` | - = note: expected type `()` - found associated type `<T as impl_trait::Trait>::Assoc` + = note: expected associated type `<T as impl_trait::Trait>::Assoc` + found type `()` help: consider constraining the associated type `<T as impl_trait::Trait>::Assoc` to `()` | LL | fn foo_fail<T: Trait<Assoc = ()>>() -> impl FooLike<Output=T::Assoc> { @@ -30,10 +30,10 @@ error[E0271]: type mismatch resolving `<Foo<()> as FooLike>::Output == <T as lif --> $DIR/bound-normalization-fail.rs:43:41 | LL | fn foo2_fail<'a, T: Trait<'a>>() -> impl FooLike<Output=T::Assoc> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected associated type, found `()` | - = note: expected type `()` - found associated type `<T as lifetimes::Trait<'static>>::Assoc` + = note: expected associated type `<T as lifetimes::Trait<'static>>::Assoc` + found type `()` help: consider constraining the associated type `<T as lifetimes::Trait<'static>>::Assoc` to `()` | LL | fn foo2_fail<'a, T: Trait<'a, Assoc = ()>>() -> impl FooLike<Output=T::Assoc> { diff --git a/src/test/ui/impl-trait/equality2.stderr b/src/test/ui/impl-trait/equality2.stderr index 1443b76048b..3318866c52c 100644 --- a/src/test/ui/impl-trait/equality2.stderr +++ b/src/test/ui/impl-trait/equality2.stderr @@ -35,8 +35,10 @@ LL | let _: i32 = Leak::leak(hide(0_i32)); | = note: expected type `i32` found associated type `<impl Foo as Leak>::T` - = help: consider constraining the associated type `<impl Foo as Leak>::T` to `i32` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html +help: consider constraining the associated type `<impl Foo as Leak>::T` to `i32` + | +LL | fn hide<T: Foo>(x: T) -> impl Foo<T = i32> { + | ^^^^^^^^^ error[E0308]: mismatched types --> $DIR/equality2.rs:38:10 diff --git a/src/test/ui/impl-trait/issues/issue-70877.full_tait.stderr b/src/test/ui/impl-trait/issues/issue-70877.full_tait.stderr index bd4d4fdf2a6..8e42b9d46db 100644 --- a/src/test/ui/impl-trait/issues/issue-70877.full_tait.stderr +++ b/src/test/ui/impl-trait/issues/issue-70877.full_tait.stderr @@ -2,13 +2,13 @@ error[E0271]: type mismatch resolving `<Bar as Iterator>::Item == Box<(dyn for<' --> $DIR/issue-70877.rs:11:12 | LL | type FooRet = impl std::fmt::Debug; - | -------------------- the expected opaque type + | -------------------- the found opaque type ... LL | type Foo = impl Iterator<Item = FooItem>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected opaque type, found enum `Option` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `Option`, found opaque type | - = note: expected struct `Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> impl Debug + 'static)>` - found struct `Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> Option<String> + 'static)>` + = note: expected struct `Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> Option<String> + 'static)>` + found struct `Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> impl Debug + 'static)>` error: aborting due to previous error diff --git a/src/test/ui/impl-trait/issues/issue-70877.min_tait.stderr b/src/test/ui/impl-trait/issues/issue-70877.min_tait.stderr index bd4d4fdf2a6..8e42b9d46db 100644 --- a/src/test/ui/impl-trait/issues/issue-70877.min_tait.stderr +++ b/src/test/ui/impl-trait/issues/issue-70877.min_tait.stderr @@ -2,13 +2,13 @@ error[E0271]: type mismatch resolving `<Bar as Iterator>::Item == Box<(dyn for<' --> $DIR/issue-70877.rs:11:12 | LL | type FooRet = impl std::fmt::Debug; - | -------------------- the expected opaque type + | -------------------- the found opaque type ... LL | type Foo = impl Iterator<Item = FooItem>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected opaque type, found enum `Option` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `Option`, found opaque type | - = note: expected struct `Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> impl Debug + 'static)>` - found struct `Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> Option<String> + 'static)>` + = note: expected struct `Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> Option<String> + 'static)>` + found struct `Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> impl Debug + 'static)>` error: aborting due to previous error diff --git a/src/test/ui/impl-trait/projection-mismatch-in-impl-where-clause.rs b/src/test/ui/impl-trait/projection-mismatch-in-impl-where-clause.rs new file mode 100644 index 00000000000..b4fd6b3e743 --- /dev/null +++ b/src/test/ui/impl-trait/projection-mismatch-in-impl-where-clause.rs @@ -0,0 +1,20 @@ +pub trait Super { + type Assoc; +} + +impl Super for () { + type Assoc = u8; +} + +pub trait Test {} + +impl<T> Test for T where T: Super<Assoc = ()> {} + +fn test() -> impl Test { + //~^ERROR type mismatch resolving `<() as Super>::Assoc == ()` + () +} + +fn main() { + let a = test(); +} diff --git a/src/test/ui/impl-trait/projection-mismatch-in-impl-where-clause.stderr b/src/test/ui/impl-trait/projection-mismatch-in-impl-where-clause.stderr new file mode 100644 index 00000000000..d1956a9afb8 --- /dev/null +++ b/src/test/ui/impl-trait/projection-mismatch-in-impl-where-clause.stderr @@ -0,0 +1,11 @@ +error[E0271]: type mismatch resolving `<() as Super>::Assoc == ()` + --> $DIR/projection-mismatch-in-impl-where-clause.rs:13:14 + | +LL | fn test() -> impl Test { + | ^^^^^^^^^ expected `()`, found `u8` + | + = note: required because of the requirements on the impl of `Test` for `()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/inference/issue-83606.rs b/src/test/ui/inference/issue-83606.rs new file mode 100644 index 00000000000..be56a3020cc --- /dev/null +++ b/src/test/ui/inference/issue-83606.rs @@ -0,0 +1,10 @@ +// Regression test for #83606. + +fn foo<const N: usize>(_: impl std::fmt::Display) -> [usize; N] { + [0; N] +} + +fn main() { + let _ = foo("foo"); //<- Do not suggest `foo::<N>("foo");`! + //~^ ERROR: type annotations needed for `[usize; _]` +} diff --git a/src/test/ui/inference/issue-83606.stderr b/src/test/ui/inference/issue-83606.stderr new file mode 100644 index 00000000000..65f3336b935 --- /dev/null +++ b/src/test/ui/inference/issue-83606.stderr @@ -0,0 +1,11 @@ +error[E0282]: type annotations needed for `[usize; _]` + --> $DIR/issue-83606.rs:8:13 + | +LL | let _ = foo("foo"); //<- Do not suggest `foo::<N>("foo");`! + | - ^^^ cannot infer the value of const parameter `N` declared on the function `foo` + | | + | consider giving this pattern the explicit type `[usize; _]`, where the type parameter `N` is specified + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/issue-83639.rs b/src/test/ui/issue-83639.rs new file mode 100644 index 00000000000..6ddbedfa0bc --- /dev/null +++ b/src/test/ui/issue-83639.rs @@ -0,0 +1,6 @@ +// check-fail +// ignore-tidy-tab + +fn main() { + """ " //~ ERROR +} diff --git a/src/test/ui/issue-83639.stderr b/src/test/ui/issue-83639.stderr new file mode 100644 index 00000000000..4c10df1917c --- /dev/null +++ b/src/test/ui/issue-83639.stderr @@ -0,0 +1,8 @@ +error: expected one of `.`, `;`, `?`, `}`, or an operator, found `" "` + --> $DIR/issue-83639.rs:5:7 + | +LL | """ " + | ^^^^^^ expected one of `.`, `;`, `?`, `}`, or an operator + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-27060-rpass.rs b/src/test/ui/issues/issue-27060-rpass.rs index b20d614b303..d9159f6669d 100644 --- a/src/test/ui/issues/issue-27060-rpass.rs +++ b/src/test/ui/issues/issue-27060-rpass.rs @@ -8,14 +8,12 @@ pub struct Good { } // kill this test when that turns to a hard error -#[allow(safe_packed_borrows)] +#[allow(unaligned_references)] fn main() { let good = Good { data: &0, data2: [&0, &0], aligned: [0; 32] }; - unsafe { - let _ = &good.data; // ok - let _ = &good.data2[0]; // ok - } + let _ = &good.data; // ok + let _ = &good.data2[0]; // ok let _ = &good.data; let _ = &good.data2[0]; diff --git a/src/test/ui/issues/issue-27060.rs b/src/test/ui/issues/issue-27060.rs index 78f2022ed38..5317a616719 100644 --- a/src/test/ui/issues/issue-27060.rs +++ b/src/test/ui/issues/issue-27060.rs @@ -5,7 +5,7 @@ pub struct Good { aligned: [u8; 32], } -#[deny(safe_packed_borrows)] +#[deny(unaligned_references)] fn main() { let good = Good { data: &0, @@ -13,14 +13,14 @@ fn main() { aligned: [0; 32] }; - unsafe { - let _ = &good.data; // ok - let _ = &good.data2[0]; // ok - } + let _ = &good.data; //~ ERROR reference to packed field + //~| hard error + let _ = &good.data2[0]; //~ ERROR reference to packed field + //~| hard error - let _ = &good.data; //~ ERROR borrow of packed field is unsafe + let _ = &good.data; //~ ERROR reference to packed field //~| hard error - let _ = &good.data2[0]; //~ ERROR borrow of packed field is unsafe + let _ = &good.data2[0]; //~ ERROR reference to packed field //~| hard error let _ = &*good.data; // ok, behind a pointer let _ = &good.aligned; // ok, has align 1 diff --git a/src/test/ui/issues/issue-27060.stderr b/src/test/ui/issues/issue-27060.stderr index d14ae4d41d5..09297884ed3 100644 --- a/src/test/ui/issues/issue-27060.stderr +++ b/src/test/ui/issues/issue-27060.stderr @@ -1,5 +1,5 @@ -error: borrow of packed field is unsafe and requires unsafe function or block (error E0133) - --> $DIR/issue-27060.rs:21:13 +error: reference to packed field is unaligned + --> $DIR/issue-27060.rs:16:13 | LL | let _ = &good.data; | ^^^^^^^^^^ @@ -7,21 +7,41 @@ LL | let _ = &good.data; note: the lint level is defined here --> $DIR/issue-27060.rs:8:8 | -LL | #[deny(safe_packed_borrows)] - | ^^^^^^^^^^^^^^^^^^^ +LL | #[deny(unaligned_references)] + | ^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> + = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + +error: reference to packed field is unaligned + --> $DIR/issue-27060.rs:18:13 + | +LL | let _ = &good.data2[0]; + | ^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> + = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + +error: reference to packed field is unaligned + --> $DIR/issue-27060.rs:21:13 + | +LL | let _ = &good.data; + | ^^^^^^^^^^ + | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #46043 <https://github.com/rust-lang/rust/issues/46043> - = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior + = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> + = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) -error: borrow of packed field is unsafe and requires unsafe function or block (error E0133) +error: reference to packed field is unaligned --> $DIR/issue-27060.rs:23:13 | LL | let _ = &good.data2[0]; | ^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #46043 <https://github.com/rust-lang/rust/issues/46043> - = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior + = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> + = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors diff --git a/src/test/ui/issues/issue-2823.stderr b/src/test/ui/issues/issue-2823.stderr index e044352e954..b3bc946292f 100644 --- a/src/test/ui/issues/issue-2823.stderr +++ b/src/test/ui/issues/issue-2823.stderr @@ -6,14 +6,6 @@ LL | struct C { ... LL | let _d = c.clone(); | ^^^^^ method not found in `C` - | - ::: $SRC_DIR/core/src/clone.rs:LL:COL - | -LL | fn clone(&self) -> Self; - | ----- - | | - | the method is available for `Arc<C>` here - | the method is available for `Rc<C>` here | = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `clone`, perhaps you need to implement it: diff --git a/src/test/ui/issues/issue-33941.stderr b/src/test/ui/issues/issue-33941.stderr index e91dae08b3a..043658c9508 100644 --- a/src/test/ui/issues/issue-33941.stderr +++ b/src/test/ui/issues/issue-33941.stderr @@ -11,10 +11,10 @@ error[E0271]: type mismatch resolving `<std::collections::hash_map::Iter<'_, _, --> $DIR/issue-33941.rs:4:14 | LL | for _ in HashMap::new().iter().cloned() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected tuple, found reference + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected reference, found tuple | - = note: expected tuple `(&_, &_)` - found reference `&_` + = note: expected reference `&_` + found tuple `(&_, &_)` = note: required because of the requirements on the impl of `Iterator` for `Cloned<std::collections::hash_map::Iter<'_, _, _>>` = note: required because of the requirements on the impl of `IntoIterator` for `Cloned<std::collections::hash_map::Iter<'_, _, _>>` = note: required by `into_iter` @@ -23,10 +23,10 @@ error[E0271]: type mismatch resolving `<std::collections::hash_map::Iter<'_, _, --> $DIR/issue-33941.rs:4:14 | LL | for _ in HashMap::new().iter().cloned() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected tuple, found reference + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected reference, found tuple | - = note: expected tuple `(&_, &_)` - found reference `&_` + = note: expected reference `&_` + found tuple `(&_, &_)` = note: required because of the requirements on the impl of `Iterator` for `Cloned<std::collections::hash_map::Iter<'_, _, _>>` = note: required by `std::iter::Iterator::next` diff --git a/src/test/ui/issues/issue-39970.stderr b/src/test/ui/issues/issue-39970.stderr index 6f342b459c0..8ecde9d1e68 100644 --- a/src/test/ui/issues/issue-39970.stderr +++ b/src/test/ui/issues/issue-39970.stderr @@ -5,7 +5,7 @@ LL | fn visit() {} | ---------- required by `Visit::visit` ... LL | <() as Visit>::visit(); - | ^^^^^^^^^^^^^^^^^^^^ expected `&()`, found `()` + | ^^^^^^^^^^^^^^^^^^^^ expected `()`, found `&()` | = note: required because of the requirements on the impl of `Visit` for `()` diff --git a/src/test/ui/issues/issue-69725.stderr b/src/test/ui/issues/issue-69725.stderr index 48c71d76af0..4dd6b4bbb68 100644 --- a/src/test/ui/issues/issue-69725.stderr +++ b/src/test/ui/issues/issue-69725.stderr @@ -8,14 +8,6 @@ LL | let _ = Struct::<A>::new().clone(); | LL | pub struct Struct<A>(A); | ------------------------ doesn't satisfy `Struct<A>: Clone` - | - ::: $SRC_DIR/core/src/clone.rs:LL:COL - | -LL | fn clone(&self) -> Self; - | ----- - | | - | the method is available for `Arc<Struct<A>>` here - | the method is available for `Rc<Struct<A>>` here | = note: the following trait bounds were not satisfied: `A: Clone` diff --git a/src/test/ui/iterators/array-of-ranges.stderr b/src/test/ui/iterators/array-of-ranges.stderr index 601983a6153..7d58eb948ea 100644 --- a/src/test/ui/iterators/array-of-ranges.stderr +++ b/src/test/ui/iterators/array-of-ranges.stderr @@ -13,10 +13,10 @@ error[E0277]: `[RangeInclusive<{integer}>; 1]` is not an iterator --> $DIR/array-of-ranges.rs:4:14 | LL | for _ in [0..=1] {} - | ^^^^^^^ borrow the array with `&` or call `.iter()` on it to iterate over it + | ^^^^^^^ if you meant to iterate between two values, remove the square brackets | = help: the trait `Iterator` is not implemented for `[RangeInclusive<{integer}>; 1]` - = note: arrays are not iterators, but slices like the following are: `&[1, 2, 3]` + = note: `[start..=end]` is an array of one `RangeInclusive`; you might have meant to have a `RangeInclusive` without the brackets: `start..=end` = note: required because of the requirements on the impl of `IntoIterator` for `[RangeInclusive<{integer}>; 1]` = note: required by `into_iter` @@ -24,10 +24,10 @@ error[E0277]: `[RangeFrom<{integer}>; 1]` is not an iterator --> $DIR/array-of-ranges.rs:6:14 | LL | for _ in [0..] {} - | ^^^^^ borrow the array with `&` or call `.iter()` on it to iterate over it + | ^^^^^ if you meant to iterate from a value onwards, remove the square brackets | = help: the trait `Iterator` is not implemented for `[RangeFrom<{integer}>; 1]` - = note: arrays are not iterators, but slices like the following are: `&[1, 2, 3]` + = note: `[start..]` is an array of one `RangeFrom`; you might have meant to have a `RangeFrom` without the brackets: `start..`, keeping in mind that iterating over an unbounded iterator will run forever unless you `break` or `return` from within the loop = note: required because of the requirements on the impl of `IntoIterator` for `[RangeFrom<{integer}>; 1]` = note: required by `into_iter` @@ -35,10 +35,10 @@ error[E0277]: `[RangeTo<{integer}>; 1]` is not an iterator --> $DIR/array-of-ranges.rs:8:14 | LL | for _ in [..1] {} - | ^^^^^ borrow the array with `&` or call `.iter()` on it to iterate over it + | ^^^^^ if you meant to iterate until a value, remove the square brackets and add a starting value | = help: the trait `Iterator` is not implemented for `[RangeTo<{integer}>; 1]` - = note: arrays are not iterators, but slices like the following are: `&[1, 2, 3]` + = note: `[..end]` is an array of one `RangeTo`; you might have meant to have a bounded `Range` without the brackets: `0..end` = note: required because of the requirements on the impl of `IntoIterator` for `[RangeTo<{integer}>; 1]` = note: required by `into_iter` @@ -46,10 +46,10 @@ error[E0277]: `[RangeToInclusive<{integer}>; 1]` is not an iterator --> $DIR/array-of-ranges.rs:10:14 | LL | for _ in [..=1] {} - | ^^^^^^ borrow the array with `&` or call `.iter()` on it to iterate over it + | ^^^^^^ if you meant to iterate until a value (including it), remove the square brackets and add a starting value | = help: the trait `Iterator` is not implemented for `[RangeToInclusive<{integer}>; 1]` - = note: arrays are not iterators, but slices like the following are: `&[1, 2, 3]` + = note: `[..=end]` is an array of one `RangeToInclusive`; you might have meant to have a bounded `RangeInclusive` without the brackets: `0..=end` = note: required because of the requirements on the impl of `IntoIterator` for `[RangeToInclusive<{integer}>; 1]` = note: required by `into_iter` @@ -79,10 +79,10 @@ error[E0277]: `[std::ops::Range<{integer}>; 2]` is not an iterator --> $DIR/array-of-ranges.rs:19:14 | LL | for _ in [0..1, 2..3] {} - | ^^^^^^^^^^^^ borrow the array with `&` or call `.iter()` on it to iterate over it + | ^^^^^^^^^^^^ arrays do not yet implement `IntoIterator`; try using `std::array::IntoIter::new(arr)` | = help: the trait `Iterator` is not implemented for `[std::ops::Range<{integer}>; 2]` - = note: arrays are not iterators, but slices like the following are: `&[1, 2, 3]` + = note: see <https://github.com/rust-lang/rust/pull/65819> for more details = note: required because of the requirements on the impl of `IntoIterator` for `[std::ops::Range<{integer}>; 2]` = note: required by `into_iter` @@ -90,10 +90,10 @@ error[E0277]: `[RangeInclusive<{integer}>; 1]` is not an iterator --> $DIR/array-of-ranges.rs:21:14 | LL | for _ in [0..=1] {} - | ^^^^^^^ borrow the array with `&` or call `.iter()` on it to iterate over it + | ^^^^^^^ if you meant to iterate between two values, remove the square brackets | = help: the trait `Iterator` is not implemented for `[RangeInclusive<{integer}>; 1]` - = note: arrays are not iterators, but slices like the following are: `&[1, 2, 3]` + = note: `[start..=end]` is an array of one `RangeInclusive`; you might have meant to have a `RangeInclusive` without the brackets: `start..=end` = note: required because of the requirements on the impl of `IntoIterator` for `[RangeInclusive<{integer}>; 1]` = note: required by `into_iter` diff --git a/src/test/ui/iterators/array.stderr b/src/test/ui/iterators/array.stderr index 68c6de5493f..7e2b600fb7a 100644 --- a/src/test/ui/iterators/array.stderr +++ b/src/test/ui/iterators/array.stderr @@ -2,10 +2,10 @@ error[E0277]: `[{integer}; 2]` is not an iterator --> $DIR/array.rs:2:14 | LL | for _ in [1, 2] {} - | ^^^^^^ borrow the array with `&` or call `.iter()` on it to iterate over it + | ^^^^^^ arrays do not yet implement `IntoIterator`; try using `std::array::IntoIter::new(arr)` | = help: the trait `Iterator` is not implemented for `[{integer}; 2]` - = note: arrays are not iterators, but slices like the following are: `&[1, 2, 3]` + = note: see <https://github.com/rust-lang/rust/pull/65819> for more details = note: required because of the requirements on the impl of `IntoIterator` for `[{integer}; 2]` = note: required by `into_iter` @@ -13,10 +13,10 @@ error[E0277]: `[{integer}; 2]` is not an iterator --> $DIR/array.rs:5:14 | LL | for _ in x {} - | ^ borrow the array with `&` or call `.iter()` on it to iterate over it + | ^ arrays do not yet implement `IntoIterator`; try using `std::array::IntoIter::new(arr)` | = help: the trait `Iterator` is not implemented for `[{integer}; 2]` - = note: arrays are not iterators, but slices like the following are: `&[1, 2, 3]` + = note: see <https://github.com/rust-lang/rust/pull/65819> for more details = note: required because of the requirements on the impl of `IntoIterator` for `[{integer}; 2]` = note: required by `into_iter` @@ -24,10 +24,10 @@ error[E0277]: `[{float}; 2]` is not an iterator --> $DIR/array.rs:7:14 | LL | for _ in [1.0, 2.0] {} - | ^^^^^^^^^^ borrow the array with `&` or call `.iter()` on it to iterate over it + | ^^^^^^^^^^ arrays do not yet implement `IntoIterator`; try using `std::array::IntoIter::new(arr)` | = help: the trait `Iterator` is not implemented for `[{float}; 2]` - = note: arrays are not iterators, but slices like the following are: `&[1, 2, 3]` + = note: see <https://github.com/rust-lang/rust/pull/65819> for more details = note: required because of the requirements on the impl of `IntoIterator` for `[{float}; 2]` = note: required by `into_iter` diff --git a/src/test/ui/iterators/ranges.stderr b/src/test/ui/iterators/ranges.stderr index 4678bafd196..73844329e36 100644 --- a/src/test/ui/iterators/ranges.stderr +++ b/src/test/ui/iterators/ranges.stderr @@ -2,9 +2,10 @@ error[E0277]: `RangeTo<{integer}>` is not an iterator --> $DIR/ranges.rs:2:14 | LL | for _ in ..10 {} - | ^^^^ `RangeTo<{integer}>` is not an iterator + | ^^^^ if you meant to iterate until a value, add a starting value | = help: the trait `Iterator` is not implemented for `RangeTo<{integer}>` + = note: `..end` is a `RangeTo`, which cannot be iterated on; you might have meant to have a bounded `Range`: `0..end` = note: required because of the requirements on the impl of `IntoIterator` for `RangeTo<{integer}>` = note: required by `into_iter` @@ -12,9 +13,10 @@ error[E0277]: `RangeToInclusive<{integer}>` is not an iterator --> $DIR/ranges.rs:4:14 | LL | for _ in ..=10 {} - | ^^^^^ `RangeToInclusive<{integer}>` is not an iterator + | ^^^^^ if you meant to iterate until a value (including it), add a starting value | = help: the trait `Iterator` is not implemented for `RangeToInclusive<{integer}>` + = note: `..=end` is a `RangeToInclusive`, which cannot be iterated on; you might have meant to have a bounded `RangeInclusive`: `0..=end` = note: required because of the requirements on the impl of `IntoIterator` for `RangeToInclusive<{integer}>` = note: required by `into_iter` diff --git a/src/test/ui/iterators/string.stderr b/src/test/ui/iterators/string.stderr index 16530066824..1d77bcb7536 100644 --- a/src/test/ui/iterators/string.stderr +++ b/src/test/ui/iterators/string.stderr @@ -2,7 +2,7 @@ error[E0277]: `String` is not an iterator --> $DIR/string.rs:2:14 | LL | for _ in "".to_owned() {} - | ^^^^^^^^^^^^^ `String` is not an iterator + | ^^^^^^^^^^^^^ `String` is not an iterator; try calling `.chars()` or `.bytes()` | = help: the trait `Iterator` is not implemented for `String` = note: required because of the requirements on the impl of `IntoIterator` for `String` diff --git a/src/test/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr b/src/test/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr index 30142e24cd5..16333a7ca38 100644 --- a/src/test/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr +++ b/src/test/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr @@ -1,4 +1,14 @@ error[E0261]: use of undeclared lifetime name `'b` + --> $DIR/undeclared-lifetime-used-in-debug-macro-issue-70152.rs:3:9 + | +LL | struct Test { + | - help: consider introducing lifetime `'b` here: `<'b>` +LL | a: &'b str, + | ^^ undeclared lifetime + | + = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes + +error[E0261]: use of undeclared lifetime name `'b` --> $DIR/undeclared-lifetime-used-in-debug-macro-issue-70152.rs:13:13 | LL | fn foo(&'b self) {} @@ -17,16 +27,6 @@ LL | fn foo<'b>(&'b self) {} error[E0261]: use of undeclared lifetime name `'b` --> $DIR/undeclared-lifetime-used-in-debug-macro-issue-70152.rs:3:9 | -LL | struct Test { - | - help: consider introducing lifetime `'b` here: `<'b>` -LL | a: &'b str, - | ^^ undeclared lifetime - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes - -error[E0261]: use of undeclared lifetime name `'b` - --> $DIR/undeclared-lifetime-used-in-debug-macro-issue-70152.rs:3:9 - | LL | #[derive(Eq, PartialEq)] | -- lifetime `'b` is missing in item created through this procedural macro LL | struct Test { diff --git a/src/test/ui/lint/unaligned_references.rs b/src/test/ui/lint/unaligned_references.rs index c4e5d065643..d06b06b504f 100644 --- a/src/test/ui/lint/unaligned_references.rs +++ b/src/test/ui/lint/unaligned_references.rs @@ -8,22 +8,43 @@ pub struct Good { aligned: [u8; 32], } +#[repr(packed(2))] +pub struct Packed2 { + x: u32, + y: u16, + z: u8, +} + fn main() { unsafe { let good = Good { data: 0, ptr: &0, data2: [0, 0], aligned: [0; 32] }; let _ = &good.ptr; //~ ERROR reference to packed field + //~^ previously accepted let _ = &good.data; //~ ERROR reference to packed field + //~^ previously accepted // Error even when turned into raw pointer immediately. let _ = &good.data as *const _; //~ ERROR reference to packed field + //~^ previously accepted let _: *const _ = &good.data; //~ ERROR reference to packed field + //~^ previously accepted // Error on method call. let _ = good.data.clone(); //~ ERROR reference to packed field + //~^ previously accepted // Error for nested fields. let _ = &good.data2[0]; //~ ERROR reference to packed field + //~^ previously accepted let _ = &*good.ptr; // ok, behind a pointer let _ = &good.aligned; // ok, has align 1 let _ = &good.aligned[2]; // ok, has align 1 } + + unsafe { + let packed2 = Packed2 { x: 0, y: 0, z: 0 }; + let _ = &packed2.x; //~ ERROR reference to packed field + //~^ previously accepted + let _ = &packed2.y; // ok, has align 2 in packed(2) struct + let _ = &packed2.z; // ok, has align 1 + } } diff --git a/src/test/ui/lint/unaligned_references.stderr b/src/test/ui/lint/unaligned_references.stderr index 8786b9c05db..b4cce3cfea2 100644 --- a/src/test/ui/lint/unaligned_references.stderr +++ b/src/test/ui/lint/unaligned_references.stderr @@ -1,5 +1,5 @@ error: reference to packed field is unaligned - --> $DIR/unaligned_references.rs:15:17 + --> $DIR/unaligned_references.rs:22:17 | LL | let _ = &good.ptr; | ^^^^^^^^^ @@ -9,47 +9,69 @@ note: the lint level is defined here | LL | #![deny(unaligned_references)] | ^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) error: reference to packed field is unaligned - --> $DIR/unaligned_references.rs:16:17 + --> $DIR/unaligned_references.rs:24:17 | LL | let _ = &good.data; | ^^^^^^^^^^ | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) error: reference to packed field is unaligned - --> $DIR/unaligned_references.rs:18:17 + --> $DIR/unaligned_references.rs:27:17 | LL | let _ = &good.data as *const _; | ^^^^^^^^^^ | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) error: reference to packed field is unaligned - --> $DIR/unaligned_references.rs:19:27 + --> $DIR/unaligned_references.rs:29:27 | LL | let _: *const _ = &good.data; | ^^^^^^^^^^ | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) error: reference to packed field is unaligned - --> $DIR/unaligned_references.rs:21:17 + --> $DIR/unaligned_references.rs:32:17 | LL | let _ = good.data.clone(); | ^^^^^^^^^ | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) error: reference to packed field is unaligned - --> $DIR/unaligned_references.rs:23:17 + --> $DIR/unaligned_references.rs:35:17 | LL | let _ = &good.data2[0]; | ^^^^^^^^^^^^^^ | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) -error: aborting due to 6 previous errors +error: reference to packed field is unaligned + --> $DIR/unaligned_references.rs:45:17 + | +LL | let _ = &packed2.x; + | ^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> + = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + +error: aborting due to 7 previous errors diff --git a/src/test/ui/lint/unaligned_references_external_macro.rs b/src/test/ui/lint/unaligned_references_external_macro.rs index 6ac501fb0e0..cb597c38e77 100644 --- a/src/test/ui/lint/unaligned_references_external_macro.rs +++ b/src/test/ui/lint/unaligned_references_external_macro.rs @@ -1,10 +1,9 @@ // aux-build:unaligned_references_external_crate.rs -#![allow(safe_packed_borrows)] - extern crate unaligned_references_external_crate; unaligned_references_external_crate::mac! { //~ERROR reference to packed field is unaligned + //~^ previously accepted #[repr(packed)] pub struct X { pub field: u16 diff --git a/src/test/ui/lint/unaligned_references_external_macro.stderr b/src/test/ui/lint/unaligned_references_external_macro.stderr index 140294b65cc..4e7c6bfc98d 100644 --- a/src/test/ui/lint/unaligned_references_external_macro.stderr +++ b/src/test/ui/lint/unaligned_references_external_macro.stderr @@ -1,7 +1,8 @@ error: reference to packed field is unaligned - --> $DIR/unaligned_references_external_macro.rs:7:1 + --> $DIR/unaligned_references_external_macro.rs:5:1 | LL | / unaligned_references_external_crate::mac! { +LL | | LL | | #[repr(packed)] LL | | pub struct X { LL | | pub field: u16 @@ -10,15 +11,18 @@ LL | | } | |_^ | note: the lint level is defined here - --> $DIR/unaligned_references_external_macro.rs:7:1 + --> $DIR/unaligned_references_external_macro.rs:5:1 | LL | / unaligned_references_external_crate::mac! { +LL | | LL | | #[repr(packed)] LL | | pub struct X { LL | | pub field: u16 LL | | } LL | | } | |_^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/macros/issue-83340.rs b/src/test/ui/macros/issue-83340.rs new file mode 100644 index 00000000000..d26200295cd --- /dev/null +++ b/src/test/ui/macros/issue-83340.rs @@ -0,0 +1,8 @@ +// check-fail + +fn main() { + println!( + "\ +\n {} │", //~ ERROR: 1 positional argument in format string, but no arguments were given + ); +} diff --git a/src/test/ui/macros/issue-83340.stderr b/src/test/ui/macros/issue-83340.stderr new file mode 100644 index 00000000000..1935de02b57 --- /dev/null +++ b/src/test/ui/macros/issue-83340.stderr @@ -0,0 +1,8 @@ +error: 1 positional argument in format string, but no arguments were given + --> $DIR/issue-83340.rs:6:4 + | +LL | \n {} │", + | ^^ + +error: aborting due to previous error + diff --git a/src/test/ui/macros/issue-83344.rs b/src/test/ui/macros/issue-83344.rs new file mode 100644 index 00000000000..c5f7f723587 --- /dev/null +++ b/src/test/ui/macros/issue-83344.rs @@ -0,0 +1,6 @@ +// check-fail + +fn main() { + println!("{}\ +"); //~^ ERROR: 1 positional argument in format string, but no arguments were given +} diff --git a/src/test/ui/macros/issue-83344.stderr b/src/test/ui/macros/issue-83344.stderr new file mode 100644 index 00000000000..1ef70f87a1f --- /dev/null +++ b/src/test/ui/macros/issue-83344.stderr @@ -0,0 +1,8 @@ +error: 1 positional argument in format string, but no arguments were given + --> $DIR/issue-83344.rs:4:15 + | +LL | println!("{}\ + | ^^ + +error: aborting due to previous error + diff --git a/src/test/ui/macros/macro-or-patterns-back-compat.fixed b/src/test/ui/macros/macro-or-patterns-back-compat.fixed new file mode 100644 index 00000000000..4e8b057457c --- /dev/null +++ b/src/test/ui/macros/macro-or-patterns-back-compat.fixed @@ -0,0 +1,26 @@ +// ignore-tidy-linelength +// run-rustfix + +#![feature(edition_macro_pats)] +#![deny(or_patterns_back_compat)] +#![allow(unused_macros)] +macro_rules! foo { ($x:pat2015 | $y:pat) => {} } //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro +macro_rules! bar { ($($x:pat2015)+ | $($y:pat)+) => {} } //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro +macro_rules! baz { ($x:pat2015 | $y:pat2015) => {} } // should be ok +macro_rules! qux { ($x:pat2015 | $y:pat) => {} } // should be ok +macro_rules! ogg { ($x:pat2015 | $y:pat2015) => {} } //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro +macro_rules! match_any { + ( $expr:expr , $( $( $pat:pat2015 )|+ => $expr_arm:expr ),+ ) => { //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro + match $expr { + $( + $( $pat => $expr_arm, )+ + )+ + } + }; +} + +fn main() { + let result: Result<i64, i32> = Err(42); + let int: i64 = match_any!(result, Ok(i) | Err(i) => i.into()); + assert_eq!(int, 42); +} diff --git a/src/test/ui/macros/macro-or-patterns-back-compat.rs b/src/test/ui/macros/macro-or-patterns-back-compat.rs new file mode 100644 index 00000000000..023abae36d0 --- /dev/null +++ b/src/test/ui/macros/macro-or-patterns-back-compat.rs @@ -0,0 +1,26 @@ +// ignore-tidy-linelength +// run-rustfix + +#![feature(edition_macro_pats)] +#![deny(or_patterns_back_compat)] +#![allow(unused_macros)] +macro_rules! foo { ($x:pat | $y:pat) => {} } //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro +macro_rules! bar { ($($x:pat)+ | $($y:pat)+) => {} } //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro +macro_rules! baz { ($x:pat2015 | $y:pat2015) => {} } // should be ok +macro_rules! qux { ($x:pat2015 | $y:pat) => {} } // should be ok +macro_rules! ogg { ($x:pat | $y:pat2015) => {} } //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro +macro_rules! match_any { + ( $expr:expr , $( $( $pat:pat )|+ => $expr_arm:expr ),+ ) => { //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro + match $expr { + $( + $( $pat => $expr_arm, )+ + )+ + } + }; +} + +fn main() { + let result: Result<i64, i32> = Err(42); + let int: i64 = match_any!(result, Ok(i) | Err(i) => i.into()); + assert_eq!(int, 42); +} diff --git a/src/test/ui/macros/macro-or-patterns-back-compat.stderr b/src/test/ui/macros/macro-or-patterns-back-compat.stderr new file mode 100644 index 00000000000..29bbd696033 --- /dev/null +++ b/src/test/ui/macros/macro-or-patterns-back-compat.stderr @@ -0,0 +1,32 @@ +error: the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro + --> $DIR/macro-or-patterns-back-compat.rs:7:21 + | +LL | macro_rules! foo { ($x:pat | $y:pat) => {} } + | ^^^^^^ help: use pat2015 to preserve semantics: `$x:pat2015` + | +note: the lint level is defined here + --> $DIR/macro-or-patterns-back-compat.rs:5:9 + | +LL | #![deny(or_patterns_back_compat)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro + --> $DIR/macro-or-patterns-back-compat.rs:8:23 + | +LL | macro_rules! bar { ($($x:pat)+ | $($y:pat)+) => {} } + | ^^^^^^ help: use pat2015 to preserve semantics: `$x:pat2015` + +error: the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro + --> $DIR/macro-or-patterns-back-compat.rs:11:21 + | +LL | macro_rules! ogg { ($x:pat | $y:pat2015) => {} } + | ^^^^^^ help: use pat2015 to preserve semantics: `$x:pat2015` + +error: the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro + --> $DIR/macro-or-patterns-back-compat.rs:13:26 + | +LL | ( $expr:expr , $( $( $pat:pat )|+ => $expr_arm:expr ),+ ) => { + | ^^^^^^^^ help: use pat2015 to preserve semantics: `$pat:pat2015` + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/mir/issue-83499-input-output-iteration-ice.rs b/src/test/ui/mir/issue-83499-input-output-iteration-ice.rs new file mode 100644 index 00000000000..4d404d015ec --- /dev/null +++ b/src/test/ui/mir/issue-83499-input-output-iteration-ice.rs @@ -0,0 +1,10 @@ +// Test that when in MIR the amount of local_decls and amount of normalized_input_tys don't match +// that an out-of-bounds access does not occur. +#![feature(c_variadic)] + +fn main() {} + +fn foo(_: Bar, ...) -> impl {} +//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic +//~| ERROR cannot find type `Bar` in this scope +//~| ERROR at least one trait must be specified diff --git a/src/test/ui/mir/issue-83499-input-output-iteration-ice.stderr b/src/test/ui/mir/issue-83499-input-output-iteration-ice.stderr new file mode 100644 index 00000000000..eb172684899 --- /dev/null +++ b/src/test/ui/mir/issue-83499-input-output-iteration-ice.stderr @@ -0,0 +1,21 @@ +error: only foreign or `unsafe extern "C" functions may be C-variadic + --> $DIR/issue-83499-input-output-iteration-ice.rs:7:16 + | +LL | fn foo(_: Bar, ...) -> impl {} + | ^^^ + +error: at least one trait must be specified + --> $DIR/issue-83499-input-output-iteration-ice.rs:7:24 + | +LL | fn foo(_: Bar, ...) -> impl {} + | ^^^^ + +error[E0412]: cannot find type `Bar` in this scope + --> $DIR/issue-83499-input-output-iteration-ice.rs:7:11 + | +LL | fn foo(_: Bar, ...) -> impl {} + | ^^^ not found in this scope + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0412`. diff --git a/src/test/ui/mismatched_types/issue-74918-missing-lifetime.rs b/src/test/ui/mismatched_types/issue-74918-missing-lifetime.rs index 0e3ea4bc8c9..6aa34354a7a 100644 --- a/src/test/ui/mismatched_types/issue-74918-missing-lifetime.rs +++ b/src/test/ui/mismatched_types/issue-74918-missing-lifetime.rs @@ -8,7 +8,7 @@ struct ChunkingIterator<T, S: 'static + Iterator<Item = T>> { impl<T, S: Iterator<Item = T>> Iterator for ChunkingIterator<T, S> { type Item = IteratorChunk<T, S>; //~ ERROR missing lifetime - fn next(&mut self) -> Option<IteratorChunk<T, S>> { //~ ERROR `impl` + fn next(&mut self) -> Option<IteratorChunk<T, S>> { todo!() } } diff --git a/src/test/ui/mismatched_types/issue-74918-missing-lifetime.stderr b/src/test/ui/mismatched_types/issue-74918-missing-lifetime.stderr index 5df35fa571c..1e035ff99d0 100644 --- a/src/test/ui/mismatched_types/issue-74918-missing-lifetime.stderr +++ b/src/test/ui/mismatched_types/issue-74918-missing-lifetime.stderr @@ -9,22 +9,6 @@ help: consider introducing a named lifetime parameter LL | type Item<'a> = IteratorChunk<'a, T, S>; | ^^^^ ^^^ -error: `impl` item signature doesn't match `trait` item signature - --> $DIR/issue-74918-missing-lifetime.rs:11:5 - | -LL | fn next(&mut self) -> Option<IteratorChunk<T, S>> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&mut ChunkingIterator<T, S>) -> Option<IteratorChunk<'_, T, S>>` - | - ::: $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL - | -LL | fn next(&mut self) -> Option<Self::Item>; - | ----------------------------------------- expected `fn(&mut ChunkingIterator<T, S>) -> Option<IteratorChunk<'static, _, _>>` - | - = note: expected `fn(&mut ChunkingIterator<T, S>) -> Option<IteratorChunk<'static, _, _>>` - found `fn(&mut ChunkingIterator<T, S>) -> Option<IteratorChunk<'_, _, _>>` - = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait` - = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr b/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr index 4e122d930fc..ff16bf0e078 100644 --- a/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr +++ b/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr @@ -6,7 +6,7 @@ LL | let mut closure = expect_sig(|p, y| *p = y); | = note: defining type: test::{closure#0} with closure substs [ i16, - for<'r, 's, 't0> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) mut &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) i32, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t0) }) i32)), + for<'r, 's, 't0> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) mut &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) i32, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrNamed('t0) }) i32)), (), ] diff --git a/src/test/ui/nll/closure-requirements/escape-argument.stderr b/src/test/ui/nll/closure-requirements/escape-argument.stderr index 44d1d2327fc..22398f08572 100644 --- a/src/test/ui/nll/closure-requirements/escape-argument.stderr +++ b/src/test/ui/nll/closure-requirements/escape-argument.stderr @@ -6,7 +6,7 @@ LL | let mut closure = expect_sig(|p, y| *p = y); | = note: defining type: test::{closure#0} with closure substs [ i16, - for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) mut &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) i32, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) i32)), + for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) mut &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) i32, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) i32)), (), ] diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr index fa9f994c4fa..11420efaa06 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr @@ -10,7 +10,7 @@ LL | | }, | = note: defining type: supply::{closure#0} with closure substs [ i16, - for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) u32>, std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) &'_#3r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) u32>)), + for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) u32>, std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) &'_#3r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) u32>)), (), ] = note: late-bound region is '_#4r diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr index 0555f79bcb0..98c3c28fb43 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr @@ -11,7 +11,7 @@ LL | | }); | = note: defining type: supply::{closure#0} with closure substs [ i16, - for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t0) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t1) }) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t2) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t3) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t1) }) u32>)), + for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrNamed('t0) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrNamed('t1) }) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrNamed('t2) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 5, kind: BrNamed('t3) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrNamed('t1) }) u32>)), (), ] = note: late-bound region is '_#3r diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr index 0932f941548..30ef343b261 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr @@ -10,7 +10,7 @@ LL | | }) | = note: defining type: case1::{closure#0} with closure substs [ i32, - for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) u32>)), + for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) u32>)), (), ] @@ -49,7 +49,7 @@ LL | | }) | = note: defining type: case2::{closure#0} with closure substs [ i32, - for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) u32>)), + for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) u32>)), (), ] = note: number of external vids: 2 diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr index bf6e2a922ed..29993b129c7 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr @@ -12,7 +12,7 @@ LL | | }); | = note: defining type: supply::{closure#0} with closure substs [ i16, - for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t0) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t1) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t2) }) u32>)), + for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrNamed('t0) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrNamed('t1) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrNamed('t2) }) u32>)), (), ] = note: late-bound region is '_#2r diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr index a3d993848cb..cb505d8b1ec 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr @@ -12,7 +12,7 @@ LL | | }); | = note: defining type: supply::{closure#0} with closure substs [ i16, - for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t0) }) std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t1) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t2) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t3) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t1) }) u32>)), + for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrNamed('t0) }) std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrNamed('t1) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrNamed('t2) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 5, kind: BrNamed('t3) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrNamed('t1) }) u32>)), (), ] = note: late-bound region is '_#3r diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr index 60dca1baa40..2ec9d4d8db1 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr @@ -11,7 +11,7 @@ LL | | }); | = note: defining type: test::{closure#0} with closure substs [ i16, - for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) u32>)), + for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) u32>)), (), ] = note: late-bound region is '_#3r diff --git a/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr b/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr index cbb10eb187e..21e4232c788 100644 --- a/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr @@ -10,7 +10,7 @@ LL | | }, | = note: defining type: supply::{closure#0} with closure substs [ i16, - for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) u32>)), + for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) u32>)), (), ] = note: late-bound region is '_#3r diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr index f9f1d8bb6ff..8b9b0435420 100644 --- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr @@ -11,7 +11,7 @@ LL | | }); | = note: defining type: supply::{closure#0} with closure substs [ i16, - for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t0) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t1) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t2) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) u32>)), + for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrNamed('t0) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrNamed('t1) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrNamed('t2) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) u32>)), (), ] = note: late-bound region is '_#2r diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr index 1587c28e1be..060ce690f03 100644 --- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr @@ -11,7 +11,7 @@ LL | | }); | = note: defining type: supply::{closure#0} with closure substs [ i16, - for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t0) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t1) }) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t2) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t3) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t1) }) u32>)), + for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrNamed('t0) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrNamed('t1) }) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrNamed('t2) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 5, kind: BrNamed('t3) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrNamed('t1) }) u32>)), (), ] = note: late-bound region is '_#3r diff --git a/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr b/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr index 44f743310b4..5fc1d5c4361 100644 --- a/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr +++ b/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr @@ -6,7 +6,7 @@ LL | expect_sig(|a, b| b); // ought to return `a` | = note: defining type: test::{closure#0} with closure substs [ i16, - for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) i32, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) i32)) -> &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) i32, + for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) i32, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) i32)) -> &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) i32, (), ] diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr index dbf76cd1329..baf223b786b 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr @@ -6,7 +6,7 @@ LL | twice(cell, value, |a, b| invoke(a, b)); | = note: defining type: generic::<T>::{closure#0} with closure substs [ i16, - for<'r, 's> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) ()>>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) T)), + for<'r, 's> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) ()>>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) T)), (), ] = note: number of external vids: 2 @@ -31,7 +31,7 @@ LL | twice(cell, value, |a, b| invoke(a, b)); | = note: defining type: generic_fail::<T>::{closure#0} with closure substs [ i16, - for<'r, 's> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) ()>>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) T)), + for<'r, 's> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) ()>>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) T)), (), ] = note: late-bound region is '_#2r diff --git a/src/test/ui/non-copyable-void.stderr b/src/test/ui/non-copyable-void.stderr index 8395a3a0563..99af04e7cd9 100644 --- a/src/test/ui/non-copyable-void.stderr +++ b/src/test/ui/non-copyable-void.stderr @@ -3,14 +3,6 @@ error[E0599]: no method named `clone` found for enum `c_void` in the current sco | LL | let _z = (*y).clone(); | ^^^^^ method not found in `c_void` - | - ::: $SRC_DIR/core/src/clone.rs:LL:COL - | -LL | fn clone(&self) -> Self; - | ----- - | | - | the method is available for `Arc<c_void>` here - | the method is available for `Rc<c_void>` here error: aborting due to previous error diff --git a/src/test/ui/noncopyable-class.stderr b/src/test/ui/noncopyable-class.stderr index b8e467d8402..4674c16eb43 100644 --- a/src/test/ui/noncopyable-class.stderr +++ b/src/test/ui/noncopyable-class.stderr @@ -6,14 +6,6 @@ LL | struct Foo { ... LL | let _y = x.clone(); | ^^^^^ method not found in `Foo` - | - ::: $SRC_DIR/core/src/clone.rs:LL:COL - | -LL | fn clone(&self) -> Self; - | ----- - | | - | the method is available for `Arc<Foo>` here - | the method is available for `Rc<Foo>` here | = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `clone`, perhaps you need to implement it: diff --git a/src/test/ui/packed/packed-struct-address-of-element.rs b/src/test/ui/packed/packed-struct-address-of-element.rs index 812d23fb580..fb3875e6804 100644 --- a/src/test/ui/packed/packed-struct-address-of-element.rs +++ b/src/test/ui/packed/packed-struct-address-of-element.rs @@ -1,6 +1,6 @@ // run-pass #![allow(dead_code)] -#![deny(safe_packed_borrows)] +#![deny(unaligned_references)] #![feature(raw_ref_op)] // ignore-emscripten weird assertion? diff --git a/src/test/ui/packed/packed-struct-borrow-element-64bit.rs b/src/test/ui/packed/packed-struct-borrow-element-64bit.rs new file mode 100644 index 00000000000..ad932fdcd01 --- /dev/null +++ b/src/test/ui/packed/packed-struct-borrow-element-64bit.rs @@ -0,0 +1,17 @@ +// run-pass (note: this is spec-UB, but it works for now) +// ignore-32bit (needs `usize` to be 8-aligned to reproduce all the errors below) +#![allow(dead_code)] +// ignore-emscripten weird assertion? + +#[repr(C, packed(4))] +struct Foo4C { + bar: u8, + baz: usize +} + +pub fn main() { + let foo = Foo4C { bar: 1, baz: 2 }; + let brw = &foo.baz; //~WARN reference to packed field is unaligned + //~^ previously accepted + assert_eq!(*brw, 2); +} diff --git a/src/test/ui/packed/packed-struct-borrow-element-64bit.stderr b/src/test/ui/packed/packed-struct-borrow-element-64bit.stderr new file mode 100644 index 00000000000..766d8a72c34 --- /dev/null +++ b/src/test/ui/packed/packed-struct-borrow-element-64bit.stderr @@ -0,0 +1,13 @@ +warning: reference to packed field is unaligned + --> $DIR/packed-struct-borrow-element-64bit.rs:14:15 + | +LL | let brw = &foo.baz; + | ^^^^^^^^ + | + = note: `#[warn(unaligned_references)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> + = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + +warning: 1 warning emitted + diff --git a/src/test/ui/packed/packed-struct-borrow-element.rs b/src/test/ui/packed/packed-struct-borrow-element.rs index 0072b6191eb..fb6c9c11d56 100644 --- a/src/test/ui/packed/packed-struct-borrow-element.rs +++ b/src/test/ui/packed/packed-struct-borrow-element.rs @@ -22,14 +22,12 @@ struct Foo4C { pub fn main() { let foo = Foo1 { bar: 1, baz: 2 }; - let brw = unsafe { &foo.baz }; + let brw = &foo.baz; //~WARN reference to packed field is unaligned + //~^ previously accepted assert_eq!(*brw, 2); let foo = Foo2 { bar: 1, baz: 2 }; - let brw = unsafe { &foo.baz }; - assert_eq!(*brw, 2); - - let foo = Foo4C { bar: 1, baz: 2 }; - let brw = unsafe { &foo.baz }; + let brw = &foo.baz; //~WARN reference to packed field is unaligned + //~^ previously accepted assert_eq!(*brw, 2); } diff --git a/src/test/ui/packed/packed-struct-borrow-element.stderr b/src/test/ui/packed/packed-struct-borrow-element.stderr new file mode 100644 index 00000000000..5764e951a46 --- /dev/null +++ b/src/test/ui/packed/packed-struct-borrow-element.stderr @@ -0,0 +1,23 @@ +warning: reference to packed field is unaligned + --> $DIR/packed-struct-borrow-element.rs:25:15 + | +LL | let brw = &foo.baz; + | ^^^^^^^^ + | + = note: `#[warn(unaligned_references)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> + = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + +warning: reference to packed field is unaligned + --> $DIR/packed-struct-borrow-element.rs:30:15 + | +LL | let brw = &foo.baz; + | ^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> + = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + +warning: 2 warnings emitted + diff --git a/src/test/ui/proc-macro/auxiliary/issue-75801.rs b/src/test/ui/proc-macro/auxiliary/issue-75801.rs new file mode 100644 index 00000000000..d6c031d7d4f --- /dev/null +++ b/src/test/ui/proc-macro/auxiliary/issue-75801.rs @@ -0,0 +1,13 @@ +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; + +use proc_macro::TokenStream; + +#[proc_macro_attribute] +pub fn foo(_args: TokenStream, item: TokenStream) -> TokenStream { + item +} diff --git a/src/test/ui/proc-macro/auxiliary/issue-79825.rs b/src/test/ui/proc-macro/auxiliary/issue-79825.rs new file mode 100644 index 00000000000..930891b1d43 --- /dev/null +++ b/src/test/ui/proc-macro/auxiliary/issue-79825.rs @@ -0,0 +1,14 @@ +// force-host +// no-prefer-dynamic +#![crate_type = "proc-macro"] + +extern crate proc_macro; + +use proc_macro::TokenStream; + +#[proc_macro_attribute] +pub fn assert_input(args: TokenStream, input: TokenStream) -> TokenStream { + assert_eq!(input.to_string(), "trait Alias = Sized ;"); + assert!(args.is_empty()); + TokenStream::new() +} diff --git a/src/test/ui/proc-macro/auxiliary/nested-macro-rules.rs b/src/test/ui/proc-macro/auxiliary/nested-macro-rules.rs index 52ebe8e7fb2..27676a5cb81 100644 --- a/src/test/ui/proc-macro/auxiliary/nested-macro-rules.rs +++ b/src/test/ui/proc-macro/auxiliary/nested-macro-rules.rs @@ -2,14 +2,15 @@ pub struct FirstStruct; #[macro_export] macro_rules! outer_macro { - ($name:ident) => { + ($name:ident, $attr_struct_name:ident) => { #[macro_export] macro_rules! inner_macro { - ($wrapper:ident) => { - $wrapper!($name) + ($bang_macro:ident, $attr_macro:ident) => { + $bang_macro!($name); + #[$attr_macro] struct $attr_struct_name {} } } } } -outer_macro!(FirstStruct); +outer_macro!(FirstStruct, FirstAttrStruct); diff --git a/src/test/ui/proc-macro/generate-mod.stderr b/src/test/ui/proc-macro/generate-mod.stderr index 9b946b5e244..5a4ed65ecdc 100644 --- a/src/test/ui/proc-macro/generate-mod.stderr +++ b/src/test/ui/proc-macro/generate-mod.stderr @@ -46,7 +46,8 @@ LL | #[derive(generate_mod::CheckDerive)] | = note: `#[warn(proc_macro_derive_resolution_fallback)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #50504 <https://github.com/rust-lang/rust/issues/50504> + = note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583> + = note: this warning originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) warning: cannot find type `OuterDerive` in this scope --> $DIR/generate-mod.rs:16:10 @@ -55,7 +56,8 @@ LL | #[derive(generate_mod::CheckDerive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #50504 <https://github.com/rust-lang/rust/issues/50504> + = note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583> + = note: this warning originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) warning: cannot find type `FromOutside` in this scope --> $DIR/generate-mod.rs:23:14 @@ -64,7 +66,8 @@ LL | #[derive(generate_mod::CheckDerive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #50504 <https://github.com/rust-lang/rust/issues/50504> + = note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583> + = note: this warning originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) warning: cannot find type `OuterDerive` in this scope --> $DIR/generate-mod.rs:23:14 @@ -73,7 +76,8 @@ LL | #[derive(generate_mod::CheckDerive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #50504 <https://github.com/rust-lang/rust/issues/50504> + = note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583> + = note: this warning originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 4 previous errors; 4 warnings emitted diff --git a/src/test/ui/proc-macro/inner-attrs.rs b/src/test/ui/proc-macro/inner-attrs.rs index 6a353ca3263..5707621f80e 100644 --- a/src/test/ui/proc-macro/inner-attrs.rs +++ b/src/test/ui/proc-macro/inner-attrs.rs @@ -1,10 +1,10 @@ -// check-pass // compile-flags: -Z span-debug --error-format human // aux-build:test-macros.rs #![feature(custom_inner_attributes)] #![feature(proc_macro_hygiene)] #![feature(stmt_expr_attributes)] +#![feature(rustc_attrs)] #![no_std] // Don't load unnecessary hygiene information from std extern crate std; @@ -25,17 +25,34 @@ struct MyStruct { fn bar() { (#![print_target_and_args(fifth)] 1, 2); + //~^ ERROR expected non-macro inner attribute, found attribute macro + + #[print_target_and_args(tuple_attrs)] ( + #![cfg_attr(FALSE, rustc_dummy)] + 3, 4, { + #![cfg_attr(not(FALSE), rustc_dummy(innermost))] + 5 + } + ); + + #[print_target_and_args(array_attrs)] [ + #![rustc_dummy(inner)] + true; 0 + ]; [#![print_target_and_args(sixth)] 1 , 2]; + //~^ ERROR expected non-macro inner attribute, found attribute macro [#![print_target_and_args(seventh)] true ; 5]; - + //~^ ERROR expected non-macro inner attribute, found attribute macro match 0 { #![print_target_and_args(eighth)] + //~^ ERROR expected non-macro inner attribute, found attribute macro _ => {} } MyStruct { #![print_target_and_args(ninth)] field: true }; + //~^ ERROR expected non-macro inner attribute, found attribute macro } extern { diff --git a/src/test/ui/proc-macro/inner-attrs.stderr b/src/test/ui/proc-macro/inner-attrs.stderr new file mode 100644 index 00000000000..db774cbfb8f --- /dev/null +++ b/src/test/ui/proc-macro/inner-attrs.stderr @@ -0,0 +1,32 @@ +error: expected non-macro inner attribute, found attribute macro `print_target_and_args` + --> $DIR/inner-attrs.rs:27:9 + | +LL | (#![print_target_and_args(fifth)] 1, 2); + | ^^^^^^^^^^^^^^^^^^^^^ not a non-macro inner attribute + +error: expected non-macro inner attribute, found attribute macro `print_target_and_args` + --> $DIR/inner-attrs.rs:43:9 + | +LL | [#![print_target_and_args(sixth)] 1 , 2]; + | ^^^^^^^^^^^^^^^^^^^^^ not a non-macro inner attribute + +error: expected non-macro inner attribute, found attribute macro `print_target_and_args` + --> $DIR/inner-attrs.rs:45:9 + | +LL | [#![print_target_and_args(seventh)] true ; 5]; + | ^^^^^^^^^^^^^^^^^^^^^ not a non-macro inner attribute + +error: expected non-macro inner attribute, found attribute macro `print_target_and_args` + --> $DIR/inner-attrs.rs:49:12 + | +LL | #![print_target_and_args(eighth)] + | ^^^^^^^^^^^^^^^^^^^^^ not a non-macro inner attribute + +error: expected non-macro inner attribute, found attribute macro `print_target_and_args` + --> $DIR/inner-attrs.rs:54:19 + | +LL | MyStruct { #![print_target_and_args(ninth)] field: true }; + | ^^^^^^^^^^^^^^^^^^^^^ not a non-macro inner attribute + +error: aborting due to 5 previous errors + diff --git a/src/test/ui/proc-macro/inner-attrs.stdout b/src/test/ui/proc-macro/inner-attrs.stdout index 2fd8d8a242e..ae04544e533 100644 --- a/src/test/ui/proc-macro/inner-attrs.stdout +++ b/src/test/ui/proc-macro/inner-attrs.stdout @@ -290,231 +290,251 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ span: $DIR/inner-attrs.rs:17:1: 20:2 (#0), }, ] -PRINT-ATTR_ARGS INPUT (DISPLAY): fifth +PRINT-ATTR_ARGS INPUT (DISPLAY): tuple_attrs PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [ Ident { - ident: "fifth", - span: $DIR/inner-attrs.rs:27:31: 27:36 (#0), + ident: "tuple_attrs", + span: $DIR/inner-attrs.rs:30:29: 30:40 (#0), }, ] -PRINT-ATTR INPUT (DISPLAY): (1, 2) ; +PRINT-ATTR INPUT (DISPLAY): (# ! [cfg_attr(FALSE, rustc_dummy)] 3, 4, + { # ! [cfg_attr(not(FALSE), rustc_dummy(innermost))] 5 }) ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Group { delimiter: Parenthesis, stream: TokenStream [ - Literal { - kind: Integer, - symbol: "1", - suffix: None, - span: $DIR/inner-attrs.rs:27:5: 27:45 (#0), + Punct { + ch: '#', + spacing: Joint, + span: $DIR/inner-attrs.rs:31:9: 31:10 (#0), }, Punct { - ch: ',', + ch: '!', spacing: Alone, - span: $DIR/inner-attrs.rs:27:5: 27:45 (#0), + span: $DIR/inner-attrs.rs:31:10: 31:11 (#0), }, - Literal { - kind: Integer, - symbol: "2", - suffix: None, - span: $DIR/inner-attrs.rs:27:5: 27:45 (#0), + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg_attr", + span: $DIR/inner-attrs.rs:31:12: 31:20 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/inner-attrs.rs:31:21: 31:26 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/inner-attrs.rs:31:26: 31:27 (#0), + }, + Ident { + ident: "rustc_dummy", + span: $DIR/inner-attrs.rs:31:28: 31:39 (#0), + }, + ], + span: $DIR/inner-attrs.rs:31:20: 31:40 (#0), + }, + ], + span: $DIR/inner-attrs.rs:31:11: 31:41 (#0), }, - ], - span: $DIR/inner-attrs.rs:27:5: 27:45 (#0), - }, - Punct { - ch: ';', - spacing: Alone, - span: $DIR/inner-attrs.rs:27:5: 27:45 (#0), - }, -] -PRINT-ATTR_ARGS INPUT (DISPLAY): sixth -PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [ - Ident { - ident: "sixth", - span: $DIR/inner-attrs.rs:29:31: 29:36 (#0), - }, -] -PRINT-ATTR INPUT (DISPLAY): [1, 2] ; -PRINT-ATTR INPUT (DEBUG): TokenStream [ - Group { - delimiter: Bracket, - stream: TokenStream [ Literal { kind: Integer, - symbol: "1", + symbol: "3", suffix: None, - span: $DIR/inner-attrs.rs:29:5: 29:46 (#0), + span: $DIR/inner-attrs.rs:32:9: 32:10 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/inner-attrs.rs:29:5: 29:46 (#0), + span: $DIR/inner-attrs.rs:32:10: 32:11 (#0), }, Literal { kind: Integer, - symbol: "2", + symbol: "4", suffix: None, - span: $DIR/inner-attrs.rs:29:5: 29:46 (#0), - }, - ], - span: $DIR/inner-attrs.rs:29:5: 29:46 (#0), - }, - Punct { - ch: ';', - spacing: Alone, - span: $DIR/inner-attrs.rs:29:5: 29:46 (#0), - }, -] -PRINT-ATTR_ARGS INPUT (DISPLAY): seventh -PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [ - Ident { - ident: "seventh", - span: $DIR/inner-attrs.rs:30:31: 30:38 (#0), - }, -] -PRINT-ATTR INPUT (DISPLAY): [true ; 5] ; -PRINT-ATTR INPUT (DEBUG): TokenStream [ - Group { - delimiter: Bracket, - stream: TokenStream [ - Ident { - ident: "true", - span: $DIR/inner-attrs.rs:30:5: 30:51 (#0), + span: $DIR/inner-attrs.rs:32:12: 32:13 (#0), }, Punct { - ch: ';', + ch: ',', spacing: Alone, - span: $DIR/inner-attrs.rs:30:5: 30:51 (#0), + span: $DIR/inner-attrs.rs:32:13: 32:14 (#0), }, - Literal { - kind: Integer, - symbol: "5", - suffix: None, - span: $DIR/inner-attrs.rs:30:5: 30:51 (#0), + Group { + delimiter: Brace, + stream: TokenStream [ + Punct { + ch: '#', + spacing: Joint, + span: $DIR/inner-attrs.rs:33:13: 33:14 (#0), + }, + Punct { + ch: '!', + spacing: Alone, + span: $DIR/inner-attrs.rs:33:14: 33:15 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg_attr", + span: $DIR/inner-attrs.rs:33:16: 33:24 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "not", + span: $DIR/inner-attrs.rs:33:25: 33:28 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/inner-attrs.rs:33:29: 33:34 (#0), + }, + ], + span: $DIR/inner-attrs.rs:33:28: 33:35 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/inner-attrs.rs:33:35: 33:36 (#0), + }, + Ident { + ident: "rustc_dummy", + span: $DIR/inner-attrs.rs:33:37: 33:48 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "innermost", + span: $DIR/inner-attrs.rs:33:49: 33:58 (#0), + }, + ], + span: $DIR/inner-attrs.rs:33:48: 33:59 (#0), + }, + ], + span: $DIR/inner-attrs.rs:33:24: 33:60 (#0), + }, + ], + span: $DIR/inner-attrs.rs:33:15: 33:61 (#0), + }, + Literal { + kind: Integer, + symbol: "5", + suffix: None, + span: $DIR/inner-attrs.rs:34:13: 34:14 (#0), + }, + ], + span: $DIR/inner-attrs.rs:32:15: 35:10 (#0), }, ], - span: $DIR/inner-attrs.rs:30:5: 30:51 (#0), + span: $DIR/inner-attrs.rs:30:43: 36:6 (#0), }, Punct { ch: ';', spacing: Alone, - span: $DIR/inner-attrs.rs:30:5: 30:51 (#0), + span: $DIR/inner-attrs.rs:36:6: 36:7 (#0), }, ] -PRINT-ATTR_ARGS INPUT (DISPLAY): eighth +PRINT-ATTR_ARGS INPUT (DISPLAY): array_attrs PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [ Ident { - ident: "eighth", - span: $DIR/inner-attrs.rs:34:34: 34:40 (#0), + ident: "array_attrs", + span: $DIR/inner-attrs.rs:38:29: 38:40 (#0), }, ] -PRINT-ATTR INPUT (DISPLAY): match 0 { _ => { } } +PRINT-ATTR INPUT (DISPLAY): [# ! [rustc_dummy(inner)] true ; 0] ; PRINT-ATTR INPUT (DEBUG): TokenStream [ - Ident { - ident: "match", - span: $DIR/inner-attrs.rs:33:5: 36:6 (#0), - }, - Literal { - kind: Integer, - symbol: "0", - suffix: None, - span: $DIR/inner-attrs.rs:33:5: 36:6 (#0), - }, Group { - delimiter: Brace, + delimiter: Bracket, stream: TokenStream [ - Ident { - ident: "_", - span: $DIR/inner-attrs.rs:33:5: 36:6 (#0), - }, Punct { - ch: '=', + ch: '#', spacing: Joint, - span: $DIR/inner-attrs.rs:33:5: 36:6 (#0), + span: $DIR/inner-attrs.rs:38:43: 41:7 (#0), }, Punct { - ch: '>', + ch: '!', spacing: Alone, - span: $DIR/inner-attrs.rs:33:5: 36:6 (#0), + span: $DIR/inner-attrs.rs:38:43: 41:7 (#0), }, Group { - delimiter: Brace, - stream: TokenStream [], - span: $DIR/inner-attrs.rs:33:5: 36:6 (#0), - }, - ], - span: $DIR/inner-attrs.rs:33:5: 36:6 (#0), - }, -] -PRINT-ATTR_ARGS INPUT (DISPLAY): ninth -PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [ - Ident { - ident: "ninth", - span: $DIR/inner-attrs.rs:38:41: 38:46 (#0), - }, -] -PRINT-ATTR INPUT (DISPLAY): MyStruct { field : true, } ; -PRINT-ATTR INPUT (DEBUG): TokenStream [ - Ident { - ident: "MyStruct", - span: $DIR/inner-attrs.rs:38:5: 38:63 (#0), - }, - Group { - delimiter: Brace, - stream: TokenStream [ - Ident { - ident: "field", - span: $DIR/inner-attrs.rs:38:5: 38:63 (#0), - }, - Punct { - ch: ':', - spacing: Alone, - span: $DIR/inner-attrs.rs:38:5: 38:63 (#0), + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "rustc_dummy", + span: $DIR/inner-attrs.rs:38:43: 41:7 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "inner", + span: $DIR/inner-attrs.rs:38:43: 41:7 (#0), + }, + ], + span: $DIR/inner-attrs.rs:38:43: 41:7 (#0), + }, + ], + span: $DIR/inner-attrs.rs:38:43: 41:7 (#0), }, Ident { ident: "true", - span: $DIR/inner-attrs.rs:38:5: 38:63 (#0), + span: $DIR/inner-attrs.rs:38:43: 41:7 (#0), }, Punct { - ch: ',', + ch: ';', spacing: Alone, - span: $DIR/inner-attrs.rs:38:5: 38:63 (#0), + span: $DIR/inner-attrs.rs:38:43: 41:7 (#0), + }, + Literal { + kind: Integer, + symbol: "0", + suffix: None, + span: $DIR/inner-attrs.rs:38:43: 41:7 (#0), }, ], - span: $DIR/inner-attrs.rs:38:5: 38:63 (#0), + span: $DIR/inner-attrs.rs:38:43: 41:7 (#0), }, Punct { ch: ';', spacing: Alone, - span: $DIR/inner-attrs.rs:38:5: 38:63 (#0), + span: $DIR/inner-attrs.rs:38:43: 41:7 (#0), }, ] PRINT-ATTR_ARGS INPUT (DISPLAY): tenth PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [ Ident { ident: "tenth", - span: $DIR/inner-attrs.rs:43:42: 43:47 (#0), + span: $DIR/inner-attrs.rs:60:42: 60:47 (#0), }, ] PRINT-ATTR INPUT (DISPLAY): fn weird_extern() { } PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "fn", - span: $DIR/inner-attrs.rs:42:5: 44:6 (#0), + span: $DIR/inner-attrs.rs:59:5: 61:6 (#0), }, Ident { ident: "weird_extern", - span: $DIR/inner-attrs.rs:42:5: 44:6 (#0), + span: $DIR/inner-attrs.rs:59:5: 61:6 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [], - span: $DIR/inner-attrs.rs:42:5: 44:6 (#0), + span: $DIR/inner-attrs.rs:59:5: 61:6 (#0), }, Group { delimiter: Brace, stream: TokenStream [], - span: $DIR/inner-attrs.rs:42:5: 44:6 (#0), + span: $DIR/inner-attrs.rs:59:5: 61:6 (#0), }, ] diff --git a/src/test/ui/proc-macro/issue-75801.rs b/src/test/ui/proc-macro/issue-75801.rs new file mode 100644 index 00000000000..b07cde0fabd --- /dev/null +++ b/src/test/ui/proc-macro/issue-75801.rs @@ -0,0 +1,19 @@ +// aux-build: issue-75801.rs + +// Regression test for #75801. + +#[macro_use] +extern crate issue_75801; + +macro_rules! foo { + ($arg:expr) => { + #[foo] + fn bar() { + let _bar: u32 = $arg; + } + }; +} + +foo!("baz"); //~ ERROR: mismatched types [E0308] + +fn main() {} diff --git a/src/test/ui/proc-macro/issue-75801.stderr b/src/test/ui/proc-macro/issue-75801.stderr new file mode 100644 index 00000000000..ee0a9bd7783 --- /dev/null +++ b/src/test/ui/proc-macro/issue-75801.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/issue-75801.rs:17:6 + | +LL | let _bar: u32 = $arg; + | --- expected due to this +... +LL | foo!("baz"); + | ^^^^^ expected `u32`, found `&str` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/proc-macro/issue-79825.rs b/src/test/ui/proc-macro/issue-79825.rs new file mode 100644 index 00000000000..f628469ce3a --- /dev/null +++ b/src/test/ui/proc-macro/issue-79825.rs @@ -0,0 +1,10 @@ +// check-pass +// aux-build:issue-79825.rs +#![feature(trait_alias)] + +extern crate issue_79825; + +#[issue_79825::assert_input] +trait Alias = Sized; + +fn main() {} diff --git a/src/test/ui/proc-macro/issue-81555.rs b/src/test/ui/proc-macro/issue-81555.rs new file mode 100644 index 00000000000..693f1f7dc39 --- /dev/null +++ b/src/test/ui/proc-macro/issue-81555.rs @@ -0,0 +1,15 @@ +// check-pass +// aux-build:test-macros.rs +#![feature(stmt_expr_attributes, proc_macro_hygiene)] + +extern crate test_macros; + +use test_macros::identity_attr; + +#[identity_attr] +fn main() { + let _x; + let y = (); + #[identity_attr] + _x = y; +} diff --git a/src/test/ui/proc-macro/issue-83469-global-alloc-invalid-stmt.rs b/src/test/ui/proc-macro/issue-83469-global-alloc-invalid-stmt.rs new file mode 100644 index 00000000000..25adc5d2578 --- /dev/null +++ b/src/test/ui/proc-macro/issue-83469-global-alloc-invalid-stmt.rs @@ -0,0 +1,10 @@ +// Regression test for issue #83469 +// Ensures that we recover from `#[global_alloc]` on an invalid +// stmt without an ICE + +fn outer() { + #[global_allocator] + fn inner() {} //~ ERROR allocators must be statics +} + +fn main() {} diff --git a/src/test/ui/proc-macro/issue-83469-global-alloc-invalid-stmt.stderr b/src/test/ui/proc-macro/issue-83469-global-alloc-invalid-stmt.stderr new file mode 100644 index 00000000000..ec0e3c4c754 --- /dev/null +++ b/src/test/ui/proc-macro/issue-83469-global-alloc-invalid-stmt.stderr @@ -0,0 +1,8 @@ +error: allocators must be statics + --> $DIR/issue-83469-global-alloc-invalid-stmt.rs:7:5 + | +LL | fn inner() {} + | ^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/proc-macro/nested-macro-rules.rs b/src/test/ui/proc-macro/nested-macro-rules.rs index 2fef0e5fad0..25ffcfad7c7 100644 --- a/src/test/ui/proc-macro/nested-macro-rules.rs +++ b/src/test/ui/proc-macro/nested-macro-rules.rs @@ -1,7 +1,7 @@ // run-pass // aux-build:nested-macro-rules.rs // aux-build:test-macros.rs -// compile-flags: -Z span-debug +// compile-flags: -Z span-debug -Z macro-backtrace // edition:2018 #![no_std] // Don't load unnecessary hygiene information from std @@ -10,14 +10,14 @@ extern crate std; extern crate nested_macro_rules; extern crate test_macros; -use test_macros::print_bang; +use test_macros::{print_bang, print_attr}; use nested_macro_rules::FirstStruct; struct SecondStruct; fn main() { - nested_macro_rules::inner_macro!(print_bang); + nested_macro_rules::inner_macro!(print_bang, print_attr); - nested_macro_rules::outer_macro!(SecondStruct); - inner_macro!(print_bang); + nested_macro_rules::outer_macro!(SecondStruct, SecondAttrStruct); + inner_macro!(print_bang, print_attr); } diff --git a/src/test/ui/proc-macro/nested-macro-rules.stdout b/src/test/ui/proc-macro/nested-macro-rules.stdout index dcafe3b4bda..8292617fc16 100644 --- a/src/test/ui/proc-macro/nested-macro-rules.stdout +++ b/src/test/ui/proc-macro/nested-macro-rules.stdout @@ -5,10 +5,32 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ stream: TokenStream [ Ident { ident: "FirstStruct", - span: $DIR/auxiliary/nested-macro-rules.rs:15:14: 15:25 (#7), + span: $DIR/auxiliary/nested-macro-rules.rs:16:14: 16:25 (#7), }, ], - span: $DIR/auxiliary/nested-macro-rules.rs:9:27: 9:32 (#6), + span: $DIR/auxiliary/nested-macro-rules.rs:9:30: 9:35 (#6), + }, +] +PRINT-ATTR INPUT (DISPLAY): struct FirstAttrStruct { } +PRINT-ATTR INPUT (DEBUG): TokenStream [ + Ident { + ident: "struct", + span: $DIR/auxiliary/nested-macro-rules.rs:10:32: 10:38 (#6), + }, + Group { + delimiter: None, + stream: TokenStream [ + Ident { + ident: "FirstAttrStruct", + span: $DIR/auxiliary/nested-macro-rules.rs:16:27: 16:42 (#7), + }, + ], + span: $DIR/auxiliary/nested-macro-rules.rs:10:39: 10:56 (#6), + }, + Group { + delimiter: Brace, + stream: TokenStream [], + span: $DIR/auxiliary/nested-macro-rules.rs:10:57: 10:59 (#6), }, ] PRINT-BANG INPUT (DISPLAY): SecondStruct @@ -18,9 +40,31 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ stream: TokenStream [ Ident { ident: "SecondStruct", - span: $DIR/nested-macro-rules.rs:21:38: 21:50 (#13), + span: $DIR/nested-macro-rules.rs:21:38: 21:50 (#16), }, ], - span: $DIR/auxiliary/nested-macro-rules.rs:9:27: 9:32 (#12), + span: $DIR/auxiliary/nested-macro-rules.rs:9:30: 9:35 (#15), + }, +] +PRINT-ATTR INPUT (DISPLAY): struct SecondAttrStruct { } +PRINT-ATTR INPUT (DEBUG): TokenStream [ + Ident { + ident: "struct", + span: $DIR/auxiliary/nested-macro-rules.rs:10:32: 10:38 (#15), + }, + Group { + delimiter: None, + stream: TokenStream [ + Ident { + ident: "SecondAttrStruct", + span: $DIR/nested-macro-rules.rs:21:52: 21:68 (#16), + }, + ], + span: $DIR/auxiliary/nested-macro-rules.rs:10:39: 10:56 (#15), + }, + Group { + delimiter: Brace, + stream: TokenStream [], + span: $DIR/auxiliary/nested-macro-rules.rs:10:57: 10:59 (#15), }, ] diff --git a/src/test/ui/regions/regions-name-undeclared.stderr b/src/test/ui/regions/regions-name-undeclared.stderr index ad0e7bd5afb..5f6ff280e65 100644 --- a/src/test/ui/regions/regions-name-undeclared.stderr +++ b/src/test/ui/regions/regions-name-undeclared.stderr @@ -1,3 +1,23 @@ +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/regions-name-undeclared.rs:28:13 + | +LL | enum E { + | - help: consider introducing lifetime `'a` here: `<'a>` +LL | E1(&'a isize) + | ^^ undeclared lifetime + | + = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes + +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/regions-name-undeclared.rs:31:13 + | +LL | struct S { + | - help: consider introducing lifetime `'a` here: `<'a>` +LL | f: &'a isize + | ^^ undeclared lifetime + | + = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes + error[E0261]: use of undeclared lifetime name `'b` --> $DIR/regions-name-undeclared.rs:16:24 | @@ -57,26 +77,6 @@ LL | type X = Option<&'a isize>; = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/regions-name-undeclared.rs:28:13 - | -LL | enum E { - | - help: consider introducing lifetime `'a` here: `<'a>` -LL | E1(&'a isize) - | ^^ undeclared lifetime - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes - -error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/regions-name-undeclared.rs:31:13 - | -LL | struct S { - | - help: consider introducing lifetime `'a` here: `<'a>` -LL | f: &'a isize - | ^^ undeclared lifetime - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes - -error[E0261]: use of undeclared lifetime name `'a` --> $DIR/regions-name-undeclared.rs:33:14 | LL | fn f(a: &'a isize) { } diff --git a/src/test/ui/resolve/issue-82865.rs b/src/test/ui/resolve/issue-82865.rs new file mode 100644 index 00000000000..07d88c413bf --- /dev/null +++ b/src/test/ui/resolve/issue-82865.rs @@ -0,0 +1,13 @@ +// Regression test for #82865. + +#![feature(decl_macro)] + +use x::y::z; //~ ERROR: failed to resolve: maybe a missing crate `x`? + +macro mac () { + Box::z //~ ERROR: no function or associated item +} + +fn main() { + mac!(); +} diff --git a/src/test/ui/resolve/issue-82865.stderr b/src/test/ui/resolve/issue-82865.stderr new file mode 100644 index 00000000000..027d7a0e0e4 --- /dev/null +++ b/src/test/ui/resolve/issue-82865.stderr @@ -0,0 +1,21 @@ +error[E0433]: failed to resolve: maybe a missing crate `x`? + --> $DIR/issue-82865.rs:5:5 + | +LL | use x::y::z; + | ^ maybe a missing crate `x`? + +error[E0599]: no function or associated item named `z` found for struct `Box<_, _>` in the current scope + --> $DIR/issue-82865.rs:8:10 + | +LL | Box::z + | ^ function or associated item not found in `Box<_, _>` +... +LL | mac!(); + | ------- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0433, E0599. +For more information about an error, try `rustc --explain E0433`. diff --git a/src/test/ui/rustdoc/check-doc-alias-attr.stderr b/src/test/ui/rustdoc/check-doc-alias-attr.stderr index f99d69dc101..250568be333 100644 --- a/src/test/ui/rustdoc/check-doc-alias-attr.stderr +++ b/src/test/ui/rustdoc/check-doc-alias-attr.stderr @@ -10,7 +10,7 @@ error: doc alias attribute expects a string `#[doc(alias = "a")]` or a list of s LL | #[doc(alias = 0)] | ^^^^^^^^^ -error: '\"' character isn't allowed in `#[doc(alias = "...")]` +error: '"' character isn't allowed in `#[doc(alias = "...")]` --> $DIR/check-doc-alias-attr.rs:9:15 | LL | #[doc(alias = "\"")] @@ -60,7 +60,7 @@ error: `#[doc(alias("a"))]` expects string literals LL | #[doc(alias(0))] | ^ -error: '\"' character isn't allowed in `#[doc(alias("..."))]` +error: '"' character isn't allowed in `#[doc(alias("..."))]` --> $DIR/check-doc-alias-attr.rs:20:13 | LL | #[doc(alias("\""))] diff --git a/src/test/ui/self/point-at-arbitrary-self-type-method.stderr b/src/test/ui/self/point-at-arbitrary-self-type-method.stderr index 2954a499c18..b804ddfb024 100644 --- a/src/test/ui/self/point-at-arbitrary-self-type-method.stderr +++ b/src/test/ui/self/point-at-arbitrary-self-type-method.stderr @@ -9,6 +9,11 @@ LL | fn foo(self: Box<Self>) {} ... LL | A.foo(); | ^^^ method not found in `A` + | +help: consider wrapping the receiver expression with the appropriate type + | +LL | Box::new(A).foo(); + | ^^^^^^^^^ ^ error: aborting due to previous error diff --git a/src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr b/src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr index 89fe84c0d2d..e1ed0e42f98 100644 --- a/src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr +++ b/src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr @@ -10,6 +10,11 @@ LL | struct A; ... LL | A.foo() | ^^^ method not found in `A` + | +help: consider wrapping the receiver expression with the appropriate type + | +LL | Box::new(A).foo() + | ^^^^^^^^^ ^ error: aborting due to previous error diff --git a/src/test/ui/simd/simd-intrinsic-generic-reduction.rs b/src/test/ui/simd/simd-intrinsic-generic-reduction.rs index 8b5afeac0bc..7193fb3527f 100644 --- a/src/test/ui/simd/simd-intrinsic-generic-reduction.rs +++ b/src/test/ui/simd/simd-intrinsic-generic-reduction.rs @@ -2,7 +2,6 @@ #![allow(non_camel_case_types)] // ignore-emscripten -// min-system-llvm-version: 9.0 // Test that the simd_reduce_{op} intrinsics produce the correct results. diff --git a/src/test/ui/specialization/issue-68830-spurious-diagnostics.rs b/src/test/ui/specialization/issue-68830-spurious-diagnostics.rs new file mode 100644 index 00000000000..d11ec798332 --- /dev/null +++ b/src/test/ui/specialization/issue-68830-spurious-diagnostics.rs @@ -0,0 +1,23 @@ +// A regression test for #68830. This checks we don't emit +// a verbose `conflicting implementations` error. + +#![feature(specialization)] +#![allow(incomplete_features)] + +struct BadStruct { + err: MissingType //~ ERROR: cannot find type `MissingType` in this scope +} + +trait MyTrait<T> { + fn foo(); +} + +impl<T, D> MyTrait<T> for D { + default fn foo() {} +} + +impl<T> MyTrait<T> for BadStruct { + fn foo() {} +} + +fn main() {} diff --git a/src/test/ui/specialization/issue-68830-spurious-diagnostics.stderr b/src/test/ui/specialization/issue-68830-spurious-diagnostics.stderr new file mode 100644 index 00000000000..833f61dca8c --- /dev/null +++ b/src/test/ui/specialization/issue-68830-spurious-diagnostics.stderr @@ -0,0 +1,9 @@ +error[E0412]: cannot find type `MissingType` in this scope + --> $DIR/issue-68830-spurious-diagnostics.rs:8:10 + | +LL | err: MissingType + | ^^^^^^^^^^^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0412`. diff --git a/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr b/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr index 92208231b17..fa59d7a0313 100644 --- a/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr +++ b/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr @@ -1,4 +1,4 @@ -error: cannot specialize on `Binder(ProjectionPredicate(ProjectionTy { substs: [V], item_def_id: DefId(0:6 ~ repeated_projection_type[317d]::Id::This) }, (I,)))` +error: cannot specialize on `Binder(ProjectionPredicate(ProjectionTy { substs: [V], item_def_id: DefId(0:6 ~ repeated_projection_type[317d]::Id::This) }, (I,)), [])` --> $DIR/repeated_projection_type.rs:19:1 | LL | / impl<I, V: Id<This = (I,)>> X for V { diff --git a/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr index 32961b7f87b..3786457fb1a 100644 --- a/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr +++ b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr @@ -46,6 +46,7 @@ error[E0277]: `dyn Future<Output = i32> + Send` cannot be unpinned LL | Pin::new(x) | ^^^^^^^^ the trait `Unpin` is not implemented for `dyn Future<Output = i32> + Send` | + = note: consider using `Box::pin` = note: required by `Pin::<P>::new` error[E0277]: `dyn Future<Output = i32> + Send` cannot be unpinned @@ -54,6 +55,7 @@ error[E0277]: `dyn Future<Output = i32> + Send` cannot be unpinned LL | Pin::new(Box::new(x)) | ^^^^^^^^ the trait `Unpin` is not implemented for `dyn Future<Output = i32> + Send` | + = note: consider using `Box::pin` = note: required by `Pin::<P>::new` error[E0308]: mismatched types diff --git a/src/test/ui/suggestions/into-str.stderr b/src/test/ui/suggestions/into-str.stderr index 2854b830ba8..26efd50bb8f 100644 --- a/src/test/ui/suggestions/into-str.stderr +++ b/src/test/ui/suggestions/into-str.stderr @@ -7,6 +7,7 @@ LL | fn foo<'a, T>(_t: T) where T: Into<&'a str> {} LL | foo(String::new()); | ^^^ the trait `From<String>` is not implemented for `&str` | + = note: to coerce a `String` into a `&str`, use `&*` as a prefix = note: required because of the requirements on the impl of `Into<&str>` for `String` error: aborting due to previous error diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.nll.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.nll.stderr deleted file mode 100644 index b509610b89e..00000000000 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.nll.stderr +++ /dev/null @@ -1,92 +0,0 @@ -error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/missing-lifetimes-in-signature.rs:37:11 - | -LL | fn baz<G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ - | - ^^ undeclared lifetime - | | - | help: consider introducing lifetime `'a` here: `'a,` - -error: lifetime may not live long enough - --> $DIR/missing-lifetimes-in-signature.rs:15:37 - | -LL | fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce() - | - ^^^^^^^^^^^^^ opaque type requires that `'1` must outlive `'static` - | | - | let's call the lifetime of this reference `'1` - | -help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as a bound - | -LL | fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ - | ^^^^^^^^^^^^^^^^^^ - -error[E0311]: the parameter type `G` may not live long enough - --> $DIR/missing-lifetimes-in-signature.rs:25:37 - | -LL | fn bar<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ - | ^^^^^^^^^^^^^^^^^^ - | -note: the parameter type `G` must be valid for the anonymous lifetime defined on the function body at 25:26... - --> $DIR/missing-lifetimes-in-signature.rs:25:26 - | -LL | fn bar<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ - | ^^^^^^ - -error[E0311]: the parameter type `G` may not live long enough - --> $DIR/missing-lifetimes-in-signature.rs:47:45 - | -LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ - | ^^^^^^^^^^^^^^^^^^ - | -note: the parameter type `G` must be valid for the anonymous lifetime defined on the function body at 47:34... - --> $DIR/missing-lifetimes-in-signature.rs:47:34 - | -LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ - | ^^^^^^ - -error[E0311]: the parameter type `G` may not live long enough - --> $DIR/missing-lifetimes-in-signature.rs:59:58 - | -LL | fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ { - | ^^^^^^^^^^^^^^^^^^ - | -note: the parameter type `G` must be valid for the anonymous lifetime defined on the method body at 59:47... - --> $DIR/missing-lifetimes-in-signature.rs:59:47 - | -LL | fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ { - | ^^^^^^ - -error[E0311]: the parameter type `G` may not live long enough - --> $DIR/missing-lifetimes-in-signature.rs:68:45 - | -LL | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a - | ^^^^^^^^^^^^^^^^^^^^^^^ - | -note: the parameter type `G` must be valid for the anonymous lifetime defined on the function body at 68:34... - --> $DIR/missing-lifetimes-in-signature.rs:68:34 - | -LL | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a - | ^^^^^^ - -error[E0621]: explicit lifetime required in the type of `dest` - --> $DIR/missing-lifetimes-in-signature.rs:73:5 - | -LL | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a - | ------ help: add explicit lifetime `'a` to the type of `dest`: `&'a mut T` -... -LL | / move || { -LL | | *dest = g.get(); -LL | | } - | |_____^ lifetime `'a` required - -error[E0309]: the parameter type `G` may not live long enough - --> $DIR/missing-lifetimes-in-signature.rs:79:44 - | -LL | fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a - | ^^^^^^^^^^^^^^^^^^ - | - = help: consider adding an explicit lifetime bound `G: 'a`... - -error: aborting due to 8 previous errors - -Some errors have detailed explanations: E0261, E0309, E0621. -For more information about an error, try `rustc --explain E0261`. diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs index 94dd826a15c..dd434ea5318 100644 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs @@ -16,14 +16,13 @@ fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce() where G: Get<T> { - move || { //~ ERROR `dest` + move || { *dest = g.get(); } } // After applying suggestion for `foo`: fn bar<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ -//~^ ERROR the parameter type `G` may not live long enough where G: Get<T> { @@ -45,7 +44,6 @@ where // After applying suggestion for `baz`: fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ -//~^ ERROR the parameter type `G` may not live long enough where G: Get<T> { @@ -57,7 +55,6 @@ where // Same as above, but show that we pay attention to lifetime names from parent item impl<'a> Foo { fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ { - //~^ ERROR the parameter type `G` may not live long enough move || { *dest = g.get(); } @@ -66,7 +63,6 @@ impl<'a> Foo { // After applying suggestion for `qux`: fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a -//~^ ERROR explicit lifetime required in the type of `dest` where G: Get<T> { @@ -77,7 +73,6 @@ where // Potential incorrect attempt: fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a -//~^ ERROR the parameter type `G` may not live long enough where G: Get<T> { diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr index 789fff7acc2..916a6c2bf12 100644 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr @@ -1,112 +1,11 @@ error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/missing-lifetimes-in-signature.rs:37:11 + --> $DIR/missing-lifetimes-in-signature.rs:36:11 | LL | fn baz<G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ | - ^^ undeclared lifetime | | | help: consider introducing lifetime `'a` here: `'a,` -error[E0759]: `dest` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement - --> $DIR/missing-lifetimes-in-signature.rs:19:5 - | -LL | fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce() - | ------ this data with an anonymous lifetime `'_`... -... -LL | / move || { -LL | | *dest = g.get(); -LL | | } - | |_____^ ...is captured here... - | -note: ...and is required to live as long as `'static` here - --> $DIR/missing-lifetimes-in-signature.rs:15:37 - | -LL | fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce() - | ^^^^^^^^^^^^^ -help: to declare that the `impl Trait` captures data from argument `dest`, you can add an explicit `'_` lifetime bound - | -LL | fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ - | ^^^^ - -error[E0311]: the parameter type `G` may not live long enough - --> $DIR/missing-lifetimes-in-signature.rs:25:37 - | -LL | fn bar<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ - | ^^^^^^^^^^^^^^^^^^ - | -note: the parameter type `G` must be valid for the anonymous lifetime defined on the function body at 25:26... - --> $DIR/missing-lifetimes-in-signature.rs:25:26 - | -LL | fn bar<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ - | ^^^^^^ -note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:30:5: 32:6]` will meet its required lifetime bounds - --> $DIR/missing-lifetimes-in-signature.rs:25:37 - | -LL | fn bar<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ - | ^^^^^^^^^^^^^^^^^^ -help: consider introducing an explicit lifetime bound - | -LL | fn bar<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a - | ^^^^^ ^^^^ - -error[E0311]: the parameter type `G` may not live long enough - --> $DIR/missing-lifetimes-in-signature.rs:47:45 - | -LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ - | ^^^^^^^^^^^^^^^^^^ - | -note: the parameter type `G` must be valid for the anonymous lifetime defined on the function body at 47:34... - --> $DIR/missing-lifetimes-in-signature.rs:47:34 - | -LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ - | ^^^^^^ -note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:52:5: 54:6]` will meet its required lifetime bounds - --> $DIR/missing-lifetimes-in-signature.rs:47:45 - | -LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ - | ^^^^^^^^^^^^^^^^^^ -help: consider introducing an explicit lifetime bound - | -LL | fn qux<'b, 'a, G: 'b + 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'b - | ^^^ ^^^^^^^ ^^^^ - -error[E0311]: the parameter type `G` may not live long enough - --> $DIR/missing-lifetimes-in-signature.rs:59:58 - | -LL | fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ { - | ^^^^^^^^^^^^^^^^^^ - | -note: the parameter type `G` must be valid for the anonymous lifetime defined on the method body at 59:47... - --> $DIR/missing-lifetimes-in-signature.rs:59:47 - | -LL | fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ { - | ^^^^^^ -note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:61:9: 63:10]` will meet its required lifetime bounds - --> $DIR/missing-lifetimes-in-signature.rs:59:58 - | -LL | fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ { - | ^^^^^^^^^^^^^^^^^^ -help: consider introducing an explicit lifetime bound - | -LL | fn qux<'c, 'b, G: 'c + Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'c { - | ^^^ ^^^^^^^ ^^^^ - -error[E0621]: explicit lifetime required in the type of `dest` - --> $DIR/missing-lifetimes-in-signature.rs:68:45 - | -LL | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a - | ------ ^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required - | | - | help: add explicit lifetime `'a` to the type of `dest`: `&'a mut T` - -error[E0309]: the parameter type `G` may not live long enough - --> $DIR/missing-lifetimes-in-signature.rs:79:44 - | -LL | fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a - | - ^^^^^^^^^^^^^^^^^^ ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:84:5: 86:6]` will meet its required lifetime bounds - | | - | help: consider adding an explicit lifetime bound...: `G: 'a` - -error: aborting due to 7 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0261, E0309, E0621, E0759. -For more information about an error, try `rustc --explain E0261`. +For more information about this error, try `rustc --explain E0261`. diff --git a/src/test/ui/suggestions/missing-lifetime-specifier.stderr b/src/test/ui/suggestions/missing-lifetime-specifier.stderr index e6cec5cbd45..489926ea78a 100644 --- a/src/test/ui/suggestions/missing-lifetime-specifier.stderr +++ b/src/test/ui/suggestions/missing-lifetime-specifier.stderr @@ -142,30 +142,6 @@ help: consider using the `'static` lifetime LL | static d: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'static, i32>>>>> = RefCell::new(HashMap::new()); | ^^^^^^^^^^^^^^^^^ -error[E0106]: missing lifetime specifier - --> $DIR/missing-lifetime-specifier.rs:50:44 - | -LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new()); - | ^ expected named lifetime parameter - | - = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime - | -LL | static f: RefCell<HashMap<i32, Vec<Vec<&'static Tar<'static, i32>>>>> = RefCell::new(HashMap::new()); - | ^^^^^^^^ - -error[E0106]: missing lifetime specifier - --> $DIR/missing-lifetime-specifier.rs:50:44 - | -LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new()); - | ^ expected named lifetime parameter - | - = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime - | -LL | static f: RefCell<HashMap<i32, Vec<Vec<&'static Tar<'static, i32>>>>> = RefCell::new(HashMap::new()); - | ^^^^^^^^ - error[E0107]: this union takes 2 lifetime arguments but only 1 lifetime argument was supplied --> $DIR/missing-lifetime-specifier.rs:43:44 | @@ -256,6 +232,18 @@ help: add missing lifetime argument LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'k, i32>>>>> = RefCell::new(HashMap::new()); | ^^^^ +error[E0106]: missing lifetime specifier + --> $DIR/missing-lifetime-specifier.rs:50:44 + | +LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new()); + | ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime + | +LL | static f: RefCell<HashMap<i32, Vec<Vec<&'static Tar<'static, i32>>>>> = RefCell::new(HashMap::new()); + | ^^^^^^^^ + error[E0107]: this trait takes 2 lifetime arguments but only 1 lifetime argument was supplied --> $DIR/missing-lifetime-specifier.rs:50:45 | @@ -274,6 +262,18 @@ help: add missing lifetime argument LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'k, i32>>>>> = RefCell::new(HashMap::new()); | ^^^^ +error[E0106]: missing lifetime specifier + --> $DIR/missing-lifetime-specifier.rs:50:44 + | +LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new()); + | ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime + | +LL | static f: RefCell<HashMap<i32, Vec<Vec<&'static Tar<'static, i32>>>>> = RefCell::new(HashMap::new()); + | ^^^^^^^^ + error[E0107]: this trait takes 2 lifetime arguments but only 1 lifetime argument was supplied --> $DIR/missing-lifetime-specifier.rs:50:45 | diff --git a/src/test/ui/suggestions/path-display.stderr b/src/test/ui/suggestions/path-display.stderr index b08e22eaab7..3ee2860b4ff 100644 --- a/src/test/ui/suggestions/path-display.stderr +++ b/src/test/ui/suggestions/path-display.stderr @@ -2,10 +2,10 @@ error[E0277]: `Path` doesn't implement `std::fmt::Display` --> $DIR/path-display.rs:5:20 | LL | println!("{}", path); - | ^^^^ `Path` cannot be formatted with the default formatter + | ^^^^ `Path` cannot be formatted with the default formatter; call `.display()` on it | = help: the trait `std::fmt::Display` is not implemented for `Path` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead + = note: call `.display()` or `.to_string_lossy()` to safely print paths, as they may contain non-Unicode data = note: required because of the requirements on the impl of `std::fmt::Display` for `&Path` = note: required by `std::fmt::Display::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/symbol-names/basic.legacy.stderr b/src/test/ui/symbol-names/basic.legacy.stderr index 7155d88be96..3dd2b19fbf9 100644 --- a/src/test/ui/symbol-names/basic.legacy.stderr +++ b/src/test/ui/symbol-names/basic.legacy.stderr @@ -1,10 +1,10 @@ -error: symbol-name(_ZN5basic4main17hfcf1daab33c43a6aE) +error: symbol-name(_ZN5basic4main17h6c535bbea2051f85E) --> $DIR/basic.rs:8:1 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(basic::main::hfcf1daab33c43a6a) +error: demangling(basic::main::h6c535bbea2051f85) --> $DIR/basic.rs:8:1 | LL | #[rustc_symbol_name] diff --git a/src/test/ui/symbol-names/issue-60925.legacy.stderr b/src/test/ui/symbol-names/issue-60925.legacy.stderr index 9575875f5a8..65cc62b4d1d 100644 --- a/src/test/ui/symbol-names/issue-60925.legacy.stderr +++ b/src/test/ui/symbol-names/issue-60925.legacy.stderr @@ -1,10 +1,10 @@ -error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17hb8ca3eb2682b1b51E) +error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h6244e5288326926aE) --> $DIR/issue-60925.rs:22:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::hb8ca3eb2682b1b51) +error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::h6244e5288326926a) --> $DIR/issue-60925.rs:22:9 | LL | #[rustc_symbol_name] diff --git a/src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.stderr b/src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.stderr index d39daaba206..01e36a4a62a 100644 --- a/src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.stderr +++ b/src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.stderr @@ -6,14 +6,6 @@ LL | struct Qux; ... LL | Qux.clone(); | ^^^^^ method not found in `Qux` - | - ::: $SRC_DIR/core/src/clone.rs:LL:COL - | -LL | fn clone(&self) -> Self; - | ----- - | | - | the method is available for `Arc<Qux>` here - | the method is available for `Rc<Qux>` here | = help: items from traits can only be used if the trait is implemented and in scope = note: the trait `Clone` defines an item `clone`, but is explicitely unimplemented diff --git a/src/test/ui/type-alias-impl-trait/issue-63279.full_tait.stderr b/src/test/ui/type-alias-impl-trait/issue-63279.full_tait.stderr index f544f61df97..53a0016c08e 100644 --- a/src/test/ui/type-alias-impl-trait/issue-63279.full_tait.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-63279.full_tait.stderr @@ -11,10 +11,10 @@ error[E0271]: type mismatch resolving `<[closure@$DIR/issue-63279.rs:11:5: 11:28 --> $DIR/issue-63279.rs:8:16 | LL | type Closure = impl FnOnce(); - | ^^^^^^^^^^^^^ expected opaque type, found `()` + | ^^^^^^^^^^^^^ expected `()`, found opaque type | - = note: expected opaque type `impl FnOnce<()>` - found unit type `()` + = note: expected unit type `()` + found opaque type `impl FnOnce<()>` error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/type-alias-impl-trait/issue-63279.min_tait.stderr b/src/test/ui/type-alias-impl-trait/issue-63279.min_tait.stderr index bdf414d0bad..be386ab90ea 100644 --- a/src/test/ui/type-alias-impl-trait/issue-63279.min_tait.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-63279.min_tait.stderr @@ -11,10 +11,10 @@ error[E0271]: type mismatch resolving `<[closure@$DIR/issue-63279.rs:11:5: 11:28 --> $DIR/issue-63279.rs:8:16 | LL | type Closure = impl FnOnce(); - | ^^^^^^^^^^^^^ expected opaque type, found `()` + | ^^^^^^^^^^^^^ expected `()`, found opaque type | - = note: expected opaque type `impl FnOnce<()>` - found unit type `()` + = note: expected unit type `()` + found opaque type `impl FnOnce<()>` error: aborting due to 2 previous errors diff --git a/src/test/ui/union/union-derive-clone.stderr b/src/test/ui/union/union-derive-clone.stderr index a793bf58d23..546394664df 100644 --- a/src/test/ui/union/union-derive-clone.stderr +++ b/src/test/ui/union/union-derive-clone.stderr @@ -25,14 +25,6 @@ LL | struct CloneNoCopy; ... LL | let w = u.clone(); | ^^^^^ method cannot be called on `U5<CloneNoCopy>` due to unsatisfied trait bounds - | - ::: $SRC_DIR/core/src/clone.rs:LL:COL - | -LL | fn clone(&self) -> Self; - | ----- - | | - | the method is available for `Arc<U5<CloneNoCopy>>` here - | the method is available for `Rc<U5<CloneNoCopy>>` here | = note: the following trait bounds were not satisfied: `CloneNoCopy: Copy` diff --git a/src/test/ui/unique-object-noncopyable.stderr b/src/test/ui/unique-object-noncopyable.stderr index 4bbacfc0a8b..6a355dd2562 100644 --- a/src/test/ui/unique-object-noncopyable.stderr +++ b/src/test/ui/unique-object-noncopyable.stderr @@ -10,14 +10,6 @@ LL | trait Foo { LL | let _z = y.clone(); | ^^^^^ method cannot be called on `Box<dyn Foo>` due to unsatisfied trait bounds | - ::: $SRC_DIR/core/src/clone.rs:LL:COL - | -LL | fn clone(&self) -> Self; - | ----- - | | - | the method is available for `Arc<Box<dyn Foo>>` here - | the method is available for `Rc<Box<dyn Foo>>` here - | ::: $SRC_DIR/alloc/src/boxed.rs:LL:COL | LL | / pub struct Box< diff --git a/src/test/ui/unique-pinned-nocopy.stderr b/src/test/ui/unique-pinned-nocopy.stderr index dd0b7fc5489..a4421bcf809 100644 --- a/src/test/ui/unique-pinned-nocopy.stderr +++ b/src/test/ui/unique-pinned-nocopy.stderr @@ -7,14 +7,6 @@ LL | struct R { LL | let _j = i.clone(); | ^^^^^ method cannot be called on `Box<R>` due to unsatisfied trait bounds | - ::: $SRC_DIR/core/src/clone.rs:LL:COL - | -LL | fn clone(&self) -> Self; - | ----- - | | - | the method is available for `Arc<Box<R>>` here - | the method is available for `Rc<Box<R>>` here - | ::: $SRC_DIR/alloc/src/boxed.rs:LL:COL | LL | / pub struct Box< diff --git a/src/test/ui/unsafe/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs b/src/test/ui/unsafe/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs deleted file mode 100644 index 540612a7dce..00000000000 --- a/src/test/ui/unsafe/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs +++ /dev/null @@ -1,67 +0,0 @@ -#![feature(unsafe_block_in_unsafe_fn)] - -#[repr(packed)] -pub struct Packed { - data: &'static u32, -} - -const PACKED: Packed = Packed { data: &0 }; - -#[allow(safe_packed_borrows)] -#[allow(unsafe_op_in_unsafe_fn)] -unsafe fn allow_allow() { - &PACKED.data; // allowed -} - -#[allow(safe_packed_borrows)] -#[warn(unsafe_op_in_unsafe_fn)] -unsafe fn allow_warn() { - &PACKED.data; // allowed -} - -#[allow(safe_packed_borrows)] -#[deny(unsafe_op_in_unsafe_fn)] -unsafe fn allow_deny() { - &PACKED.data; // allowed -} - -#[warn(safe_packed_borrows)] -#[allow(unsafe_op_in_unsafe_fn)] -unsafe fn warn_allow() { - &PACKED.data; // allowed -} - -#[warn(safe_packed_borrows)] -#[warn(unsafe_op_in_unsafe_fn)] -unsafe fn warn_warn() { - &PACKED.data; //~ WARN - //~| WARNING this was previously accepted by the compiler but is being phased out -} - -#[warn(safe_packed_borrows)] -#[deny(unsafe_op_in_unsafe_fn)] -unsafe fn warn_deny() { - &PACKED.data; //~ WARN - //~| WARNING this was previously accepted by the compiler but is being phased out -} - -#[deny(safe_packed_borrows)] -#[allow(unsafe_op_in_unsafe_fn)] -unsafe fn deny_allow() { - &PACKED.data; // allowed -} - -#[deny(safe_packed_borrows)] -#[warn(unsafe_op_in_unsafe_fn)] -unsafe fn deny_warn() { - &PACKED.data; //~ WARN -} - -#[deny(safe_packed_borrows)] -#[deny(unsafe_op_in_unsafe_fn)] -unsafe fn deny_deny() { - &PACKED.data; //~ ERROR - //~| WARNING this was previously accepted by the compiler but is being phased out -} - -fn main() {} diff --git a/src/test/ui/unsafe/rfc-2585-safe_packed_borrows-in-unsafe-fn.stderr b/src/test/ui/unsafe/rfc-2585-safe_packed_borrows-in-unsafe-fn.stderr deleted file mode 100644 index fda15159643..00000000000 --- a/src/test/ui/unsafe/rfc-2585-safe_packed_borrows-in-unsafe-fn.stderr +++ /dev/null @@ -1,60 +0,0 @@ -warning: borrow of packed field is unsafe and requires unsafe block (error E0133) - --> $DIR/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs:37:5 - | -LL | &PACKED.data; - | ^^^^^^^^^^^^ borrow of packed field - | -note: the lint level is defined here - --> $DIR/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs:34:8 - | -LL | #[warn(safe_packed_borrows)] - | ^^^^^^^^^^^^^^^^^^^ - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #46043 <https://github.com/rust-lang/rust/issues/46043> - = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior - -warning: borrow of packed field is unsafe and requires unsafe block (error E0133) - --> $DIR/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs:44:5 - | -LL | &PACKED.data; - | ^^^^^^^^^^^^ borrow of packed field - | -note: the lint level is defined here - --> $DIR/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs:41:8 - | -LL | #[warn(safe_packed_borrows)] - | ^^^^^^^^^^^^^^^^^^^ - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #46043 <https://github.com/rust-lang/rust/issues/46043> - = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior - -warning: borrow of packed field is unsafe and requires unsafe block (error E0133) - --> $DIR/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs:57:5 - | -LL | &PACKED.data; - | ^^^^^^^^^^^^ borrow of packed field - | -note: the lint level is defined here - --> $DIR/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs:55:8 - | -LL | #[warn(unsafe_op_in_unsafe_fn)] - | ^^^^^^^^^^^^^^^^^^^^^^ - = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior - -error: borrow of packed field is unsafe and requires unsafe block (error E0133) - --> $DIR/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs:63:5 - | -LL | &PACKED.data; - | ^^^^^^^^^^^^ borrow of packed field - | -note: the lint level is defined here - --> $DIR/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs:60:8 - | -LL | #[deny(safe_packed_borrows)] - | ^^^^^^^^^^^^^^^^^^^ - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #46043 <https://github.com/rust-lang/rust/issues/46043> - = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior - -error: aborting due to previous error; 3 warnings emitted - diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 90691f2bfe9a50291a98983b1ed2feab51d5ca5 +Subproject 3c44c3c4b7900b8b13c85ead25ccaa8abb7d898 diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index 41c334c6816..f7916511edf 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md @@ -2103,6 +2103,7 @@ Released 2018-09-13 [`if_let_some_result`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_some_result [`if_not_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_not_else [`if_same_then_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_same_then_else +[`if_then_some_else_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none [`ifs_same_cond`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond [`implicit_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_clone [`implicit_hasher`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_hasher diff --git a/src/tools/clippy/CONTRIBUTING.md b/src/tools/clippy/CONTRIBUTING.md index 5954ab25d19..e0a4d4455e9 100644 --- a/src/tools/clippy/CONTRIBUTING.md +++ b/src/tools/clippy/CONTRIBUTING.md @@ -18,11 +18,13 @@ All contributors are expected to follow the [Rust Code of Conduct]. - [Finding something to fix/improve](#finding-something-to-fiximprove) - [Writing code](#writing-code) - [Getting code-completion for rustc internals to work](#getting-code-completion-for-rustc-internals-to-work) + - [IntelliJ Rust](#intellij-rust) + - [Rust Analyzer](#rust-analyzer) - [How Clippy works](#how-clippy-works) - - [Syncing changes between Clippy and `rust-lang/rust`](#syncing-changes-between-clippy-and-rust-langrust) + - [Syncing changes between Clippy and [`rust-lang/rust`]](#syncing-changes-between-clippy-and-rust-langrust) - [Patching git-subtree to work with big repos](#patching-git-subtree-to-work-with-big-repos) - - [Performing the sync from `rust-lang/rust` to Clippy](#performing-the-sync-from-rust-langrust-to-clippy) - - [Performing the sync from Clippy to `rust-lang/rust`](#performing-the-sync-from-clippy-to-rust-langrust) + - [Performing the sync from [`rust-lang/rust`] to Clippy](#performing-the-sync-from-rust-langrust-to-clippy) + - [Performing the sync from Clippy to [`rust-lang/rust`]](#performing-the-sync-from-clippy-to-rust-langrust) - [Defining remotes](#defining-remotes) - [Issue and PR triage](#issue-and-pr-triage) - [Bors and Homu](#bors-and-homu) @@ -105,21 +107,41 @@ quick read. ## Getting code-completion for rustc internals to work -Unfortunately, [`rust-analyzer`][ra_homepage] does not (yet?) understand how Clippy uses compiler-internals +### IntelliJ Rust +Unfortunately, [`IntelliJ Rust`][IntelliJ_rust_homepage] does not (yet?) understand how Clippy uses compiler-internals using `extern crate` and it also needs to be able to read the source files of the rustc-compiler which are not available via a `rustup` component at the time of writing. To work around this, you need to have a copy of the [rustc-repo][rustc_repo] available which can be obtained via `git clone https://github.com/rust-lang/rust/`. Then you can run a `cargo dev` command to automatically make Clippy use the rustc-repo via path-dependencies -which rust-analyzer will be able to understand. -Run `cargo dev ra_setup --repo-path <repo-path>` where `<repo-path>` is an absolute path to the rustc repo +which `IntelliJ Rust` will be able to understand. +Run `cargo dev ide_setup --repo-path <repo-path>` where `<repo-path>` is a path to the rustc repo you just cloned. The command will add path-dependencies pointing towards rustc-crates inside the rustc repo to Clippys `Cargo.toml`s and should allow rust-analyzer to understand most of the types that Clippy uses. Just make sure to remove the dependencies again before finally making a pull request! -[ra_homepage]: https://rust-analyzer.github.io/ [rustc_repo]: https://github.com/rust-lang/rust/ +[IntelliJ_rust_homepage]: https://intellij-rust.github.io/ + +### Rust Analyzer +As of [#6869][6869], [`rust-analyzer`][ra_homepage] can understand that Clippy uses compiler-internals +using `extern crate` when `package.metadata.rust-analyzer.rustc_private` is set to `true` in Clippys `Cargo.toml.` +You will required a `nightly` toolchain with the `rustc-dev` component installed. +Make sure that in the `rust-analyzer` configuration, you set +``` +{ "rust-analyzer.rustcSource": "discover" } +``` +and +``` +{ "rust-analyzer.updates.channel": "nightly" } +``` +You should be able to see information on things like `Expr` or `EarlyContext` now if you hover them, also +a lot more type hints. +This will work with `rust-analyzer 2021-03-15` shipped in nightly `1.52.0-nightly (107896c32 2021-03-15)` or later. + +[ra_homepage]: https://rust-analyzer.github.io/ +[6869]: https://github.com/rust-lang/rust-clippy/pull/6869 ## How Clippy works diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml index 2b9488de289..cade44a0a9a 100644 --- a/src/tools/clippy/Cargo.toml +++ b/src/tools/clippy/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.1.52" +version = "0.1.53" authors = ["The Rust Clippy Developers"] description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" @@ -37,6 +37,8 @@ clippy-mini-macro-test = { version = "0.2", path = "mini-macro" } serde = { version = "1.0", features = ["derive"] } derive-new = "0.5" regex = "1.4" +quote = "1" +syn = { version = "1", features = ["full"] } # A noop dependency that changes in the Rust repository, it's a bit of a hack. # See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` diff --git a/src/tools/clippy/clippy_dev/src/fmt.rs b/src/tools/clippy/clippy_dev/src/fmt.rs index a26d6aba10d..111c79c332d 100644 --- a/src/tools/clippy/clippy_dev/src/fmt.rs +++ b/src/tools/clippy/clippy_dev/src/fmt.rs @@ -90,7 +90,7 @@ pub fn run(check: bool, verbose: bool) { }, CliError::RaSetupActive => { eprintln!( - "error: a local rustc repo is enabled as path dependency via `cargo dev ra_setup`. + "error: a local rustc repo is enabled as path dependency via `cargo dev ide_setup`. Not formatting because that would format the local repo as well! Please revert the changes to Cargo.tomls first." ); diff --git a/src/tools/clippy/clippy_dev/src/ra_setup.rs b/src/tools/clippy/clippy_dev/src/ide_setup.rs index d0e2193ddc5..defb1133e44 100644 --- a/src/tools/clippy/clippy_dev/src/ra_setup.rs +++ b/src/tools/clippy/clippy_dev/src/ide_setup.rs @@ -55,7 +55,7 @@ fn inject_deps_into_manifest( // do not inject deps if we have aleady done so if cargo_toml.contains("[target.'cfg(NOT_A_PLATFORM)'.dependencies]") { eprintln!( - "cargo dev ra_setup: warning: deps already found inside {}, doing nothing.", + "cargo dev ide_setup: warning: deps already found inside {}, doing nothing.", manifest_path ); return Ok(()); diff --git a/src/tools/clippy/clippy_dev/src/lib.rs b/src/tools/clippy/clippy_dev/src/lib.rs index a95abfaceaa..a5e94683878 100644 --- a/src/tools/clippy/clippy_dev/src/lib.rs +++ b/src/tools/clippy/clippy_dev/src/lib.rs @@ -12,8 +12,8 @@ use walkdir::WalkDir; pub mod bless; pub mod fmt; +pub mod ide_setup; pub mod new_lint; -pub mod ra_setup; pub mod serve; pub mod stderr_length_check; pub mod update_lints; diff --git a/src/tools/clippy/clippy_dev/src/main.rs b/src/tools/clippy/clippy_dev/src/main.rs index 2a9f3e5348c..f4da783502c 100644 --- a/src/tools/clippy/clippy_dev/src/main.rs +++ b/src/tools/clippy/clippy_dev/src/main.rs @@ -1,7 +1,7 @@ #![cfg_attr(feature = "deny-warnings", deny(warnings))] use clap::{App, Arg, ArgMatches, SubCommand}; -use clippy_dev::{bless, fmt, new_lint, ra_setup, serve, stderr_length_check, update_lints}; +use clippy_dev::{bless, fmt, ide_setup, new_lint, serve, stderr_length_check, update_lints}; fn main() { let matches = get_clap_config(); @@ -34,7 +34,7 @@ fn main() { ("limit_stderr_length", _) => { stderr_length_check::check(); }, - ("ra_setup", Some(matches)) => ra_setup::run(matches.value_of("rustc-repo-path")), + ("ide_setup", Some(matches)) => ide_setup::run(matches.value_of("rustc-repo-path")), ("serve", Some(matches)) => { let port = matches.value_of("port").unwrap().parse().unwrap(); let lint = matches.value_of("lint"); @@ -138,8 +138,8 @@ fn get_clap_config<'a>() -> ArgMatches<'a> { .about("Ensures that stderr files do not grow longer than a certain amount of lines."), ) .subcommand( - SubCommand::with_name("ra_setup") - .about("Alter dependencies so rust-analyzer can find rustc internals") + SubCommand::with_name("ide_setup") + .about("Alter dependencies so Intellij Rust can find rustc internals") .arg( Arg::with_name("rustc-repo-path") .long("repo-path") diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml index 6bd6c079276..05cdd9d064a 100644 --- a/src/tools/clippy/clippy_lints/Cargo.toml +++ b/src/tools/clippy/clippy_lints/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "clippy_lints" # begin automatic update -version = "0.1.52" +version = "0.1.53" # end automatic update authors = ["The Rust Clippy Developers"] description = "A bunch of helpful lints to avoid common pitfalls in Rust" @@ -20,7 +20,6 @@ pulldown-cmark = { version = "0.8", default-features = false } quine-mc_cluskey = "0.2.2" regex-syntax = "0.6" serde = { version = "1.0", features = ["derive"] } -smallvec = { version = "1", features = ["union"] } toml = "0.5.3" unicode-normalization = "0.1" semver = "0.11" @@ -28,8 +27,6 @@ rustc-semver = "1.1.0" # NOTE: cargo requires serde feat in its url dep # see <https://github.com/rust-lang/rust/pull/63587#issuecomment-522343864> url = { version = "2.1.0", features = ["serde"] } -quote = "1" -syn = { version = "1", features = ["full"] } [features] deny-warnings = [] diff --git a/src/tools/clippy/clippy_lints/src/approx_const.rs b/src/tools/clippy/clippy_lints/src/approx_const.rs index 1d511a86c90..3d04abe094d 100644 --- a/src/tools/clippy/clippy_lints/src/approx_const.rs +++ b/src/tools/clippy/clippy_lints/src/approx_const.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint; +use clippy_utils::diagnostics::span_lint; use rustc_ast::ast::{FloatTy, LitFloatType, LitKind}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/arithmetic.rs b/src/tools/clippy/clippy_lints/src/arithmetic.rs index 61fdf9495b9..c560f545d6a 100644 --- a/src/tools/clippy/clippy_lints/src/arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/arithmetic.rs @@ -1,5 +1,5 @@ use crate::consts::constant_simple; -use crate::utils::span_lint; +use clippy_utils::diagnostics::span_lint; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; diff --git a/src/tools/clippy/clippy_lints/src/as_conversions.rs b/src/tools/clippy/clippy_lints/src/as_conversions.rs index c30d65bbc57..4b31e16094e 100644 --- a/src/tools/clippy/clippy_lints/src/as_conversions.rs +++ b/src/tools/clippy/clippy_lints/src/as_conversions.rs @@ -1,10 +1,9 @@ +use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{Expr, ExprKind}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::span_lint_and_help; - declare_clippy_lint! { /// **What it does:** Checks for usage of `as` conversions. /// diff --git a/src/tools/clippy/clippy_lints/src/asm_syntax.rs b/src/tools/clippy/clippy_lints/src/asm_syntax.rs index ef1f1a14afc..b970c71b753 100644 --- a/src/tools/clippy/clippy_lints/src/asm_syntax.rs +++ b/src/tools/clippy/clippy_lints/src/asm_syntax.rs @@ -1,6 +1,6 @@ use std::fmt; -use crate::utils::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{Expr, ExprKind, InlineAsmOptions}; use rustc_lint::{EarlyContext, EarlyLintPass, Lint}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs index 77b26faaa58..16905781c56 100644 --- a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs +++ b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs @@ -1,5 +1,7 @@ use crate::consts::{constant, Constant}; -use crate::utils::{is_direct_expn_of, is_expn_of, match_panic_call, snippet_opt, span_lint_and_help}; +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::source::snippet_opt; +use clippy_utils::{is_direct_expn_of, is_expn_of, match_panic_call}; use if_chain::if_chain; use rustc_hir::{Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/assign_ops.rs b/src/tools/clippy/clippy_lints/src/assign_ops.rs index e13f62d0428..bc6eec0051a 100644 --- a/src/tools/clippy/clippy_lints/src/assign_ops.rs +++ b/src/tools/clippy/clippy_lints/src/assign_ops.rs @@ -1,7 +1,8 @@ -use crate::utils::{ - eq_expr_value, get_trait_def_id, implements_trait, snippet_opt, span_lint_and_then, trait_ref_of_method, -}; -use crate::utils::{higher, sugg}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::snippet_opt; +use clippy_utils::ty::implements_trait; +use clippy_utils::{eq_expr_value, get_trait_def_id, trait_ref_of_method}; +use clippy_utils::{higher, paths, sugg}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; @@ -92,7 +93,7 @@ impl<'tcx> LateLintPass<'tcx> for AssignOps { $($trait_name:ident),+) => { match $op { $(hir::BinOpKind::$trait_name => { - let [krate, module] = crate::utils::paths::OPS_MODULE; + let [krate, module] = paths::OPS_MODULE; let path: [&str; 3] = [krate, module, concat!(stringify!($trait_name), "Assign")]; let trait_id = if let Some(trait_id) = get_trait_def_id($cx, &path) { trait_id diff --git a/src/tools/clippy/clippy_lints/src/async_yields_async.rs b/src/tools/clippy/clippy_lints/src/async_yields_async.rs index 869a5c28d05..e6c7c68f91a 100644 --- a/src/tools/clippy/clippy_lints/src/async_yields_async.rs +++ b/src/tools/clippy/clippy_lints/src/async_yields_async.rs @@ -1,4 +1,6 @@ -use crate::utils::{implements_trait, snippet, span_lint_and_then}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::snippet; +use clippy_utils::ty::implements_trait; use rustc_errors::Applicability; use rustc_hir::{AsyncGeneratorKind, Body, BodyId, ExprKind, GeneratorKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/atomic_ordering.rs b/src/tools/clippy/clippy_lints/src/atomic_ordering.rs index 703d8a6f62b..dfb18199325 100644 --- a/src/tools/clippy/clippy_lints/src/atomic_ordering.rs +++ b/src/tools/clippy/clippy_lints/src/atomic_ordering.rs @@ -1,4 +1,5 @@ -use crate::utils::{match_def_path, span_lint_and_help}; +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::match_def_path; use if_chain::if_chain; use rustc_hir::def_id::DefId; use rustc_hir::{Expr, ExprKind}; diff --git a/src/tools/clippy/clippy_lints/src/attrs.rs b/src/tools/clippy/clippy_lints/src/attrs.rs index 6250810bc42..3cef8d2a78b 100644 --- a/src/tools/clippy/clippy_lints/src/attrs.rs +++ b/src/tools/clippy/clippy_lints/src/attrs.rs @@ -1,9 +1,8 @@ //! checks for attributes -use crate::utils::{ - first_line_of_span, is_present_in_source, match_panic_def_id, snippet_opt, span_lint, span_lint_and_help, - span_lint_and_sugg, span_lint_and_then, without_block_comments, -}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::match_panic_def_id; +use clippy_utils::source::{first_line_of_span, is_present_in_source, snippet_opt, without_block_comments}; use if_chain::if_chain; use rustc_ast::{AttrKind, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem}; use rustc_errors::Applicability; @@ -431,7 +430,7 @@ fn is_relevant_block(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_ |stmt| match &stmt.kind { StmtKind::Local(_) => true, StmtKind::Expr(expr) | StmtKind::Semi(expr) => is_relevant_expr(cx, typeck_results, expr), - _ => false, + StmtKind::Item(_) => false, }, ) } @@ -565,7 +564,7 @@ fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute) { // check for `rustfmt_skip` and `rustfmt::skip` if let Some(skip_item) = &items[1].meta_item(); if skip_item.has_name(sym!(rustfmt_skip)) || - skip_item.path.segments.last().expect("empty path in attribute").ident.name == sym!(skip); + skip_item.path.segments.last().expect("empty path in attribute").ident.name == sym::skip; // Only lint outer attributes, because custom inner attributes are unstable // Tracking issue: https://github.com/rust-lang/rust/issues/54726 if let AttrStyle::Outer = attr.style; @@ -614,7 +613,7 @@ fn check_mismatched_target_os(cx: &EarlyContext<'_>, attr: &Attribute) { } } }, - _ => {}, + MetaItemKind::NameValue(..) => {}, } } } diff --git a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs index 14b6a156c62..68eee0520b3 100644 --- a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs +++ b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs @@ -1,4 +1,5 @@ -use crate::utils::{match_def_path, paths, span_lint_and_note}; +use clippy_utils::diagnostics::span_lint_and_note; +use clippy_utils::{match_def_path, paths}; use rustc_hir::def_id::DefId; use rustc_hir::{AsyncGeneratorKind, Body, BodyId, GeneratorKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/bit_mask.rs b/src/tools/clippy/clippy_lints/src/bit_mask.rs index a4ee54076ee..f7daf3dab49 100644 --- a/src/tools/clippy/clippy_lints/src/bit_mask.rs +++ b/src/tools/clippy/clippy_lints/src/bit_mask.rs @@ -1,6 +1,6 @@ use crate::consts::{constant, Constant}; -use crate::utils::sugg::Sugg; -use crate::utils::{span_lint, span_lint_and_then}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; +use clippy_utils::sugg::Sugg; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; diff --git a/src/tools/clippy/clippy_lints/src/blacklisted_name.rs b/src/tools/clippy/clippy_lints/src/blacklisted_name.rs index 153870fb416..b26ef33e056 100644 --- a/src/tools/clippy/clippy_lints/src/blacklisted_name.rs +++ b/src/tools/clippy/clippy_lints/src/blacklisted_name.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint; +use clippy_utils::diagnostics::span_lint; use rustc_data_structures::fx::FxHashSet; use rustc_hir::{Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs b/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs index b53f80fd8bc..badcf8d2a43 100644 --- a/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs +++ b/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs @@ -1,7 +1,7 @@ -use crate::utils::{ - differing_macro_contexts, get_parent_expr, get_trait_def_id, implements_trait, paths, - snippet_block_with_applicability, span_lint, span_lint_and_sugg, -}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; +use clippy_utils::source::snippet_block_with_applicability; +use clippy_utils::ty::implements_trait; +use clippy_utils::{differing_macro_contexts, get_parent_expr}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; @@ -10,6 +10,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::map::Map; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// **What it does:** Checks for `if` conditions that use blocks containing an @@ -61,7 +62,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ExVisitor<'a, 'tcx> { if let Some(parent) = get_parent_expr(self.cx, expr); if let ExprKind::MethodCall(_, _, args, _) = parent.kind; let caller = self.cx.typeck_results().expr_ty(&args[0]); - if let Some(iter_id) = get_trait_def_id(self.cx, &paths::ITERATOR); + if let Some(iter_id) = self.cx.tcx.get_diagnostic_item(sym::Iterator); if implements_trait(self.cx, caller, iter_id, &[]); then { return; diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs index 0713303ec4b..58d9aa9c005 100644 --- a/src/tools/clippy/clippy_lints/src/booleans.rs +++ b/src/tools/clippy/clippy_lints/src/booleans.rs @@ -1,7 +1,7 @@ -use crate::utils::{ - eq_expr_value, get_trait_def_id, implements_trait, in_macro, is_type_diagnostic_item, paths, snippet_opt, - span_lint_and_sugg, span_lint_and_then, -}; +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::source::snippet_opt; +use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; +use clippy_utils::{eq_expr_value, get_trait_def_id, in_macro, paths}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; diff --git a/src/tools/clippy/clippy_lints/src/bytecount.rs b/src/tools/clippy/clippy_lints/src/bytecount.rs index eb5dc7ceecd..846ac08e93a 100644 --- a/src/tools/clippy/clippy_lints/src/bytecount.rs +++ b/src/tools/clippy/clippy_lints/src/bytecount.rs @@ -1,6 +1,7 @@ -use crate::utils::{ - contains_name, get_pat_name, match_type, paths, single_segment_path, snippet_with_applicability, span_lint_and_sugg, -}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::match_type; +use clippy_utils::{contains_name, get_pat_name, paths, single_segment_path}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, UnOp}; diff --git a/src/tools/clippy/clippy_lints/src/cargo_common_metadata.rs b/src/tools/clippy/clippy_lints/src/cargo_common_metadata.rs index cc2869ab495..fce5c559672 100644 --- a/src/tools/clippy/clippy_lints/src/cargo_common_metadata.rs +++ b/src/tools/clippy/clippy_lints/src/cargo_common_metadata.rs @@ -2,7 +2,8 @@ use std::path::PathBuf; -use crate::utils::{run_lints, span_lint}; +use clippy_utils::diagnostics::span_lint; +use clippy_utils::run_lints; use rustc_hir::{hir_id::CRATE_HIR_ID, Crate}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; diff --git a/src/tools/clippy/clippy_lints/src/case_sensitive_file_extension_comparisons.rs b/src/tools/clippy/clippy_lints/src/case_sensitive_file_extension_comparisons.rs index b15fe65352a..c9ef379be56 100644 --- a/src/tools/clippy/clippy_lints/src/case_sensitive_file_extension_comparisons.rs +++ b/src/tools/clippy/clippy_lints/src/case_sensitive_file_extension_comparisons.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_help; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_hir::{Expr, ExprKind, PathSegment}; diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs b/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs index 478832a5164..869deecfbd5 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs @@ -1,10 +1,12 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::in_constant; +use clippy_utils::source::snippet_opt; +use clippy_utils::ty::is_isize_or_usize; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, FloatTy, Ty}; -use crate::utils::{in_constant, is_isize_or_usize, snippet_opt, span_lint_and_sugg}; - use super::{utils, CAST_LOSSLESS}; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs index 33b06b8fe7c..833ad122e0d 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs @@ -1,9 +1,9 @@ +use clippy_utils::diagnostics::span_lint; +use clippy_utils::ty::is_isize_or_usize; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::{self, FloatTy, Ty}; -use crate::utils::{is_isize_or_usize, span_lint}; - use super::{utils, CAST_POSSIBLE_TRUNCATION}; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs b/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs index 56d301ed3e1..2c5c1d7cb46 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs @@ -1,9 +1,9 @@ +use clippy_utils::diagnostics::span_lint; +use clippy_utils::ty::is_isize_or_usize; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::Ty; -use crate::utils::{is_isize_or_usize, span_lint}; - use super::{utils, CAST_POSSIBLE_WRAP}; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_precision_loss.rs b/src/tools/clippy/clippy_lints/src/casts/cast_precision_loss.rs index a1c3900ce1f..63ac8fd2dd2 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_precision_loss.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_precision_loss.rs @@ -1,9 +1,9 @@ +use clippy_utils::diagnostics::span_lint; +use clippy_utils::ty::is_isize_or_usize; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::{self, FloatTy, Ty}; -use crate::utils::{is_isize_or_usize, span_lint}; - use super::{utils, CAST_PRECISION_LOSS}; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs index 87fb5557be0..5208156ffd2 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs @@ -1,13 +1,12 @@ +use clippy_utils::diagnostics::span_lint; +use clippy_utils::is_hir_ty_cfg_dependant; +use if_chain::if_chain; use rustc_hir::{Expr, ExprKind, GenericArg}; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; use rustc_span::symbol::sym; use rustc_target::abi::LayoutOf; -use if_chain::if_chain; - -use crate::utils::{is_hir_ty_cfg_dependant, span_lint}; - use super::CAST_PTR_ALIGNMENT; pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_ref_to_mut.rs b/src/tools/clippy/clippy_lints/src/casts/cast_ref_to_mut.rs index 3fdc1c6168b..d9bf1ea58b9 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_ref_to_mut.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_ref_to_mut.rs @@ -1,11 +1,9 @@ +use clippy_utils::diagnostics::span_lint; +use if_chain::if_chain; use rustc_hir::{Expr, ExprKind, MutTy, Mutability, TyKind, UnOp}; use rustc_lint::LateContext; use rustc_middle::ty; -use if_chain::if_chain; - -use crate::utils::span_lint; - use super::CAST_REF_TO_MUT; pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs index 9656fbebd77..bf722d0a3f4 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs @@ -1,12 +1,11 @@ +use crate::consts::{constant, Constant}; +use clippy_utils::diagnostics::span_lint; +use clippy_utils::{method_chain_args, sext}; +use if_chain::if_chain; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; -use if_chain::if_chain; - -use crate::consts::{constant, Constant}; -use crate::utils::{method_chain_args, sext, span_lint}; - use super::CAST_SIGN_LOSS; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { diff --git a/src/tools/clippy/clippy_lints/src/casts/char_lit_as_u8.rs b/src/tools/clippy/clippy_lints/src/casts/char_lit_as_u8.rs index ccaad1b8f2a..099a0de881f 100644 --- a/src/tools/clippy/clippy_lints/src/casts/char_lit_as_u8.rs +++ b/src/tools/clippy/clippy_lints/src/casts/char_lit_as_u8.rs @@ -1,13 +1,12 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::snippet_with_applicability; +use if_chain::if_chain; use rustc_ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, UintTy}; -use if_chain::if_chain; - -use crate::utils::{snippet_with_applicability, span_lint_and_then}; - use super::CHAR_LIT_AS_U8; pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { diff --git a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs index a8d508585b5..35350d8a25b 100644 --- a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs +++ b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs @@ -1,10 +1,10 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty, UintTy}; -use crate::utils::{snippet_with_applicability, span_lint_and_sugg}; - use super::{utils, FN_TO_NUMERIC_CAST}; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { diff --git a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs index 0085c7b27b2..6287f479b5b 100644 --- a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs +++ b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs @@ -1,10 +1,10 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; -use crate::utils::{snippet_with_applicability, span_lint_and_sugg}; - use super::{utils, FN_TO_NUMERIC_CAST_WITH_TRUNCATION}; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs index b726bd75f1d..d9e172c01a7 100644 --- a/src/tools/clippy/clippy_lints/src/casts/mod.rs +++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs @@ -12,14 +12,13 @@ mod ptr_as_ptr; mod unnecessary_cast; mod utils; +use clippy_utils::is_hir_ty_cfg_dependant; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use crate::utils::is_hir_ty_cfg_dependant; - declare_clippy_lint! { /// **What it does:** Checks for casts from any numerical to a float type where /// the receiving type cannot store all values from the original type without diff --git a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs index abfbadf3642..9113e5a0920 100644 --- a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs +++ b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs @@ -1,16 +1,15 @@ use std::borrow::Cow; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::meets_msrv; +use clippy_utils::sugg::Sugg; +use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Mutability, TyKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, TypeAndMut}; use rustc_semver::RustcVersion; -use if_chain::if_chain; - -use crate::utils::sugg::Sugg; -use crate::utils::{meets_msrv, span_lint_and_sugg}; - use super::PTR_AS_PTR; const PTR_AS_PTR_MSRV: RustcVersion = RustcVersion::new(1, 38, 0); diff --git a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs index fa2a07ef1da..9ed359922fd 100644 --- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs +++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs @@ -1,3 +1,7 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::numeric_literal::NumericLiteral; +use clippy_utils::source::snippet_opt; +use if_chain::if_chain; use rustc_ast::{LitFloatType, LitIntType, LitKind}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Lit, UnOp}; @@ -5,10 +9,6 @@ use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, FloatTy, InferTy, Ty}; -use if_chain::if_chain; - -use crate::utils::{numeric_literal::NumericLiteral, snippet_opt, span_lint, span_lint_and_sugg}; - use super::UNNECESSARY_CAST; pub(super) fn check( @@ -44,9 +44,18 @@ pub(super) fn check( lint_unnecessary_cast(cx, expr, &literal_str, cast_from, cast_to); }, LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::Float(_, LitFloatType::Unsuffixed) => {}, + LitKind::Int(_, LitIntType::Signed(_) | LitIntType::Unsigned(_)) + | LitKind::Float(_, LitFloatType::Suffixed(_)) + if cast_from.kind() == cast_to.kind() => + { + if let Some(src) = snippet_opt(cx, lit.span) { + let num_lit = NumericLiteral::from_lit_kind(&src, &lit.node).unwrap(); + lint_unnecessary_cast(cx, expr, num_lit.integer, cast_from, cast_to); + } + }, _ => { if cast_from.kind() == cast_to.kind() && !in_external_macro(cx.sess(), expr.span) { - span_lint( + span_lint_and_sugg( cx, UNNECESSARY_CAST, expr.span, @@ -54,6 +63,9 @@ pub(super) fn check( "casting to the same type is unnecessary (`{}` -> `{}`)", cast_from, cast_to ), + "try", + literal_str, + Applicability::MachineApplicable, ); return true; } diff --git a/src/tools/clippy/clippy_lints/src/checked_conversions.rs b/src/tools/clippy/clippy_lints/src/checked_conversions.rs index 54bc69e058b..ed46cac493a 100644 --- a/src/tools/clippy/clippy_lints/src/checked_conversions.rs +++ b/src/tools/clippy/clippy_lints/src/checked_conversions.rs @@ -1,5 +1,8 @@ //! lint on manually implemented checked conversions that could be transformed into `try_from` +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::{meets_msrv, SpanlessEq}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -9,8 +12,6 @@ use rustc_middle::lint::in_external_macro; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use crate::utils::{meets_msrv, snippet_with_applicability, span_lint_and_sugg, SpanlessEq}; - const CHECKED_CONVERSIONS_MSRV: RustcVersion = RustcVersion::new(1, 34, 0); declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs index 658d445dfec..4cc542f723c 100644 --- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs +++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs @@ -1,5 +1,9 @@ //! calculate cognitive complexity and warn about overly complex functions +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::source::snippet_opt; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::LimitStack; use rustc_ast::ast::Attribute; use rustc_hir::intravisit::{walk_expr, FnKind, NestedVisitorMap, Visitor}; use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId}; @@ -9,8 +13,6 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; use rustc_span::{sym, BytePos}; -use crate::utils::{is_type_diagnostic_item, snippet_opt, span_lint_and_help, LimitStack}; - declare_clippy_lint! { /// **What it does:** Checks for methods with high cognitive complexity. /// diff --git a/src/tools/clippy/clippy_lints/src/collapsible_if.rs b/src/tools/clippy/clippy_lints/src/collapsible_if.rs index 34f0e6ab027..dae5c86bd44 100644 --- a/src/tools/clippy/clippy_lints/src/collapsible_if.rs +++ b/src/tools/clippy/clippy_lints/src/collapsible_if.rs @@ -12,15 +12,15 @@ //! //! This lint is **warn** by default +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::source::{snippet_block, snippet_block_with_applicability}; +use clippy_utils::sugg::Sugg; use if_chain::if_chain; use rustc_ast::ast; +use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::sugg::Sugg; -use crate::utils::{snippet_block, snippet_block_with_applicability, span_lint_and_sugg, span_lint_and_then}; -use rustc_errors::Applicability; - declare_clippy_lint! { /// **What it does:** Checks for nested `if` statements which can be collapsed /// by `&&`-combining their conditions. diff --git a/src/tools/clippy/clippy_lints/src/collapsible_match.rs b/src/tools/clippy/clippy_lints/src/collapsible_match.rs index 3c45525684b..e2b3686ddf0 100644 --- a/src/tools/clippy/clippy_lints/src/collapsible_match.rs +++ b/src/tools/clippy/clippy_lints/src/collapsible_match.rs @@ -1,5 +1,6 @@ -use crate::utils::visitors::LocalUsedVisitor; -use crate::utils::{path_to_local, span_lint_and_then, SpanlessEq}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::visitors::LocalUsedVisitor; +use clippy_utils::{path_to_local, SpanlessEq}; use if_chain::if_chain; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind, QPath, StmtKind, UnOp}; diff --git a/src/tools/clippy/clippy_lints/src/comparison_chain.rs b/src/tools/clippy/clippy_lints/src/comparison_chain.rs index e309db25995..d601cb7c224 100644 --- a/src/tools/clippy/clippy_lints/src/comparison_chain.rs +++ b/src/tools/clippy/clippy_lints/src/comparison_chain.rs @@ -1,6 +1,6 @@ -use crate::utils::{ - get_trait_def_id, if_sequence, implements_trait, parent_node_is_if_expr, paths, span_lint_and_help, SpanlessEq, -}; +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::ty::implements_trait; +use clippy_utils::{get_trait_def_id, if_sequence, parent_node_is_if_expr, paths, SpanlessEq}; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs index 944aaafb46d..46093a16571 100644 --- a/src/tools/clippy/clippy_lints/src/copies.rs +++ b/src/tools/clippy/clippy_lints/src/copies.rs @@ -1,5 +1,6 @@ -use crate::utils::{eq_expr_value, in_macro, search_same, SpanlessEq, SpanlessHash}; -use crate::utils::{get_parent_expr, if_sequence, span_lint_and_note}; +use clippy_utils::diagnostics::span_lint_and_note; +use clippy_utils::{eq_expr_value, in_macro, search_same, SpanlessEq, SpanlessHash}; +use clippy_utils::{get_parent_expr, if_sequence}; use rustc_hir::{Block, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/src/tools/clippy/clippy_lints/src/copy_iterator.rs b/src/tools/clippy/clippy_lints/src/copy_iterator.rs index 004bce5f62a..35079c6bedc 100644 --- a/src/tools/clippy/clippy_lints/src/copy_iterator.rs +++ b/src/tools/clippy/clippy_lints/src/copy_iterator.rs @@ -1,7 +1,11 @@ -use crate::utils::{is_copy, match_path, paths, span_lint_and_note}; +use clippy_utils::diagnostics::span_lint_and_note; +use clippy_utils::ty::is_copy; use rustc_hir::{Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; + +use if_chain::if_chain; declare_clippy_lint! { /// **What it does:** Checks for types that implement `Copy` as well as @@ -33,14 +37,16 @@ declare_lint_pass!(CopyIterator => [COPY_ITERATOR]); impl<'tcx> LateLintPass<'tcx> for CopyIterator { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { - if let ItemKind::Impl(Impl { - of_trait: Some(ref trait_ref), - .. - }) = item.kind - { + if_chain! { + if let ItemKind::Impl(Impl { + of_trait: Some(ref trait_ref), + .. + }) = item.kind; let ty = cx.tcx.type_of(item.def_id); - - if is_copy(cx, ty) && match_path(&trait_ref.path, &paths::ITERATOR) { + if is_copy(cx, ty); + if let Some(trait_id) = trait_ref.trait_def_id(); + if cx.tcx.is_diagnostic_item(sym::Iterator, trait_id); + then { span_lint_and_note( cx, COPY_ITERATOR, diff --git a/src/tools/clippy/clippy_lints/src/create_dir.rs b/src/tools/clippy/clippy_lints/src/create_dir.rs index 200b6a565cc..ac890c90c97 100644 --- a/src/tools/clippy/clippy_lints/src/create_dir.rs +++ b/src/tools/clippy/clippy_lints/src/create_dir.rs @@ -1,4 +1,6 @@ -use crate::utils::{match_def_path, paths, snippet, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet; +use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; diff --git a/src/tools/clippy/clippy_lints/src/dbg_macro.rs b/src/tools/clippy/clippy_lints/src/dbg_macro.rs index e513dcce64e..286cc7e223e 100644 --- a/src/tools/clippy/clippy_lints/src/dbg_macro.rs +++ b/src/tools/clippy/clippy_lints/src/dbg_macro.rs @@ -1,4 +1,5 @@ -use crate::utils::{snippet_opt, span_lint_and_help, span_lint_and_sugg}; +use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; +use clippy_utils::source::snippet_opt; use rustc_ast::ast; use rustc_ast::tokenstream::TokenStream; use rustc_errors::Applicability; diff --git a/src/tools/clippy/clippy_lints/src/default.rs b/src/tools/clippy/clippy_lints/src/default.rs index 6fa1378b8c7..568a174445c 100644 --- a/src/tools/clippy/clippy_lints/src/default.rs +++ b/src/tools/clippy/clippy_lints/src/default.rs @@ -1,7 +1,6 @@ -use crate::utils::{ - any_parent_is_automatically_derived, contains_name, match_def_path, paths, snippet_with_macro_callsite, -}; -use crate::utils::{span_lint_and_note, span_lint_and_sugg}; +use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg}; +use clippy_utils::source::snippet_with_macro_callsite; +use clippy_utils::{any_parent_is_automatically_derived, contains_name, match_def_path, paths}; use if_chain::if_chain; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; @@ -105,6 +104,7 @@ impl LateLintPass<'_> for Default { } } + #[allow(clippy::too_many_lines)] fn check_block<'tcx>(&mut self, cx: &LateContext<'tcx>, block: &Block<'tcx>) { // start from the `let mut _ = _::default();` and look at all the following // statements, see if they re-assign the fields of the binding @@ -198,6 +198,24 @@ impl LateLintPass<'_> for Default { .collect::<Vec<String>>() .join(", "); + // give correct suggestion if generics are involved (see #6944) + let binding_type = if_chain! { + if let ty::Adt(adt_def, substs) = binding_type.kind(); + if !substs.is_empty(); + let adt_def_ty_name = cx.tcx.item_name(adt_def.did); + let generic_args = substs.iter().collect::<Vec<_>>(); + let tys_str = generic_args + .iter() + .map(ToString::to_string) + .collect::<Vec<_>>() + .join(", "); + then { + format!("{}::<{}>", adt_def_ty_name, &tys_str) + } else { + binding_type.to_string() + } + }; + let sugg = if ext_with_default { if field_list.is_empty() { format!("{}::default()", binding_type) diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs index 369efacc9bc..73f71d88b05 100644 --- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs +++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs @@ -1,3 +1,6 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet; +use if_chain::if_chain; use rustc_ast::ast::{LitFloatType, LitIntType, LitKind}; use rustc_errors::Applicability; use rustc_hir::{ @@ -10,10 +13,7 @@ use rustc_middle::{ ty::{self, FloatTy, IntTy, PolyFnSig, Ty}, }; use rustc_session::{declare_lint_pass, declare_tool_lint}; - -use if_chain::if_chain; - -use crate::utils::{snippet, span_lint_and_sugg}; +use std::iter; declare_clippy_lint! { /// **What it does:** Checks for usage of unconstrained numeric literals which may cause default numeric fallback in type @@ -108,7 +108,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { match &expr.kind { ExprKind::Call(func, args) => { if let Some(fn_sig) = fn_sig_opt(self.cx, func.hir_id) { - for (expr, bound) in args.iter().zip(fn_sig.skip_binder().inputs().iter()) { + for (expr, bound) in iter::zip(*args, fn_sig.skip_binder().inputs()) { // Push found arg type, then visit arg. self.ty_bounds.push(TyBound::Ty(bound)); self.visit_expr(expr); @@ -121,7 +121,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { ExprKind::MethodCall(_, _, args, _) => { if let Some(def_id) = self.cx.typeck_results().type_dependent_def_id(expr.hir_id) { let fn_sig = self.cx.tcx.fn_sig(def_id).skip_binder(); - for (expr, bound) in args.iter().zip(fn_sig.inputs().iter()) { + for (expr, bound) in iter::zip(*args, fn_sig.inputs()) { self.ty_bounds.push(TyBound::Ty(bound)); self.visit_expr(expr); self.ty_bounds.pop(); diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index b5fb51af1c7..1415f8e235a 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -1,11 +1,14 @@ -use crate::utils::{get_parent_expr, implements_trait, snippet, span_lint_and_sugg}; -use if_chain::if_chain; -use rustc_ast::util::parser::{ExprPrecedence, PREC_POSTFIX, PREC_PREFIX}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_context; +use clippy_utils::ty::peel_mid_ty_refs; +use clippy_utils::{get_parent_node, in_macro, is_allowed}; +use rustc_ast::util::parser::PREC_PREFIX; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind}; +use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, MatchSource, Mutability, Node, UnOp}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Span; +use rustc_middle::ty::{self, Ty, TyCtxt, TyS, TypeckResults}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::{symbol::sym, Span}; declare_clippy_lint! { /// **What it does:** Checks for explicit `deref()` or `deref_mut()` method calls. @@ -34,76 +37,265 @@ declare_clippy_lint! { "Explicit use of deref or deref_mut method while not in a method chain." } -declare_lint_pass!(Dereferencing => [ - EXPLICIT_DEREF_METHODS +impl_lint_pass!(Dereferencing => [ + EXPLICIT_DEREF_METHODS, ]); +#[derive(Default)] +pub struct Dereferencing { + state: Option<(State, StateData)>, + + // While parsing a `deref` method call in ufcs form, the path to the function is itself an + // expression. This is to store the id of that expression so it can be skipped when + // `check_expr` is called for it. + skip_expr: Option<HirId>, +} + +struct StateData { + /// Span of the top level expression + span: Span, + /// The required mutability + target_mut: Mutability, +} + +enum State { + // Any number of deref method calls. + DerefMethod { + // The number of calls in a sequence which changed the referenced type + ty_changed_count: usize, + is_final_ufcs: bool, + }, +} + +// A reference operation considered by this lint pass +enum RefOp { + Method(Mutability), + Deref, + AddrOf, +} + impl<'tcx> LateLintPass<'tcx> for Dereferencing { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if_chain! { - if !expr.span.from_expansion(); - if let ExprKind::MethodCall(ref method_name, _, ref args, _) = &expr.kind; - if args.len() == 1; - - then { - if let Some(parent_expr) = get_parent_expr(cx, expr) { - // Check if we have the whole call chain here - if let ExprKind::MethodCall(..) = parent_expr.kind { - return; - } - // Check for Expr that we don't want to be linted - let precedence = parent_expr.precedence(); - match precedence { - // Lint a Call is ok though - ExprPrecedence::Call | ExprPrecedence::AddrOf => (), - _ => { - if precedence.order() >= PREC_PREFIX && precedence.order() <= PREC_POSTFIX { - return; - } - } + // Skip path expressions from deref calls. e.g. `Deref::deref(e)` + if Some(expr.hir_id) == self.skip_expr.take() { + return; + } + + // Stop processing sub expressions when a macro call is seen + if in_macro(expr.span) { + if let Some((state, data)) = self.state.take() { + report(cx, expr, state, data); + } + return; + } + + let typeck = cx.typeck_results(); + let (kind, sub_expr) = if let Some(x) = try_parse_ref_op(cx.tcx, typeck, expr) { + x + } else { + // The whole chain of reference operations has been seen + if let Some((state, data)) = self.state.take() { + report(cx, expr, state, data); + } + return; + }; + + match (self.state.take(), kind) { + (None, kind) => { + let parent = get_parent_node(cx.tcx, expr.hir_id); + let expr_ty = typeck.expr_ty(expr); + + match kind { + RefOp::Method(target_mut) + if !is_allowed(cx, EXPLICIT_DEREF_METHODS, expr.hir_id) + && is_linted_explicit_deref_position(parent, expr.hir_id, expr.span) => + { + self.state = Some(( + State::DerefMethod { + ty_changed_count: if deref_method_same_type(expr_ty, typeck.expr_ty(sub_expr)) { + 0 + } else { + 1 + }, + is_final_ufcs: matches!(expr.kind, ExprKind::Call(..)), + }, + StateData { + span: expr.span, + target_mut, + }, + )); } + _ => (), } - let name = method_name.ident.as_str(); - lint_deref(cx, &*name, &args[0], args[0].span, expr.span); - } + }, + (Some((State::DerefMethod { ty_changed_count, .. }, data)), RefOp::Method(_)) => { + self.state = Some(( + State::DerefMethod { + ty_changed_count: if deref_method_same_type(typeck.expr_ty(expr), typeck.expr_ty(sub_expr)) { + ty_changed_count + } else { + ty_changed_count + 1 + }, + is_final_ufcs: matches!(expr.kind, ExprKind::Call(..)), + }, + data, + )); + }, + + (Some((state, data)), _) => report(cx, expr, state, data), } } } -fn lint_deref(cx: &LateContext<'_>, method_name: &str, call_expr: &Expr<'_>, var_span: Span, expr_span: Span) { - match method_name { - "deref" => { - let impls_deref_trait = cx.tcx.lang_items().deref_trait().map_or(false, |id| { - implements_trait(cx, cx.typeck_results().expr_ty(&call_expr), id, &[]) - }); - if impls_deref_trait { - span_lint_and_sugg( - cx, - EXPLICIT_DEREF_METHODS, - expr_span, - "explicit deref method call", - "try this", - format!("&*{}", &snippet(cx, var_span, "..")), - Applicability::MachineApplicable, - ); - } +fn try_parse_ref_op( + tcx: TyCtxt<'tcx>, + typeck: &'tcx TypeckResults<'_>, + expr: &'tcx Expr<'_>, +) -> Option<(RefOp, &'tcx Expr<'tcx>)> { + let (def_id, arg) = match expr.kind { + ExprKind::MethodCall(_, _, [arg], _) => (typeck.type_dependent_def_id(expr.hir_id)?, arg), + ExprKind::Call( + Expr { + kind: ExprKind::Path(path), + hir_id, + .. + }, + [arg], + ) => (typeck.qpath_res(path, *hir_id).opt_def_id()?, arg), + ExprKind::Unary(UnOp::Deref, sub_expr) if !typeck.expr_ty(sub_expr).is_unsafe_ptr() => { + return Some((RefOp::Deref, sub_expr)); }, - "deref_mut" => { - let impls_deref_mut_trait = cx.tcx.lang_items().deref_mut_trait().map_or(false, |id| { - implements_trait(cx, cx.typeck_results().expr_ty(&call_expr), id, &[]) - }); - if impls_deref_mut_trait { - span_lint_and_sugg( - cx, - EXPLICIT_DEREF_METHODS, - expr_span, - "explicit deref_mut method call", - "try this", - format!("&mut *{}", &snippet(cx, var_span, "..")), - Applicability::MachineApplicable, - ); - } + ExprKind::AddrOf(BorrowKind::Ref, _, sub_expr) => return Some((RefOp::AddrOf, sub_expr)), + _ => return None, + }; + if tcx.is_diagnostic_item(sym::deref_method, def_id) { + Some((RefOp::Method(Mutability::Not), arg)) + } else if tcx.trait_of_item(def_id)? == tcx.lang_items().deref_mut_trait()? { + Some((RefOp::Method(Mutability::Mut), arg)) + } else { + None + } +} + +// Checks whether the type for a deref call actually changed the type, not just the mutability of +// the reference. +fn deref_method_same_type(result_ty: Ty<'tcx>, arg_ty: Ty<'tcx>) -> bool { + match (result_ty.kind(), arg_ty.kind()) { + (ty::Ref(_, result_ty, _), ty::Ref(_, arg_ty, _)) => TyS::same_type(result_ty, arg_ty), + + // The result type for a deref method is always a reference + // Not matching the previous pattern means the argument type is not a reference + // This means that the type did change + _ => false, + } +} + +// Checks whether the parent node is a suitable context for switching from a deref method to the +// deref operator. +fn is_linted_explicit_deref_position(parent: Option<Node<'_>>, child_id: HirId, child_span: Span) -> bool { + let parent = match parent { + Some(Node::Expr(e)) if e.span.ctxt() == child_span.ctxt() => e, + _ => return true, + }; + match parent.kind { + // Leave deref calls in the middle of a method chain. + // e.g. x.deref().foo() + ExprKind::MethodCall(_, _, [self_arg, ..], _) if self_arg.hir_id == child_id => false, + + // Leave deref calls resulting in a called function + // e.g. (x.deref())() + ExprKind::Call(func_expr, _) if func_expr.hir_id == child_id => false, + + // Makes an ugly suggestion + // e.g. *x.deref() => *&*x + ExprKind::Unary(UnOp::Deref, _) + // Postfix expressions would require parens + | ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar) + | ExprKind::Field(..) + | ExprKind::Index(..) + | ExprKind::Err => false, + + ExprKind::Box(..) + | ExprKind::ConstBlock(..) + | ExprKind::Array(_) + | ExprKind::Call(..) + | ExprKind::MethodCall(..) + | ExprKind::Tup(..) + | ExprKind::Binary(..) + | ExprKind::Unary(..) + | ExprKind::Lit(..) + | ExprKind::Cast(..) + | ExprKind::Type(..) + | ExprKind::DropTemps(..) + | ExprKind::If(..) + | ExprKind::Loop(..) + | ExprKind::Match(..) + | ExprKind::Closure(..) + | ExprKind::Block(..) + | ExprKind::Assign(..) + | ExprKind::AssignOp(..) + | ExprKind::Path(..) + | ExprKind::AddrOf(..) + | ExprKind::Break(..) + | ExprKind::Continue(..) + | ExprKind::Ret(..) + | ExprKind::InlineAsm(..) + | ExprKind::LlvmInlineAsm(..) + | ExprKind::Struct(..) + | ExprKind::Repeat(..) + | ExprKind::Yield(..) => true, + } +} + +#[allow(clippy::needless_pass_by_value)] +fn report(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data: StateData) { + match state { + State::DerefMethod { + ty_changed_count, + is_final_ufcs, + } => { + let mut app = Applicability::MachineApplicable; + let (expr_str, expr_is_macro_call) = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app); + let ty = cx.typeck_results().expr_ty(expr); + let (_, ref_count) = peel_mid_ty_refs(ty); + let deref_str = if ty_changed_count >= ref_count && ref_count != 0 { + // a deref call changing &T -> &U requires two deref operators the first time + // this occurs. One to remove the reference, a second to call the deref impl. + "*".repeat(ty_changed_count + 1) + } else { + "*".repeat(ty_changed_count) + }; + let addr_of_str = if ty_changed_count < ref_count { + // Check if a reborrow from &mut T -> &T is required. + if data.target_mut == Mutability::Not && matches!(ty.kind(), ty::Ref(_, _, Mutability::Mut)) { + "&*" + } else { + "" + } + } else if data.target_mut == Mutability::Mut { + "&mut " + } else { + "&" + }; + + let expr_str = if !expr_is_macro_call && is_final_ufcs && expr.precedence().order() < PREC_PREFIX { + format!("({})", expr_str) + } else { + expr_str.into_owned() + }; + + span_lint_and_sugg( + cx, + EXPLICIT_DEREF_METHODS, + data.span, + match data.target_mut { + Mutability::Not => "explicit `deref` method call", + Mutability::Mut => "explicit `deref_mut` method call", + }, + "try this", + format!("{}{}{}", addr_of_str, deref_str, expr_str), + app, + ); }, - _ => (), } } diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs index 6d3094ed6bf..834136f910d 100644 --- a/src/tools/clippy/clippy_lints/src/derive.rs +++ b/src/tools/clippy/clippy_lints/src/derive.rs @@ -1,8 +1,7 @@ -use crate::utils::paths; -use crate::utils::{ - get_trait_def_id, is_allowed, is_automatically_derived, is_copy, match_def_path, span_lint_and_help, - span_lint_and_note, span_lint_and_then, -}; +use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note, span_lint_and_then}; +use clippy_utils::paths; +use clippy_utils::ty::is_copy; +use clippy_utils::{get_trait_def_id, is_allowed, is_automatically_derived, match_def_path}; use if_chain::if_chain; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, NestedVisitorMap, Visitor}; diff --git a/src/tools/clippy/clippy_lints/src/disallowed_method.rs b/src/tools/clippy/clippy_lints/src/disallowed_method.rs index 56dc6d18a58..ded0a0fff54 100644 --- a/src/tools/clippy/clippy_lints/src/disallowed_method.rs +++ b/src/tools/clippy/clippy_lints/src/disallowed_method.rs @@ -1,4 +1,5 @@ -use crate::utils::{fn_def_id, span_lint}; +use clippy_utils::diagnostics::span_lint; +use clippy_utils::fn_def_id; use rustc_data_structures::fx::FxHashSet; use rustc_hir::Expr; diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs index 90b02d52f8a..14338ac8faf 100644 --- a/src/tools/clippy/clippy_lints/src/doc.rs +++ b/src/tools/clippy/clippy_lints/src/doc.rs @@ -1,7 +1,6 @@ -use crate::utils::{ - implements_trait, is_entrypoint_fn, is_expn_of, is_type_diagnostic_item, match_panic_def_id, method_chain_args, - return_ty, span_lint, span_lint_and_note, -}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_note}; +use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; +use clippy_utils::{is_entrypoint_fn, is_expn_of, match_panic_def_id, method_chain_args, return_ty}; use if_chain::if_chain; use itertools::Itertools; use rustc_ast::ast::{Async, AttrKind, Attribute, FnKind, FnRetTy, ItemKind}; @@ -584,7 +583,7 @@ fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, span: Span) { let returns_nothing = match &sig.decl.output { FnRetTy::Default(..) => true, FnRetTy::Ty(ty) if ty.kind.is_unit() => true, - _ => false, + FnRetTy::Ty(_) => false, }; if returns_nothing && !is_async && !block.stmts.is_empty() { diff --git a/src/tools/clippy/clippy_lints/src/double_comparison.rs b/src/tools/clippy/clippy_lints/src/double_comparison.rs index 19f56195ec1..1d291565ec1 100644 --- a/src/tools/clippy/clippy_lints/src/double_comparison.rs +++ b/src/tools/clippy/clippy_lints/src/double_comparison.rs @@ -1,13 +1,14 @@ //! Lint on unnecessary double comparisons. Some examples: +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::eq_expr_value; +use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; -use crate::utils::{eq_expr_value, snippet_with_applicability, span_lint_and_sugg}; - declare_clippy_lint! { /// **What it does:** Checks for double comparisons that could be simplified to a single expression. /// diff --git a/src/tools/clippy/clippy_lints/src/double_parens.rs b/src/tools/clippy/clippy_lints/src/double_parens.rs index abbcaf43f41..5afdcb3c09f 100644 --- a/src/tools/clippy/clippy_lints/src/double_parens.rs +++ b/src/tools/clippy/clippy_lints/src/double_parens.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint; +use clippy_utils::diagnostics::span_lint; use rustc_ast::ast::{Expr, ExprKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs index 2aea00d883c..7e7ec017bbb 100644 --- a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs +++ b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs @@ -1,4 +1,6 @@ -use crate::utils::{is_copy, match_def_path, paths, span_lint_and_note}; +use clippy_utils::diagnostics::span_lint_and_note; +use clippy_utils::ty::is_copy; +use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/duration_subsec.rs b/src/tools/clippy/clippy_lints/src/duration_subsec.rs index c0529a34cc4..746c1f6df91 100644 --- a/src/tools/clippy/clippy_lints/src/duration_subsec.rs +++ b/src/tools/clippy/clippy_lints/src/duration_subsec.rs @@ -1,3 +1,5 @@ +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::match_type; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; @@ -6,8 +8,8 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Spanned; use crate::consts::{constant, Constant}; -use crate::utils::paths; -use crate::utils::{match_type, snippet_with_applicability, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::paths; declare_clippy_lint! { /// **What it does:** Checks for calculation of subsecond microseconds or milliseconds diff --git a/src/tools/clippy/clippy_lints/src/else_if_without_else.rs b/src/tools/clippy/clippy_lints/src/else_if_without_else.rs index 95123e6ff6f..26984df9539 100644 --- a/src/tools/clippy/clippy_lints/src/else_if_without_else.rs +++ b/src/tools/clippy/clippy_lints/src/else_if_without_else.rs @@ -1,12 +1,11 @@ //! Lint on if expressions with an else if, but without a final else branch. +use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{Expr, ExprKind}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::span_lint_and_help; - declare_clippy_lint! { /// **What it does:** Checks for usage of if expressions with an `else if` branch, /// but without a final `else` branch. diff --git a/src/tools/clippy/clippy_lints/src/empty_enum.rs b/src/tools/clippy/clippy_lints/src/empty_enum.rs index 077c3b75fb8..c92984a9834 100644 --- a/src/tools/clippy/clippy_lints/src/empty_enum.rs +++ b/src/tools/clippy/clippy_lints/src/empty_enum.rs @@ -1,6 +1,6 @@ //! lint when there is an enum with no variants -use crate::utils::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_help; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/src/tools/clippy/clippy_lints/src/entry.rs b/src/tools/clippy/clippy_lints/src/entry.rs index 55575969927..25eb048448c 100644 --- a/src/tools/clippy/clippy_lints/src/entry.rs +++ b/src/tools/clippy/clippy_lints/src/entry.rs @@ -1,6 +1,8 @@ -use crate::utils::SpanlessEq; -use crate::utils::{get_item_name, is_type_diagnostic_item, match_type, paths, snippet, snippet_opt}; -use crate::utils::{snippet_with_applicability, span_lint_and_then}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability}; +use clippy_utils::ty::{is_type_diagnostic_item, match_type}; +use clippy_utils::SpanlessEq; +use clippy_utils::{get_item_name, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; diff --git a/src/tools/clippy/clippy_lints/src/enum_clike.rs b/src/tools/clippy/clippy_lints/src/enum_clike.rs index aa235642ac3..7a98ae39d3a 100644 --- a/src/tools/clippy/clippy_lints/src/enum_clike.rs +++ b/src/tools/clippy/clippy_lints/src/enum_clike.rs @@ -2,7 +2,7 @@ //! don't fit into an `i32` use crate::consts::{miri_to_const, Constant}; -use crate::utils::span_lint; +use clippy_utils::diagnostics::span_lint; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::util::IntTypeExt; diff --git a/src/tools/clippy/clippy_lints/src/enum_variants.rs b/src/tools/clippy/clippy_lints/src/enum_variants.rs index 67a46353856..0ecc0bc3eb6 100644 --- a/src/tools/clippy/clippy_lints/src/enum_variants.rs +++ b/src/tools/clippy/clippy_lints/src/enum_variants.rs @@ -1,7 +1,8 @@ //! lint on enum variants that are prefixed or suffixed by the same characters -use crate::utils::{camel_case, is_present_in_source}; -use crate::utils::{span_lint, span_lint_and_help}; +use clippy_utils::camel_case; +use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; +use clippy_utils::source::is_present_in_source; use rustc_ast::ast::{EnumDef, Item, ItemKind, VisibilityKind}; use rustc_lint::{EarlyContext, EarlyLintPass, Lint}; use rustc_session::{declare_tool_lint, impl_lint_pass}; diff --git a/src/tools/clippy/clippy_lints/src/eq_op.rs b/src/tools/clippy/clippy_lints/src/eq_op.rs index 6308f6e2e7e..6d7046ac8b7 100644 --- a/src/tools/clippy/clippy_lints/src/eq_op.rs +++ b/src/tools/clippy/clippy_lints/src/eq_op.rs @@ -1,7 +1,7 @@ -use crate::utils::{ - ast_utils::is_useless_with_eq_exprs, eq_expr_value, higher, implements_trait, in_macro, is_copy, is_expn_of, - multispan_sugg, snippet, span_lint, span_lint_and_then, -}; +use clippy_utils::diagnostics::{multispan_sugg, span_lint, span_lint_and_then}; +use clippy_utils::source::snippet; +use clippy_utils::ty::{implements_trait, is_copy}; +use clippy_utils::{ast_utils::is_useless_with_eq_exprs, eq_expr_value, higher, in_macro, is_expn_of}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, StmtKind}; diff --git a/src/tools/clippy/clippy_lints/src/erasing_op.rs b/src/tools/clippy/clippy_lints/src/erasing_op.rs index dbd1ff514f0..59602616781 100644 --- a/src/tools/clippy/clippy_lints/src/erasing_op.rs +++ b/src/tools/clippy/clippy_lints/src/erasing_op.rs @@ -1,10 +1,10 @@ +use clippy_utils::diagnostics::span_lint; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use crate::consts::{constant_simple, Constant}; -use crate::utils::span_lint; declare_clippy_lint! { /// **What it does:** Checks for erasing operations, e.g., `x * 0`. diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs index 97216757547..3581ab41906 100644 --- a/src/tools/clippy/clippy_lints/src/escape.rs +++ b/src/tools/clippy/clippy_lints/src/escape.rs @@ -1,3 +1,5 @@ +use clippy_utils::diagnostics::span_lint; +use clippy_utils::ty::contains_ty; use rustc_hir::intravisit; use rustc_hir::{self, AssocItemKind, Body, FnDecl, HirId, HirIdSet, Impl, ItemKind, Node}; use rustc_infer::infer::TyCtxtInferExt; @@ -11,8 +13,6 @@ use rustc_target::abi::LayoutOf; use rustc_target::spec::abi::Abi; use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; -use crate::utils::{contains_ty, span_lint}; - #[derive(Copy, Clone)] pub struct BoxedLocal { pub too_large_for_stack: u64, @@ -186,7 +186,7 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { } } - fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause, _: HirId) { } + fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause, _: HirId) {} } impl<'a, 'tcx> EscapeDelegate<'a, 'tcx> { diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs index c461732fd36..99253555a95 100644 --- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs +++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs @@ -1,3 +1,9 @@ +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::higher; +use clippy_utils::higher::VecArgs; +use clippy_utils::source::snippet_opt; +use clippy_utils::ty::{implements_trait, type_is_unsafe_function}; +use clippy_utils::{is_adjusted, iter_input_pats}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{def_id, Expr, ExprKind, Param, PatKind, QPath}; @@ -6,13 +12,6 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::{ - implements_trait, is_adjusted, iter_input_pats, snippet_opt, span_lint_and_sugg, span_lint_and_then, - type_is_unsafe_function, -}; -use clippy_utils::higher; -use clippy_utils::higher::VecArgs; - declare_clippy_lint! { /// **What it does:** Checks for closures which just call another function where /// the function can be called directly. `unsafe` functions or calls where types diff --git a/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs b/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs index 83cee11c3a8..ea33a4d98fd 100644 --- a/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs +++ b/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs @@ -1,4 +1,5 @@ -use crate::utils::{get_parent_expr, path_to_local, path_to_local_id, span_lint, span_lint_and_note}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_note}; +use clippy_utils::{get_parent_expr, path_to_local, path_to_local_id}; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, Guard, HirId, Local, Node, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -272,7 +273,7 @@ fn check_stmt<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, stmt: &'tcx Stmt<'_>) - .init .as_ref() .map_or(StopEarly::KeepGoing, |expr| check_expr(vis, expr)), - _ => StopEarly::KeepGoing, + StmtKind::Item(..) => StopEarly::KeepGoing, } } diff --git a/src/tools/clippy/clippy_lints/src/excessive_bools.rs b/src/tools/clippy/clippy_lints/src/excessive_bools.rs index 6f22f65deac..6c9652fd87d 100644 --- a/src/tools/clippy/clippy_lints/src/excessive_bools.rs +++ b/src/tools/clippy/clippy_lints/src/excessive_bools.rs @@ -1,7 +1,6 @@ -use crate::utils::{attr_by_name, in_macro, match_path_ast, span_lint_and_help}; -use rustc_ast::ast::{ - AssocItemKind, Extern, FnKind, FnSig, ImplKind, Item, ItemKind, TraitKind, Ty, TyKind, -}; +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::{attr_by_name, in_macro, match_path_ast}; +use rustc_ast::ast::{AssocItemKind, Extern, FnKind, FnSig, ImplKind, Item, ItemKind, TraitKind, Ty, TyKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::Span; diff --git a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs index 316f7484862..60ad2e8ee14 100644 --- a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs +++ b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs @@ -1,4 +1,5 @@ -use crate::utils::{indent_of, span_lint_and_then}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::indent_of; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind}; diff --git a/src/tools/clippy/clippy_lints/src/exit.rs b/src/tools/clippy/clippy_lints/src/exit.rs index 91585927000..635b6d83eab 100644 --- a/src/tools/clippy/clippy_lints/src/exit.rs +++ b/src/tools/clippy/clippy_lints/src/exit.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_entrypoint_fn, match_def_path, paths, span_lint}; +use clippy_utils::diagnostics::span_lint; +use clippy_utils::{is_entrypoint_fn, match_def_path, paths}; use if_chain::if_chain; use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/explicit_write.rs b/src/tools/clippy/clippy_lints/src/explicit_write.rs index f8038d06e50..4146b7baa10 100644 --- a/src/tools/clippy/clippy_lints/src/explicit_write.rs +++ b/src/tools/clippy/clippy_lints/src/explicit_write.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_expn_of, match_function_call, paths, span_lint, span_lint_and_sugg}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; +use clippy_utils::{is_expn_of, match_function_call, paths}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; diff --git a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs index f466dddc13c..52a5a7acf0d 100644 --- a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs +++ b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs @@ -1,4 +1,6 @@ -use crate::utils::{is_expn_of, is_type_diagnostic_item, match_panic_def_id, method_chain_args, span_lint_and_then}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{is_expn_of, match_panic_def_id, method_chain_args}; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/float_equality_without_abs.rs b/src/tools/clippy/clippy_lints/src/float_equality_without_abs.rs index c1c08597ee6..0c59db360f9 100644 --- a/src/tools/clippy/clippy_lints/src/float_equality_without_abs.rs +++ b/src/tools/clippy/clippy_lints/src/float_equality_without_abs.rs @@ -1,4 +1,5 @@ -use crate::utils::{match_def_path, paths, span_lint_and_then, sugg}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::{match_def_path, paths, sugg}; use if_chain::if_chain; use rustc_ast::util::parser::AssocOp; use rustc_errors::Applicability; diff --git a/src/tools/clippy/clippy_lints/src/float_literal.rs b/src/tools/clippy/clippy_lints/src/float_literal.rs index 8e256f34684..1ca5c685a75 100644 --- a/src/tools/clippy/clippy_lints/src/float_literal.rs +++ b/src/tools/clippy/clippy_lints/src/float_literal.rs @@ -1,4 +1,5 @@ -use crate::utils::{numeric_literal, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::numeric_literal; use if_chain::if_chain; use rustc_ast::ast::{self, LitFloatType, LitKind}; use rustc_errors::Applicability; diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs index 086a791520f..0b5f0379ce6 100644 --- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs @@ -2,7 +2,8 @@ use crate::consts::{ constant, constant_simple, Constant, Constant::{Int, F32, F64}, }; -use crate::utils::{eq_expr_value, get_parent_expr, numeric_literal, span_lint_and_sugg, sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::{eq_expr_value, get_parent_expr, numeric_literal, sugg}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, UnOp}; diff --git a/src/tools/clippy/clippy_lints/src/format.rs b/src/tools/clippy/clippy_lints/src/format.rs index fd6bf19db94..a33f987b423 100644 --- a/src/tools/clippy/clippy_lints/src/format.rs +++ b/src/tools/clippy/clippy_lints/src/format.rs @@ -1,8 +1,8 @@ -use crate::utils::paths; -use crate::utils::{ - is_expn_of, is_type_diagnostic_item, last_path_segment, match_def_path, match_function_call, snippet, snippet_opt, - span_lint_and_then, -}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::paths; +use clippy_utils::source::{snippet, snippet_opt}; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{is_expn_of, last_path_segment, match_def_path, match_function_call}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; diff --git a/src/tools/clippy/clippy_lints/src/formatting.rs b/src/tools/clippy/clippy_lints/src/formatting.rs index 1bd16e6cce5..b10e83c0ea8 100644 --- a/src/tools/clippy/clippy_lints/src/formatting.rs +++ b/src/tools/clippy/clippy_lints/src/formatting.rs @@ -1,4 +1,6 @@ -use crate::utils::{differing_macro_contexts, snippet_opt, span_lint_and_help, span_lint_and_note}; +use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note}; +use clippy_utils::differing_macro_contexts; +use clippy_utils::source::snippet_opt; use if_chain::if_chain; use rustc_ast::ast::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp}; use rustc_lint::{EarlyContext, EarlyLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/from_over_into.rs b/src/tools/clippy/clippy_lints/src/from_over_into.rs index b644bb07990..e5ec245e502 100644 --- a/src/tools/clippy/clippy_lints/src/from_over_into.rs +++ b/src/tools/clippy/clippy_lints/src/from_over_into.rs @@ -1,5 +1,6 @@ -use crate::utils::paths::INTO; -use crate::utils::{match_def_path, meets_msrv, span_lint_and_help}; +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::paths::INTO; +use clippy_utils::{match_def_path, meets_msrv}; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass, LintContext}; diff --git a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs index 0933f983014..3da5bc95b6d 100644 --- a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs +++ b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs @@ -1,3 +1,6 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::sugg::Sugg; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{def, Expr, ExprKind, PrimTy, QPath, TyKind}; @@ -6,10 +9,6 @@ use rustc_middle::ty::Ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::sym; -use crate::utils::is_type_diagnostic_item; -use crate::utils::span_lint_and_sugg; -use crate::utils::sugg::Sugg; - declare_clippy_lint! { /// **What it does:** /// Checks for function invocations of the form `primitive::from_str_radix(s, 10)` diff --git a/src/tools/clippy/clippy_lints/src/functions.rs b/src/tools/clippy/clippy_lints/src/functions.rs index c474db06fe3..5fe46065348 100644 --- a/src/tools/clippy/clippy_lints/src/functions.rs +++ b/src/tools/clippy/clippy_lints/src/functions.rs @@ -1,7 +1,9 @@ -use crate::utils::{ - attr_by_name, attrs::is_proc_macro, is_must_use_ty, is_trait_impl_item, is_type_diagnostic_item, iter_input_pats, - match_def_path, must_use_attr, path_to_local, return_ty, snippet, snippet_opt, span_lint, span_lint_and_help, - span_lint_and_then, trait_ref_of_method, type_is_unsafe_function, +use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_then}; +use clippy_utils::source::{snippet, snippet_opt}; +use clippy_utils::ty::{is_must_use_ty, is_type_diagnostic_item, type_is_unsafe_function}; +use clippy_utils::{ + attr_by_name, attrs::is_proc_macro, is_trait_impl_item, iter_input_pats, match_def_path, must_use_attr, + path_to_local, return_ty, trait_ref_of_method, }; use if_chain::if_chain; use rustc_ast::ast::Attribute; @@ -514,7 +516,7 @@ fn check_needless_must_use( ); }, ); - } else if !attr.is_value_str() && is_must_use_ty(cx, return_ty(cx, item_id)) { + } else if !attr.value_str().is_some() && is_must_use_ty(cx, return_ty(cx, item_id)) { span_lint_and_help( cx, DOUBLE_MUST_USE, diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs index 9e1a8864a3e..04730ace887 100644 --- a/src/tools/clippy/clippy_lints/src/future_not_send.rs +++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs @@ -1,4 +1,5 @@ -use crate::utils; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::return_ty; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl, HirId}; use rustc_infer::infer::TyCtxtInferExt; @@ -61,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { if let FnKind::Closure = kind { return; } - let ret_ty = utils::return_ty(cx, hir_id); + let ret_ty = return_ty(cx, hir_id); if let Opaque(id, subst) = *ret_ty.kind() { let preds = cx.tcx.explicit_item_bounds(id); let mut is_future = false; @@ -84,7 +85,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { fulfillment_cx.select_all_or_error(&infcx) }); if let Err(send_errors) = send_result { - utils::span_lint_and_then( + span_lint_and_then( cx, FUTURE_NOT_SEND, span, diff --git a/src/tools/clippy/clippy_lints/src/get_last_with_len.rs b/src/tools/clippy/clippy_lints/src/get_last_with_len.rs index cdd8a42e7cd..cbcef567c53 100644 --- a/src/tools/clippy/clippy_lints/src/get_last_with_len.rs +++ b/src/tools/clippy/clippy_lints/src/get_last_with_len.rs @@ -1,6 +1,9 @@ //! lint on using `x.get(x.len() - 1)` instead of `x.last()` -use crate::utils::{is_type_diagnostic_item, snippet_with_applicability, span_lint_and_sugg, SpanlessEq}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::SpanlessEq; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; diff --git a/src/tools/clippy/clippy_lints/src/identity_op.rs b/src/tools/clippy/clippy_lints/src/identity_op.rs index 8501d347702..8bed5e1bf64 100644 --- a/src/tools/clippy/clippy_lints/src/identity_op.rs +++ b/src/tools/clippy/clippy_lints/src/identity_op.rs @@ -1,3 +1,4 @@ +use clippy_utils::source::snippet; use if_chain::if_chain; use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -6,7 +7,8 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use crate::consts::{constant_simple, Constant}; -use crate::utils::{clip, snippet, span_lint, unsext}; +use clippy_utils::diagnostics::span_lint; +use clippy_utils::{clip, unsext}; declare_clippy_lint! { /// **What it does:** Checks for identity operations, e.g., `x + 0`. diff --git a/src/tools/clippy/clippy_lints/src/if_let_mutex.rs b/src/tools/clippy/clippy_lints/src/if_let_mutex.rs index 58511c6d57c..4aab43256bf 100644 --- a/src/tools/clippy/clippy_lints/src/if_let_mutex.rs +++ b/src/tools/clippy/clippy_lints/src/if_let_mutex.rs @@ -1,4 +1,6 @@ -use crate::utils::{is_type_diagnostic_item, span_lint_and_help, SpanlessEq}; +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::SpanlessEq; use if_chain::if_chain; use rustc_hir::intravisit::{self as visit, NestedVisitorMap, Visitor}; use rustc_hir::{Expr, ExprKind, MatchSource}; diff --git a/src/tools/clippy/clippy_lints/src/if_let_some_result.rs b/src/tools/clippy/clippy_lints/src/if_let_some_result.rs index 1194bd7e55e..6e9280c8c7e 100644 --- a/src/tools/clippy/clippy_lints/src/if_let_some_result.rs +++ b/src/tools/clippy/clippy_lints/src/if_let_some_result.rs @@ -1,4 +1,7 @@ -use crate::utils::{is_type_diagnostic_item, method_chain_args, snippet_with_applicability, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::method_chain_args; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, MatchSource, PatKind, QPath}; diff --git a/src/tools/clippy/clippy_lints/src/if_not_else.rs b/src/tools/clippy/clippy_lints/src/if_not_else.rs index b86d2e76656..c56f67df061 100644 --- a/src/tools/clippy/clippy_lints/src/if_not_else.rs +++ b/src/tools/clippy/clippy_lints/src/if_not_else.rs @@ -1,13 +1,12 @@ //! lint on if branches that could be swapped so no `!` operation is necessary //! on the condition +use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::span_lint_and_help; - declare_clippy_lint! { /// **What it does:** Checks for usage of `!` or `!=` in an if condition with an /// else branch. diff --git a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs new file mode 100644 index 00000000000..0b5bf060d4c --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs @@ -0,0 +1,117 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::source::snippet_with_macro_callsite; +use clippy_utils::{match_qpath, meets_msrv, parent_node_is_if_expr}; +use if_chain::if_chain; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; +use rustc_semver::RustcVersion; +use rustc_session::{declare_tool_lint, impl_lint_pass}; + +const IF_THEN_SOME_ELSE_NONE_MSRV: RustcVersion = RustcVersion::new(1, 50, 0); + +declare_clippy_lint! { + /// **What it does:** Checks for if-else that could be written to `bool::then`. + /// + /// **Why is this bad?** Looks a little redundant. Using `bool::then` helps it have less lines of code. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// # let v = vec![0]; + /// let a = if v.is_empty() { + /// println!("true!"); + /// Some(42) + /// } else { + /// None + /// }; + /// ``` + /// + /// Could be written: + /// + /// ```rust + /// # let v = vec![0]; + /// let a = v.is_empty().then(|| { + /// println!("true!"); + /// 42 + /// }); + /// ``` + pub IF_THEN_SOME_ELSE_NONE, + restriction, + "Finds if-else that could be written using `bool::then`" +} + +pub struct IfThenSomeElseNone { + msrv: Option<RustcVersion>, +} + +impl IfThenSomeElseNone { + #[must_use] + pub fn new(msrv: Option<RustcVersion>) -> Self { + Self { msrv } + } +} + +impl_lint_pass!(IfThenSomeElseNone => [IF_THEN_SOME_ELSE_NONE]); + +impl LateLintPass<'_> for IfThenSomeElseNone { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'tcx Expr<'_>) { + if !meets_msrv(self.msrv.as_ref(), &IF_THEN_SOME_ELSE_NONE_MSRV) { + return; + } + + if in_external_macro(cx.sess(), expr.span) { + return; + } + + // We only care about the top-most `if` in the chain + if parent_node_is_if_expr(expr, cx) { + return; + } + + if_chain! { + if let ExprKind::If(ref cond, ref then, Some(ref els)) = expr.kind; + if let ExprKind::Block(ref then_block, _) = then.kind; + if let Some(ref then_expr) = then_block.expr; + if let ExprKind::Call(ref then_call, [then_arg]) = then_expr.kind; + if let ExprKind::Path(ref then_call_qpath) = then_call.kind; + if match_qpath(then_call_qpath, &clippy_utils::paths::OPTION_SOME); + if let ExprKind::Block(ref els_block, _) = els.kind; + if els_block.stmts.is_empty(); + if let Some(ref els_expr) = els_block.expr; + if let ExprKind::Path(ref els_call_qpath) = els_expr.kind; + if match_qpath(els_call_qpath, &clippy_utils::paths::OPTION_NONE); + then { + let cond_snip = snippet_with_macro_callsite(cx, cond.span, "[condition]"); + let cond_snip = if matches!(cond.kind, ExprKind::Unary(_, _) | ExprKind::Binary(_, _, _)) { + format!("({})", cond_snip) + } else { + cond_snip.into_owned() + }; + let arg_snip = snippet_with_macro_callsite(cx, then_arg.span, ""); + let closure_body = if then_block.stmts.is_empty() { + arg_snip.into_owned() + } else { + format!("{{ /* snippet */ {} }}", arg_snip) + }; + let help = format!( + "consider using `bool::then` like: `{}.then(|| {})`", + cond_snip, + closure_body, + ); + span_lint_and_help( + cx, + IF_THEN_SOME_ELSE_NONE, + expr.span, + "this could be simplified with `bool::then`", + None, + &help, + ); + } + } + } + + extract_msrv_attr!(LateContext); +} diff --git a/src/tools/clippy/clippy_lints/src/implicit_return.rs b/src/tools/clippy/clippy_lints/src/implicit_return.rs index b4f814e1dcc..6863645a92d 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_return.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_return.rs @@ -1,4 +1,6 @@ -use crate::utils::{match_panic_def_id, snippet_opt, span_lint_and_then}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::match_panic_def_id; +use clippy_utils::source::snippet_opt; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; diff --git a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs index 16e162badb5..5207c628987 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs @@ -1,4 +1,5 @@ -use crate::utils::{in_macro, match_qpath, span_lint_and_sugg, SpanlessEq}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::{in_macro, match_qpath, SpanlessEq}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; diff --git a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs index 48aef74e4d3..d7ca24487a8 100644 --- a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs +++ b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs @@ -1,3 +1,6 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet; +use if_chain::if_chain; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; use rustc_hir::{self as hir, ExprKind}; @@ -5,13 +8,10 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::Symbol; -use if_chain::if_chain; - -use crate::utils::{snippet, span_lint_and_sugg}; - declare_clippy_lint! { - /// **What it does:** Checks for struct constructors where the order of the field init - /// shorthand in the constructor is inconsistent with the order in the struct definition. + /// **What it does:** Checks for struct constructors where all fields are shorthand and + /// the order of the field init shorthand in the constructor is inconsistent + /// with the order in the struct definition. /// /// **Why is this bad?** Since the order of fields in a constructor doesn't affect the /// resulted instance as the below example indicates, @@ -25,11 +25,11 @@ declare_clippy_lint! { /// let x = 1; /// let y = 2; /// - /// // This assertion never fails. + /// // This assertion never fails: /// assert_eq!(Foo { x, y }, Foo { y, x }); /// ``` /// - /// inconsistent order means nothing and just decreases readability and consistency. + /// inconsistent order can be confusing and decreases readability and consistency. /// /// **Known problems:** None. /// @@ -42,6 +42,7 @@ declare_clippy_lint! { /// } /// let x = 1; /// let y = 2; + /// /// Foo { y, x }; /// ``` /// @@ -107,7 +108,7 @@ impl LateLintPass<'_> for InconsistentStructConstructor { cx, INCONSISTENT_STRUCT_CONSTRUCTOR, expr.span, - "inconsistent struct constructor", + "struct constructor field order is inconsistent with struct definition field order", "try", sugg, Applicability::MachineApplicable, diff --git a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs index c919ec097a2..94d39019608 100644 --- a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs +++ b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs @@ -1,7 +1,8 @@ //! lint on indexing and slicing operations use crate::consts::{constant, Constant}; -use crate::utils::{higher, span_lint, span_lint_and_help}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; +use clippy_utils::higher; use rustc_ast::ast::RangeLimits; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/infinite_iter.rs b/src/tools/clippy/clippy_lints/src/infinite_iter.rs index 7040ac3191f..fb35bc1e780 100644 --- a/src/tools/clippy/clippy_lints/src/infinite_iter.rs +++ b/src/tools/clippy/clippy_lints/src/infinite_iter.rs @@ -1,9 +1,10 @@ +use clippy_utils::diagnostics::span_lint; +use clippy_utils::ty::{implements_trait, match_type}; +use clippy_utils::{get_trait_def_id, higher, match_qpath, paths}; use rustc_hir::{BorrowKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::{get_trait_def_id, higher, implements_trait, match_qpath, match_type, paths, span_lint}; - declare_clippy_lint! { /// **What it does:** Checks for iteration that is guaranteed to be infinite. /// diff --git a/src/tools/clippy/clippy_lints/src/inherent_impl.rs b/src/tools/clippy/clippy_lints/src/inherent_impl.rs index 005c461f105..5b2e70e3ce9 100644 --- a/src/tools/clippy/clippy_lints/src/inherent_impl.rs +++ b/src/tools/clippy/clippy_lints/src/inherent_impl.rs @@ -1,6 +1,7 @@ //! lint on inherent implementations -use crate::utils::{in_macro, span_lint_and_then}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::in_macro; use rustc_data_structures::fx::FxHashMap; use rustc_hir::{def_id, Crate, Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs index c1f3e1d9d68..b023e13e846 100644 --- a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs +++ b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs @@ -1,14 +1,12 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; +use clippy_utils::{get_trait_def_id, paths, return_ty, trait_ref_of_method}; use if_chain::if_chain; use rustc_hir::{ImplItem, ImplItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; -use crate::utils::{ - get_trait_def_id, implements_trait, is_type_diagnostic_item, paths, return_ty, span_lint_and_help, - trait_ref_of_method, -}; - declare_clippy_lint! { /// **What it does:** Checks for the definition of inherent methods with a signature of `to_string(&self) -> String`. /// diff --git a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs index 00acbd6cc3f..20f00bd51ba 100644 --- a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs +++ b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs @@ -1,7 +1,7 @@ //! checks for `#[inline]` on trait methods without bodies -use crate::utils::span_lint_and_then; -use crate::utils::sugg::DiagnosticBuilderExt; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::sugg::DiagnosticBuilderExt; use rustc_ast::ast::Attribute; use rustc_errors::Applicability; use rustc_hir::{TraitFn, TraitItem, TraitItemKind}; diff --git a/src/tools/clippy/clippy_lints/src/int_plus_one.rs b/src/tools/clippy/clippy_lints/src/int_plus_one.rs index 260b8988d37..c4a1222b51f 100644 --- a/src/tools/clippy/clippy_lints/src/int_plus_one.rs +++ b/src/tools/clippy/clippy_lints/src/int_plus_one.rs @@ -1,12 +1,12 @@ //! lint on blocks unnecessarily using >= with a + 1 or - 1 +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_opt; use rustc_ast::ast::{BinOpKind, Expr, ExprKind, Lit, LitKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::{snippet_opt, span_lint_and_sugg}; - declare_clippy_lint! { /// **What it does:** Checks for usage of `x >= y + 1` or `x - 1 >= y` (and `<=`) in a block /// diff --git a/src/tools/clippy/clippy_lints/src/integer_division.rs b/src/tools/clippy/clippy_lints/src/integer_division.rs index 39b4605e72f..e5482f675e7 100644 --- a/src/tools/clippy/clippy_lints/src/integer_division.rs +++ b/src/tools/clippy/clippy_lints/src/integer_division.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_help; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/items_after_statements.rs b/src/tools/clippy/clippy_lints/src/items_after_statements.rs index 0927d218446..c69571f32a2 100644 --- a/src/tools/clippy/clippy_lints/src/items_after_statements.rs +++ b/src/tools/clippy/clippy_lints/src/items_after_statements.rs @@ -1,6 +1,6 @@ //! lint when items are used after statements -use crate::utils::span_lint; +use clippy_utils::diagnostics::span_lint; use rustc_ast::ast::{Block, ItemKind, StmtKind}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; diff --git a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs index a76595ed089..48dc5fefe99 100644 --- a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs +++ b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs @@ -1,5 +1,5 @@ use crate::rustc_target::abi::LayoutOf; -use crate::utils::span_lint_and_then; +use clippy_utils::diagnostics::span_lint_and_then; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind}; diff --git a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs index ab4cb33612d..76584dc1822 100644 --- a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs +++ b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs @@ -1,6 +1,7 @@ //! lint when there is a large size difference between variants on an enum -use crate::utils::{snippet_opt, span_lint_and_then}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::snippet_opt; use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind, VariantData}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs index 9a448ab1256..c46b98022c6 100644 --- a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs +++ b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs @@ -1,13 +1,13 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::source::snippet; +use if_chain::if_chain; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::interpret::ConstValue; use rustc_middle::ty::{self, ConstKind}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use if_chain::if_chain; - use crate::rustc_target::abi::LayoutOf; -use crate::utils::{snippet, span_lint_and_help}; declare_clippy_lint! { /// **What it does:** Checks for local arrays that may be too large. diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index 1e1023b2743..717f2ea84f4 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -1,7 +1,6 @@ -use crate::utils::{ - get_item_name, get_parent_as_impl, is_allowed, snippet_with_applicability, span_lint, span_lint_and_sugg, - span_lint_and_then, -}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::{get_item_name, get_parent_as_impl, is_allowed}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_data_structures::fx::FxHashSet; diff --git a/src/tools/clippy/clippy_lints/src/let_if_seq.rs b/src/tools/clippy/clippy_lints/src/let_if_seq.rs index 5863eef8a26..2d7d9c9befb 100644 --- a/src/tools/clippy/clippy_lints/src/let_if_seq.rs +++ b/src/tools/clippy/clippy_lints/src/let_if_seq.rs @@ -1,4 +1,6 @@ -use crate::utils::{path_to_local_id, snippet, span_lint_and_then, visitors::LocalUsedVisitor}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::snippet; +use clippy_utils::{path_to_local_id, visitors::LocalUsedVisitor}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs index 7e96dfcc7da..7e3a76ded2c 100644 --- a/src/tools/clippy/clippy_lints/src/let_underscore.rs +++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs @@ -1,3 +1,6 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::ty::{is_must_use_ty, match_type}; +use clippy_utils::{is_must_use_func_call, paths}; use if_chain::if_chain; use rustc_hir::{Local, PatKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -5,8 +8,6 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::ty::subst::GenericArgKind; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::{is_must_use_func_call, is_must_use_ty, match_type, paths, span_lint_and_help}; - declare_clippy_lint! { /// **What it does:** Checks for `let _ = <expr>` /// where expr is #[must_use] diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index b4c450bda5c..a99ed7656bf 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -4,6 +4,7 @@ #![feature(box_syntax)] #![feature(drain_filter)] #![feature(in_band_lifetimes)] +#![feature(iter_zip)] #![feature(once_cell)] #![cfg_attr(bootstrap, feature(or_patterns))] #![feature(rustc_private)] @@ -42,7 +43,7 @@ extern crate rustc_target; extern crate rustc_trait_selection; extern crate rustc_typeck; -use crate::utils::parse_msrv; +use clippy_utils::parse_msrv; use rustc_data_structures::fx::FxHashSet; use rustc_lint::LintId; use rustc_session::Session; @@ -231,6 +232,7 @@ mod identity_op; mod if_let_mutex; mod if_let_some_result; mod if_not_else; +mod if_then_some_else_none; mod implicit_return; mod implicit_saturating_sub; mod inconsistent_struct_constructor; @@ -349,6 +351,7 @@ mod types; mod undropped_manually_drops; mod unicode; mod unit_return_expecting_ord; +mod unit_types; mod unnamed_address; mod unnecessary_sort_by; mod unnecessary_wraps; @@ -680,6 +683,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &if_let_mutex::IF_LET_MUTEX, &if_let_some_result::IF_LET_SOME_RESULT, &if_not_else::IF_NOT_ELSE, + &if_then_some_else_none::IF_THEN_SOME_ELSE_NONE, &implicit_return::IMPLICIT_RETURN, &implicit_saturating_sub::IMPLICIT_SATURATING_SUB, &inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR, @@ -958,20 +962,20 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &types::BOX_VEC, &types::IMPLICIT_HASHER, &types::INVALID_UPCAST_COMPARISONS, - &types::LET_UNIT_VALUE, &types::LINKEDLIST, &types::OPTION_OPTION, &types::RC_BUFFER, &types::REDUNDANT_ALLOCATION, &types::TYPE_COMPLEXITY, - &types::UNIT_ARG, - &types::UNIT_CMP, &types::VEC_BOX, &undropped_manually_drops::UNDROPPED_MANUALLY_DROPS, &unicode::INVISIBLE_CHARACTERS, &unicode::NON_ASCII_LITERAL, &unicode::UNICODE_NOT_NFC, &unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD, + &unit_types::LET_UNIT_VALUE, + &unit_types::UNIT_ARG, + &unit_types::UNIT_CMP, &unnamed_address::FN_ADDRESS_COMPARISONS, &unnamed_address::VTABLE_ADDRESS_COMPARISONS, &unnecessary_sort_by::UNNECESSARY_SORT_BY, @@ -1082,8 +1086,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box map_clone::MapClone); store.register_late_pass(|| box map_err_ignore::MapErrIgnore); store.register_late_pass(|| box shadow::Shadow); - store.register_late_pass(|| box types::LetUnitValue); - store.register_late_pass(|| box types::UnitCmp); + store.register_late_pass(|| box unit_types::UnitTypes); store.register_late_pass(|| box loops::Loops); store.register_late_pass(|| box main_recursion::MainRecursion::default()); store.register_late_pass(|| box lifetimes::Lifetimes); @@ -1158,7 +1161,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box useless_conversion::UselessConversion::default()); store.register_late_pass(|| box types::ImplicitHasher); store.register_late_pass(|| box fallible_impl_from::FallibleImplFrom); - store.register_late_pass(|| box types::UnitArg); store.register_late_pass(|| box double_comparison::DoubleComparisons); store.register_late_pass(|| box question_mark::QuestionMark); store.register_early_pass(|| box suspicious_operation_groupings::SuspiciousOperationGroupings); @@ -1241,7 +1243,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box verbose_file_reads::VerboseFileReads); store.register_late_pass(|| box redundant_pub_crate::RedundantPubCrate::default()); store.register_late_pass(|| box unnamed_address::UnnamedAddress); - store.register_late_pass(|| box dereference::Dereferencing); + store.register_late_pass(|| box dereference::Dereferencing::default()); store.register_late_pass(|| box option_if_let_else::OptionIfLetElse); store.register_late_pass(|| box future_not_send::FutureNotSend); store.register_late_pass(|| box if_let_mutex::IfLetMutex); @@ -1280,6 +1282,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box redundant_slicing::RedundantSlicing); store.register_late_pass(|| box from_str_radix_10::FromStrRadix10); store.register_late_pass(|| box manual_map::ManualMap); + store.register_late_pass(move || box if_then_some_else_none::IfThenSomeElseNone::new(msrv)); store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(&arithmetic::FLOAT_ARITHMETIC), @@ -1295,6 +1298,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&exhaustive_items::EXHAUSTIVE_STRUCTS), LintId::of(&exit::EXIT), LintId::of(&float_literal::LOSSY_FLOAT_LITERAL), + LintId::of(&if_then_some_else_none::IF_THEN_SOME_ELSE_NONE), LintId::of(&implicit_return::IMPLICIT_RETURN), LintId::of(&indexing_slicing::INDEXING_SLICING), LintId::of(&inherent_impl::MULTIPLE_INHERENT_IMPL), @@ -1411,11 +1415,11 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&trait_bounds::TYPE_REPETITION_IN_BOUNDS), LintId::of(&types::IMPLICIT_HASHER), LintId::of(&types::INVALID_UPCAST_COMPARISONS), - LintId::of(&types::LET_UNIT_VALUE), LintId::of(&types::LINKEDLIST), LintId::of(&types::OPTION_OPTION), LintId::of(&unicode::NON_ASCII_LITERAL), LintId::of(&unicode::UNICODE_NOT_NFC), + LintId::of(&unit_types::LET_UNIT_VALUE), LintId::of(&unnecessary_wraps::UNNECESSARY_WRAPS), LintId::of(&unnested_or_patterns::UNNESTED_OR_PATTERNS), LintId::of(&unused_self::UNUSED_SELF), @@ -1704,12 +1708,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&types::BOX_VEC), LintId::of(&types::REDUNDANT_ALLOCATION), LintId::of(&types::TYPE_COMPLEXITY), - LintId::of(&types::UNIT_ARG), - LintId::of(&types::UNIT_CMP), LintId::of(&types::VEC_BOX), LintId::of(&undropped_manually_drops::UNDROPPED_MANUALLY_DROPS), LintId::of(&unicode::INVISIBLE_CHARACTERS), LintId::of(&unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD), + LintId::of(&unit_types::UNIT_ARG), + LintId::of(&unit_types::UNIT_CMP), LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS), LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS), LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY), @@ -1930,8 +1934,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&transmute::TRANSMUTE_PTR_TO_REF), LintId::of(&types::BORROWED_BOX), LintId::of(&types::TYPE_COMPLEXITY), - LintId::of(&types::UNIT_ARG), LintId::of(&types::VEC_BOX), + LintId::of(&unit_types::UNIT_ARG), LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY), LintId::of(&unwrap::UNNECESSARY_UNWRAP), LintId::of(&useless_conversion::USELESS_CONVERSION), @@ -2001,10 +2005,10 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&transmute::WRONG_TRANSMUTE), LintId::of(&transmuting_null::TRANSMUTING_NULL), LintId::of(&types::ABSURD_EXTREME_COMPARISONS), - LintId::of(&types::UNIT_CMP), LintId::of(&undropped_manually_drops::UNDROPPED_MANUALLY_DROPS), LintId::of(&unicode::INVISIBLE_CHARACTERS), LintId::of(&unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD), + LintId::of(&unit_types::UNIT_CMP), LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS), LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS), LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT), diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs index 3ac6e6cbbef..e3b3fa21cab 100644 --- a/src/tools/clippy/clippy_lints/src/lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs @@ -1,4 +1,5 @@ -use crate::utils::{in_macro, span_lint, trait_ref_of_method}; +use clippy_utils::diagnostics::span_lint; +use clippy_utils::{in_macro, trait_ref_of_method}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::intravisit::{ walk_fn_decl, walk_generic_param, walk_generics, walk_item, walk_param_bound, walk_poly_trait_ref, walk_ty, diff --git a/src/tools/clippy/clippy_lints/src/literal_representation.rs b/src/tools/clippy/clippy_lints/src/literal_representation.rs index 87a957a9bd2..54470519260 100644 --- a/src/tools/clippy/clippy_lints/src/literal_representation.rs +++ b/src/tools/clippy/clippy_lints/src/literal_representation.rs @@ -1,10 +1,11 @@ //! Lints concerned with the grouping of digits with underscores in integral or //! floating-point literal expressions. -use crate::utils::{ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_opt; +use clippy_utils::{ in_macro, numeric_literal::{NumericLiteral, Radix}, - snippet_opt, span_lint_and_sugg, }; use if_chain::if_chain; use rustc_ast::ast::{Expr, ExprKind, Lit, LitKind}; @@ -12,6 +13,7 @@ use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_tool_lint, impl_lint_pass}; +use std::iter; declare_clippy_lint! { /// **What it does:** Warns if a long integral or floating-point constant does @@ -348,7 +350,7 @@ impl LiteralDigitGrouping { let group_sizes: Vec<usize> = num_lit.integer.split('_').map(str::len).collect(); if UUID_GROUP_LENS.len() == group_sizes.len() { - UUID_GROUP_LENS.iter().zip(&group_sizes).all(|(&a, &b)| a == b) + iter::zip(&UUID_GROUP_LENS, &group_sizes).all(|(&a, &b)| a == b) } else { false } diff --git a/src/tools/clippy/clippy_lints/src/loops/empty_loop.rs b/src/tools/clippy/clippy_lints/src/loops/empty_loop.rs index 43e85538f28..dda09fecdf9 100644 --- a/src/tools/clippy/clippy_lints/src/loops/empty_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/empty_loop.rs @@ -1,5 +1,6 @@ use super::EMPTY_LOOP; -use crate::utils::{is_in_panic_handler, is_no_std_crate, span_lint_and_help}; +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::{is_in_panic_handler, is_no_std_crate}; use rustc_hir::{Block, Expr}; use rustc_lint::LateContext; diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs index 8d98b940c66..f14dbb1d642 100644 --- a/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs @@ -1,7 +1,9 @@ use super::{ get_span_of_entire_for_loop, make_iterator_snippet, IncrementVisitor, InitializeVisitor, EXPLICIT_COUNTER_LOOP, }; -use crate::utils::{get_enclosing_block, is_integer_const, snippet_with_applicability, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::{get_enclosing_block, is_integer_const}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_block, walk_expr}; diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_into_iter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_into_iter_loop.rs index 1d778205a2a..4871a031187 100644 --- a/src/tools/clippy/clippy_lints/src/loops/explicit_into_iter_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/explicit_into_iter_loop.rs @@ -1,5 +1,6 @@ use super::EXPLICIT_INTO_ITER_LOOP; -use crate::utils::{snippet_with_applicability, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs index 9683e59a396..92aa2beb66d 100644 --- a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs @@ -1,13 +1,14 @@ use super::EXPLICIT_ITER_LOOP; -use crate::utils::{match_trait_method, snippet_with_applicability, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::{is_type_diagnostic_item, match_type}; +use clippy_utils::{match_trait_method, paths}; use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability}; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty, TyS}; use rustc_span::sym; -use crate::utils::{is_type_diagnostic_item, match_type, paths}; - pub(super) fn check(cx: &LateContext<'_>, args: &[Expr<'_>], arg: &Expr<'_>, method_name: &str) { let should_lint = match method_name { "iter" | "iter_mut" => is_ref_iterable_type(cx, &args[0]), diff --git a/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs b/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs index 6ee9b95a3b6..8f18f54119b 100644 --- a/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs +++ b/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs @@ -1,6 +1,9 @@ use super::FOR_KV_MAP; -use crate::utils::visitors::LocalUsedVisitor; -use crate::utils::{is_type_diagnostic_item, match_type, multispan_sugg, paths, snippet, span_lint_and_then, sugg}; +use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; +use clippy_utils::source::snippet; +use clippy_utils::ty::{is_type_diagnostic_item, match_type}; +use clippy_utils::visitors::LocalUsedVisitor; +use clippy_utils::{paths, sugg}; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty; diff --git a/src/tools/clippy/clippy_lints/src/loops/for_loops_over_fallibles.rs b/src/tools/clippy/clippy_lints/src/loops/for_loops_over_fallibles.rs index db22d90a304..d49b0517dcf 100644 --- a/src/tools/clippy/clippy_lints/src/loops/for_loops_over_fallibles.rs +++ b/src/tools/clippy/clippy_lints/src/loops/for_loops_over_fallibles.rs @@ -1,5 +1,7 @@ use super::FOR_LOOPS_OVER_FALLIBLES; -use crate::utils::{is_type_diagnostic_item, snippet, span_lint_and_help}; +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::source::snippet; +use clippy_utils::ty::is_type_diagnostic_item; use rustc_hir::{Expr, Pat}; use rustc_lint::LateContext; use rustc_span::symbol::sym; diff --git a/src/tools/clippy/clippy_lints/src/loops/iter_next_loop.rs b/src/tools/clippy/clippy_lints/src/loops/iter_next_loop.rs index cf78bbc49a3..9148fbfd497 100644 --- a/src/tools/clippy/clippy_lints/src/loops/iter_next_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/iter_next_loop.rs @@ -1,10 +1,12 @@ use super::ITER_NEXT_LOOP; -use crate::utils::{match_trait_method, paths, span_lint}; +use clippy_utils::diagnostics::span_lint; +use clippy_utils::is_trait_method; use rustc_hir::Expr; use rustc_lint::LateContext; +use rustc_span::sym; pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>, expr: &Expr<'_>) -> bool { - if match_trait_method(cx, arg, &paths::ITERATOR) { + if is_trait_method(cx, arg, sym::Iterator) { span_lint( cx, ITER_NEXT_LOOP, diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs b/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs index 3d3ae6f3152..8d2b9cccba4 100644 --- a/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs +++ b/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs @@ -1,10 +1,12 @@ use super::utils::make_iterator_snippet; use super::MANUAL_FLATTEN; -use crate::utils::{is_ok_ctor, is_some_ctor, path_to_local_id, span_lint_and_then}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::{is_ok_ctor, is_some_ctor, path_to_local_id}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, MatchSource, Pat, PatKind, QPath, StmtKind}; use rustc_lint::LateContext; +use rustc_middle::ty; use rustc_span::source_map::Span; /// Check for unnecessary `if let` usage in a for loop where only the `Some` or `Ok` variant of the @@ -53,6 +55,13 @@ pub(super) fn check<'tcx>( // Prepare the help message let mut applicability = Applicability::MaybeIncorrect; let arg_snippet = make_iterator_snippet(cx, arg, &mut applicability); + let copied = match cx.typeck_results().expr_ty(match_expr).kind() { + ty::Ref(_, inner, _) => match inner.kind() { + ty::Ref(..) => ".copied()", + _ => "" + } + _ => "" + }; span_lint_and_then( cx, @@ -60,7 +69,7 @@ pub(super) fn check<'tcx>( span, &msg, |diag| { - let sugg = format!("{}.flatten()", arg_snippet); + let sugg = format!("{}{}.flatten()", arg_snippet, copied); diag.span_suggestion( arg.span, "try", diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs index 11660a8fe0d..f5758b68f60 100644 --- a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs +++ b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs @@ -1,8 +1,9 @@ use super::{get_span_of_entire_for_loop, IncrementVisitor, InitializeVisitor, MANUAL_MEMCPY}; -use crate::utils::sugg::Sugg; -use crate::utils::{ - get_enclosing_block, higher, is_type_diagnostic_item, path_to_local, snippet, span_lint_and_sugg, sugg, -}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet; +use clippy_utils::sugg::Sugg; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{get_enclosing_block, higher, path_to_local, sugg}; use if_chain::if_chain; use rustc_ast::ast; use rustc_errors::Applicability; diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs index 2a372c6307e..20291491998 100644 --- a/src/tools/clippy/clippy_lints/src/loops/mod.rs +++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs @@ -18,7 +18,7 @@ mod while_immutable_condition; mod while_let_loop; mod while_let_on_iterator; -use crate::utils::higher; +use clippy_utils::higher; use rustc_hir::{Expr, ExprKind, LoopSource, Pat}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs index cb56512db60..1425d50f560 100644 --- a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs +++ b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs @@ -1,11 +1,11 @@ use super::MUT_RANGE_BOUND; -use crate::utils::{higher, path_to_local, span_lint}; +use clippy_utils::diagnostics::span_lint; +use clippy_utils::{higher, path_to_local}; use if_chain::if_chain; use rustc_hir::{BindingAnnotation, Expr, HirId, Node, PatKind}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; -use rustc_middle::mir::FakeReadCause; -use rustc_middle::ty; +use rustc_middle::{mir::FakeReadCause, ty}; use rustc_span::source_map::Span; use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; @@ -108,7 +108,7 @@ impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> { } } - fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause, _:HirId) { } + fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause, _: HirId) {} } impl MutatePairDelegate<'_, '_> { diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs b/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs index 92560c80629..5594fc7b046 100644 --- a/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs +++ b/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs @@ -1,9 +1,9 @@ use super::NEEDLESS_COLLECT; -use crate::utils::sugg::Sugg; -use crate::utils::{ - is_type_diagnostic_item, match_trait_method, match_type, path_to_local_id, paths, snippet, span_lint_and_sugg, - span_lint_and_then, -}; +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::source::snippet; +use clippy_utils::sugg::Sugg; +use clippy_utils::ty::{is_type_diagnostic_item, match_type}; +use clippy_utils::{is_trait_method, path_to_local_id, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_block, walk_expr, NestedVisitorMap, Visitor}; @@ -23,7 +23,7 @@ fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCont if_chain! { if let ExprKind::MethodCall(ref method, _, ref args, _) = expr.kind; if let ExprKind::MethodCall(ref chain_method, _, _, _) = args[0].kind; - if chain_method.ident.name == sym!(collect) && match_trait_method(cx, &args[0], &paths::ITERATOR); + if chain_method.ident.name == sym!(collect) && is_trait_method(cx, &args[0], sym::Iterator); if let Some(ref generic_args) = chain_method.args; if let Some(GenericArg::Type(ref ty)) = generic_args.args.get(0); then { @@ -94,7 +94,7 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo init: Some(ref init_expr), .. } ) = stmt.kind; if let ExprKind::MethodCall(ref method_name, _, &[ref iter_source], ..) = init_expr.kind; - if method_name.ident.name == sym!(collect) && match_trait_method(cx, &init_expr, &paths::ITERATOR); + if method_name.ident.name == sym!(collect) && is_trait_method(cx, &init_expr, sym::Iterator); if let Some(ref generic_args) = method_name.args; if let Some(GenericArg::Type(ref ty)) = generic_args.args.get(0); if let ty = cx.typeck_results().node_type(ty.hir_id); diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs index 5f02e4b9d87..64ab3b6bfec 100644 --- a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs @@ -1,8 +1,10 @@ use super::NEEDLESS_RANGE_LOOP; -use crate::utils::visitors::LocalUsedVisitor; -use crate::utils::{ - contains_name, has_iter_method, higher, is_integer_const, match_trait_method, multispan_sugg, path_to_local_id, - paths, snippet, span_lint_and_then, sugg, SpanlessEq, +use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; +use clippy_utils::source::snippet; +use clippy_utils::ty::has_iter_method; +use clippy_utils::visitors::LocalUsedVisitor; +use clippy_utils::{ + contains_name, higher, is_integer_const, match_trait_method, path_to_local_id, paths, sugg, SpanlessEq, }; use if_chain::if_chain; use rustc_ast::ast; @@ -15,7 +17,7 @@ use rustc_middle::hir::map::Map; use rustc_middle::middle::region; use rustc_middle::ty::{self, Ty}; use rustc_span::symbol::{sym, Symbol}; -use std::iter::Iterator; +use std::iter::{self, Iterator}; use std::mem; /// Checks for looping over a range and then indexing a sequence with it. @@ -367,7 +369,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> { }, ExprKind::MethodCall(_, _, args, _) => { let def_id = self.cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap(); - for (ty, expr) in self.cx.tcx.fn_sig(def_id).inputs().skip_binder().iter().zip(args) { + for (ty, expr) in iter::zip(self.cx.tcx.fn_sig(def_id).inputs().skip_binder(), args) { self.prefer_mutable = false; if let ty::Ref(_, _, mutbl) = *ty.kind() { if mutbl == Mutability::Mut { diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs index 45e1001d755..f63a3761a0d 100644 --- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs @@ -1,5 +1,5 @@ use super::NEVER_LOOP; -use crate::utils::span_lint; +use clippy_utils::diagnostics::span_lint; use rustc_hir::{Block, Expr, ExprKind, HirId, InlineAsmOperand, Stmt, StmtKind}; use rustc_lint::LateContext; use std::iter::{once, Iterator}; @@ -78,7 +78,7 @@ fn stmt_to_expr<'tcx>(stmt: &Stmt<'tcx>) -> Option<&'tcx Expr<'tcx>> { match stmt.kind { StmtKind::Semi(ref e, ..) | StmtKind::Expr(ref e, ..) => Some(e), StmtKind::Local(ref local) => local.init.as_deref(), - _ => None, + StmtKind::Item(..) => None, } } diff --git a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs index f3585830e4a..849d7ec718c 100644 --- a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs +++ b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs @@ -1,5 +1,7 @@ use super::SAME_ITEM_PUSH; -use crate::utils::{implements_trait, is_type_diagnostic_item, snippet_with_macro_callsite, span_lint_and_help}; +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::source::snippet_with_macro_callsite; +use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use if_chain::if_chain; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; diff --git a/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs b/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs index 38400c93c9a..8451c1c6130 100644 --- a/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs @@ -1,5 +1,7 @@ use super::{get_span_of_entire_for_loop, SINGLE_ELEMENT_LOOP}; -use crate::utils::{indent_of, single_segment_path, snippet, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::single_segment_path; +use clippy_utils::source::{indent_of, snippet}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, Pat, PatKind}; diff --git a/src/tools/clippy/clippy_lints/src/loops/utils.rs b/src/tools/clippy/clippy_lints/src/loops/utils.rs index 9e38e17719a..bb409c48532 100644 --- a/src/tools/clippy/clippy_lints/src/loops/utils.rs +++ b/src/tools/clippy/clippy_lints/src/loops/utils.rs @@ -1,7 +1,5 @@ -use crate::utils::{ - get_parent_expr, get_trait_def_id, has_iter_method, implements_trait, is_integer_const, path_to_local, - path_to_local_id, paths, sugg, -}; +use clippy_utils::ty::{has_iter_method, implements_trait}; +use clippy_utils::{get_parent_expr, is_integer_const, path_to_local, path_to_local_id, sugg}; use if_chain::if_chain; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; @@ -10,7 +8,7 @@ use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, HirId, Mutability, Pat, P use rustc_lint::LateContext; use rustc_middle::hir::map::Map; use rustc_span::source_map::Span; -use rustc_span::symbol::Symbol; +use rustc_span::symbol::{sym, Symbol}; use std::iter::Iterator; #[derive(Debug, PartialEq)] @@ -316,7 +314,7 @@ pub(super) fn get_span_of_entire_for_loop(expr: &Expr<'_>) -> Span { /// If `arg` was the argument to a `for` loop, return the "cleanest" way of writing the /// actual `Iterator` that the loop uses. pub(super) fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applic_ref: &mut Applicability) -> String { - let impls_iterator = get_trait_def_id(cx, &paths::ITERATOR).map_or(false, |id| { + let impls_iterator = cx.tcx.get_diagnostic_item(sym::Iterator).map_or(false, |id| { implements_trait(cx, cx.typeck_results().expr_ty(arg), id, &[]) }); if impls_iterator { diff --git a/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs b/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs index 05e0a722563..cad9ff8489a 100644 --- a/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs +++ b/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs @@ -1,7 +1,7 @@ use super::WHILE_IMMUTABLE_CONDITION; use crate::consts::constant; -use crate::utils::span_lint_and_then; -use crate::utils::usage::mutated_variables; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::usage::mutated_variables; use if_chain::if_chain; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def::{DefKind, Res}; diff --git a/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs b/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs index 65d8f2f1111..ffe8c0c5494 100644 --- a/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs @@ -1,5 +1,6 @@ use super::WHILE_LET_LOOP; -use crate::utils::{snippet_with_applicability, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir::{Block, Expr, ExprKind, MatchSource, StmtKind}; use rustc_lint::{LateContext, LintContext}; diff --git a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs index e5a47694faa..57fc6250a9a 100644 --- a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs +++ b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs @@ -1,9 +1,11 @@ use super::utils::{LoopNestVisitor, Nesting}; use super::WHILE_LET_ON_ITERATOR; -use crate::utils::usage::mutated_variables; -use crate::utils::{ - get_enclosing_block, get_trait_def_id, implements_trait, is_refutable, last_path_segment, match_trait_method, - path_to_local, path_to_local_id, paths, snippet_with_applicability, span_lint_and_sugg, +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::implements_trait; +use clippy_utils::usage::mutated_variables; +use clippy_utils::{ + get_enclosing_block, is_refutable, is_trait_method, last_path_segment, path_to_local, path_to_local_id, }; use if_chain::if_chain; use rustc_errors::Applicability; @@ -11,7 +13,6 @@ use rustc_hir::intravisit::{walk_block, walk_expr, NestedVisitorMap, Visitor}; use rustc_hir::{Expr, ExprKind, HirId, MatchSource, Node, PatKind}; use rustc_lint::LateContext; use rustc_middle::hir::map::Map; - use rustc_span::symbol::sym; pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { @@ -27,7 +28,7 @@ pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { // Don't lint when the iterator is recreated on every iteration if_chain! { if let ExprKind::MethodCall(..) | ExprKind::Call(..) = iter_expr.kind; - if let Some(iter_def_id) = get_trait_def_id(cx, &paths::ITERATOR); + if let Some(iter_def_id) = cx.tcx.get_diagnostic_item(sym::Iterator); if implements_trait(cx, cx.typeck_results().expr_ty(iter_expr), iter_def_id, &[]); then { return; @@ -36,7 +37,7 @@ pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { let lhs_constructor = last_path_segment(qpath); if method_path.ident.name == sym::next - && match_trait_method(cx, match_expr, &paths::ITERATOR) + && is_trait_method(cx, match_expr, sym::Iterator) && lhs_constructor.ident.name == sym::Some && (pat_args.is_empty() || !is_refutable(cx, &pat_args[0]) diff --git a/src/tools/clippy/clippy_lints/src/macro_use.rs b/src/tools/clippy/clippy_lints/src/macro_use.rs index 6d9c78393c8..d573c297838 100644 --- a/src/tools/clippy/clippy_lints/src/macro_use.rs +++ b/src/tools/clippy/clippy_lints/src/macro_use.rs @@ -1,4 +1,6 @@ -use crate::utils::{in_macro, snippet, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::in_macro; +use clippy_utils::source::snippet; use hir::def::{DefKind, Res}; use if_chain::if_chain; use rustc_ast::ast; diff --git a/src/tools/clippy/clippy_lints/src/main_recursion.rs b/src/tools/clippy/clippy_lints/src/main_recursion.rs index 1b274c79d38..07d8a440aea 100644 --- a/src/tools/clippy/clippy_lints/src/main_recursion.rs +++ b/src/tools/clippy/clippy_lints/src/main_recursion.rs @@ -1,10 +1,11 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::source::snippet; +use clippy_utils::{is_entrypoint_fn, is_no_std_crate}; +use if_chain::if_chain; use rustc_hir::{Crate, Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use crate::utils::{is_entrypoint_fn, is_no_std_crate, snippet, span_lint_and_help}; -use if_chain::if_chain; - declare_clippy_lint! { /// **What it does:** Checks for recursion using the entrypoint. /// diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs index 2e2e693592c..5d88ff3b99f 100644 --- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs +++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs @@ -1,5 +1,7 @@ -use crate::utils::paths::FUTURE_FROM_GENERATOR; -use crate::utils::{match_function_call, position_before_rarrow, snippet_block, snippet_opt, span_lint_and_then}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::match_function_call; +use clippy_utils::paths::FUTURE_FROM_GENERATOR; +use clippy_utils::source::{position_before_rarrow, snippet_block, snippet_opt}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; diff --git a/src/tools/clippy/clippy_lints/src/manual_map.rs b/src/tools/clippy/clippy_lints/src/manual_map.rs index ac1d51e1993..ed157783b72 100644 --- a/src/tools/clippy/clippy_lints/src/manual_map.rs +++ b/src/tools/clippy/clippy_lints/src/manual_map.rs @@ -1,18 +1,14 @@ -use crate::{ - map_unit_fn::OPTION_MAP_UNIT_FN, - matches::MATCH_AS_REF, - utils::{ - can_partially_move_ty, is_allowed, is_type_diagnostic_item, match_def_path, match_var, paths, - peel_hir_expr_refs, peel_mid_ty_refs_is_mutable, snippet_with_applicability, snippet_with_context, - span_lint_and_sugg, - }, -}; +use crate::{map_unit_fn::OPTION_MAP_UNIT_FN, matches::MATCH_AS_REF}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; +use clippy_utils::ty::{can_partially_move_ty, is_type_diagnostic_item, peel_mid_ty_refs_is_mutable}; +use clippy_utils::{is_allowed, is_else_clause_of_if_let_else, match_def_path, match_var, paths, peel_hir_expr_refs}; use rustc_ast::util::parser::PREC_POSTFIX; use rustc_errors::Applicability; use rustc_hir::{ def::Res, intravisit::{walk_expr, ErasedMap, NestedVisitorMap, Visitor}, - Arm, BindingAnnotation, Block, Expr, ExprKind, Mutability, Pat, PatKind, Path, QPath, + Arm, BindingAnnotation, Block, Expr, ExprKind, MatchSource, Mutability, Pat, PatKind, Path, QPath, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; @@ -55,8 +51,11 @@ impl LateLintPass<'_> for ManualMap { return; } - if let ExprKind::Match(scrutinee, [arm1 @ Arm { guard: None, .. }, arm2 @ Arm { guard: None, .. }], _) = - expr.kind + if let ExprKind::Match( + scrutinee, + [arm1 @ Arm { guard: None, .. }, arm2 @ Arm { guard: None, .. }], + match_kind, + ) = expr.kind { let (scrutinee_ty, ty_ref_count, ty_mutability) = peel_mid_ty_refs_is_mutable(cx.typeck_results().expr_ty(scrutinee)); @@ -129,7 +128,7 @@ impl LateLintPass<'_> for ManualMap { // Remove address-of expressions from the scrutinee. Either `as_ref` will be called, or // it's being passed by value. let scrutinee = peel_hir_expr_refs(scrutinee).0; - let scrutinee_str = snippet_with_context(cx, scrutinee.span, expr_ctxt, "..", &mut app); + let (scrutinee_str, _) = snippet_with_context(cx, scrutinee.span, expr_ctxt, "..", &mut app); let scrutinee_str = if scrutinee.span.ctxt() == expr.span.ctxt() && scrutinee.precedence().order() < PREC_POSTFIX { format!("({})", scrutinee_str) @@ -160,7 +159,7 @@ impl LateLintPass<'_> for ManualMap { "|{}{}| {}", annotation, some_binding, - snippet_with_context(cx, some_expr.span, expr_ctxt, "..", &mut app) + snippet_with_context(cx, some_expr.span, expr_ctxt, "..", &mut app).0 ) }, } @@ -168,8 +167,8 @@ impl LateLintPass<'_> for ManualMap { // TODO: handle explicit reference annotations. format!( "|{}| {}", - snippet_with_context(cx, some_pat.span, expr_ctxt, "..", &mut app), - snippet_with_context(cx, some_expr.span, expr_ctxt, "..", &mut app) + snippet_with_context(cx, some_pat.span, expr_ctxt, "..", &mut app).0, + snippet_with_context(cx, some_expr.span, expr_ctxt, "..", &mut app).0 ) } else { // Refutable bindings and mixed reference annotations can't be handled by `map`. @@ -182,7 +181,12 @@ impl LateLintPass<'_> for ManualMap { expr.span, "manual implementation of `Option::map`", "try this", - format!("{}{}.map({})", scrutinee_str, as_ref_str, body_str), + if matches!(match_kind, MatchSource::IfLetDesugar { .. }) && is_else_clause_of_if_let_else(cx.tcx, expr) + { + format!("{{ {}{}.map({}) }}", scrutinee_str, as_ref_str, body_str) + } else { + format!("{}{}.map({})", scrutinee_str, as_ref_str, body_str) + }, app, ); } diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs index 7e6d4d3a216..95261580b8e 100644 --- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs +++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs @@ -1,6 +1,8 @@ -use crate::utils::{meets_msrv, snippet_opt, span_lint_and_then}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::meets_msrv; +use clippy_utils::source::snippet_opt; use if_chain::if_chain; -use rustc_ast::ast::{Attribute, Item, ItemKind, FieldDef, Variant, VariantData, VisibilityKind}; +use rustc_ast::ast::{Attribute, FieldDef, Item, ItemKind, Variant, VariantData, VisibilityKind}; use rustc_attr as attr; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/manual_ok_or.rs b/src/tools/clippy/clippy_lints/src/manual_ok_or.rs index efb05b8ffdf..9bfae602c40 100644 --- a/src/tools/clippy/clippy_lints/src/manual_ok_or.rs +++ b/src/tools/clippy/clippy_lints/src/manual_ok_or.rs @@ -1,7 +1,7 @@ -use crate::utils::{ - indent_of, is_type_diagnostic_item, match_qpath, path_to_local_id, paths, reindent_multiline, snippet_opt, - span_lint_and_sugg, -}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{match_qpath, path_to_local_id, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, PatKind}; diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs index 42a92104a49..9da37efddac 100644 --- a/src/tools/clippy/clippy_lints/src/manual_strip.rs +++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs @@ -1,9 +1,8 @@ use crate::consts::{constant, Constant}; -use crate::utils::usage::mutated_variables; -use crate::utils::{ - eq_expr_value, higher, match_def_path, meets_msrv, multispan_sugg, paths, snippet, span_lint_and_then, -}; - +use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; +use clippy_utils::source::snippet; +use clippy_utils::usage::mutated_variables; +use clippy_utils::{eq_expr_value, higher, match_def_path, meets_msrv, paths}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_hir::def::Res; diff --git a/src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs index b452225b5db..f296d6a1a15 100644 --- a/src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs +++ b/src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs @@ -1,6 +1,9 @@ use crate::consts::constant_simple; -use crate::utils; -use crate::utils::{path_to_local_id, sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::usage::contains_return_break_continue_macro; +use clippy_utils::{in_constant, match_qpath, path_to_local_id, paths, sugg}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Arm, Expr, ExprKind, Pat, PatKind}; @@ -42,7 +45,7 @@ declare_lint_pass!(ManualUnwrapOr => [MANUAL_UNWRAP_OR]); impl LateLintPass<'_> for ManualUnwrapOr { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if in_external_macro(cx.sess(), expr.span) { + if in_external_macro(cx.sess(), expr.span) || in_constant(cx, expr.hir_id) { return; } lint_manual_unwrap_or(cx, expr); @@ -72,19 +75,19 @@ fn lint_manual_unwrap_or<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if let Some((idx, or_arm)) = arms.iter().enumerate().find(|(_, arm)| match arm.pat.kind { PatKind::Path(ref some_qpath) => - utils::match_qpath(some_qpath, &utils::paths::OPTION_NONE), + match_qpath(some_qpath, &paths::OPTION_NONE), PatKind::TupleStruct(ref err_qpath, &[Pat { kind: PatKind::Wild, .. }], _) => - utils::match_qpath(err_qpath, &utils::paths::RESULT_ERR), + match_qpath(err_qpath, &paths::RESULT_ERR), _ => false, } ); let unwrap_arm = &arms[1 - idx]; if let PatKind::TupleStruct(ref unwrap_qpath, &[unwrap_pat], _) = unwrap_arm.pat.kind; - if utils::match_qpath(unwrap_qpath, &utils::paths::OPTION_SOME) - || utils::match_qpath(unwrap_qpath, &utils::paths::RESULT_OK); + if match_qpath(unwrap_qpath, &paths::OPTION_SOME) + || match_qpath(unwrap_qpath, &paths::RESULT_OK); if let PatKind::Binding(_, binding_hir_id, ..) = unwrap_pat.kind; if path_to_local_id(unwrap_arm.body, binding_hir_id); - if !utils::usage::contains_return_break_continue_macro(or_arm.body); + if !contains_return_break_continue_macro(or_arm.body); then { Some(or_arm) } else { @@ -96,21 +99,21 @@ fn lint_manual_unwrap_or<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if_chain! { if let ExprKind::Match(scrutinee, match_arms, _) = expr.kind; let ty = cx.typeck_results().expr_ty(scrutinee); - if let Some(case) = if utils::is_type_diagnostic_item(cx, ty, sym::option_type) { + if let Some(case) = if is_type_diagnostic_item(cx, ty, sym::option_type) { Some(Case::Option) - } else if utils::is_type_diagnostic_item(cx, ty, sym::result_type) { + } else if is_type_diagnostic_item(cx, ty, sym::result_type) { Some(Case::Result) } else { None }; if let Some(or_arm) = applicable_or_arm(match_arms); - if let Some(or_body_snippet) = utils::snippet_opt(cx, or_arm.body.span); - if let Some(indent) = utils::indent_of(cx, expr.span); + if let Some(or_body_snippet) = snippet_opt(cx, or_arm.body.span); + if let Some(indent) = indent_of(cx, expr.span); if constant_simple(cx, cx.typeck_results(), or_arm.body).is_some(); then { let reindented_or_body = - utils::reindent_multiline(or_body_snippet.into(), true, Some(indent)); - utils::span_lint_and_sugg( + reindent_multiline(or_body_snippet.into(), true, Some(indent)); + span_lint_and_sugg( cx, MANUAL_UNWRAP_OR, expr.span, &format!("this pattern reimplements `{}`", case.unwrap_fn_path()), diff --git a/src/tools/clippy/clippy_lints/src/map_clone.rs b/src/tools/clippy/clippy_lints/src/map_clone.rs index 4b685c09a05..cfcc705eabc 100644 --- a/src/tools/clippy/clippy_lints/src/map_clone.rs +++ b/src/tools/clippy/clippy_lints/src/map_clone.rs @@ -1,7 +1,8 @@ -use crate::utils::paths; -use crate::utils::{ - is_copy, is_type_diagnostic_item, match_trait_method, remove_blocks, snippet_with_applicability, span_lint_and_sugg, -}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_trait_method; +use clippy_utils::remove_blocks; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::{is_copy, is_type_diagnostic_item}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; @@ -55,7 +56,7 @@ impl<'tcx> LateLintPass<'tcx> for MapClone { if args.len() == 2; if method.ident.name == sym::map; let ty = cx.typeck_results().expr_ty(&args[0]); - if is_type_diagnostic_item(cx, ty, sym::option_type) || match_trait_method(cx, e, &paths::ITERATOR); + if is_type_diagnostic_item(cx, ty, sym::option_type) || is_trait_method(cx, e, sym::Iterator); if let hir::ExprKind::Closure(_, _, body_id, _, _) = args[1].kind; let closure_body = cx.tcx.hir().body(body_id); let closure_expr = remove_blocks(&closure_body.value); diff --git a/src/tools/clippy/clippy_lints/src/map_err_ignore.rs b/src/tools/clippy/clippy_lints/src/map_err_ignore.rs index 76fe8e776ea..a6a63961be5 100644 --- a/src/tools/clippy/clippy_lints/src/map_err_ignore.rs +++ b/src/tools/clippy/clippy_lints/src/map_err_ignore.rs @@ -1,5 +1,4 @@ -use crate::utils::span_lint_and_help; - +use clippy_utils::diagnostics::span_lint_and_help; use rustc_hir::{CaptureBy, Expr, ExprKind, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/src/tools/clippy/clippy_lints/src/map_identity.rs b/src/tools/clippy/clippy_lints/src/map_identity.rs index 9f9c108a85a..75191e1f9ee 100644 --- a/src/tools/clippy/clippy_lints/src/map_identity.rs +++ b/src/tools/clippy/clippy_lints/src/map_identity.rs @@ -1,7 +1,6 @@ -use crate::utils::{ - is_adjusted, is_type_diagnostic_item, match_path, match_trait_method, match_var, paths, remove_blocks, - span_lint_and_sugg, -}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{is_adjusted, is_trait_method, match_path, match_var, paths, remove_blocks}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Body, Expr, ExprKind, Pat, PatKind, QPath, StmtKind}; @@ -65,7 +64,7 @@ fn get_map_argument<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<&'a if let ExprKind::MethodCall(ref method, _, ref args, _) = expr.kind; if args.len() == 2 && method.ident.name == sym::map; let caller_ty = cx.typeck_results().expr_ty(&args[0]); - if match_trait_method(cx, expr, &paths::ITERATOR) + if is_trait_method(cx, expr, sym::Iterator) || is_type_diagnostic_item(cx, caller_ty, sym::result_type) || is_type_diagnostic_item(cx, caller_ty, sym::option_type); then { diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs index 01126e86199..d4764b5ccff 100644 --- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs +++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs @@ -1,4 +1,7 @@ -use crate::utils::{is_type_diagnostic_item, iter_input_pats, method_chain_args, snippet, span_lint_and_then}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::snippet; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{iter_input_pats, method_chain_args}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/src/tools/clippy/clippy_lints/src/match_on_vec_items.rs b/src/tools/clippy/clippy_lints/src/match_on_vec_items.rs index 086dae9422f..ccaa5e98c83 100644 --- a/src/tools/clippy/clippy_lints/src/match_on_vec_items.rs +++ b/src/tools/clippy/clippy_lints/src/match_on_vec_items.rs @@ -1,4 +1,6 @@ -use crate::utils::{is_type_diagnostic_item, is_type_lang_item, snippet, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet; +use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem, MatchSource}; diff --git a/src/tools/clippy/clippy_lints/src/matches.rs b/src/tools/clippy/clippy_lints/src/matches.rs index 8570cd724b2..2f2dc4cfc6b 100644 --- a/src/tools/clippy/clippy_lints/src/matches.rs +++ b/src/tools/clippy/clippy_lints/src/matches.rs @@ -1,32 +1,35 @@ use crate::consts::{constant, miri_to_const, Constant}; -use crate::utils::sugg::Sugg; -use crate::utils::visitors::LocalUsedVisitor; -use crate::utils::{ - expr_block, get_parent_expr, implements_trait, in_macro, indent_of, is_allowed, is_expn_of, is_refutable, - is_type_diagnostic_item, is_wild, match_qpath, match_type, meets_msrv, multispan_sugg, path_to_local, - path_to_local_id, peel_hir_pat_refs, peel_mid_ty_refs, peel_n_hir_expr_refs, remove_blocks, snippet, snippet_block, - snippet_opt, snippet_with_applicability, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, - span_lint_and_then, strip_pat_refs, +use clippy_utils::diagnostics::{ + multispan_sugg, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then, }; -use crate::utils::{paths, search_same, SpanlessEq, SpanlessHash}; +use clippy_utils::source::{expr_block, indent_of, snippet, snippet_block, snippet_opt, snippet_with_applicability}; +use clippy_utils::sugg::Sugg; +use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, match_type, peel_mid_ty_refs}; +use clippy_utils::visitors::LocalUsedVisitor; +use clippy_utils::{ + get_parent_expr, in_macro, is_allowed, is_expn_of, is_refutable, is_wild, match_qpath, meets_msrv, path_to_local, + path_to_local_id, peel_hir_pat_refs, peel_n_hir_expr_refs, recurse_or_patterns, remove_blocks, strip_pat_refs, +}; +use clippy_utils::{paths, search_same, SpanlessEq, SpanlessHash}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability; -use rustc_hir::def::CtorKind; +use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::{ - Arm, BindingAnnotation, Block, BorrowKind, Expr, ExprKind, Guard, HirId, Local, MatchSource, Mutability, Node, Pat, - PatKind, QPath, RangeEnd, + self as hir, Arm, BindingAnnotation, Block, BorrowKind, Expr, ExprKind, Guard, HirId, Local, MatchSource, + Mutability, Node, Pat, PatKind, PathSegment, QPath, RangeEnd, TyKind, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_middle::ty::{self, Ty, TyS}; +use rustc_middle::ty::{self, Ty, TyS, VariantDef}; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::{Span, Spanned}; use rustc_span::sym; use std::cmp::Ordering; use std::collections::hash_map::Entry; +use std::iter; use std::ops::Bound; declare_clippy_lint! { @@ -954,114 +957,181 @@ fn check_wild_err_arm<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm } } -fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) { - let ty = cx.typeck_results().expr_ty(ex); - if !ty.is_enum() { - // If there isn't a nice closed set of possible values that can be conveniently enumerated, - // don't complain about not enumerating the mall. - return; +enum CommonPrefixSearcher<'a> { + None, + Path(&'a [PathSegment<'a>]), + Mixed, +} +impl CommonPrefixSearcher<'a> { + fn with_path(&mut self, path: &'a [PathSegment<'a>]) { + match path { + [path @ .., _] => self.with_prefix(path), + [] => (), + } } + fn with_prefix(&mut self, path: &'a [PathSegment<'a>]) { + match self { + Self::None => *self = Self::Path(path), + Self::Path(self_path) + if path + .iter() + .map(|p| p.ident.name) + .eq(self_path.iter().map(|p| p.ident.name)) => {}, + Self::Path(_) => *self = Self::Mixed, + Self::Mixed => (), + } + } +} + +#[allow(clippy::too_many_lines)] +fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) { + let ty = cx.typeck_results().expr_ty(ex).peel_refs(); + let adt_def = match ty.kind() { + ty::Adt(adt_def, _) + if adt_def.is_enum() + && !(is_type_diagnostic_item(cx, ty, sym::option_type) + || is_type_diagnostic_item(cx, ty, sym::result_type)) => + { + adt_def + }, + _ => return, + }; + // First pass - check for violation, but don't do much book-keeping because this is hopefully // the uncommon case, and the book-keeping is slightly expensive. let mut wildcard_span = None; let mut wildcard_ident = None; + let mut has_non_wild = false; for arm in arms { - if let PatKind::Wild = arm.pat.kind { - wildcard_span = Some(arm.pat.span); - } else if let PatKind::Binding(_, _, ident, None) = arm.pat.kind { - wildcard_span = Some(arm.pat.span); - wildcard_ident = Some(ident); + match peel_hir_pat_refs(arm.pat).0.kind { + PatKind::Wild => wildcard_span = Some(arm.pat.span), + PatKind::Binding(_, _, ident, None) => { + wildcard_span = Some(arm.pat.span); + wildcard_ident = Some(ident); + }, + _ => has_non_wild = true, } } + let wildcard_span = match wildcard_span { + Some(x) if has_non_wild => x, + _ => return, + }; - if let Some(wildcard_span) = wildcard_span { - // Accumulate the variants which should be put in place of the wildcard because they're not - // already covered. + // Accumulate the variants which should be put in place of the wildcard because they're not + // already covered. + let mut missing_variants: Vec<_> = adt_def.variants.iter().collect(); - let mut missing_variants = vec![]; - if let ty::Adt(def, _) = ty.kind() { - for variant in &def.variants { - missing_variants.push(variant); + let mut path_prefix = CommonPrefixSearcher::None; + for arm in arms { + // Guards mean that this case probably isn't exhaustively covered. Technically + // this is incorrect, as we should really check whether each variant is exhaustively + // covered by the set of guards that cover it, but that's really hard to do. + recurse_or_patterns(arm.pat, |pat| { + let path = match &peel_hir_pat_refs(pat).0.kind { + PatKind::Path(path) => { + #[allow(clippy::match_same_arms)] + let id = match cx.qpath_res(path, pat.hir_id) { + Res::Def(DefKind::Const | DefKind::ConstParam | DefKind::AnonConst, _) => return, + Res::Def(_, id) => id, + _ => return, + }; + if arm.guard.is_none() { + missing_variants.retain(|e| e.ctor_def_id != Some(id)); + } + path + }, + PatKind::TupleStruct(path, patterns, ..) => { + if arm.guard.is_none() && patterns.iter().all(|p| !is_refutable(cx, p)) { + let id = cx.qpath_res(path, pat.hir_id).def_id(); + missing_variants.retain(|e| e.ctor_def_id != Some(id)); + } + path + }, + PatKind::Struct(path, patterns, ..) => { + if arm.guard.is_none() && patterns.iter().all(|p| !is_refutable(cx, p.pat)) { + let id = cx.qpath_res(path, pat.hir_id).def_id(); + missing_variants.retain(|e| e.def_id != id); + } + path + }, + _ => return, + }; + match path { + QPath::Resolved(_, path) => path_prefix.with_path(path.segments), + QPath::TypeRelative( + hir::Ty { + kind: TyKind::Path(QPath::Resolved(_, path)), + .. + }, + _, + ) => path_prefix.with_prefix(path.segments), + _ => (), } - } + }); + } - for arm in arms { - if arm.guard.is_some() { - // Guards mean that this case probably isn't exhaustively covered. Technically - // this is incorrect, as we should really check whether each variant is exhaustively - // covered by the set of guards that cover it, but that's really hard to do. - continue; - } - if let PatKind::Path(ref path) = arm.pat.kind { - if let QPath::Resolved(_, p) = path { - missing_variants.retain(|e| e.ctor_def_id != Some(p.res.def_id())); - } - } else if let PatKind::TupleStruct(QPath::Resolved(_, p), ref patterns, ..) = arm.pat.kind { - // Some simple checks for exhaustive patterns. - // There is a room for improvements to detect more cases, - // but it can be more expensive to do so. - let is_pattern_exhaustive = - |pat: &&Pat<'_>| matches!(pat.kind, PatKind::Wild | PatKind::Binding(.., None)); - if patterns.iter().all(is_pattern_exhaustive) { - missing_variants.retain(|e| e.ctor_def_id != Some(p.res.def_id())); + let format_suggestion = |variant: &VariantDef| { + format!( + "{}{}{}{}", + if let Some(ident) = wildcard_ident { + format!("{} @ ", ident.name) + } else { + String::new() + }, + if let CommonPrefixSearcher::Path(path_prefix) = path_prefix { + let mut s = String::new(); + for seg in path_prefix { + s.push_str(&seg.ident.as_str()); + s.push_str("::"); } + s + } else { + let mut s = cx.tcx.def_path_str(adt_def.did); + s.push_str("::"); + s + }, + variant.ident.name, + match variant.ctor_kind { + CtorKind::Fn if variant.fields.len() == 1 => "(_)", + CtorKind::Fn => "(..)", + CtorKind::Const => "", + CtorKind::Fictive => "{ .. }", } - } - - let mut suggestion: Vec<String> = missing_variants - .iter() - .map(|v| { - let suffix = match v.ctor_kind { - CtorKind::Fn => "(..)", - CtorKind::Const | CtorKind::Fictive => "", - }; - let ident_str = if let Some(ident) = wildcard_ident { - format!("{} @ ", ident.name) - } else { - String::new() - }; - // This path assumes that the enum type is imported into scope. - format!("{}{}{}", ident_str, cx.tcx.def_path_str(v.def_id), suffix) - }) - .collect(); - - if suggestion.is_empty() { - return; - } - - let mut message = "wildcard match will miss any future added variants"; + ) + }; - if let ty::Adt(def, _) = ty.kind() { - if def.is_variant_list_non_exhaustive() { - message = "match on non-exhaustive enum doesn't explicitly match all known variants"; - suggestion.push(String::from("_")); - } - } + match missing_variants.as_slice() { + [] => (), + [x] if !adt_def.is_variant_list_non_exhaustive() => span_lint_and_sugg( + cx, + MATCH_WILDCARD_FOR_SINGLE_VARIANTS, + wildcard_span, + "wildcard matches only a single variant and will also match any future added variants", + "try this", + format_suggestion(x), + Applicability::MaybeIncorrect, + ), + variants => { + let mut suggestions: Vec<_> = variants.iter().cloned().map(format_suggestion).collect(); + let message = if adt_def.is_variant_list_non_exhaustive() { + suggestions.push("_".into()); + "wildcard matches known variants and will also match future added variants" + } else { + "wildcard match will also match any future added variants" + }; - if suggestion.len() == 1 { - // No need to check for non-exhaustive enum as in that case len would be greater than 1 span_lint_and_sugg( cx, - MATCH_WILDCARD_FOR_SINGLE_VARIANTS, + WILDCARD_ENUM_MATCH_ARM, wildcard_span, message, "try this", - suggestion[0].clone(), + suggestions.join(" | "), Applicability::MaybeIncorrect, ) - }; - - span_lint_and_sugg( - cx, - WILDCARD_ENUM_MATCH_ARM, - wildcard_span, - message, - "try this", - suggestion.join(" | "), - Applicability::MaybeIncorrect, - ) - } + }, + }; } // If the block contains only a `panic!` macro (as expression or statement) @@ -1284,6 +1354,7 @@ fn find_bool_lit(ex: &ExprKind<'_>, desugared: bool) -> Option<bool> { } } +#[allow(clippy::too_many_lines)] fn check_match_single_binding<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], expr: &Expr<'_>) { if in_macro(expr.span) || arms.len() != 1 || is_refutable(cx, arms[0].pat) { return; @@ -1358,7 +1429,18 @@ fn check_match_single_binding<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[A indent = " ".repeat(indent_of(cx, bind_names).unwrap_or(0)); cbrace_start = format!("{{\n{}", indent); } - }; + } + // If the parent is already an arm, and the body is another match statement, + // we need curly braces around suggestion + let parent_node_id = cx.tcx.hir().get_parent_node(expr.hir_id); + if let Node::Arm(arm) = &cx.tcx.hir().get(parent_node_id) { + if let ExprKind::Match(..) = arm.body.kind { + cbrace_end = format!("\n{}}}", indent); + // Fix body indent due to the match + indent = " ".repeat(indent_of(cx, bind_names).unwrap_or(0)); + cbrace_start = format!("{{\n{}", indent); + } + } ( expr.span, format!( @@ -1587,7 +1669,7 @@ where values.sort(); - for (a, b) in values.iter().zip(values.iter().skip(1)) { + for (a, b) in iter::zip(&values, &values[1..]) { match (a, b) { (&Kind::Start(_, ra), &Kind::End(_, rb)) => { if ra.node != rb.node { @@ -1614,7 +1696,9 @@ where mod redundant_pattern_match { use super::REDUNDANT_PATTERN_MATCHING; - use crate::utils::{match_qpath, match_trait_method, paths, snippet, span_lint_and_then}; + use clippy_utils::diagnostics::span_lint_and_then; + use clippy_utils::source::snippet; + use clippy_utils::{is_trait_method, match_qpath, paths}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -1679,7 +1763,7 @@ mod redundant_pattern_match { if keyword == "while"; if let ExprKind::MethodCall(method_path, _, _, _) = op.kind; if method_path.ident.name == sym::next; - if match_trait_method(cx, op, &paths::ITERATOR); + if is_trait_method(cx, op, sym::Iterator); then { return; } diff --git a/src/tools/clippy/clippy_lints/src/mem_discriminant.rs b/src/tools/clippy/clippy_lints/src/mem_discriminant.rs index c71c2ee7d70..7895ba9f1e0 100644 --- a/src/tools/clippy/clippy_lints/src/mem_discriminant.rs +++ b/src/tools/clippy/clippy_lints/src/mem_discriminant.rs @@ -1,10 +1,12 @@ -use crate::utils::{match_def_path, paths, snippet, span_lint_and_then, walk_ptrs_ty_depth}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::snippet; +use clippy_utils::ty::walk_ptrs_ty_depth; +use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; - use std::iter; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/mem_forget.rs b/src/tools/clippy/clippy_lints/src/mem_forget.rs index d34f9761e26..c13802e3953 100644 --- a/src/tools/clippy/clippy_lints/src/mem_forget.rs +++ b/src/tools/clippy/clippy_lints/src/mem_forget.rs @@ -1,4 +1,5 @@ -use crate::utils::{match_def_path, paths, span_lint}; +use clippy_utils::diagnostics::span_lint; +use clippy_utils::{match_def_path, paths}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/src/tools/clippy/clippy_lints/src/mem_replace.rs b/src/tools/clippy/clippy_lints/src/mem_replace.rs index 19087b02077..426c108d89f 100644 --- a/src/tools/clippy/clippy_lints/src/mem_replace.rs +++ b/src/tools/clippy/clippy_lints/src/mem_replace.rs @@ -1,9 +1,10 @@ -use crate::utils::{ - in_macro, match_def_path, match_qpath, meets_msrv, paths, snippet, snippet_with_applicability, span_lint_and_help, - span_lint_and_sugg, span_lint_and_then, -}; +use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::is_diagnostic_assoc_item; +use clippy_utils::source::{snippet, snippet_with_applicability}; +use clippy_utils::{in_macro, match_def_path, match_qpath, meets_msrv, paths}; use if_chain::if_chain; use rustc_errors::Applicability; +use rustc_hir::def_id::DefId; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, QPath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; @@ -194,13 +195,44 @@ fn check_replace_with_uninit(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<' } } +/// Returns true if the `def_id` associated with the `path` is recognized as a "default-equivalent" +/// constructor from the std library +fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath<'_>) -> bool { + let std_types_symbols = &[ + sym::string_type, + sym::vec_type, + sym::vecdeque_type, + sym::LinkedList, + sym::hashmap_type, + sym::BTreeMap, + sym::hashset_type, + sym::BTreeSet, + sym::BinaryHeap, + ]; + + if std_types_symbols + .iter() + .any(|symbol| is_diagnostic_assoc_item(cx, def_id, *symbol)) + { + if let QPath::TypeRelative(_, ref method) = path { + if method.ident.name == sym::new { + return true; + } + } + } + + false +} + fn check_replace_with_default(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'_>, expr_span: Span) { if let ExprKind::Call(ref repl_func, _) = src.kind { if_chain! { if !in_external_macro(cx.tcx.sess, expr_span); if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind; if let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id(); - if match_def_path(cx, repl_def_id, &paths::DEFAULT_TRAIT_METHOD); + if is_diagnostic_assoc_item(cx, repl_def_id, sym::Default) + || is_default_equivalent_ctor(cx, repl_def_id, repl_func_qpath); + then { span_lint_and_then( cx, diff --git a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs index 5decb81d9f2..0ba8a98a018 100644 --- a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs @@ -1,8 +1,8 @@ use super::{contains_return, BIND_INSTEAD_OF_MAP}; -use crate::utils::{ - in_macro, match_qpath, match_type, method_calls, multispan_sugg_with_applicability, paths, remove_blocks, snippet, - snippet_with_macro_callsite, span_lint_and_sugg, span_lint_and_then, visitors::find_all_ret_expressions, -}; +use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::source::{snippet, snippet_with_macro_callsite}; +use clippy_utils::ty::match_type; +use clippy_utils::{in_macro, match_qpath, method_calls, paths, remove_blocks, visitors::find_all_ret_expressions}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs b/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs index 71a7e195e41..4f88f80a304 100644 --- a/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs +++ b/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs @@ -1,4 +1,6 @@ -use crate::utils::{is_type_diagnostic_item, snippet_with_applicability, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; diff --git a/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs b/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs new file mode 100644 index 00000000000..c668fe52781 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs @@ -0,0 +1,54 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::{method_chain_args, single_segment_path}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_lint::Lint; +use rustc_middle::ty; +use rustc_span::sym; + +/// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints. +pub(super) fn check( + cx: &LateContext<'_>, + info: &crate::methods::BinaryExprInfo<'_>, + chain_methods: &[&str], + lint: &'static Lint, + suggest: &str, +) -> bool { + if_chain! { + if let Some(args) = method_chain_args(info.chain, chain_methods); + if let hir::ExprKind::Call(ref fun, ref arg_char) = info.other.kind; + if arg_char.len() == 1; + if let hir::ExprKind::Path(ref qpath) = fun.kind; + if let Some(segment) = single_segment_path(qpath); + if segment.ident.name == sym::Some; + then { + let mut applicability = Applicability::MachineApplicable; + let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0][0]).peel_refs(); + + if *self_ty.kind() != ty::Str { + return false; + } + + span_lint_and_sugg( + cx, + lint, + info.expr.span, + &format!("you should use the `{}` method", suggest), + "like this", + format!("{}{}.{}({})", + if info.eq { "" } else { "!" }, + snippet_with_applicability(cx, args[0][0].span, "..", &mut applicability), + suggest, + snippet_with_applicability(cx, arg_char[0].span, "..", &mut applicability)), + applicability, + ); + + return true; + } + } + + false +} diff --git a/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs new file mode 100644 index 00000000000..4275857757f --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs @@ -0,0 +1,44 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::method_chain_args; +use clippy_utils::source::snippet_with_applicability; +use if_chain::if_chain; +use rustc_ast::ast; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_lint::Lint; + +/// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints with `unwrap()`. +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + info: &crate::methods::BinaryExprInfo<'_>, + chain_methods: &[&str], + lint: &'static Lint, + suggest: &str, +) -> bool { + if_chain! { + if let Some(args) = method_chain_args(info.chain, chain_methods); + if let hir::ExprKind::Lit(ref lit) = info.other.kind; + if let ast::LitKind::Char(c) = lit.node; + then { + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + lint, + info.expr.span, + &format!("you should use the `{}` method", suggest), + "like this", + format!("{}{}.{}('{}')", + if info.eq { "" } else { "!" }, + snippet_with_applicability(cx, args[0][0].span, "..", &mut applicability), + suggest, + c), + applicability, + ); + + true + } else { + false + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/methods/chars_last_cmp.rs b/src/tools/clippy/clippy_lints/src/methods/chars_last_cmp.rs new file mode 100644 index 00000000000..07bbc5ca1bf --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/methods/chars_last_cmp.rs @@ -0,0 +1,13 @@ +use crate::methods::chars_cmp; +use rustc_lint::LateContext; + +use super::CHARS_LAST_CMP; + +/// Checks for the `CHARS_LAST_CMP` lint. +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, info: &crate::methods::BinaryExprInfo<'_>) -> bool { + if chars_cmp::check(cx, info, &["chars", "last"], CHARS_LAST_CMP, "ends_with") { + true + } else { + chars_cmp::check(cx, info, &["chars", "next_back"], CHARS_LAST_CMP, "ends_with") + } +} diff --git a/src/tools/clippy/clippy_lints/src/methods/chars_last_cmp_with_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/chars_last_cmp_with_unwrap.rs new file mode 100644 index 00000000000..c29ee0ec8c8 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/methods/chars_last_cmp_with_unwrap.rs @@ -0,0 +1,13 @@ +use crate::methods::chars_cmp_with_unwrap; +use rustc_lint::LateContext; + +use super::CHARS_LAST_CMP; + +/// Checks for the `CHARS_LAST_CMP` lint with `unwrap()`. +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, info: &crate::methods::BinaryExprInfo<'_>) -> bool { + if chars_cmp_with_unwrap::check(cx, info, &["chars", "last", "unwrap"], CHARS_LAST_CMP, "ends_with") { + true + } else { + chars_cmp_with_unwrap::check(cx, info, &["chars", "next_back", "unwrap"], CHARS_LAST_CMP, "ends_with") + } +} diff --git a/src/tools/clippy/clippy_lints/src/methods/chars_next_cmp.rs b/src/tools/clippy/clippy_lints/src/methods/chars_next_cmp.rs new file mode 100644 index 00000000000..a6701d8830e --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/methods/chars_next_cmp.rs @@ -0,0 +1,8 @@ +use rustc_lint::LateContext; + +use super::CHARS_NEXT_CMP; + +/// Checks for the `CHARS_NEXT_CMP` lint. +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, info: &crate::methods::BinaryExprInfo<'_>) -> bool { + crate::methods::chars_cmp::check(cx, info, &["chars", "next"], CHARS_NEXT_CMP, "starts_with") +} diff --git a/src/tools/clippy/clippy_lints/src/methods/chars_next_cmp_with_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/chars_next_cmp_with_unwrap.rs new file mode 100644 index 00000000000..28ede28e935 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/methods/chars_next_cmp_with_unwrap.rs @@ -0,0 +1,8 @@ +use rustc_lint::LateContext; + +use super::CHARS_NEXT_CMP; + +/// Checks for the `CHARS_NEXT_CMP` lint with `unwrap()`. +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, info: &crate::methods::BinaryExprInfo<'_>) -> bool { + crate::methods::chars_cmp_with_unwrap::check(cx, info, &["chars", "next", "unwrap"], CHARS_NEXT_CMP, "starts_with") +} diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs index 4a130ed47db..edb6649b87b 100644 --- a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs +++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs @@ -1,15 +1,23 @@ -use crate::utils::{is_copy, span_lint_and_then, sugg}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::sugg; +use clippy_utils::ty::is_copy; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty; +use rustc_span::symbol::{sym, Symbol}; use std::iter; use super::CLONE_DOUBLE_REF; use super::CLONE_ON_COPY; /// Checks for the `CLONE_ON_COPY` lint. -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>, arg_ty: Ty<'_>) { +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol, args: &[hir::Expr<'_>]) { + if !(args.len() == 1 && method_name == sym::clone) { + return; + } + let arg = &args[0]; + let arg_ty = cx.typeck_results().expr_ty_adjusted(&args[0]); let ty = cx.typeck_results().expr_ty(expr); if let ty::Ref(_, inner, _) = arg_ty.kind() { if let ty::Ref(_, innermost, _) = inner.kind() { diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs index 3d5a68d69d7..6417bc81304 100644 --- a/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs +++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs @@ -1,13 +1,20 @@ -use crate::utils::{is_type_diagnostic_item, match_type, paths, snippet_with_macro_callsite, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::paths; +use clippy_utils::source::snippet_with_macro_callsite; +use clippy_utils::ty::{is_type_diagnostic_item, match_type}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::symbol::sym; +use rustc_span::symbol::{sym, Symbol}; use super::CLONE_ON_REF_PTR; -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>) { +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol, args: &[hir::Expr<'_>]) { + if !(args.len() == 1 && method_name == sym::clone) { + return; + } + let arg = &args[0]; let obj_ty = cx.typeck_results().expr_ty(arg).peel_refs(); if let ty::Adt(_, subst) = obj_ty.kind() { diff --git a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs index 6866e9c652a..e7bffa66b3f 100644 --- a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs +++ b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs @@ -1,4 +1,7 @@ -use crate::utils::{is_expn_of, is_type_diagnostic_item, snippet, snippet_with_applicability, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_expn_of; +use clippy_utils::source::{snippet, snippet_with_applicability}; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/src/tools/clippy/clippy_lints/src/methods/expect_used.rs b/src/tools/clippy/clippy_lints/src/methods/expect_used.rs index 90b781bd9d1..64531b29ade 100644 --- a/src/tools/clippy/clippy_lints/src/methods/expect_used.rs +++ b/src/tools/clippy/clippy_lints/src/methods/expect_used.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_type_diagnostic_item, span_lint_and_help}; +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::ty::is_type_diagnostic_item; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::sym; diff --git a/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs b/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs index b03835f97e6..39d2f15dbc8 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs @@ -1,4 +1,6 @@ -use crate::utils::{get_parent_expr, match_type, paths, span_lint_and_help}; +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::ty::match_type; +use clippy_utils::{get_parent_expr, paths}; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_flat_map.rs b/src/tools/clippy/clippy_lints/src/methods/filter_flat_map.rs index 8da867fce51..1588eec8882 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_flat_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_flat_map.rs @@ -1,18 +1,15 @@ -use crate::utils::{match_trait_method, paths, span_lint_and_help}; +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::is_trait_method; use rustc_hir as hir; use rustc_lint::LateContext; +use rustc_span::sym; use super::FILTER_MAP; /// lint use of `filter().flat_map()` for `Iterators` -pub(super) fn check<'tcx>( - cx: &LateContext<'tcx>, - expr: &'tcx hir::Expr<'_>, - _filter_args: &'tcx [hir::Expr<'_>], - _map_args: &'tcx [hir::Expr<'_>], -) { +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { // lint if caller of `.filter().flat_map()` is an Iterator - if match_trait_method(cx, expr, &paths::ITERATOR) { + if is_trait_method(cx, expr, sym::Iterator) { let msg = "called `filter(..).flat_map(..)` on an `Iterator`"; let hint = "this is more succinctly expressed by calling `.flat_map(..)` \ and filtering by returning `iter::empty()`"; diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs index f559160004c..2cb476acb2b 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs @@ -1,4 +1,6 @@ -use crate::utils::{match_trait_method, path_to_local_id, paths, snippet, span_lint_and_sugg, SpanlessEq}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet; +use clippy_utils::{is_trait_method, path_to_local_id, SpanlessEq}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; @@ -15,7 +17,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, is_ if_chain! { if let ExprKind::MethodCall(_, _, [map_recv, map_arg], map_span) = expr.kind; if let ExprKind::MethodCall(_, _, [_, filter_arg], filter_span) = map_recv.kind; - if match_trait_method(cx, map_recv, &paths::ITERATOR); + if is_trait_method(cx, map_recv, sym::Iterator); // filter(|x| ...is_some())... if let ExprKind::Closure(_, _, filter_body_id, ..) = filter_arg.kind; diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map_flat_map.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map_flat_map.rs index a6db138623a..741b1e7e361 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_map_flat_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_map_flat_map.rs @@ -1,18 +1,15 @@ -use crate::utils::{match_trait_method, paths, span_lint_and_help}; +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::is_trait_method; use rustc_hir as hir; use rustc_lint::LateContext; +use rustc_span::sym; use super::FILTER_MAP; /// lint use of `filter_map().flat_map()` for `Iterators` -pub(super) fn check<'tcx>( - cx: &LateContext<'tcx>, - expr: &'tcx hir::Expr<'_>, - _filter_args: &'tcx [hir::Expr<'_>], - _map_args: &'tcx [hir::Expr<'_>], -) { +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { // lint if caller of `.filter_map().flat_map()` is an Iterator - if match_trait_method(cx, expr, &paths::ITERATOR) { + if is_trait_method(cx, expr, sym::Iterator) { let msg = "called `filter_map(..).flat_map(..)` on an `Iterator`"; let hint = "this is more succinctly expressed by calling `.flat_map(..)` \ and filtering by returning `iter::empty()`"; diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs index 9e646360a40..80598d88508 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs @@ -1,9 +1,10 @@ -use crate::utils::{match_qpath, match_trait_method, path_to_local_id, paths, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::{is_trait_method, match_qpath, path_to_local_id, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::source_map::Span; +use rustc_span::{source_map::Span, sym}; use super::FILTER_MAP_IDENTITY; @@ -13,7 +14,7 @@ pub(super) fn check( filter_map_args: &[hir::Expr<'_>], filter_map_span: Span, ) { - if match_trait_method(cx, expr, &paths::ITERATOR) { + if is_trait_method(cx, expr, sym::Iterator) { let arg_node = &filter_map_args[1].kind; let apply_lint = |message: &str| { diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map_map.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map_map.rs index d015b4c7b38..713bbf25837 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_map_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_map_map.rs @@ -1,18 +1,15 @@ -use crate::utils::{match_trait_method, paths, span_lint_and_help}; +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::is_trait_method; use rustc_hir as hir; use rustc_lint::LateContext; +use rustc_span::sym; use super::FILTER_MAP; /// lint use of `filter_map().map()` for `Iterators` -pub(super) fn check<'tcx>( - cx: &LateContext<'tcx>, - expr: &'tcx hir::Expr<'_>, - _filter_args: &'tcx [hir::Expr<'_>], - _map_args: &'tcx [hir::Expr<'_>], -) { +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { // lint if caller of `.filter_map().map()` is an Iterator - if match_trait_method(cx, expr, &paths::ITERATOR) { + if is_trait_method(cx, expr, sym::Iterator) { let msg = "called `filter_map(..).map(..)` on an `Iterator`"; let hint = "this is more succinctly expressed by only calling `.filter_map(..)` instead"; span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint); diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs index a789df922ff..ba57abd16c9 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs @@ -1,8 +1,11 @@ -use crate::utils::{match_trait_method, meets_msrv, paths, snippet, span_lint, span_lint_and_sugg}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; +use clippy_utils::source::snippet; +use clippy_utils::{is_trait_method, meets_msrv}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_semver::RustcVersion; +use rustc_span::sym; use super::FILTER_MAP_NEXT; @@ -14,7 +17,7 @@ pub(super) fn check<'tcx>( filter_args: &'tcx [hir::Expr<'_>], msrv: Option<&RustcVersion>, ) { - if match_trait_method(cx, expr, &paths::ITERATOR) { + if is_trait_method(cx, expr, sym::Iterator) { if !meets_msrv(msrv, &FILTER_MAP_NEXT_MSRV) { return; } diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_next.rs b/src/tools/clippy/clippy_lints/src/methods/filter_next.rs index 81619e73017..6cd24334414 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_next.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_next.rs @@ -1,14 +1,17 @@ -use crate::utils::{match_trait_method, paths, snippet, span_lint, span_lint_and_sugg}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; +use clippy_utils::is_trait_method; +use clippy_utils::source::snippet; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; +use rustc_span::sym; use super::FILTER_NEXT; /// lint use of `filter().next()` for `Iterators` pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, filter_args: &'tcx [hir::Expr<'_>]) { // lint if caller of `.filter().next()` is an Iterator - if match_trait_method(cx, expr, &paths::ITERATOR) { + if is_trait_method(cx, expr, sym::Iterator) { let msg = "called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling \ `.find(..)` instead"; let filter_snippet = snippet(cx, filter_args[1].span, ".."); diff --git a/src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs b/src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs index ce3194f8a23..034ea6c6562 100644 --- a/src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs +++ b/src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs @@ -1,9 +1,10 @@ -use crate::utils::{match_qpath, match_trait_method, paths, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::{is_trait_method, match_qpath, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::source_map::Span; +use rustc_span::{source_map::Span, sym}; use super::FLAT_MAP_IDENTITY; @@ -14,7 +15,7 @@ pub(super) fn check<'tcx>( flat_map_args: &'tcx [hir::Expr<'_>], flat_map_span: Span, ) { - if match_trait_method(cx, expr, &paths::ITERATOR) { + if is_trait_method(cx, expr, sym::Iterator) { let arg_node = &flat_map_args[1].kind; let apply_lint = |message: &str| { diff --git a/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs b/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs index e50d0a33400..15cf5674313 100644 --- a/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs @@ -1,19 +1,24 @@ -use crate::utils::{get_trait_def_id, implements_trait, paths, span_lint_and_sugg, sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::ty::implements_trait; +use clippy_utils::{get_trait_def_id, match_qpath, paths, sugg}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; +use rustc_hir::ExprKind; use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty::Ty; +use rustc_span::sym; use super::FROM_ITER_INSTEAD_OF_COLLECT; -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { - let ty = cx.typeck_results().expr_ty(expr); - let arg_ty = cx.typeck_results().expr_ty(&args[0]); - +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>], func_kind: &ExprKind<'_>) { if_chain! { + if let hir::ExprKind::Path(path) = func_kind; + if match_qpath(path, &["from_iter"]); + let ty = cx.typeck_results().expr_ty(expr); + let arg_ty = cx.typeck_results().expr_ty(&args[0]); if let Some(from_iter_id) = get_trait_def_id(cx, &paths::FROM_ITERATOR); - if let Some(iter_id) = get_trait_def_id(cx, &paths::ITERATOR); + if let Some(iter_id) = cx.tcx.get_diagnostic_item(sym::Iterator); if implements_trait(cx, ty, from_iter_id, &[]) && implements_trait(cx, arg_ty, iter_id, &[]); then { diff --git a/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs index e157db2712a..b3a9743c614 100644 --- a/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs @@ -1,7 +1,8 @@ -use crate::methods::derefs_to_slice; -use crate::utils::{ - get_parent_expr, is_type_diagnostic_item, match_type, paths, snippet_with_applicability, span_lint_and_sugg, -}; +use super::utils::derefs_to_slice; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::{is_type_diagnostic_item, match_type}; +use clippy_utils::{get_parent_expr, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs b/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs index a769493d11d..04461ad5c3a 100644 --- a/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs +++ b/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_sugg; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs b/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs index 3045b09c238..950ec62c9fe 100644 --- a/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs +++ b/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs @@ -1,20 +1,24 @@ -use super::INEFFICIENT_TO_STRING; -use crate::utils::{ - is_type_diagnostic_item, match_def_path, paths, snippet_with_applicability, span_lint_and_then, walk_ptrs_ty_depth, -}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::{is_type_diagnostic_item, walk_ptrs_ty_depth}; +use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; -use rustc_span::sym; +use rustc_span::symbol::{sym, Symbol}; + +use super::INEFFICIENT_TO_STRING; /// Checks for the `INEFFICIENT_TO_STRING` lint -pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>, arg_ty: Ty<'tcx>) { +pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Symbol, args: &[hir::Expr<'_>]) { if_chain! { + if args.len() == 1 && method_name == sym!(to_string); if let Some(to_string_meth_did) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if match_def_path(cx, to_string_meth_did, &paths::TO_STRING_METHOD); if let Some(substs) = cx.typeck_results().node_substs_opt(expr.hir_id); + let arg_ty = cx.typeck_results().expr_ty_adjusted(&args[0]); let self_ty = substs.type_at(0); let (deref_self_ty, deref_count) = walk_ptrs_ty_depth(self_ty); if deref_count >= 1; @@ -31,7 +35,7 @@ pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, arg: &hir::Expr self_ty, deref_self_ty )); let mut applicability = Applicability::MachineApplicable; - let arg_snippet = snippet_with_applicability(cx, arg.span, "..", &mut applicability); + let arg_snippet = snippet_with_applicability(cx, args[0].span, "..", &mut applicability); diag.span_suggestion( expr.span, "try dereferencing the receiver", diff --git a/src/tools/clippy/clippy_lints/src/methods/inspect_for_each.rs b/src/tools/clippy/clippy_lints/src/methods/inspect_for_each.rs index 959457a5bfc..7fd3ef1a622 100644 --- a/src/tools/clippy/clippy_lints/src/methods/inspect_for_each.rs +++ b/src/tools/clippy/clippy_lints/src/methods/inspect_for_each.rs @@ -1,14 +1,14 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::is_trait_method; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::source_map::Span; - -use crate::utils::{match_trait_method, paths, span_lint_and_help}; +use rustc_span::{source_map::Span, sym}; use super::INSPECT_FOR_EACH; /// lint use of `inspect().for_each()` for `Iterators` pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, inspect_span: Span) { - if match_trait_method(cx, expr, &paths::ITERATOR) { + if is_trait_method(cx, expr, sym::Iterator) { let msg = "called `inspect(..).for_each(..)` on an `Iterator`"; let hint = "move the code from `inspect(..)` to `for_each(..)` and remove the `inspect(..)`"; span_lint_and_help( diff --git a/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs b/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs index 1e8315dbee2..da13b4ba37a 100644 --- a/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs +++ b/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs @@ -1,30 +1,43 @@ -use crate::utils::{has_iter_method, match_trait_method, paths, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_trait_method; +use clippy_utils::ty::has_iter_method; +use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; use rustc_span::source_map::Span; -use rustc_span::symbol::Symbol; +use rustc_span::symbol::{sym, Symbol}; use super::INTO_ITER_ON_REF; -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, self_ref_ty: Ty<'_>, method_span: Span) { - if !match_trait_method(cx, expr, &paths::INTO_ITERATOR) { - return; - } - if let Some((kind, method_name)) = ty_has_iter_method(cx, self_ref_ty) { - span_lint_and_sugg( - cx, - INTO_ITER_ON_REF, - method_span, - &format!( - "this `.into_iter()` call is equivalent to `.{}()` and will not consume the `{}`", - method_name, kind, - ), - "call directly", - method_name.to_string(), - Applicability::MachineApplicable, - ); +pub(super) fn check( + cx: &LateContext<'_>, + expr: &hir::Expr<'_>, + method_span: Span, + method_name: Symbol, + args: &[hir::Expr<'_>], +) { + let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0]); + if_chain! { + if let ty::Ref(..) = self_ty.kind(); + if method_name == sym::into_iter; + if is_trait_method(cx, expr, sym::IntoIterator); + if let Some((kind, method_name)) = ty_has_iter_method(cx, self_ty); + then { + span_lint_and_sugg( + cx, + INTO_ITER_ON_REF, + method_span, + &format!( + "this `.into_iter()` call is equivalent to `.{}()` and will not consume the `{}`", + method_name, kind, + ), + "call directly", + method_name.to_string(), + Applicability::MachineApplicable, + ); + } } } diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs b/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs index c3e48ffa5fa..848f47e39f6 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs @@ -1,5 +1,6 @@ -use crate::methods::derefs_to_slice; -use crate::utils::{is_type_diagnostic_item, span_lint_and_sugg}; +use crate::methods::utils::derefs_to_slice; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_count.rs b/src/tools/clippy/clippy_lints/src/methods/iter_count.rs index 869440e0165..e394a8fe819 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_count.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_count.rs @@ -1,6 +1,8 @@ -use crate::methods::derefs_to_slice; -use crate::utils::{is_type_diagnostic_item, match_type, paths, snippet_with_applicability, span_lint_and_sugg}; - +use super::utils::derefs_to_slice; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::paths; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::{is_type_diagnostic_item, match_type}; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs b/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs index 3c03a949cfe..e9b37b6f2bd 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs @@ -1,5 +1,8 @@ -use crate::methods::derefs_to_slice; -use crate::utils::{get_parent_expr, higher, is_type_diagnostic_item, snippet_with_applicability, span_lint_and_sugg}; +use super::utils::derefs_to_slice; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{get_parent_expr, higher}; use if_chain::if_chain; use rustc_ast::ast; use rustc_errors::Applicability; @@ -44,12 +47,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, ite ); } } - } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(caller_expr), sym::vec_type) - || matches!( - &cx.typeck_results().expr_ty(caller_expr).peel_refs().kind(), - ty::Array(_, _) - ) - { + } else if is_vec_or_array(cx, caller_expr) { // caller is a Vec or an Array let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( @@ -66,3 +64,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, ite ); } } + +fn is_vec_or_array<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) -> bool { + is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::vec_type) + || matches!(&cx.typeck_results().expr_ty(expr).peel_refs().kind(), ty::Array(_, _)) +} diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs b/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs index cc3e56ea872..c46af427b3c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs @@ -1,6 +1,7 @@ -use crate::methods::derefs_to_slice; +use super::utils::derefs_to_slice; use crate::methods::iter_nth_zero; -use crate::utils::{is_type_diagnostic_item, span_lint_and_help}; +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::ty::is_type_diagnostic_item; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::symbol::sym; diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs b/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs index 247192d81f3..a12f672739c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs @@ -1,15 +1,18 @@ use crate::consts::{constant, Constant}; -use crate::utils::{match_trait_method, paths, snippet_with_applicability, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_trait_method; +use clippy_utils::source::snippet_with_applicability; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; +use rustc_span::sym; use super::ITER_NTH_ZERO; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, nth_args: &'tcx [hir::Expr<'_>]) { if_chain! { - if match_trait_method(cx, expr, &paths::ITERATOR); + if is_trait_method(cx, expr, sym::Iterator); if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), &nth_args[1]); then { let mut applicability = Applicability::MachineApplicable; diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs b/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs index 5f5969134e4..b1d398876d3 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs @@ -1,22 +1,24 @@ -use crate::utils::{match_trait_method, paths, snippet, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_trait_method; +use clippy_utils::source::snippet; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; +use rustc_span::sym; use super::ITER_SKIP_NEXT; pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, skip_args: &[hir::Expr<'_>]) { // lint if caller of skip is an Iterator - if match_trait_method(cx, expr, &paths::ITERATOR) { + if is_trait_method(cx, expr, sym::Iterator) { if let [caller, n] = skip_args { - let hint = format!(".nth({})", snippet(cx, n.span, "..")); span_lint_and_sugg( cx, ITER_SKIP_NEXT, expr.span.trim_start(caller.span).unwrap(), "called `skip(..).next()` on an iterator", "use `nth` instead", - hint, + format!(".nth({})", snippet(cx, n.span, "..")), Applicability::MachineApplicable, ); } diff --git a/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs b/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs index 3e05d7f76b7..3baa580314f 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs @@ -1,12 +1,14 @@ use crate::consts::{constant, Constant}; -use crate::utils::{match_trait_method, paths, span_lint}; +use clippy_utils::diagnostics::span_lint; +use clippy_utils::is_trait_method; use rustc_hir as hir; use rustc_lint::LateContext; +use rustc_span::sym; use super::ITERATOR_STEP_BY_ZERO; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, args: &'tcx [hir::Expr<'_>]) { - if match_trait_method(cx, expr, &paths::ITERATOR) { + if is_trait_method(cx, expr, sym::Iterator) { if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), &args[1]) { span_lint( cx, diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs index 0b414e0eb95..f16699322d1 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs @@ -1,4 +1,6 @@ -use crate::utils::{match_qpath, snippet_with_applicability, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::match_qpath; +use clippy_utils::source::snippet_with_applicability; use if_chain::if_chain; use rustc_ast::ast; use rustc_errors::Applicability; diff --git a/src/tools/clippy/clippy_lints/src/methods/map_collect_result_unit.rs b/src/tools/clippy/clippy_lints/src/methods/map_collect_result_unit.rs index 5b20e268d9f..e4402b2da21 100644 --- a/src/tools/clippy/clippy_lints/src/methods/map_collect_result_unit.rs +++ b/src/tools/clippy/clippy_lints/src/methods/map_collect_result_unit.rs @@ -1,4 +1,7 @@ -use crate::utils::{is_type_diagnostic_item, match_trait_method, paths, snippet, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_trait_method; +use clippy_utils::source::snippet; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; @@ -17,7 +20,7 @@ pub(super) fn check( if_chain! { // called on Iterator if let [map_expr] = collect_args; - if match_trait_method(cx, map_expr, &paths::ITERATOR); + if is_trait_method(cx, map_expr, sym::Iterator); // return of collect `Result<(),_>` let collect_ret_ty = cx.typeck_results().expr_ty(expr); if is_type_diagnostic_item(cx, collect_ret_ty, sym::result_type); diff --git a/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs b/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs index 14a14e4f9ec..4bc52b036a8 100644 --- a/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs +++ b/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs @@ -1,4 +1,7 @@ -use crate::utils::{is_type_diagnostic_item, match_trait_method, paths, snippet, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_trait_method; +use clippy_utils::source::snippet; +use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -10,7 +13,7 @@ use super::MAP_FLATTEN; /// lint use of `map().flatten()` for `Iterators` and 'Options' pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map_args: &'tcx [hir::Expr<'_>]) { // lint if caller of `.map().flatten()` is an Iterator - if match_trait_method(cx, expr, &paths::ITERATOR) { + if is_trait_method(cx, expr, sym::Iterator) { let map_closure_ty = cx.typeck_results().expr_ty(&map_args[1]); let is_map_to_option = match map_closure_ty.kind() { ty::Closure(_, _) | ty::FnDef(_, _) | ty::FnPtr(_) => { diff --git a/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs index 63b2cf87f32..deb4b4492b5 100644 --- a/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs +++ b/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs @@ -1,5 +1,8 @@ -use crate::utils::usage::mutated_variables; -use crate::utils::{is_type_diagnostic_item, meets_msrv, snippet, span_lint, span_lint_and_sugg}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; +use clippy_utils::meets_msrv; +use clippy_utils::source::snippet; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::usage::mutated_variables; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index 7fd14c4f9b1..fccdee07877 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -1,5 +1,11 @@ mod bind_instead_of_map; mod bytes_nth; +mod chars_cmp; +mod chars_cmp_with_unwrap; +mod chars_last_cmp; +mod chars_last_cmp_with_unwrap; +mod chars_next_cmp; +mod chars_next_cmp_with_unwrap; mod clone_on_copy; mod clone_on_ref_ptr; mod expect_fun_call; @@ -36,6 +42,7 @@ mod option_map_or_none; mod option_map_unwrap_or; mod or_fun_call; mod search_is_some; +mod single_char_add_str; mod single_char_insert_string; mod single_char_pattern; mod single_char_push_string; @@ -48,16 +55,19 @@ mod unnecessary_fold; mod unnecessary_lazy_eval; mod unwrap_used; mod useless_asref; +mod utils; mod wrong_self_convention; mod zst_offset; use bind_instead_of_map::BindInsteadOfMap; +use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; +use clippy_utils::ty::{contains_adt_constructor, contains_ty, implements_trait, is_copy, is_type_diagnostic_item}; +use clippy_utils::{contains_return, get_trait_def_id, in_macro, iter_input_pats, method_calls, paths, return_ty}; use if_chain::if_chain; -use rustc_ast::ast; -use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::{TraitItem, TraitItemKind}; -use rustc_lint::{LateContext, LateLintPass, Lint, LintContext}; +use rustc_hir::def::Res; +use rustc_hir::{PrimTy, QPath, TraitItem, TraitItemKind}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, TraitRef, Ty, TyS}; use rustc_semver::RustcVersion; @@ -65,12 +75,6 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::symbol::{sym, SymbolStr}; use rustc_typeck::hir_ty_to_ty; -use crate::utils::{ - contains_return, contains_ty, get_trait_def_id, implements_trait, in_macro, is_copy, is_type_diagnostic_item, - iter_input_pats, match_def_path, match_qpath, method_calls, method_chain_args, paths, return_ty, - single_segment_path, snippet_with_applicability, span_lint, span_lint_and_help, span_lint_and_sugg, SpanlessEq, -}; - declare_clippy_lint! { /// **What it does:** Checks for `.unwrap()` calls on `Option`s and on `Result`s. /// @@ -191,13 +195,18 @@ declare_clippy_lint! { /// **What it does:** Checks for methods with certain name prefixes and which /// doesn't match how self is taken. The actual rules are: /// - /// |Prefix |`self` taken | - /// |-------|----------------------| - /// |`as_` |`&self` or `&mut self`| - /// |`from_`| none | - /// |`into_`|`self` | - /// |`is_` |`&self` or none | - /// |`to_` |`&self` | + /// |Prefix |Postfix |`self` taken | `self` type | + /// |-------|------------|-----------------------|--------------| + /// |`as_` | none |`&self` or `&mut self` | any | + /// |`from_`| none | none | any | + /// |`into_`| none |`self` | any | + /// |`is_` | none |`&self` or none | any | + /// |`to_` | `_mut` |`&mut self` | any | + /// |`to_` | not `_mut` |`self` | `Copy` | + /// |`to_` | not `_mut` |`&self` | not `Copy` | + /// + /// Please find more info here: + /// https://rust-lang.github.io/api-guidelines/naming.html#ad-hoc-conversions-follow-as_-to_-into_-conventions-c-conv /// /// **Why is this bad?** Consistency breeds readability. If you follow the /// conventions, your users won't be surprised that they, e.g., need to supply a @@ -582,26 +591,31 @@ declare_clippy_lint! { declare_clippy_lint! { /// **What it does:** Checks for an iterator or string search (such as `find()`, - /// `position()`, or `rposition()`) followed by a call to `is_some()`. + /// `position()`, or `rposition()`) followed by a call to `is_some()` or `is_none()`. /// - /// **Why is this bad?** Readability, this can be written more concisely as - /// `_.any(_)` or `_.contains(_)`. + /// **Why is this bad?** Readability, this can be written more concisely as: + /// * `_.any(_)`, or `_.contains(_)` for `is_some()`, + /// * `!_.any(_)`, or `!_.contains(_)` for `is_none()`. /// /// **Known problems:** None. /// /// **Example:** /// ```rust - /// # let vec = vec![1]; + /// let vec = vec![1]; /// vec.iter().find(|x| **x == 0).is_some(); + /// + /// let _ = "hello world".find("world").is_none(); /// ``` /// Could be written as /// ```rust - /// # let vec = vec![1]; + /// let vec = vec![1]; /// vec.iter().any(|x| *x == 0); + /// + /// let _ = !"hello world".contains("world"); /// ``` pub SEARCH_IS_SOME, complexity, - "using an iterator or string search followed by `is_some()`, which is more succinctly expressed as a call to `any()` or `contains()`" + "using an iterator or string search followed by `is_some()` or `is_none()`, which is more succinctly expressed as a call to `any()` or `contains()` (with negation in case of `is_none()`)" } declare_clippy_lint! { @@ -1707,19 +1721,49 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["next", "skip_while"] => skip_while_next::check(cx, expr, arg_lists[1]), ["next", "iter"] => iter_next_slice::check(cx, expr, arg_lists[1]), ["map", "filter"] => filter_map::check(cx, expr, false), - ["map", "filter_map"] => filter_map_map::check(cx, expr, arg_lists[1], arg_lists[0]), + ["map", "filter_map"] => filter_map_map::check(cx, expr), ["next", "filter_map"] => filter_map_next::check(cx, expr, arg_lists[1], self.msrv.as_ref()), ["map", "find"] => filter_map::check(cx, expr, true), - ["flat_map", "filter"] => filter_flat_map::check(cx, expr, arg_lists[1], arg_lists[0]), - ["flat_map", "filter_map"] => filter_map_flat_map::check(cx, expr, arg_lists[1], arg_lists[0]), + ["flat_map", "filter"] => filter_flat_map::check(cx, expr), + ["flat_map", "filter_map"] => filter_map_flat_map::check(cx, expr), ["flat_map", ..] => flat_map_identity::check(cx, expr, arg_lists[0], method_spans[0]), ["flatten", "map"] => map_flatten::check(cx, expr, arg_lists[1]), - ["is_some", "find"] => search_is_some::check(cx, expr, "find", arg_lists[1], arg_lists[0], method_spans[1]), - ["is_some", "position"] => { - search_is_some::check(cx, expr, "position", arg_lists[1], arg_lists[0], method_spans[1]) + [option_check_method, "find"] if "is_some" == *option_check_method || "is_none" == *option_check_method => { + search_is_some::check( + cx, + expr, + "find", + option_check_method, + arg_lists[1], + arg_lists[0], + method_spans[1], + ) }, - ["is_some", "rposition"] => { - search_is_some::check(cx, expr, "rposition", arg_lists[1], arg_lists[0], method_spans[1]) + [option_check_method, "position"] + if "is_some" == *option_check_method || "is_none" == *option_check_method => + { + search_is_some::check( + cx, + expr, + "position", + option_check_method, + arg_lists[1], + arg_lists[0], + method_spans[1], + ) + }, + [option_check_method, "rposition"] + if "is_some" == *option_check_method || "is_none" == *option_check_method => + { + search_is_some::check( + cx, + expr, + "rposition", + option_check_method, + arg_lists[1], + arg_lists[0], + method_spans[1], + ) }, ["extend", ..] => string_extend_chars::check(cx, expr, arg_lists[0]), ["count", "into_iter"] => iter_count::check(cx, expr, &arg_lists[1], "into_iter"), @@ -1739,7 +1783,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { unnecessary_filter_map::check(cx, expr, arg_lists[0]); filter_map_identity::check(cx, expr, arg_lists[0], method_spans[0]); }, - ["count", "map"] => suspicious_map::check(cx, expr), + ["count", "map"] => suspicious_map::check(cx, expr, arg_lists[1], arg_lists[0]), ["assume_init"] => uninit_assumed_init::check(cx, &arg_lists[0][0], expr), ["unwrap_or", arith @ ("checked_add" | "checked_sub" | "checked_mul")] => { manual_saturating_arithmetic::check(cx, expr, &arg_lists, &arith["checked_".len()..]) @@ -1768,46 +1812,17 @@ impl<'tcx> LateLintPass<'tcx> for Methods { match expr.kind { hir::ExprKind::Call(ref func, ref args) => { - if let hir::ExprKind::Path(path) = &func.kind { - if match_qpath(path, &["from_iter"]) { - from_iter_instead_of_collect::check(cx, expr, args); - } - } + from_iter_instead_of_collect::check(cx, expr, args, &func.kind); }, hir::ExprKind::MethodCall(ref method_call, ref method_span, ref args, _) => { or_fun_call::check(cx, expr, *method_span, &method_call.ident.as_str(), args); expect_fun_call::check(cx, expr, *method_span, &method_call.ident.as_str(), args); - - let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0]); - if args.len() == 1 && method_call.ident.name == sym::clone { - clone_on_copy::check(cx, expr, &args[0], self_ty); - clone_on_ref_ptr::check(cx, expr, &args[0]); - } - if args.len() == 1 && method_call.ident.name == sym!(to_string) { - inefficient_to_string::check(cx, expr, &args[0], self_ty); - } - - if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) { - if match_def_path(cx, fn_def_id, &paths::PUSH_STR) { - single_char_push_string::check(cx, expr, args); - } else if match_def_path(cx, fn_def_id, &paths::INSERT_STR) { - single_char_insert_string::check(cx, expr, args); - } - } - - match self_ty.kind() { - ty::Ref(_, ty, _) if *ty.kind() == ty::Str => { - for &(method, pos) in &PATTERN_METHODS { - if method_call.ident.name.as_str() == method && args.len() > pos { - single_char_pattern::check(cx, expr, &args[pos]); - } - } - }, - ty::Ref(..) if method_call.ident.name == sym::into_iter => { - into_iter_on_ref::check(cx, expr, self_ty, *method_span); - }, - _ => (), - } + clone_on_copy::check(cx, expr, method_call.ident.name, args); + clone_on_ref_ptr::check(cx, expr, method_call.ident.name, args); + inefficient_to_string::check(cx, expr, method_call.ident.name, args); + single_char_add_str::check(cx, expr, args); + into_iter_on_ref::check(cx, expr, *method_span, method_call.ident.name, args); + single_char_pattern::check(cx, expr, method_call.ident.name, args); }, hir::ExprKind::Binary(op, ref lhs, ref rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => @@ -1834,10 +1849,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { let item = cx.tcx.hir().expect_item(parent); let self_ty = cx.tcx.type_of(item.def_id); - // if this impl block implements a trait, lint in trait definition instead - if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) = item.kind { - return; - } + let implements_trait = matches!(item.kind, hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. })); if_chain! { if let hir::ImplItemKind::Fn(ref sig, id) = impl_item.kind; @@ -1852,12 +1864,13 @@ impl<'tcx> LateLintPass<'tcx> for Methods { if let Some(first_arg_ty) = first_arg_ty; then { - if cx.access_levels.is_exported(impl_item.hir_id()) { + // if this impl block implements a trait, lint in trait definition instead + if !implements_trait && cx.access_levels.is_exported(impl_item.hir_id()) { // check missing trait implementations for method_config in &TRAIT_METHODS { if name == method_config.method_name && sig.decl.inputs.len() == method_config.param_count && - method_config.output_type.matches(cx, &sig.decl.output) && + method_config.output_type.matches(&sig.decl.output) && method_config.self_kind.matches(cx, self_ty, first_arg_ty) && fn_header_equals(method_config.fn_header, sig.header) && method_config.lifetime_param_cond(&impl_item) @@ -1888,16 +1901,26 @@ impl<'tcx> LateLintPass<'tcx> for Methods { item.vis.node.is_pub(), self_ty, first_arg_ty, - first_arg.pat.span + first_arg.pat.span, + false ); } } + // if this impl block implements a trait, lint in trait definition instead + if implements_trait { + return; + } + if let hir::ImplItemKind::Fn(_, _) = impl_item.kind { let ret_ty = return_ty(cx, impl_item.hir_id()); // walk the return type and check for Self (this does not check associated types) - if contains_ty(ret_ty, self_ty) { + if let Some(self_adt) = self_ty.ty_adt_def() { + if contains_adt_constructor(ret_ty, self_adt) { + return; + } + } else if contains_ty(ret_ty, self_ty) { return; } @@ -1907,7 +1930,11 @@ impl<'tcx> LateLintPass<'tcx> for Methods { for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) { if let ty::PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder() { // walk the associated type and check for Self - if contains_ty(projection_predicate.ty, self_ty) { + if let Some(self_adt) = self_ty.ty_adt_def() { + if contains_adt_constructor(projection_predicate.ty, self_adt) { + return; + } + } else if contains_ty(projection_predicate.ty, self_ty) { return; } } @@ -1944,7 +1971,8 @@ impl<'tcx> LateLintPass<'tcx> for Methods { false, self_ty, first_arg_ty, - first_arg_span + first_arg_span, + true ); } } @@ -1969,47 +1997,6 @@ impl<'tcx> LateLintPass<'tcx> for Methods { extract_msrv_attr!(LateContext); } - -fn derefs_to_slice<'tcx>( - cx: &LateContext<'tcx>, - expr: &'tcx hir::Expr<'tcx>, - ty: Ty<'tcx>, -) -> Option<&'tcx hir::Expr<'tcx>> { - fn may_slice<'a>(cx: &LateContext<'a>, ty: Ty<'a>) -> bool { - match ty.kind() { - ty::Slice(_) => true, - ty::Adt(def, _) if def.is_box() => may_slice(cx, ty.boxed_ty()), - ty::Adt(..) => is_type_diagnostic_item(cx, ty, sym::vec_type), - ty::Array(_, size) => size - .try_eval_usize(cx.tcx, cx.param_env) - .map_or(false, |size| size < 32), - ty::Ref(_, inner, _) => may_slice(cx, inner), - _ => false, - } - } - - if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind { - if path.ident.name == sym::iter && may_slice(cx, cx.typeck_results().expr_ty(&args[0])) { - Some(&args[0]) - } else { - None - } - } else { - match ty.kind() { - ty::Slice(_) => Some(expr), - ty::Adt(def, _) if def.is_box() && may_slice(cx, ty.boxed_ty()) => Some(expr), - ty::Ref(_, inner, _) => { - if may_slice(cx, inner) { - Some(expr) - } else { - None - } - }, - _ => None, - } - } -} - /// Used for `lint_binary_expr_with_method_call`. #[derive(Copy, Clone)] struct BinaryExprInfo<'a> { @@ -2022,7 +2009,7 @@ struct BinaryExprInfo<'a> { /// Checks for the `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints. fn lint_binary_expr_with_method_call(cx: &LateContext<'_>, info: &mut BinaryExprInfo<'_>) { macro_rules! lint_with_both_lhs_and_rhs { - ($func:ident, $cx:expr, $info:ident) => { + ($func:expr, $cx:expr, $info:ident) => { if !$func($cx, $info) { ::std::mem::swap(&mut $info.chain, &mut $info.other); if $func($cx, $info) { @@ -2032,145 +2019,10 @@ fn lint_binary_expr_with_method_call(cx: &LateContext<'_>, info: &mut BinaryExpr }; } - lint_with_both_lhs_and_rhs!(lint_chars_next_cmp, cx, info); - lint_with_both_lhs_and_rhs!(lint_chars_last_cmp, cx, info); - lint_with_both_lhs_and_rhs!(lint_chars_next_cmp_with_unwrap, cx, info); - lint_with_both_lhs_and_rhs!(lint_chars_last_cmp_with_unwrap, cx, info); -} - -/// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints. -fn lint_chars_cmp( - cx: &LateContext<'_>, - info: &BinaryExprInfo<'_>, - chain_methods: &[&str], - lint: &'static Lint, - suggest: &str, -) -> bool { - if_chain! { - if let Some(args) = method_chain_args(info.chain, chain_methods); - if let hir::ExprKind::Call(ref fun, ref arg_char) = info.other.kind; - if arg_char.len() == 1; - if let hir::ExprKind::Path(ref qpath) = fun.kind; - if let Some(segment) = single_segment_path(qpath); - if segment.ident.name == sym::Some; - then { - let mut applicability = Applicability::MachineApplicable; - let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0][0]).peel_refs(); - - if *self_ty.kind() != ty::Str { - return false; - } - - span_lint_and_sugg( - cx, - lint, - info.expr.span, - &format!("you should use the `{}` method", suggest), - "like this", - format!("{}{}.{}({})", - if info.eq { "" } else { "!" }, - snippet_with_applicability(cx, args[0][0].span, "..", &mut applicability), - suggest, - snippet_with_applicability(cx, arg_char[0].span, "..", &mut applicability)), - applicability, - ); - - return true; - } - } - - false -} - -/// Checks for the `CHARS_NEXT_CMP` lint. -fn lint_chars_next_cmp<'tcx>(cx: &LateContext<'tcx>, info: &BinaryExprInfo<'_>) -> bool { - lint_chars_cmp(cx, info, &["chars", "next"], CHARS_NEXT_CMP, "starts_with") -} - -/// Checks for the `CHARS_LAST_CMP` lint. -fn lint_chars_last_cmp<'tcx>(cx: &LateContext<'tcx>, info: &BinaryExprInfo<'_>) -> bool { - if lint_chars_cmp(cx, info, &["chars", "last"], CHARS_LAST_CMP, "ends_with") { - true - } else { - lint_chars_cmp(cx, info, &["chars", "next_back"], CHARS_LAST_CMP, "ends_with") - } -} - -/// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints with `unwrap()`. -fn lint_chars_cmp_with_unwrap<'tcx>( - cx: &LateContext<'tcx>, - info: &BinaryExprInfo<'_>, - chain_methods: &[&str], - lint: &'static Lint, - suggest: &str, -) -> bool { - if_chain! { - if let Some(args) = method_chain_args(info.chain, chain_methods); - if let hir::ExprKind::Lit(ref lit) = info.other.kind; - if let ast::LitKind::Char(c) = lit.node; - then { - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - lint, - info.expr.span, - &format!("you should use the `{}` method", suggest), - "like this", - format!("{}{}.{}('{}')", - if info.eq { "" } else { "!" }, - snippet_with_applicability(cx, args[0][0].span, "..", &mut applicability), - suggest, - c), - applicability, - ); - - true - } else { - false - } - } -} - -/// Checks for the `CHARS_NEXT_CMP` lint with `unwrap()`. -fn lint_chars_next_cmp_with_unwrap<'tcx>(cx: &LateContext<'tcx>, info: &BinaryExprInfo<'_>) -> bool { - lint_chars_cmp_with_unwrap(cx, info, &["chars", "next", "unwrap"], CHARS_NEXT_CMP, "starts_with") -} - -/// Checks for the `CHARS_LAST_CMP` lint with `unwrap()`. -fn lint_chars_last_cmp_with_unwrap<'tcx>(cx: &LateContext<'tcx>, info: &BinaryExprInfo<'_>) -> bool { - if lint_chars_cmp_with_unwrap(cx, info, &["chars", "last", "unwrap"], CHARS_LAST_CMP, "ends_with") { - true - } else { - lint_chars_cmp_with_unwrap(cx, info, &["chars", "next_back", "unwrap"], CHARS_LAST_CMP, "ends_with") - } -} - -fn get_hint_if_single_char_arg( - cx: &LateContext<'_>, - arg: &hir::Expr<'_>, - applicability: &mut Applicability, -) -> Option<String> { - if_chain! { - if let hir::ExprKind::Lit(lit) = &arg.kind; - if let ast::LitKind::Str(r, style) = lit.node; - let string = r.as_str(); - if string.chars().count() == 1; - then { - let snip = snippet_with_applicability(cx, arg.span, &string, applicability); - let ch = if let ast::StrStyle::Raw(nhash) = style { - let nhash = nhash as usize; - // for raw string: r##"a"## - &snip[(nhash + 2)..(snip.len() - 1 - nhash)] - } else { - // for regular string: "a" - &snip[1..(snip.len() - 1)] - }; - let hint = format!("'{}'", if ch == "'" { "\\'" } else { ch }); - Some(hint) - } else { - None - } - } + lint_with_both_lhs_and_rhs!(chars_next_cmp::check, cx, info); + lint_with_both_lhs_and_rhs!(chars_last_cmp::check, cx, info); + lint_with_both_lhs_and_rhs!(chars_next_cmp_with_unwrap::check, cx, info); + lint_with_both_lhs_and_rhs!(chars_last_cmp_with_unwrap::check, cx, info); } const FN_HEADER: hir::FnHeader = hir::FnHeader { @@ -2336,10 +2188,10 @@ impl SelfKind { #[must_use] fn description(self) -> &'static str { match self { - Self::Value => "self by value", - Self::Ref => "self by reference", - Self::RefMut => "self by mutable reference", - Self::No => "no self", + Self::Value => "`self` by value", + Self::Ref => "`self` by reference", + Self::RefMut => "`self` by mutable reference", + Self::No => "no `self`", } } } @@ -2353,8 +2205,8 @@ enum OutType { } impl OutType { - fn matches(self, cx: &LateContext<'_>, ty: &hir::FnRetTy<'_>) -> bool { - let is_unit = |ty: &hir::Ty<'_>| SpanlessEq::new(cx).eq_ty_kind(&ty.kind, &hir::TyKind::Tup(&[])); + fn matches(self, ty: &hir::FnRetTy<'_>) -> bool { + let is_unit = |ty: &hir::Ty<'_>| matches!(ty.kind, hir::TyKind::Tup(&[])); match (self, ty) { (Self::Unit, &hir::FnRetTy::DefaultReturn(_)) => true, (Self::Unit, &hir::FnRetTy::Return(ref ty)) if is_unit(ty) => true, @@ -2367,8 +2219,8 @@ impl OutType { } fn is_bool(ty: &hir::Ty<'_>) -> bool { - if let hir::TyKind::Path(ref p) = ty.kind { - match_qpath(p, &["bool"]) + if let hir::TyKind::Path(QPath::Resolved(_, path)) = ty.kind { + matches!(path.res, Res::PrimTy(PrimTy::Bool)) } else { false } diff --git a/src/tools/clippy/clippy_lints/src/methods/ok_expect.rs b/src/tools/clippy/clippy_lints/src/methods/ok_expect.rs index c1706cc7cc7..e6ce9cac397 100644 --- a/src/tools/clippy/clippy_lints/src/methods/ok_expect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/ok_expect.rs @@ -1,4 +1,5 @@ -use crate::utils::{implements_trait, is_type_diagnostic_item, span_lint_and_help}; +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs index 89067dbfe0e..d11ede080dc 100644 --- a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs +++ b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs @@ -1,7 +1,7 @@ -use crate::utils::{ - is_type_diagnostic_item, match_def_path, meets_msrv, path_to_local_id, paths, remove_blocks, snippet, - span_lint_and_sugg, -}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{match_def_path, meets_msrv, path_to_local_id, paths, remove_blocks}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs b/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs index 64f6ebc5062..d93db2c22e4 100644 --- a/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs +++ b/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs @@ -1,4 +1,7 @@ -use crate::utils::{is_type_diagnostic_item, match_qpath, paths, snippet, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{match_qpath, paths}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs index 7cdd49bbf03..e252abc177a 100644 --- a/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -1,5 +1,8 @@ -use crate::utils::{differing_macro_contexts, snippet_with_applicability, span_lint_and_then}; -use crate::utils::{is_copy, is_type_diagnostic_item}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::differing_macro_contexts; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::is_copy; +use clippy_utils::ty::is_type_diagnostic_item; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_path, NestedVisitorMap, Visitor}; diff --git a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs index 5f7fc431d22..89dedc5f0d8 100644 --- a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs +++ b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs @@ -1,11 +1,12 @@ -use crate::utils::eager_or_lazy::is_lazyness_candidate; -use crate::utils::{ - contains_return, get_trait_def_id, implements_trait, is_type_diagnostic_item, last_path_segment, match_type, paths, - snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint_and_sugg, -}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::eager_or_lazy::is_lazyness_candidate; +use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_macro_callsite}; +use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, match_type}; +use clippy_utils::{contains_return, get_trait_def_id, last_path_segment, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; +use rustc_hir::{BlockCheckMode, UnsafeSource}; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_span::source_map::Span; @@ -90,7 +91,7 @@ pub(super) fn check<'tcx>( let ty = cx.typeck_results().expr_ty(&args[0]).peel_refs(); match ty.kind() { - ty::Slice(_) | ty::Array(_, _) => return, + ty::Slice(_) | ty::Array(_, _) | ty::Str => return, _ => (), } @@ -167,7 +168,16 @@ pub(super) fn check<'tcx>( hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => { check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, None); }, - _ => {}, + hir::ExprKind::Block(block, _) => { + if let BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) = block.rules { + if let Some(block_expr) = block.expr { + if let hir::ExprKind::MethodCall(..) = block_expr.kind { + check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, None); + } + } + } + }, + _ => (), } } } diff --git a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs index e9e65443220..de7d168295f 100644 --- a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs +++ b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs @@ -1,7 +1,7 @@ -use crate::utils::{ - is_type_diagnostic_item, match_trait_method, paths, snippet, snippet_with_applicability, span_lint_and_help, - span_lint_and_sugg, strip_pat_refs, -}; +use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; +use clippy_utils::source::{snippet, snippet_with_applicability}; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{is_trait_method, strip_pat_refs}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; @@ -14,22 +14,23 @@ use rustc_span::symbol::sym; use super::SEARCH_IS_SOME; /// lint searching an Iterator followed by `is_some()` -/// or calling `find()` on a string followed by `is_some()` +/// or calling `find()` on a string followed by `is_some()` or `is_none()` +#[allow(clippy::too_many_lines)] pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, search_method: &str, + option_check_method: &str, search_args: &'tcx [hir::Expr<'_>], is_some_args: &'tcx [hir::Expr<'_>], method_span: Span, ) { // lint if caller of search is an Iterator - if match_trait_method(cx, &is_some_args[0], &paths::ITERATOR) { + if is_trait_method(cx, &is_some_args[0], sym::Iterator) { let msg = format!( - "called `is_some()` after searching an `Iterator` with `{}`", - search_method + "called `{}()` after searching an `Iterator` with `{}`", + option_check_method, search_method ); - let hint = "this is more succinctly expressed by calling `any()`"; let search_snippet = snippet(cx, search_args[1].span, ".."); if search_snippet.lines().count() <= 1 { // suggest `any(|x| ..)` instead of `any(|&x| ..)` for `find(|&x| ..).is_some()` @@ -53,20 +54,49 @@ pub(super) fn check<'tcx>( } }; // add note if not multi-line - span_lint_and_sugg( - cx, - SEARCH_IS_SOME, - method_span.with_hi(expr.span.hi()), - &msg, - "use `any()` instead", - format!( - "any({})", - any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str) - ), - Applicability::MachineApplicable, - ); + match option_check_method { + "is_some" => { + span_lint_and_sugg( + cx, + SEARCH_IS_SOME, + method_span.with_hi(expr.span.hi()), + &msg, + "use `any()` instead", + format!( + "any({})", + any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str) + ), + Applicability::MachineApplicable, + ); + }, + "is_none" => { + let iter = snippet(cx, search_args[0].span, ".."); + span_lint_and_sugg( + cx, + SEARCH_IS_SOME, + expr.span, + &msg, + "use `!_.any()` instead", + format!( + "!{}.any({})", + iter, + any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str) + ), + Applicability::MachineApplicable, + ); + }, + _ => (), + } } else { - span_lint_and_help(cx, SEARCH_IS_SOME, expr.span, &msg, None, hint); + let hint = format!( + "this is more succinctly expressed by calling `any()`{}", + if option_check_method == "is_none" { + " with negation" + } else { + "" + } + ); + span_lint_and_help(cx, SEARCH_IS_SOME, expr.span, &msg, None, &hint); } } // lint if `find()` is called by `String` or `&str` @@ -83,18 +113,37 @@ pub(super) fn check<'tcx>( if is_string_or_str_slice(&search_args[0]); if is_string_or_str_slice(&search_args[1]); then { - let msg = "called `is_some()` after calling `find()` on a string"; - let mut applicability = Applicability::MachineApplicable; - let find_arg = snippet_with_applicability(cx, search_args[1].span, "..", &mut applicability); - span_lint_and_sugg( - cx, - SEARCH_IS_SOME, - method_span.with_hi(expr.span.hi()), - msg, - "use `contains()` instead", - format!("contains({})", find_arg), - applicability, - ); + let msg = format!("called `{}()` after calling `find()` on a string", option_check_method); + match option_check_method { + "is_some" => { + let mut applicability = Applicability::MachineApplicable; + let find_arg = snippet_with_applicability(cx, search_args[1].span, "..", &mut applicability); + span_lint_and_sugg( + cx, + SEARCH_IS_SOME, + method_span.with_hi(expr.span.hi()), + &msg, + "use `contains()` instead", + format!("contains({})", find_arg), + applicability, + ); + }, + "is_none" => { + let string = snippet(cx, search_args[0].span, ".."); + let mut applicability = Applicability::MachineApplicable; + let find_arg = snippet_with_applicability(cx, search_args[1].span, "..", &mut applicability); + span_lint_and_sugg( + cx, + SEARCH_IS_SOME, + expr.span, + &msg, + "use `!_.contains()` instead", + format!("!{}.contains({})", string, find_arg), + applicability, + ); + }, + _ => (), + } } } } diff --git a/src/tools/clippy/clippy_lints/src/methods/single_char_add_str.rs b/src/tools/clippy/clippy_lints/src/methods/single_char_add_str.rs new file mode 100644 index 00000000000..9a5fabcf7cd --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/methods/single_char_add_str.rs @@ -0,0 +1,14 @@ +use crate::methods::{single_char_insert_string, single_char_push_string}; +use clippy_utils::{match_def_path, paths}; +use rustc_hir as hir; +use rustc_lint::LateContext; + +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { + if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) { + if match_def_path(cx, fn_def_id, &paths::PUSH_STR) { + single_char_push_string::check(cx, expr, args); + } else if match_def_path(cx, fn_def_id, &paths::INSERT_STR) { + single_char_insert_string::check(cx, expr, args); + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/methods/single_char_insert_string.rs b/src/tools/clippy/clippy_lints/src/methods/single_char_insert_string.rs index 0ce8b66978d..6cdc954c03b 100644 --- a/src/tools/clippy/clippy_lints/src/methods/single_char_insert_string.rs +++ b/src/tools/clippy/clippy_lints/src/methods/single_char_insert_string.rs @@ -1,5 +1,6 @@ -use crate::methods::get_hint_if_single_char_arg; -use crate::utils::{snippet_with_applicability, span_lint_and_sugg}; +use super::utils::get_hint_if_single_char_arg; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs b/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs index 61cbc9d2f0a..f4090c7c617 100644 --- a/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs +++ b/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs @@ -1,23 +1,35 @@ -use crate::methods::get_hint_if_single_char_arg; -use crate::utils::span_lint_and_sugg; +use super::utils::get_hint_if_single_char_arg; +use clippy_utils::diagnostics::span_lint_and_sugg; +use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; +use rustc_middle::ty; +use rustc_span::symbol::Symbol; use super::SINGLE_CHAR_PATTERN; /// lint for length-1 `str`s for methods in `PATTERN_METHODS` -pub(super) fn check(cx: &LateContext<'_>, _expr: &hir::Expr<'_>, arg: &hir::Expr<'_>) { - let mut applicability = Applicability::MachineApplicable; - if let Some(hint) = get_hint_if_single_char_arg(cx, arg, &mut applicability) { - span_lint_and_sugg( - cx, - SINGLE_CHAR_PATTERN, - arg.span, - "single-character string constant used as pattern", - "try using a `char` instead", - hint, - applicability, - ); +pub(super) fn check(cx: &LateContext<'_>, _expr: &hir::Expr<'_>, method_name: Symbol, args: &[hir::Expr<'_>]) { + for &(method, pos) in &crate::methods::PATTERN_METHODS { + if_chain! { + if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(&args[0]).kind(); + if *ty.kind() == ty::Str; + if method_name.as_str() == method && args.len() > pos; + let arg = &args[pos]; + let mut applicability = Applicability::MachineApplicable; + if let Some(hint) = get_hint_if_single_char_arg(cx, arg, &mut applicability); + then { + span_lint_and_sugg( + cx, + SINGLE_CHAR_PATTERN, + arg.span, + "single-character string constant used as pattern", + "try using a `char` instead", + hint, + applicability, + ); + } + } } } diff --git a/src/tools/clippy/clippy_lints/src/methods/single_char_push_string.rs b/src/tools/clippy/clippy_lints/src/methods/single_char_push_string.rs index deacc70b713..0237d39cbdb 100644 --- a/src/tools/clippy/clippy_lints/src/methods/single_char_push_string.rs +++ b/src/tools/clippy/clippy_lints/src/methods/single_char_push_string.rs @@ -1,5 +1,6 @@ -use crate::methods::get_hint_if_single_char_arg; -use crate::utils::{snippet_with_applicability, span_lint_and_sugg}; +use super::utils::get_hint_if_single_char_arg; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/src/tools/clippy/clippy_lints/src/methods/skip_while_next.rs b/src/tools/clippy/clippy_lints/src/methods/skip_while_next.rs index 8ba6ae95200..3db83785b59 100644 --- a/src/tools/clippy/clippy_lints/src/methods/skip_while_next.rs +++ b/src/tools/clippy/clippy_lints/src/methods/skip_while_next.rs @@ -1,13 +1,15 @@ -use crate::utils::{match_trait_method, paths, span_lint_and_help}; +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::is_trait_method; use rustc_hir as hir; use rustc_lint::LateContext; +use rustc_span::sym; use super::SKIP_WHILE_NEXT; /// lint use of `skip_while().next()` for `Iterators` pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, _skip_while_args: &'tcx [hir::Expr<'_>]) { // lint if caller of `.skip_while().next()` is an Iterator - if match_trait_method(cx, expr, &paths::ITERATOR) { + if is_trait_method(cx, expr, sym::Iterator) { span_lint_and_help( cx, SKIP_WHILE_NEXT, diff --git a/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs b/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs index 0a08ea26175..5c688ac5621 100644 --- a/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs +++ b/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs @@ -1,4 +1,7 @@ -use crate::utils::{is_type_diagnostic_item, method_chain_args, snippet_with_applicability, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::method_chain_args; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -9,34 +12,35 @@ use super::STRING_EXTEND_CHARS; pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { let obj_ty = cx.typeck_results().expr_ty(&args[0]).peel_refs(); - if is_type_diagnostic_item(cx, obj_ty, sym::string_type) { - let arg = &args[1]; - if let Some(arglists) = method_chain_args(arg, &["chars"]) { - let target = &arglists[0][0]; - let self_ty = cx.typeck_results().expr_ty(target).peel_refs(); - let ref_str = if *self_ty.kind() == ty::Str { - "" - } else if is_type_diagnostic_item(cx, self_ty, sym::string_type) { - "&" - } else { - return; - }; + if !is_type_diagnostic_item(cx, obj_ty, sym::string_type) { + return; + } + let arg = &args[1]; + if let Some(arglists) = method_chain_args(arg, &["chars"]) { + let target = &arglists[0][0]; + let self_ty = cx.typeck_results().expr_ty(target).peel_refs(); + let ref_str = if *self_ty.kind() == ty::Str { + "" + } else if is_type_diagnostic_item(cx, self_ty, sym::string_type) { + "&" + } else { + return; + }; - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - STRING_EXTEND_CHARS, - expr.span, - "calling `.extend(_.chars())`", - "try this", - format!( - "{}.push_str({}{})", - snippet_with_applicability(cx, args[0].span, "..", &mut applicability), - ref_str, - snippet_with_applicability(cx, target.span, "..", &mut applicability) - ), - applicability, - ); - } + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + STRING_EXTEND_CHARS, + expr.span, + "calling `.extend(_.chars())`", + "try this", + format!( + "{}.push_str({}{})", + snippet_with_applicability(cx, args[0].span, "..", &mut applicability), + ref_str, + snippet_with_applicability(cx, target.span, "..", &mut applicability) + ), + applicability, + ); } } diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs index e135a826dc4..7015bd54c35 100644 --- a/src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs @@ -1,16 +1,42 @@ -use crate::utils::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::usage::mutated_variables; +use clippy_utils::{expr_or_init, is_trait_method}; +use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::LateContext; +use rustc_span::sym; use super::SUSPICIOUS_MAP; -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>) { - span_lint_and_help( - cx, - SUSPICIOUS_MAP, - expr.span, - "this call to `map()` won't have an effect on the call to `count()`", - None, - "make sure you did not confuse `map` with `filter` or `for_each`", - ); +pub fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &hir::Expr<'_>, + map_args: &[hir::Expr<'_>], + count_args: &[hir::Expr<'_>], +) { + if_chain! { + if let [count_recv] = count_args; + if let [_, map_arg] = map_args; + if is_trait_method(cx, count_recv, sym::Iterator); + let closure = expr_or_init(cx, map_arg); + if let Some(body_id) = cx.tcx.hir().maybe_body_owned_by(closure.hir_id); + let closure_body = cx.tcx.hir().body(body_id); + if !cx.typeck_results().expr_ty(&closure_body.value).is_unit(); + then { + if let Some(map_mutated_vars) = mutated_variables(&closure_body.value, cx) { + // A variable is used mutably inside of the closure. Suppress the lint. + if !map_mutated_vars.is_empty() { + return; + } + } + span_lint_and_help( + cx, + SUSPICIOUS_MAP, + expr.span, + "this call to `map()` won't have an effect on the call to `count()`", + None, + "make sure you did not confuse `map` with `filter` or `for_each`", + ); + } + } } diff --git a/src/tools/clippy/clippy_lints/src/methods/uninit_assumed_init.rs b/src/tools/clippy/clippy_lints/src/methods/uninit_assumed_init.rs index 798b66192c8..f2f6ef4be6c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/uninit_assumed_init.rs +++ b/src/tools/clippy/clippy_lints/src/methods/uninit_assumed_init.rs @@ -1,4 +1,5 @@ -use crate::utils::{match_def_path, match_qpath, paths, span_lint}; +use clippy_utils::diagnostics::span_lint; +use clippy_utils::{match_def_path, match_qpath, paths}; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs index 12b2cf0a165..48d905ab833 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -1,16 +1,17 @@ -use crate::utils::usage::mutated_variables; -use crate::utils::{match_qpath, match_trait_method, path_to_local_id, paths, span_lint}; +use clippy_utils::diagnostics::span_lint; +use clippy_utils::usage::mutated_variables; +use clippy_utils::{is_trait_method, match_qpath, path_to_local_id, paths}; +use if_chain::if_chain; use rustc_hir as hir; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc_lint::LateContext; use rustc_middle::hir::map::Map; - -use if_chain::if_chain; +use rustc_span::sym; use super::UNNECESSARY_FILTER_MAP; pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { - if !match_trait_method(cx, expr, &paths::ITERATOR) { + if !is_trait_method(cx, expr, sym::Iterator) { return; } diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs index a26443f4ee9..1268fd4bda9 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs @@ -1,14 +1,13 @@ -use crate::utils::{ - match_trait_method, path_to_local_id, paths, remove_blocks, snippet_with_applicability, span_lint_and_sugg, - strip_pat_refs, -}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::{is_trait_method, path_to_local_id, remove_blocks, strip_pat_refs}; use if_chain::if_chain; use rustc_ast::ast; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::PatKind; use rustc_lint::LateContext; -use rustc_span::source_map::Span; +use rustc_span::{source_map::Span, sym}; use super::UNNECESSARY_FOLD; @@ -71,7 +70,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, fold_args: &[hir } // Check that this is a call to Iterator::fold rather than just some function called fold - if !match_trait_method(cx, expr, &paths::ITERATOR) { + if !is_trait_method(cx, expr, sym::Iterator) { return; } diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs index a17259d697f..a86185bf0a6 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -1,5 +1,7 @@ -use crate::utils::{eager_or_lazy, usage}; -use crate::utils::{is_type_diagnostic_item, snippet, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{eager_or_lazy, usage}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs b/src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs index 094c3fc45c4..2f5806115bd 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_type_diagnostic_item, span_lint_and_help}; +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::ty::is_type_diagnostic_item; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::sym; diff --git a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs index e4554f8d489..b5505af0f7e 100644 --- a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs +++ b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs @@ -1,6 +1,7 @@ -use crate::utils::{ - get_parent_expr, match_trait_method, paths, snippet_with_applicability, span_lint_and_sugg, walk_ptrs_ty_depth, -}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::walk_ptrs_ty_depth; +use clippy_utils::{get_parent_expr, match_trait_method, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/src/tools/clippy/clippy_lints/src/methods/utils.rs b/src/tools/clippy/clippy_lints/src/methods/utils.rs new file mode 100644 index 00000000000..ac6b55396da --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/methods/utils.rs @@ -0,0 +1,77 @@ +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::is_type_diagnostic_item; +use if_chain::if_chain; +use rustc_ast::ast; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_middle::ty::{self, Ty}; +use rustc_span::symbol::sym; + +pub(super) fn derefs_to_slice<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'tcx>, + ty: Ty<'tcx>, +) -> Option<&'tcx hir::Expr<'tcx>> { + fn may_slice<'a>(cx: &LateContext<'a>, ty: Ty<'a>) -> bool { + match ty.kind() { + ty::Slice(_) => true, + ty::Adt(def, _) if def.is_box() => may_slice(cx, ty.boxed_ty()), + ty::Adt(..) => is_type_diagnostic_item(cx, ty, sym::vec_type), + ty::Array(_, size) => size + .try_eval_usize(cx.tcx, cx.param_env) + .map_or(false, |size| size < 32), + ty::Ref(_, inner, _) => may_slice(cx, inner), + _ => false, + } + } + + if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind { + if path.ident.name == sym::iter && may_slice(cx, cx.typeck_results().expr_ty(&args[0])) { + Some(&args[0]) + } else { + None + } + } else { + match ty.kind() { + ty::Slice(_) => Some(expr), + ty::Adt(def, _) if def.is_box() && may_slice(cx, ty.boxed_ty()) => Some(expr), + ty::Ref(_, inner, _) => { + if may_slice(cx, inner) { + Some(expr) + } else { + None + } + }, + _ => None, + } + } +} + +pub(super) fn get_hint_if_single_char_arg( + cx: &LateContext<'_>, + arg: &hir::Expr<'_>, + applicability: &mut Applicability, +) -> Option<String> { + if_chain! { + if let hir::ExprKind::Lit(lit) = &arg.kind; + if let ast::LitKind::Str(r, style) = lit.node; + let string = r.as_str(); + if string.chars().count() == 1; + then { + let snip = snippet_with_applicability(cx, arg.span, &string, applicability); + let ch = if let ast::StrStyle::Raw(nhash) = style { + let nhash = nhash as usize; + // for raw string: r##"a"## + &snip[(nhash + 2)..(snip.len() - 1 - nhash)] + } else { + // for regular string: "a" + &snip[1..(snip.len() - 1)] + }; + let hint = format!("'{}'", if ch == "'" { "\\'" } else { ch }); + Some(hint) + } else { + None + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs b/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs index 90fab577436..59e683aa9a7 100644 --- a/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs +++ b/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs @@ -1,5 +1,6 @@ use crate::methods::SelfKind; -use crate::utils::span_lint; +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::ty::is_copy; use rustc_lint::LateContext; use rustc_middle::ty::TyS; use rustc_span::source_map::Span; @@ -9,26 +10,40 @@ use super::WRONG_PUB_SELF_CONVENTION; use super::WRONG_SELF_CONVENTION; #[rustfmt::skip] -const CONVENTIONS: [(Convention, &[SelfKind]); 7] = [ - (Convention::Eq("new"), &[SelfKind::No]), - (Convention::StartsWith("as_"), &[SelfKind::Ref, SelfKind::RefMut]), - (Convention::StartsWith("from_"), &[SelfKind::No]), - (Convention::StartsWith("into_"), &[SelfKind::Value]), - (Convention::StartsWith("is_"), &[SelfKind::Ref, SelfKind::No]), - (Convention::Eq("to_mut"), &[SelfKind::RefMut]), - (Convention::StartsWith("to_"), &[SelfKind::Ref]), +const CONVENTIONS: [(&[Convention], &[SelfKind]); 9] = [ + (&[Convention::Eq("new")], &[SelfKind::No]), + (&[Convention::StartsWith("as_")], &[SelfKind::Ref, SelfKind::RefMut]), + (&[Convention::StartsWith("from_")], &[SelfKind::No]), + (&[Convention::StartsWith("into_")], &[SelfKind::Value]), + (&[Convention::StartsWith("is_")], &[SelfKind::Ref, SelfKind::No]), + (&[Convention::Eq("to_mut")], &[SelfKind::RefMut]), + (&[Convention::StartsWith("to_"), Convention::EndsWith("_mut")], &[SelfKind::RefMut]), + + // Conversion using `to_` can use borrowed (non-Copy types) or owned (Copy types). + // Source: https://rust-lang.github.io/api-guidelines/naming.html#ad-hoc-conversions-follow-as_-to_-into_-conventions-c-conv + (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(false), Convention::ImplementsTrait(false)], &[SelfKind::Ref]), + (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(true), Convention::ImplementsTrait(false)], &[SelfKind::Value]), ]; + enum Convention { Eq(&'static str), StartsWith(&'static str), + EndsWith(&'static str), + NotEndsWith(&'static str), + IsSelfTypeCopy(bool), + ImplementsTrait(bool), } impl Convention { #[must_use] - fn check(&self, other: &str) -> bool { + fn check<'tcx>(&self, cx: &LateContext<'tcx>, self_ty: &'tcx TyS<'tcx>, other: &str, is_trait_def: bool) -> bool { match *self { Self::Eq(this) => this == other, Self::StartsWith(this) => other.starts_with(this) && this != other, + Self::EndsWith(this) => other.ends_with(this) && this != other, + Self::NotEndsWith(this) => !Self::EndsWith(this).check(cx, self_ty, other, is_trait_def), + Self::IsSelfTypeCopy(is_true) => is_true == is_copy(cx, self_ty), + Self::ImplementsTrait(is_true) => is_true == is_trait_def, } } } @@ -36,8 +51,17 @@ impl Convention { impl fmt::Display for Convention { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { match *self { - Self::Eq(this) => this.fmt(f), - Self::StartsWith(this) => this.fmt(f).and_then(|_| '*'.fmt(f)), + Self::Eq(this) => format!("`{}`", this).fmt(f), + Self::StartsWith(this) => format!("`{}*`", this).fmt(f), + Self::EndsWith(this) => format!("`*{}`", this).fmt(f), + Self::NotEndsWith(this) => format!("`~{}`", this).fmt(f), + Self::IsSelfTypeCopy(is_true) => { + format!("`self` type is{} `Copy`", if is_true { "" } else { " not" }).fmt(f) + }, + Self::ImplementsTrait(is_true) => { + let (negation, s_suffix) = if is_true { ("", "s") } else { (" does not", "") }; + format!("Method{} implement{} a trait", negation, s_suffix).fmt(f) + }, } } } @@ -49,27 +73,62 @@ pub(super) fn check<'tcx>( self_ty: &'tcx TyS<'tcx>, first_arg_ty: &'tcx TyS<'tcx>, first_arg_span: Span, + is_trait_item: bool, ) { let lint = if is_pub { WRONG_PUB_SELF_CONVENTION } else { WRONG_SELF_CONVENTION }; - if let Some((ref conv, self_kinds)) = &CONVENTIONS.iter().find(|(ref conv, _)| conv.check(item_name)) { + if let Some((conventions, self_kinds)) = &CONVENTIONS.iter().find(|(convs, _)| { + convs + .iter() + .all(|conv| conv.check(cx, self_ty, item_name, is_trait_item)) + }) { if !self_kinds.iter().any(|k| k.matches(cx, self_ty, first_arg_ty)) { - span_lint( + let suggestion = { + if conventions.len() > 1 { + // Don't mention `NotEndsWith` when there is also `StartsWith` convention present + let cut_ends_with_conv = conventions.iter().any(|conv| matches!(conv, Convention::StartsWith(_))) + && conventions + .iter() + .any(|conv| matches!(conv, Convention::NotEndsWith(_))); + + let s = conventions + .iter() + .filter_map(|conv| { + if (cut_ends_with_conv && matches!(conv, Convention::NotEndsWith(_))) + || matches!(conv, Convention::ImplementsTrait(_)) + { + None + } else { + Some(conv.to_string()) + } + }) + .collect::<Vec<_>>() + .join(" and "); + + format!("methods with the following characteristics: ({})", &s) + } else { + format!("methods called {}", &conventions[0]) + } + }; + + span_lint_and_help( cx, lint, first_arg_span, &format!( - "methods called `{}` usually take {}; consider choosing a less ambiguous name", - conv, + "{} usually take {}", + suggestion, &self_kinds .iter() .map(|k| k.description()) .collect::<Vec<_>>() .join(" or ") ), + None, + "consider choosing a less ambiguous name", ); } } diff --git a/src/tools/clippy/clippy_lints/src/methods/zst_offset.rs b/src/tools/clippy/clippy_lints/src/methods/zst_offset.rs index f1335726736..9f6a7c4db17 100644 --- a/src/tools/clippy/clippy_lints/src/methods/zst_offset.rs +++ b/src/tools/clippy/clippy_lints/src/methods/zst_offset.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint; +use clippy_utils::diagnostics::span_lint; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/src/tools/clippy/clippy_lints/src/minmax.rs b/src/tools/clippy/clippy_lints/src/minmax.rs index 8d0c3b8e0fe..776f4c7b741 100644 --- a/src/tools/clippy/clippy_lints/src/minmax.rs +++ b/src/tools/clippy/clippy_lints/src/minmax.rs @@ -1,5 +1,6 @@ use crate::consts::{constant_simple, Constant}; -use crate::utils::{match_def_path, match_trait_method, paths, span_lint}; +use clippy_utils::diagnostics::span_lint; +use clippy_utils::{match_def_path, match_trait_method, paths}; use if_chain::if_chain; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs index acdc245456b..026ea50936a 100644 --- a/src/tools/clippy/clippy_lints/src/misc.rs +++ b/src/tools/clippy/clippy_lints/src/misc.rs @@ -1,3 +1,6 @@ +use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then, span_lint_hir_and_then}; +use clippy_utils::source::{snippet, snippet_opt}; +use clippy_utils::ty::implements_trait; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -15,11 +18,10 @@ use rustc_span::source_map::{ExpnKind, Span}; use rustc_span::symbol::sym; use crate::consts::{constant, Constant}; -use crate::utils::sugg::Sugg; -use crate::utils::{ - get_item_name, get_parent_expr, higher, implements_trait, in_constant, is_diagnostic_assoc_item, is_integer_const, - iter_input_pats, last_path_segment, match_qpath, snippet, snippet_opt, span_lint, span_lint_and_sugg, - span_lint_and_then, span_lint_hir_and_then, unsext, SpanlessEq, +use clippy_utils::sugg::Sugg; +use clippy_utils::{ + get_item_name, get_parent_expr, higher, in_constant, is_diagnostic_assoc_item, is_integer_const, iter_input_pats, + last_path_segment, match_qpath, unsext, SpanlessEq, }; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/misc_early.rs b/src/tools/clippy/clippy_lints/src/misc_early.rs index 84a0df92f5b..3c6a7071c24 100644 --- a/src/tools/clippy/clippy_lints/src/misc_early.rs +++ b/src/tools/clippy/clippy_lints/src/misc_early.rs @@ -1,4 +1,5 @@ -use crate::utils::{snippet_opt, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::source::snippet_opt; use rustc_ast::ast::{ BindingMode, Expr, ExprKind, GenericParamKind, Generics, Lit, LitFloatType, LitIntType, LitKind, Mutability, NodeId, Pat, PatKind, UnOp, diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs index b0998a80128..23554669d97 100644 --- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs +++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs @@ -1,7 +1,7 @@ -use crate::utils::qualify_min_const_fn::is_min_const_fn; -use crate::utils::{ - fn_has_unsatisfiable_preds, has_drop, is_entrypoint_fn, meets_msrv, span_lint, trait_ref_of_method, -}; +use clippy_utils::diagnostics::span_lint; +use clippy_utils::qualify_min_const_fn::is_min_const_fn; +use clippy_utils::ty::has_drop; +use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, meets_msrv, trait_ref_of_method}; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, Constness, FnDecl, GenericParamKind, HirId}; diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs index 985a66b6cfc..21b4983a1af 100644 --- a/src/tools/clippy/clippy_lints/src/missing_doc.rs +++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs @@ -5,7 +5,7 @@ // [`missing_doc`]: https://github.com/rust-lang/rust/blob/cf9cf7c923eb01146971429044f216a3ca905e06/compiler/rustc_lint/src/builtin.rs#L415 // -use crate::utils::span_lint; +use clippy_utils::diagnostics::span_lint; use if_chain::if_chain; use rustc_ast::ast::{self, MetaItem, MetaItemKind}; use rustc_ast::attr; @@ -95,7 +95,7 @@ impl MissingDoc { let has_doc = attrs .iter() - .any(|a| a.is_doc_comment() || a.doc_str().is_some() || a.is_value_str() || Self::has_include(a.meta())); + .any(|a| a.is_doc_comment() || a.doc_str().is_some() || a.value_str().is_some() || Self::has_include(a.meta())); if !has_doc { span_lint( cx, @@ -128,7 +128,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { fn check_crate(&mut self, cx: &LateContext<'tcx>, krate: &'tcx hir::Crate<'_>) { let attrs = cx.tcx.hir().attrs(hir::CRATE_HIR_ID); - self.check_missing_docs_attrs(cx, attrs, krate.item.span, "the", "crate"); + self.check_missing_docs_attrs(cx, attrs, krate.item.inner, "the", "crate"); } fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) { diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs index da59c820999..dd4488f3f02 100644 --- a/src/tools/clippy/clippy_lints/src/missing_inline.rs +++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint; +use clippy_utils::diagnostics::span_lint; use rustc_ast::ast; use rustc_hir as hir; use rustc_lint::{self, LateContext, LateLintPass, LintContext}; diff --git a/src/tools/clippy/clippy_lints/src/modulo_arithmetic.rs b/src/tools/clippy/clippy_lints/src/modulo_arithmetic.rs index da3ae1d652f..6a52de4f713 100644 --- a/src/tools/clippy/clippy_lints/src/modulo_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/modulo_arithmetic.rs @@ -1,5 +1,6 @@ use crate::consts::{constant, Constant}; -use crate::utils::{sext, span_lint_and_then}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::sext; use if_chain::if_chain; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/multiple_crate_versions.rs b/src/tools/clippy/clippy_lints/src/multiple_crate_versions.rs index c1773cef7a8..584daa5e119 100644 --- a/src/tools/clippy/clippy_lints/src/multiple_crate_versions.rs +++ b/src/tools/clippy/clippy_lints/src/multiple_crate_versions.rs @@ -1,6 +1,7 @@ //! lint on multiple versions of a crate being used -use crate::utils::{run_lints, span_lint}; +use clippy_utils::diagnostics::span_lint; +use clippy_utils::run_lints; use rustc_hir::def_id::LOCAL_CRATE; use rustc_hir::{Crate, CRATE_HIR_ID}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/mut_key.rs b/src/tools/clippy/clippy_lints/src/mut_key.rs index 908b7bb7ce0..4d3dff36a20 100644 --- a/src/tools/clippy/clippy_lints/src/mut_key.rs +++ b/src/tools/clippy/clippy_lints/src/mut_key.rs @@ -1,10 +1,12 @@ -use crate::utils::{match_def_path, paths, span_lint, trait_ref_of_method}; +use clippy_utils::diagnostics::span_lint; +use clippy_utils::{match_def_path, paths, trait_ref_of_method}; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::TypeFoldable; use rustc_middle::ty::{Adt, Array, RawPtr, Ref, Slice, Tuple, Ty, TypeAndMut}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; +use std::iter; declare_clippy_lint! { /// **What it does:** Checks for sets/maps with mutable key types. @@ -86,7 +88,7 @@ impl<'tcx> LateLintPass<'tcx> for MutableKeyType { fn check_sig<'tcx>(cx: &LateContext<'tcx>, item_hir_id: hir::HirId, decl: &hir::FnDecl<'_>) { let fn_def_id = cx.tcx.hir().local_def_id(item_hir_id); let fn_sig = cx.tcx.fn_sig(fn_def_id); - for (hir_ty, ty) in decl.inputs.iter().zip(fn_sig.inputs().skip_binder().iter()) { + for (hir_ty, ty) in iter::zip(decl.inputs, fn_sig.inputs().skip_binder()) { check_ty(cx, hir_ty.span, ty); } check_ty(cx, decl.output.span(), cx.tcx.erase_late_bound_regions(fn_sig.output())); diff --git a/src/tools/clippy/clippy_lints/src/mut_mut.rs b/src/tools/clippy/clippy_lints/src/mut_mut.rs index d7239b328bb..ef33e41a5fa 100644 --- a/src/tools/clippy/clippy_lints/src/mut_mut.rs +++ b/src/tools/clippy/clippy_lints/src/mut_mut.rs @@ -1,4 +1,5 @@ -use crate::utils::{higher, span_lint}; +use clippy_utils::diagnostics::span_lint; +use clippy_utils::higher; use rustc_hir as hir; use rustc_hir::intravisit; use rustc_lint::{LateContext, LateLintPass, LintContext}; diff --git a/src/tools/clippy/clippy_lints/src/mut_mutex_lock.rs b/src/tools/clippy/clippy_lints/src/mut_mutex_lock.rs index df1cecb328c..b9ba74c7d02 100644 --- a/src/tools/clippy/clippy_lints/src/mut_mutex_lock.rs +++ b/src/tools/clippy/clippy_lints/src/mut_mutex_lock.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_type_diagnostic_item, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Mutability}; diff --git a/src/tools/clippy/clippy_lints/src/mut_reference.rs b/src/tools/clippy/clippy_lints/src/mut_reference.rs index 3f0b765df15..05457e80d52 100644 --- a/src/tools/clippy/clippy_lints/src/mut_reference.rs +++ b/src/tools/clippy/clippy_lints/src/mut_reference.rs @@ -1,9 +1,10 @@ -use crate::utils::span_lint; +use clippy_utils::diagnostics::span_lint; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use std::iter; declare_clippy_lint! { /// **What it does:** Detects passing a mutable reference to a function that only @@ -64,7 +65,7 @@ fn check_arguments<'tcx>( match type_definition.kind() { ty::FnDef(..) | ty::FnPtr(_) => { let parameters = type_definition.fn_sig(cx.tcx).skip_binder().inputs(); - for (argument, parameter) in arguments.iter().zip(parameters.iter()) { + for (argument, parameter) in iter::zip(arguments, parameters) { match parameter.kind() { ty::Ref(_, _, Mutability::Not) | ty::RawPtr(ty::TypeAndMut { diff --git a/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs b/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs index 9caacb5db7c..7dfe12cd4eb 100644 --- a/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs +++ b/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs @@ -1,4 +1,5 @@ -use crate::utils::{higher, is_direct_expn_of, span_lint}; +use clippy_utils::diagnostics::span_lint; +use clippy_utils::{higher, is_direct_expn_of}; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc_hir::{BorrowKind, Expr, ExprKind, MatchSource, Mutability}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs index 40b236493a3..354e2c3fb74 100644 --- a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs +++ b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs @@ -2,7 +2,8 @@ //! //! This lint is **warn** by default -use crate::utils::{is_type_diagnostic_item, span_lint}; +use clippy_utils::diagnostics::span_lint; +use clippy_utils::ty::is_type_diagnostic_item; use rustc_hir::Expr; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; diff --git a/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs index 7687962bdd9..3e2b2782ed5 100644 --- a/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs +++ b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs @@ -1,4 +1,5 @@ -use crate::utils::{in_macro, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::in_macro; use if_chain::if_chain; use rustc_ast::ast::{BindingMode, Lifetime, Mutability, Param, PatKind, Path, TyKind}; use rustc_errors::Applicability; diff --git a/src/tools/clippy/clippy_lints/src/needless_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bool.rs index f283ff1715f..db7b3423ad9 100644 --- a/src/tools/clippy/clippy_lints/src/needless_bool.rs +++ b/src/tools/clippy/clippy_lints/src/needless_bool.rs @@ -2,8 +2,10 @@ //! //! This lint is **warn** by default -use crate::utils::sugg::Sugg; -use crate::utils::{is_expn_of, parent_node_is_if_expr, snippet_with_applicability, span_lint, span_lint_and_sugg}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::sugg::Sugg; +use clippy_utils::{is_expn_of, parent_node_is_if_expr}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp}; diff --git a/src/tools/clippy/clippy_lints/src/needless_borrow.rs b/src/tools/clippy/clippy_lints/src/needless_borrow.rs index 1aadcfd87b6..79d84da2dfc 100644 --- a/src/tools/clippy/clippy_lints/src/needless_borrow.rs +++ b/src/tools/clippy/clippy_lints/src/needless_borrow.rs @@ -2,7 +2,9 @@ //! //! This lint is **warn** by default -use crate::utils::{is_automatically_derived, snippet_opt, span_lint_and_then}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::is_automatically_derived; +use clippy_utils::source::snippet_opt; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BindingAnnotation, BorrowKind, Expr, ExprKind, Item, Mutability, Pat, PatKind}; diff --git a/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs b/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs index f449f397e7d..7fbffe04a3f 100644 --- a/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs +++ b/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs @@ -1,4 +1,5 @@ -use crate::utils::{snippet_with_applicability, span_lint_and_then}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::snippet_with_applicability; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BindingAnnotation, Mutability, Node, Pat, PatKind}; diff --git a/src/tools/clippy/clippy_lints/src/needless_continue.rs b/src/tools/clippy/clippy_lints/src/needless_continue.rs index 30fe2d6225c..91c97ef7c2a 100644 --- a/src/tools/clippy/clippy_lints/src/needless_continue.rs +++ b/src/tools/clippy/clippy_lints/src/needless_continue.rs @@ -33,14 +33,14 @@ //! ``` //! //! This lint is **warn** by default. +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::source::{indent_of, snippet, snippet_block}; use rustc_ast::ast; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::{original_sp, DUMMY_SP}; use rustc_span::Span; -use crate::utils::{indent_of, snippet, snippet_block, span_lint_and_help}; - declare_clippy_lint! { /// **What it does:** The lint checks for `if`-statements appearing in loops /// that contain a `continue` statement in either their main blocks or their diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index d439577f9c3..e70c248e87b 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -1,8 +1,8 @@ -use crate::utils::ptr::get_spans; -use crate::utils::{ - get_trait_def_id, implements_trait, is_copy, is_self, is_type_diagnostic_item, multispan_sugg, paths, snippet, - snippet_opt, span_lint_and_then, -}; +use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; +use clippy_utils::ptr::get_spans; +use clippy_utils::source::{snippet, snippet_opt}; +use clippy_utils::ty::{implements_trait, is_copy, is_type_diagnostic_item}; +use clippy_utils::{get_trait_def_id, is_self, paths}; use if_chain::if_chain; use rustc_ast::ast::Attribute; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -335,5 +335,5 @@ impl<'tcx> euv::Delegate<'tcx> for MovedVariablesCtxt { fn mutate(&mut self, _: &euv::PlaceWithHirId<'tcx>, _: HirId) {} - fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause, _: HirId) { } + fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause, _: HirId) {} } diff --git a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs index a3293f1b361..9852633b734 100644 --- a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs @@ -1,3 +1,8 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{differing_macro_contexts, is_ok_ctor, is_some_ctor, meets_msrv}; +use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Body, Expr, ExprKind, LangItem, MatchSource, QPath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -5,9 +10,6 @@ use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::sym; -use crate::utils; -use if_chain::if_chain; - declare_clippy_lint! { /// **What it does:** /// Suggests alternatives for useless applications of `?` in terminating expressions @@ -138,13 +140,13 @@ fn emit_lint(cx: &LateContext<'_>, expr: &SomeOkCall<'_>) { SomeOkCall::OkCall(outer, inner) | SomeOkCall::SomeCall(outer, inner) => (outer, inner), }; - utils::span_lint_and_sugg( + span_lint_and_sugg( cx, NEEDLESS_QUESTION_MARK, entire_expr.span, "question mark operator is useless here", "try", - format!("{}", utils::snippet(cx, inner_expr.span, r#""...""#)), + format!("{}", snippet(cx, inner_expr.span, r#""...""#)), Applicability::MachineApplicable, ); } @@ -158,7 +160,7 @@ fn is_some_or_ok_call<'a>( // Check outer expression matches CALL_IDENT(ARGUMENT) format if let ExprKind::Call(path, args) = &expr.kind; if let ExprKind::Path(QPath::Resolved(None, path)) = &path.kind; - if utils::is_some_ctor(cx, path.res) || utils::is_ok_ctor(cx, path.res); + if is_some_ctor(cx, path.res) || is_ok_ctor(cx, path.res); // Extract inner expression from ARGUMENT if let ExprKind::Match(inner_expr_with_q, _, MatchSource::TryDesugar) = &args[0].kind; @@ -171,29 +173,34 @@ fn is_some_or_ok_call<'a>( // question mark operator let inner_expr = &args[0]; + // if the inner expr is inside macro but the outer one is not, do not lint (#6921) + if differing_macro_contexts(expr.span, inner_expr.span) { + return None; + } + let inner_ty = cx.typeck_results().expr_ty(inner_expr); let outer_ty = cx.typeck_results().expr_ty(expr); // Check if outer and inner type are Option - let outer_is_some = utils::is_type_diagnostic_item(cx, outer_ty, sym::option_type); - let inner_is_some = utils::is_type_diagnostic_item(cx, inner_ty, sym::option_type); + let outer_is_some = is_type_diagnostic_item(cx, outer_ty, sym::option_type); + let inner_is_some = is_type_diagnostic_item(cx, inner_ty, sym::option_type); // Check for Option MSRV - let meets_option_msrv = utils::meets_msrv(nqml.msrv.as_ref(), &NEEDLESS_QUESTION_MARK_OPTION_MSRV); + let meets_option_msrv = meets_msrv(nqml.msrv.as_ref(), &NEEDLESS_QUESTION_MARK_OPTION_MSRV); if outer_is_some && inner_is_some && meets_option_msrv { return Some(SomeOkCall::SomeCall(expr, inner_expr)); } // Check if outer and inner type are Result - let outer_is_result = utils::is_type_diagnostic_item(cx, outer_ty, sym::result_type); - let inner_is_result = utils::is_type_diagnostic_item(cx, inner_ty, sym::result_type); + let outer_is_result = is_type_diagnostic_item(cx, outer_ty, sym::result_type); + let inner_is_result = is_type_diagnostic_item(cx, inner_ty, sym::result_type); // Additional check: if the error type of the Result can be converted // via the From trait, then don't match let does_not_call_from = !has_implicit_error_from(cx, expr, inner_expr); // Must meet Result MSRV - let meets_result_msrv = utils::meets_msrv(nqml.msrv.as_ref(), &NEEDLESS_QUESTION_MARK_RESULT_MSRV); + let meets_result_msrv = meets_msrv(nqml.msrv.as_ref(), &NEEDLESS_QUESTION_MARK_RESULT_MSRV); if outer_is_result && inner_is_result && does_not_call_from && meets_result_msrv { return Some(SomeOkCall::OkCall(expr, inner_expr)); } diff --git a/src/tools/clippy/clippy_lints/src/needless_update.rs b/src/tools/clippy/clippy_lints/src/needless_update.rs index 41cf541ecf5..e93de8a252a 100644 --- a/src/tools/clippy/clippy_lints/src/needless_update.rs +++ b/src/tools/clippy/clippy_lints/src/needless_update.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint; +use clippy_utils::diagnostics::span_lint; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; diff --git a/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs index ec0ad58ca9c..4b935c7b906 100644 --- a/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs +++ b/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs @@ -1,11 +1,12 @@ +use clippy_utils::diagnostics::span_lint; +use clippy_utils::ty::implements_trait; +use clippy_utils::{self, get_trait_def_id, paths}; use if_chain::if_chain; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::{self, paths, span_lint}; - declare_clippy_lint! { /// **What it does:** /// Checks for the usage of negated comparison operators on types which only implement @@ -59,8 +60,8 @@ impl<'tcx> LateLintPass<'tcx> for NoNegCompOpForPartialOrd { let ty = cx.typeck_results().expr_ty(left); let implements_ord = { - if let Some(id) = utils::get_trait_def_id(cx, &paths::ORD) { - utils::implements_trait(cx, ty, id, &[]) + if let Some(id) = get_trait_def_id(cx, &paths::ORD) { + implements_trait(cx, ty, id, &[]) } else { return; } @@ -68,7 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for NoNegCompOpForPartialOrd { let implements_partial_ord = { if let Some(id) = cx.tcx.lang_items().partial_ord_trait() { - utils::implements_trait(cx, ty, id, &[]) + implements_trait(cx, ty, id, &[]) } else { return; } diff --git a/src/tools/clippy/clippy_lints/src/neg_multiply.rs b/src/tools/clippy/clippy_lints/src/neg_multiply.rs index ef7cc65cfcf..7b00879251f 100644 --- a/src/tools/clippy/clippy_lints/src/neg_multiply.rs +++ b/src/tools/clippy/clippy_lints/src/neg_multiply.rs @@ -1,3 +1,4 @@ +use clippy_utils::diagnostics::span_lint; use if_chain::if_chain; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; @@ -5,7 +6,6 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use crate::consts::{self, Constant}; -use crate::utils::span_lint; declare_clippy_lint! { /// **What it does:** Checks for multiplication by -1 as a form of negation. diff --git a/src/tools/clippy/clippy_lints/src/new_without_default.rs b/src/tools/clippy/clippy_lints/src/new_without_default.rs index de2899c3462..3789572ad43 100644 --- a/src/tools/clippy/clippy_lints/src/new_without_default.rs +++ b/src/tools/clippy/clippy_lints/src/new_without_default.rs @@ -1,6 +1,8 @@ -use crate::utils::paths; -use crate::utils::sugg::DiagnosticBuilderExt; -use crate::utils::{get_trait_def_id, return_ty, span_lint_hir_and_then}; +use clippy_utils::diagnostics::span_lint_hir_and_then; +use clippy_utils::paths; +use clippy_utils::source::snippet; +use clippy_utils::sugg::DiagnosticBuilderExt; +use clippy_utils::{get_trait_def_id, return_ty}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; @@ -61,7 +63,10 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { #[allow(clippy::too_many_lines)] fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { if let hir::ItemKind::Impl(hir::Impl { - of_trait: None, items, .. + of_trait: None, + ref generics, + items, + .. }) = item.kind { for assoc_item in items { @@ -125,6 +130,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { } } + let generics_sugg = snippet(cx, generics.span, ""); span_lint_hir_and_then( cx, NEW_WITHOUT_DEFAULT, @@ -139,7 +145,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { cx, item.span, "try this", - &create_new_without_default_suggest_msg(self_ty), + &create_new_without_default_suggest_msg(self_ty, &generics_sugg), Applicability::MaybeIncorrect, ); }, @@ -154,12 +160,12 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { } } -fn create_new_without_default_suggest_msg(ty: Ty<'_>) -> String { +fn create_new_without_default_suggest_msg(ty: Ty<'_>, generics_sugg: &str) -> String { #[rustfmt::skip] format!( -"impl Default for {} {{ +"impl{} Default for {} {{ fn default() -> Self {{ Self::new() }} -}}", ty) +}}", generics_sugg, ty) } diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs index 69302d695ce..83953a16bc8 100644 --- a/src/tools/clippy/clippy_lints/src/no_effect.rs +++ b/src/tools/clippy/clippy_lints/src/no_effect.rs @@ -1,4 +1,6 @@ -use crate::utils::{has_drop, snippet_opt, span_lint, span_lint_and_sugg}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; +use clippy_utils::source::snippet_opt; +use clippy_utils::ty::has_drop; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{BinOpKind, BlockCheckMode, Expr, ExprKind, Stmt, StmtKind, UnsafeSource}; diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs index 3e1db233696..aa1d8fbe300 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -4,6 +4,9 @@ use std::ptr; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::in_constant; +use if_chain::if_chain; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{ @@ -18,9 +21,6 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{InnerSpan, Span, DUMMY_SP}; use rustc_typeck::hir_ty_to_ty; -use crate::utils::{in_constant, span_lint_and_then}; -use if_chain::if_chain; - // FIXME: this is a correctness problem but there's no suitable // warn-by-default category. declare_clippy_lint! { @@ -179,17 +179,15 @@ fn is_value_unfrozen_poly<'tcx>(cx: &LateContext<'tcx>, body_id: BodyId, ty: Ty< fn is_value_unfrozen_expr<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId, def_id: DefId, ty: Ty<'tcx>) -> bool { let substs = cx.typeck_results().node_substs(hir_id); - let result = cx - .tcx - .const_eval_resolve( - cx.param_env, - ty::Unevaluated { - def: ty::WithOptConstParam::unknown(def_id), - substs, - promoted: None - }, - None - ); + let result = cx.tcx.const_eval_resolve( + cx.param_env, + ty::Unevaluated { + def: ty::WithOptConstParam::unknown(def_id), + substs, + promoted: None, + }, + None, + ); is_value_unfrozen_raw(cx, result, ty) } diff --git a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs index d5222a030d7..4c8bceaf2cb 100644 --- a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs +++ b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs @@ -1,4 +1,4 @@ -use crate::utils::{span_lint, span_lint_and_then}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use rustc_ast::ast::{ Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, FnKind, Item, ItemKind, Local, Pat, PatKind, diff --git a/src/tools/clippy/clippy_lints/src/open_options.rs b/src/tools/clippy/clippy_lints/src/open_options.rs index 07ca196990d..c61dff4b8e0 100644 --- a/src/tools/clippy/clippy_lints/src/open_options.rs +++ b/src/tools/clippy/clippy_lints/src/open_options.rs @@ -1,4 +1,6 @@ -use crate::utils::{match_type, paths, span_lint}; +use clippy_utils::diagnostics::span_lint; +use clippy_utils::paths; +use clippy_utils::ty::match_type; use rustc_ast::ast::LitKind; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs b/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs index fd653044a1b..a0bc324e026 100644 --- a/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_direct_expn_of, span_lint_and_help}; +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::is_direct_expn_of; use if_chain::if_chain; use rustc_ast::ast::{Expr, ExprKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs index 9ef0d267b0b..a76a4a33f1f 100644 --- a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs +++ b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs @@ -1,9 +1,10 @@ -use crate::utils; -use crate::utils::eager_or_lazy; -use crate::utils::sugg::Sugg; -use crate::utils::{is_type_diagnostic_item, paths, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::paths; +use clippy_utils::sugg::Sugg; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::usage::contains_return_break_continue_macro; +use clippy_utils::{eager_or_lazy, get_enclosing_block, in_macro, match_qpath}; use if_chain::if_chain; - use rustc_errors::Applicability; use rustc_hir::{Arm, BindingAnnotation, Block, Expr, ExprKind, MatchSource, Mutability, PatKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; @@ -108,7 +109,7 @@ fn extract_body_from_arm<'a>(arm: &'a Arm<'a>) -> Option<&'a Expr<'a>> { /// If this is the else body of an if/else expression, then we need to wrap /// it in curly braces. Otherwise, we don't. fn should_wrap_in_braces(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - utils::get_enclosing_block(cx, expr.hir_id).map_or(false, |parent| { + get_enclosing_block(cx, expr.hir_id).map_or(false, |parent| { let mut should_wrap = false; if let Some(Expr { @@ -158,15 +159,15 @@ fn detect_option_if_let_else<'tcx>( expr: &'_ Expr<'tcx>, ) -> Option<OptionIfLetElseOccurence> { if_chain! { - if !utils::in_macro(expr.span); // Don't lint macros, because it behaves weirdly + if !in_macro(expr.span); // Don't lint macros, because it behaves weirdly if let ExprKind::Match(cond_expr, arms, MatchSource::IfLetDesugar{contains_else_clause: true}) = &expr.kind; if arms.len() == 2; if !is_result_ok(cx, cond_expr); // Don't lint on Result::ok because a different lint does it already if let PatKind::TupleStruct(struct_qpath, &[inner_pat], _) = &arms[0].pat.kind; - if utils::match_qpath(struct_qpath, &paths::OPTION_SOME); + if match_qpath(struct_qpath, &paths::OPTION_SOME); if let PatKind::Binding(bind_annotation, _, id, _) = &inner_pat.kind; - if !utils::usage::contains_return_break_continue_macro(arms[0].body); - if !utils::usage::contains_return_break_continue_macro(arms[1].body); + if !contains_return_break_continue_macro(arms[0].body); + if !contains_return_break_continue_macro(arms[1].body); then { let capture_mut = if bind_annotation == &BindingAnnotation::Mutable { "mut " } else { "" }; let some_body = extract_body_from_arm(&arms[0])?; diff --git a/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs b/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs index 3c041bac234..cf667c6e805 100644 --- a/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs +++ b/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs @@ -1,4 +1,5 @@ -use crate::utils::{span_lint, SpanlessEq}; +use clippy_utils::diagnostics::span_lint; +use clippy_utils::SpanlessEq; use if_chain::if_chain; use rustc_hir::{BinOpKind, Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs b/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs index 207423a1861..d32b937b209 100644 --- a/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs +++ b/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs @@ -1,4 +1,6 @@ -use crate::utils::{find_macro_calls, is_type_diagnostic_item, return_ty, span_lint_and_then}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{find_macro_calls, return_ty}; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; use rustc_lint::{LateContext, LateLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs b/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs index 359620cc079..d06e7f8fe1e 100644 --- a/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs +++ b/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_expn_of, match_panic_call, span_lint}; +use clippy_utils::diagnostics::span_lint; +use clippy_utils::{is_expn_of, match_panic_call}; use if_chain::if_chain; use rustc_hir::Expr; use rustc_lint::{LateContext, LateLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs b/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs index aca1ed5ca65..1251ddd9a02 100644 --- a/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs +++ b/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_automatically_derived, span_lint_hir}; +use clippy_utils::diagnostics::span_lint_hir; +use clippy_utils::is_automatically_derived; use if_chain::if_chain; use rustc_hir::{Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs index ff700aa5146..e151f85a391 100644 --- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs +++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs @@ -1,6 +1,10 @@ use std::cmp; +use std::iter; -use crate::utils::{is_copy, is_self_ty, snippet, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_self_ty; +use clippy_utils::source::snippet; +use clippy_utils::ty::is_copy; use if_chain::if_chain; use rustc_ast::attr; use rustc_errors::Applicability; @@ -119,7 +123,7 @@ impl<'tcx> PassByRefOrValue { let fn_body = cx.enclosing_body.map(|id| cx.tcx.hir().body(id)); - for (index, (input, &ty)) in decl.inputs.iter().zip(fn_sig.inputs()).enumerate() { + for (index, (input, &ty)) in iter::zip(decl.inputs, fn_sig.inputs()).enumerate() { // All spans generated from a proc-macro invocation are the same... match span { Some(s) if s == input.span => return, diff --git a/src/tools/clippy/clippy_lints/src/path_buf_push_overwrite.rs b/src/tools/clippy/clippy_lints/src/path_buf_push_overwrite.rs index 4a7b0ad07aa..95ffae28d8c 100644 --- a/src/tools/clippy/clippy_lints/src/path_buf_push_overwrite.rs +++ b/src/tools/clippy/clippy_lints/src/path_buf_push_overwrite.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_type_diagnostic_item, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; diff --git a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs index e76c8624b6f..c0c2ab67e38 100644 --- a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs +++ b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs @@ -1,6 +1,7 @@ -use crate::utils::{last_path_segment, span_lint_and_help}; +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::last_path_segment; use rustc_hir::{ - intravisit, Body, Expr, ExprKind, PatField, FnDecl, HirId, LocalSource, MatchSource, Mutability, Pat, PatKind, + intravisit, Body, Expr, ExprKind, FnDecl, HirId, LocalSource, MatchSource, Mutability, Pat, PatField, PatKind, QPath, Stmt, StmtKind, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -9,6 +10,7 @@ use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{AdtDef, FieldDef, Ty, TyKind, VariantDef}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; +use std::iter; declare_clippy_lint! { /// **What it does:** Checks for patterns that aren't exact representations of the types @@ -133,7 +135,7 @@ impl<'tcx> LateLintPass<'tcx> for PatternTypeMismatch { hir_id: HirId, ) { if let Some(fn_sig) = cx.typeck_results().liberated_fn_sigs().get(hir_id) { - for (param, ty) in body.params.iter().zip(fn_sig.inputs().iter()) { + for (param, ty) in iter::zip(body.params, fn_sig.inputs()) { apply_lint(cx, ¶m.pat, ty, DerefPossible::Impossible); } } diff --git a/src/tools/clippy/clippy_lints/src/precedence.rs b/src/tools/clippy/clippy_lints/src/precedence.rs index c9d18c3cb72..9cf00c953b9 100644 --- a/src/tools/clippy/clippy_lints/src/precedence.rs +++ b/src/tools/clippy/clippy_lints/src/precedence.rs @@ -1,4 +1,5 @@ -use crate::utils::{snippet_with_applicability, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; use if_chain::if_chain; use rustc_ast::ast::{BinOpKind, Expr, ExprKind, LitKind, UnOp}; use rustc_errors::Applicability; diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs index 6ea2d8b06d8..be686b1b0cd 100644 --- a/src/tools/clippy/clippy_lints/src/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/ptr.rs @@ -1,10 +1,10 @@ //! Checks for usage of `&Vec[_]` and `&String`. -use crate::utils::ptr::get_spans; -use crate::utils::{ - is_allowed, is_type_diagnostic_item, match_qpath, match_type, paths, snippet_opt, span_lint, span_lint_and_sugg, - span_lint_and_then, walk_ptrs_hir_ty, -}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::ptr::get_spans; +use clippy_utils::source::snippet_opt; +use clippy_utils::ty::{is_type_diagnostic_item, match_type, walk_ptrs_hir_ty}; +use clippy_utils::{is_allowed, match_qpath, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{ diff --git a/src/tools/clippy/clippy_lints/src/ptr_eq.rs b/src/tools/clippy/clippy_lints/src/ptr_eq.rs index 3be792ce5e4..5796c59c8b3 100644 --- a/src/tools/clippy/clippy_lints/src/ptr_eq.rs +++ b/src/tools/clippy/clippy_lints/src/ptr_eq.rs @@ -1,4 +1,6 @@ -use crate::utils; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::in_macro; +use clippy_utils::source::snippet_opt; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; @@ -40,7 +42,7 @@ static LINT_MSG: &str = "use `std::ptr::eq` when comparing raw pointers"; impl LateLintPass<'_> for PtrEq { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if utils::in_macro(expr.span) { + if in_macro(expr.span) { return; } @@ -54,10 +56,10 @@ impl LateLintPass<'_> for PtrEq { if_chain! { if let Some(left_var) = expr_as_cast_to_raw_pointer(cx, left); if let Some(right_var) = expr_as_cast_to_raw_pointer(cx, right); - if let Some(left_snip) = utils::snippet_opt(cx, left_var.span); - if let Some(right_snip) = utils::snippet_opt(cx, right_var.span); + if let Some(left_snip) = snippet_opt(cx, left_var.span); + if let Some(right_snip) = snippet_opt(cx, right_var.span); then { - utils::span_lint_and_sugg( + span_lint_and_sugg( cx, PTR_EQ, expr.span, diff --git a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs index e0996804a59..c04b4255256 100644 --- a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs +++ b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs @@ -1,4 +1,5 @@ -use crate::utils::{snippet_opt, span_lint, span_lint_and_sugg}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; +use clippy_utils::source::snippet_opt; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs index 6c480d48c75..2054255a7c9 100644 --- a/src/tools/clippy/clippy_lints/src/question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/question_mark.rs @@ -1,3 +1,8 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::sugg::Sugg; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{eq_expr_value, match_def_path, match_qpath, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; @@ -6,12 +11,6 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; -use crate::utils::sugg::Sugg; -use crate::utils::{ - eq_expr_value, is_type_diagnostic_item, match_def_path, match_qpath, paths, snippet_with_applicability, - span_lint_and_sugg, -}; - declare_clippy_lint! { /// **What it does:** Checks for expressions that could be replaced by the question mark operator. /// diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs index 59503817c0f..95b21489eb5 100644 --- a/src/tools/clippy/clippy_lints/src/ranges.rs +++ b/src/tools/clippy/clippy_lints/src/ranges.rs @@ -1,4 +1,9 @@ use crate::consts::{constant, Constant}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability}; +use clippy_utils::sugg::Sugg; +use clippy_utils::{get_parent_expr, in_constant, is_integer_const, meets_msrv, single_segment_path}; +use clippy_utils::{higher, SpanlessEq}; use if_chain::if_chain; use rustc_ast::ast::RangeLimits; use rustc_errors::Applicability; @@ -12,13 +17,6 @@ use rustc_span::sym; use rustc_span::symbol::Ident; use std::cmp::Ordering; -use crate::utils::sugg::Sugg; -use crate::utils::{ - get_parent_expr, in_constant, is_integer_const, meets_msrv, single_segment_path, snippet, snippet_opt, - snippet_with_applicability, span_lint, span_lint_and_sugg, span_lint_and_then, -}; -use crate::utils::{higher, SpanlessEq}; - declare_clippy_lint! { /// **What it does:** Checks for zipping a collection with the range of /// `0.._.len()`. diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs index f90d4820563..3abe619207e 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs @@ -1,7 +1,7 @@ -use crate::utils::{ - fn_has_unsatisfiable_preds, has_drop, is_copy, is_type_diagnostic_item, match_def_path, paths, snippet_opt, - span_lint_hir, span_lint_hir_and_then, walk_ptrs_ty_depth, -}; +use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then}; +use clippy_utils::source::snippet_opt; +use clippy_utils::ty::{has_drop, is_copy, is_type_diagnostic_item, walk_ptrs_ty_depth}; +use clippy_utils::{fn_has_unsatisfiable_preds, match_def_path, paths}; use if_chain::if_chain; use rustc_data_structures::{fx::FxHashMap, transitive_relation::TransitiveRelation}; use rustc_errors::Applicability; @@ -556,7 +556,7 @@ impl<'a, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'tcx> { mir::Operand::Copy(p) | mir::Operand::Move(p) => { self.possible_borrower.add(p.local, *dest); }, - _ => (), + mir::Operand::Constant(..) => (), } } } @@ -578,7 +578,7 @@ fn rvalue_locals(rvalue: &mir::Rvalue<'_>, mut visit: impl FnMut(mir::Local)) { let mut visit_op = |op: &mir::Operand<'_>| match op { mir::Operand::Copy(p) | mir::Operand::Move(p) => visit(p.local), - _ => (), + mir::Operand::Constant(..) => (), }; match rvalue { diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs index f398b3fff25..2977a108d14 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs @@ -1,4 +1,5 @@ -use crate::utils::{snippet_with_applicability, span_lint, span_lint_and_then}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; +use clippy_utils::source::snippet_with_applicability; use if_chain::if_chain; use rustc_ast::ast; use rustc_ast::visit as ast_visit; diff --git a/src/tools/clippy/clippy_lints/src/redundant_else.rs b/src/tools/clippy/clippy_lints/src/redundant_else.rs index 3d585cd27a3..061526c6f09 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_else.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_else.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{Block, Expr, ExprKind, Stmt, StmtKind}; use rustc_ast::visit::{walk_expr, Visitor}; use rustc_lint::{EarlyContext, EarlyLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/redundant_field_names.rs b/src/tools/clippy/clippy_lints/src/redundant_field_names.rs index 9688ef39331..abebd422797 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_field_names.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_field_names.rs @@ -1,4 +1,5 @@ -use crate::utils::{meets_msrv, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::meets_msrv; use rustc_ast::ast::{Expr, ExprKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs index c876bae2303..e091095de13 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint_and_then; +use clippy_utils::diagnostics::span_lint_and_then; use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind, VisibilityKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs index e5ced13514f..6da7b5fbcc8 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs @@ -1,3 +1,6 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::is_type_lang_item; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem}; @@ -5,8 +8,6 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::{lint::in_external_macro, ty::TyS}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::{is_type_lang_item, snippet_with_applicability, span_lint_and_sugg}; - declare_clippy_lint! { /// **What it does:** Checks for redundant slicing expressions which use the full range, and /// do not change the type. diff --git a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs index fcfa3c12755..32b57698ec5 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs @@ -1,4 +1,6 @@ -use crate::utils::{meets_msrv, snippet, span_lint_and_then}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::meets_msrv; +use clippy_utils::source::snippet; use rustc_ast::ast::{Item, ItemKind, Ty, TyKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/ref_option_ref.rs b/src/tools/clippy/clippy_lints/src/ref_option_ref.rs index 8cd6692ce03..0922cfa494e 100644 --- a/src/tools/clippy/clippy_lints/src/ref_option_ref.rs +++ b/src/tools/clippy/clippy_lints/src/ref_option_ref.rs @@ -1,12 +1,13 @@ -use crate::utils::{last_path_segment, snippet, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::last_path_segment; +use clippy_utils::source::snippet; +use if_chain::if_chain; +use rustc_errors::Applicability; use rustc_hir::{GenericArg, Mutability, Ty, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::sym; -use if_chain::if_chain; -use rustc_errors::Applicability; - declare_clippy_lint! { /// **What it does:** Checks for usage of `&Option<&T>`. /// diff --git a/src/tools/clippy/clippy_lints/src/reference.rs b/src/tools/clippy/clippy_lints/src/reference.rs index e1450466a7c..d6336389b0a 100644 --- a/src/tools/clippy/clippy_lints/src/reference.rs +++ b/src/tools/clippy/clippy_lints/src/reference.rs @@ -1,5 +1,7 @@ -use crate::utils::sugg::Sugg; -use crate::utils::{in_macro, snippet_opt, snippet_with_applicability, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::in_macro; +use clippy_utils::source::{snippet_opt, snippet_with_applicability}; +use clippy_utils::sugg::Sugg; use if_chain::if_chain; use rustc_ast::ast::{Expr, ExprKind, Mutability, UnOp}; use rustc_errors::Applicability; diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs index 1edea613148..1cc332de894 100644 --- a/src/tools/clippy/clippy_lints/src/regex.rs +++ b/src/tools/clippy/clippy_lints/src/regex.rs @@ -1,5 +1,6 @@ use crate::consts::{constant, Constant}; -use crate::utils::{match_def_path, paths, span_lint, span_lint_and_help}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; +use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_ast::ast::{LitKind, StrStyle}; use rustc_data_structures::fx::FxHashSet; diff --git a/src/tools/clippy/clippy_lints/src/repeat_once.rs b/src/tools/clippy/clippy_lints/src/repeat_once.rs index d34e744eb94..63e5ec69e66 100644 --- a/src/tools/clippy/clippy_lints/src/repeat_once.rs +++ b/src/tools/clippy/clippy_lints/src/repeat_once.rs @@ -1,5 +1,8 @@ use crate::consts::{constant_context, Constant}; -use crate::utils::{in_macro, is_type_diagnostic_item, snippet, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::in_macro; +use clippy_utils::source::snippet; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs index 40c0f1f4589..8995ae431ad 100644 --- a/src/tools/clippy/clippy_lints/src/returns.rs +++ b/src/tools/clippy/clippy_lints/src/returns.rs @@ -1,3 +1,6 @@ +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::source::snippet_opt; +use clippy_utils::{fn_def_id, in_macro, match_qpath}; use if_chain::if_chain; use rustc_ast::ast::Attribute; use rustc_errors::Applicability; @@ -11,8 +14,6 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::sym; -use crate::utils::{fn_def_id, in_macro, match_qpath, snippet_opt, span_lint_and_sugg, span_lint_and_then}; - declare_clippy_lint! { /// **What it does:** Checks for `let`-bindings, which are subsequently /// returned. diff --git a/src/tools/clippy/clippy_lints/src/self_assignment.rs b/src/tools/clippy/clippy_lints/src/self_assignment.rs index e096c9aebc1..e7925c4fbde 100644 --- a/src/tools/clippy/clippy_lints/src/self_assignment.rs +++ b/src/tools/clippy/clippy_lints/src/self_assignment.rs @@ -1,4 +1,6 @@ -use crate::utils::{eq_expr_value, snippet, span_lint}; +use clippy_utils::diagnostics::span_lint; +use clippy_utils::eq_expr_value; +use clippy_utils::source::snippet; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs b/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs index 839c995e525..f61af15fbed 100644 --- a/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs +++ b/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs @@ -1,4 +1,6 @@ -use crate::utils::{in_macro, snippet_with_macro_callsite, span_lint_and_sugg, sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_macro_callsite; +use clippy_utils::{in_macro, sugg}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Block, ExprKind}; diff --git a/src/tools/clippy/clippy_lints/src/serde_api.rs b/src/tools/clippy/clippy_lints/src/serde_api.rs index 90cf1b6c861..169f7d26285 100644 --- a/src/tools/clippy/clippy_lints/src/serde_api.rs +++ b/src/tools/clippy/clippy_lints/src/serde_api.rs @@ -1,4 +1,5 @@ -use crate::utils::{get_trait_def_id, paths, span_lint}; +use clippy_utils::diagnostics::span_lint; +use clippy_utils::{get_trait_def_id, paths}; use rustc_hir::{Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs index 32f6bc74642..612d2fd84cb 100644 --- a/src/tools/clippy/clippy_lints/src/shadow.rs +++ b/src/tools/clippy/clippy_lints/src/shadow.rs @@ -1,4 +1,6 @@ -use crate::utils::{contains_name, higher, iter_input_pats, snippet, span_lint_and_then}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::snippet; +use clippy_utils::{contains_name, higher, iter_input_pats}; use rustc_hir::intravisit::FnKind; use rustc_hir::{ Block, Body, Expr, ExprKind, FnDecl, Guard, HirId, Local, MutTy, Pat, PatKind, Path, QPath, StmtKind, Ty, TyKind, diff --git a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs index 1fc4ff5c2e6..c9d72aabb6a 100644 --- a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs +++ b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs @@ -1,4 +1,5 @@ -use crate::utils::{in_macro, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::in_macro; use if_chain::if_chain; use rustc_ast::{Item, ItemKind, UseTreeKind}; use rustc_errors::Applicability; diff --git a/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs b/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs index 87e386baadc..09e00866815 100644 --- a/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs +++ b/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs @@ -1,7 +1,8 @@ //! Lint on use of `size_of` or `size_of_val` of T in an expression //! expecting a count of T -use crate::utils::{match_def_path, paths, span_lint_and_help}; +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_hir::BinOpKind; use rustc_hir::{Expr, ExprKind}; diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs index 96f6881556c..d55a83f1613 100644 --- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs +++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs @@ -1,5 +1,6 @@ -use crate::utils::sugg::Sugg; -use crate::utils::{get_enclosing_block, match_qpath, span_lint_and_then, SpanlessEq}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::sugg::Sugg; +use clippy_utils::{get_enclosing_block, match_qpath, SpanlessEq}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; diff --git a/src/tools/clippy/clippy_lints/src/stable_sort_primitive.rs b/src/tools/clippy/clippy_lints/src/stable_sort_primitive.rs index 276a9338819..65790375c73 100644 --- a/src/tools/clippy/clippy_lints/src/stable_sort_primitive.rs +++ b/src/tools/clippy/clippy_lints/src/stable_sort_primitive.rs @@ -1,7 +1,6 @@ -use crate::utils::{is_slice_of_primitives, span_lint_and_then, sugg::Sugg}; - +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::{is_slice_of_primitives, sugg::Sugg}; use if_chain::if_chain; - use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs index 31dd5965473..99ca7ef77a5 100644 --- a/src/tools/clippy/clippy_lints/src/strings.rs +++ b/src/tools/clippy/clippy_lints/src/strings.rs @@ -1,3 +1,9 @@ +use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg}; +use clippy_utils::source::{snippet, snippet_with_applicability}; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::SpanlessEq; +use clippy_utils::{get_parent_expr, is_allowed, match_function_call, method_calls, paths}; +use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, LangItem, QPath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -7,14 +13,6 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Spanned; use rustc_span::sym; -use if_chain::if_chain; - -use crate::utils::SpanlessEq; -use crate::utils::{ - get_parent_expr, is_allowed, is_type_diagnostic_item, match_function_call, method_calls, paths, span_lint, - span_lint_and_help, span_lint_and_sugg, -}; - declare_clippy_lint! { /// **What it does:** Checks for string appends of the form `x = x + y` (without /// `let`!). @@ -205,7 +203,6 @@ declare_lint_pass!(StringLitAsBytes => [STRING_LIT_AS_BYTES, STRING_FROM_UTF8_AS impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { - use crate::utils::{snippet, snippet_with_applicability}; use rustc_ast::LitKind; if_chain! { @@ -287,6 +284,35 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { } } } + + if_chain! { + if let ExprKind::MethodCall(path, _, [recv], _) = &e.kind; + if path.ident.name == sym!(into_bytes); + if let ExprKind::MethodCall(path, _, [recv], _) = &recv.kind; + if matches!(&*path.ident.name.as_str(), "to_owned" | "to_string"); + if let ExprKind::Lit(lit) = &recv.kind; + if let LitKind::Str(lit_content, _) = &lit.node; + + if lit_content.as_str().is_ascii(); + if lit_content.as_str().len() <= MAX_LENGTH_BYTE_STRING_LIT; + if !recv.span.from_expansion(); + then { + let mut applicability = Applicability::MachineApplicable; + + span_lint_and_sugg( + cx, + STRING_LIT_AS_BYTES, + e.span, + "calling `into_bytes()` on a string literal", + "consider using a byte string literal instead", + format!( + "b{}.to_vec()", + snippet_with_applicability(cx, recv.span, r#""..""#, &mut applicability) + ), + applicability, + ); + } + } } } diff --git a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs index 9acc47deb06..46f423204a2 100644 --- a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs +++ b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs @@ -1,5 +1,6 @@ -use crate::utils::ast_utils::{eq_id, is_useless_with_eq_exprs, IdentIter}; -use crate::utils::{snippet_with_applicability, span_lint_and_sugg}; +use clippy_utils::ast_utils::{eq_id, is_useless_with_eq_exprs, IdentIter}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; use core::ops::{Add, AddAssign}; use if_chain::if_chain; use rustc_ast::ast::{BinOpKind, Expr, ExprKind, StmtKind}; diff --git a/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs b/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs index 0b7d08cb164..99e3d818b79 100644 --- a/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs +++ b/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs @@ -1,4 +1,5 @@ -use crate::utils::{get_trait_def_id, span_lint, trait_ref_of_method}; +use clippy_utils::diagnostics::span_lint; +use clippy_utils::{get_trait_def_id, paths, trait_ref_of_method}; use if_chain::if_chain; use rustc_hir as hir; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; @@ -158,7 +159,7 @@ fn check_binop( expected_ops: &[hir::BinOpKind], ) -> Option<&'static str> { let mut trait_ids = vec![]; - let [krate, module] = crate::utils::paths::OPS_MODULE; + let [krate, module] = paths::OPS_MODULE; for &t in traits { let path = [krate, module, t]; diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs index 9d8a0c24833..14519eaa962 100644 --- a/src/tools/clippy/clippy_lints/src/swap.rs +++ b/src/tools/clippy/clippy_lints/src/swap.rs @@ -1,7 +1,8 @@ -use crate::utils::sugg::Sugg; -use crate::utils::{ - differing_macro_contexts, eq_expr_value, is_type_diagnostic_item, snippet_with_applicability, span_lint_and_then, -}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::sugg::Sugg; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{differing_macro_contexts, eq_expr_value}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Block, Expr, ExprKind, PatKind, QPath, StmtKind}; diff --git a/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs b/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs index 74ccd9235de..88bd2feaadd 100644 --- a/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs +++ b/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_sugg; use rustc_ast::ast; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/temporary_assignment.rs b/src/tools/clippy/clippy_lints/src/temporary_assignment.rs index fb891866364..8ef25dc816c 100644 --- a/src/tools/clippy/clippy_lints/src/temporary_assignment.rs +++ b/src/tools/clippy/clippy_lints/src/temporary_assignment.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_adjusted, span_lint}; +use clippy_utils::diagnostics::span_lint; +use clippy_utils::is_adjusted; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs b/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs index eeda39bfa20..c66a596c784 100644 --- a/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs +++ b/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs @@ -1,4 +1,6 @@ -use crate::utils::{match_def_path, snippet_with_applicability, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::match_def_path; +use clippy_utils::source::snippet_with_applicability; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/src/tools/clippy/clippy_lints/src/to_string_in_display.rs b/src/tools/clippy/clippy_lints/src/to_string_in_display.rs index 84ec2aa18ab..42ec14c31b5 100644 --- a/src/tools/clippy/clippy_lints/src/to_string_in_display.rs +++ b/src/tools/clippy/clippy_lints/src/to_string_in_display.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_diagnostic_assoc_item, match_def_path, path_to_local_id, paths, span_lint}; +use clippy_utils::diagnostics::span_lint; +use clippy_utils::{is_diagnostic_assoc_item, match_def_path, path_to_local_id, paths}; use if_chain::if_chain; use rustc_hir::{Expr, ExprKind, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs index daff5f81e8c..3ff27c3bcf4 100644 --- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs +++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs @@ -1,4 +1,6 @@ -use crate::utils::{in_macro, snippet, snippet_with_applicability, span_lint_and_help, SpanlessHash}; +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::source::{snippet, snippet_with_applicability}; +use clippy_utils::{in_macro, SpanlessHash}; use if_chain::if_chain; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; diff --git a/src/tools/clippy/clippy_lints/src/transmute/crosspointer_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/crosspointer_transmute.rs index ce87defaa94..25d0543c861 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/crosspointer_transmute.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/crosspointer_transmute.rs @@ -1,5 +1,5 @@ use super::CROSSPOINTER_TRANSMUTE; -use crate::utils::span_lint; +use clippy_utils::diagnostics::span_lint; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; diff --git a/src/tools/clippy/clippy_lints/src/transmute/mod.rs b/src/tools/clippy/clippy_lints/src/transmute/mod.rs index c1870f5208b..47d58bd30db 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/mod.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/mod.rs @@ -12,7 +12,7 @@ mod useless_transmute; mod utils; mod wrong_transmute; -use crate::utils::{in_constant, match_def_path, paths}; +use clippy_utils::{in_constant, match_def_path, paths}; use if_chain::if_chain; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs index 562d880e39a..72489f27cd3 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs @@ -1,5 +1,6 @@ use super::TRANSMUTE_FLOAT_TO_INT; -use crate::utils::{span_lint_and_then, sugg}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::sugg; use if_chain::if_chain; use rustc_ast as ast; use rustc_errors::Applicability; diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_bool.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_bool.rs index 5b609f906a3..cc0a5643e2a 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_bool.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_bool.rs @@ -1,5 +1,6 @@ use super::TRANSMUTE_INT_TO_BOOL; -use crate::utils::{span_lint_and_then, sugg}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::sugg; use rustc_ast as ast; use rustc_errors::Applicability; use rustc_hir::Expr; diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_char.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_char.rs index 29d2450618a..8f884e6a4a1 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_char.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_char.rs @@ -1,5 +1,6 @@ use super::TRANSMUTE_INT_TO_CHAR; -use crate::utils::{span_lint_and_then, sugg}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::sugg; use rustc_ast as ast; use rustc_errors::Applicability; use rustc_hir::Expr; diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_float.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_float.rs index f83fba8966a..2b6a4cff81e 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_float.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_float.rs @@ -1,5 +1,6 @@ use super::TRANSMUTE_INT_TO_FLOAT; -use crate::utils::{span_lint_and_then, sugg}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::sugg; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs index f4e60a3020c..7b646bfc0c6 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs @@ -1,5 +1,6 @@ use super::TRANSMUTE_PTR_TO_PTR; -use crate::utils::{span_lint_and_then, sugg}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::sugg; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs index f5dbbbe33bc..f14eef93645 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs @@ -1,6 +1,7 @@ use super::utils::get_type_snippet; use super::TRANSMUTE_PTR_TO_REF; -use crate::utils::{span_lint_and_then, sugg}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::sugg; use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability, QPath}; use rustc_lint::LateContext; diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs index 01b00bb0a22..d105e37abf9 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs @@ -1,5 +1,7 @@ use super::{TRANSMUTE_BYTES_TO_STR, TRANSMUTE_PTR_TO_PTR}; -use crate::utils::{snippet, span_lint_and_sugg, span_lint_and_then, sugg}; +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::source::snippet; +use clippy_utils::sugg; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability}; diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs b/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs index dea896622f1..e2c6d130f3c 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs @@ -1,6 +1,7 @@ use super::utils::can_be_expressed_as_pointer_cast; use super::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS; -use crate::utils::{span_lint_and_then, sugg}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::sugg; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; diff --git a/src/tools/clippy/clippy_lints/src/transmute/unsound_collection_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/unsound_collection_transmute.rs index 503c5e0ff38..de9277e016e 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/unsound_collection_transmute.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/unsound_collection_transmute.rs @@ -1,6 +1,7 @@ use super::utils::is_layout_incompatible; use super::UNSOUND_COLLECTION_TRANSMUTE; -use crate::utils::{match_def_path, paths, span_lint}; +use clippy_utils::diagnostics::span_lint; +use clippy_utils::{match_def_path, paths}; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; diff --git a/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs index 83441514af0..445bcf60fa7 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs @@ -1,5 +1,6 @@ use super::USELESS_TRANSMUTE; -use crate::utils::{span_lint, span_lint_and_then, sugg}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; +use clippy_utils::sugg; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; diff --git a/src/tools/clippy/clippy_lints/src/transmute/utils.rs b/src/tools/clippy/clippy_lints/src/transmute/utils.rs index 55008d8ec3f..c6d0d63b0b5 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/utils.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/utils.rs @@ -1,4 +1,6 @@ -use crate::utils::{is_normalizable, last_path_segment, snippet}; +use clippy_utils::last_path_segment; +use clippy_utils::source::snippet; +use clippy_utils::ty::is_normalizable; use if_chain::if_chain; use rustc_hir::{Expr, GenericArg, QPath, TyKind}; use rustc_lint::LateContext; diff --git a/src/tools/clippy/clippy_lints/src/transmute/wrong_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/wrong_transmute.rs index d6d77f2c834..2118f3d6950 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/wrong_transmute.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/wrong_transmute.rs @@ -1,5 +1,5 @@ use super::WRONG_TRANSMUTE; -use crate::utils::span_lint; +use clippy_utils::diagnostics::span_lint; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; diff --git a/src/tools/clippy/clippy_lints/src/transmuting_null.rs b/src/tools/clippy/clippy_lints/src/transmuting_null.rs index 2ba2b646f00..d42cdde110e 100644 --- a/src/tools/clippy/clippy_lints/src/transmuting_null.rs +++ b/src/tools/clippy/clippy_lints/src/transmuting_null.rs @@ -1,5 +1,6 @@ use crate::consts::{constant_context, Constant}; -use crate::utils::{match_qpath, paths, span_lint}; +use clippy_utils::diagnostics::span_lint; +use clippy_utils::{match_qpath, paths}; use if_chain::if_chain; use rustc_ast::LitKind; use rustc_hir::{Expr, ExprKind}; diff --git a/src/tools/clippy/clippy_lints/src/try_err.rs b/src/tools/clippy/clippy_lints/src/try_err.rs index 73e3a04aec9..e61058c2749 100644 --- a/src/tools/clippy/clippy_lints/src/try_err.rs +++ b/src/tools/clippy/clippy_lints/src/try_err.rs @@ -1,7 +1,7 @@ -use crate::utils::{ - differing_macro_contexts, in_macro, is_type_diagnostic_item, match_def_path, match_qpath, paths, snippet, - snippet_with_macro_callsite, span_lint_and_sugg, -}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::{snippet, snippet_with_macro_callsite}; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{differing_macro_contexts, in_macro, match_def_path, match_qpath, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem, MatchSource, QPath}; diff --git a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs index 81090040d92..d68c6db4e23 100644 --- a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs +++ b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs @@ -1,3 +1,7 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet; +use clippy_utils::{match_path, paths}; +use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{ self as hir, GenericArg, GenericBounds, GenericParamKind, HirId, Lifetime, MutTy, Mutability, Node, QPath, @@ -5,10 +9,6 @@ use rustc_hir::{ }; use rustc_lint::LateContext; -use if_chain::if_chain; - -use crate::utils::{match_path, paths, snippet, span_lint_and_sugg}; - use super::BORROWED_BOX; pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, mut_ty: &MutTy<'_>) -> bool { diff --git a/src/tools/clippy/clippy_lints/src/types/box_vec.rs b/src/tools/clippy/clippy_lints/src/types/box_vec.rs index 6aa98e435e1..d8b1953457c 100644 --- a/src/tools/clippy/clippy_lints/src/types/box_vec.rs +++ b/src/tools/clippy/clippy_lints/src/types/box_vec.rs @@ -1,9 +1,9 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::is_ty_param_diagnostic_item; use rustc_hir::{self as hir, def_id::DefId, QPath}; use rustc_lint::LateContext; use rustc_span::symbol::sym; -use crate::utils::{is_ty_param_diagnostic_item, span_lint_and_help}; - use super::BOX_VEC; pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool { diff --git a/src/tools/clippy/clippy_lints/src/types/linked_list.rs b/src/tools/clippy/clippy_lints/src/types/linked_list.rs index 47eb4ede4e4..a9fbe7aa315 100644 --- a/src/tools/clippy/clippy_lints/src/types/linked_list.rs +++ b/src/tools/clippy/clippy_lints/src/types/linked_list.rs @@ -1,8 +1,8 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::{match_def_path, paths}; use rustc_hir::{self as hir, def_id::DefId}; use rustc_lint::LateContext; -use crate::utils::{match_def_path, paths, span_lint_and_help}; - use super::LINKEDLIST; pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, def_id: DefId) -> bool { diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs index 4a1a608e8ae..c73c1c9d92d 100644 --- a/src/tools/clippy/clippy_lints/src/types/mod.rs +++ b/src/tools/clippy/clippy_lints/src/types/mod.rs @@ -13,21 +13,22 @@ use std::borrow::Cow; use std::cmp::Ordering; use std::collections::BTreeMap; +use clippy_utils::diagnostics::{multispan_sugg, span_lint, span_lint_and_help, span_lint_and_then}; +use clippy_utils::source::{snippet, snippet_opt}; +use clippy_utils::ty::{is_isize_or_usize, is_type_diagnostic_item}; use if_chain::if_chain; -use rustc_errors::{Applicability, DiagnosticBuilder}; +use rustc_errors::DiagnosticBuilder; use rustc_hir as hir; use rustc_hir::intravisit::{walk_body, walk_expr, walk_ty, FnKind, NestedVisitorMap, Visitor}; use rustc_hir::{ - BinOpKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, FnSig, GenericArg, GenericParamKind, HirId, ImplItem, - ImplItemKind, Item, ItemKind, Local, MatchSource, MutTy, Node, QPath, Stmt, StmtKind, TraitFn, TraitItem, - TraitItemKind, TyKind, + BinOpKind, Body, Expr, ExprKind, FnDecl, FnRetTy, FnSig, GenericArg, GenericParamKind, HirId, ImplItem, + ImplItemKind, Item, ItemKind, Local, MutTy, QPath, TraitFn, TraitItem, TraitItemKind, TyKind, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::map::Map; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, IntTy, Ty, TyS, TypeckResults, UintTy}; use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; -use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::Span; use rustc_span::symbol::sym; use rustc_target::abi::LayoutOf; @@ -35,12 +36,8 @@ use rustc_target::spec::abi::Abi; use rustc_typeck::hir_ty_to_ty; use crate::consts::{constant, Constant}; -use crate::utils::paths; -use crate::utils::{ - clip, comparisons, differing_macro_contexts, higher, indent_of, int_bits, is_isize_or_usize, - is_type_diagnostic_item, match_path, multispan_sugg, reindent_multiline, sext, snippet, snippet_opt, - snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_then, unsext, -}; +use clippy_utils::paths; +use clippy_utils::{clip, comparisons, differing_macro_contexts, int_bits, match_path, sext, unsext}; declare_clippy_lint! { /// **What it does:** Checks for use of `Box<Vec<_>>` anywhere in the code. @@ -279,7 +276,7 @@ impl<'tcx> LateLintPass<'tcx> for Types { match item.kind { TraitItemKind::Const(ref ty, _) | TraitItemKind::Type(_, Some(ref ty)) => self.check_ty(cx, ty, false), TraitItemKind::Fn(ref sig, _) => self.check_fn_decl(cx, &sig.decl), - _ => (), + TraitItemKind::Type(..) => (), } } @@ -391,390 +388,6 @@ impl Types { } declare_clippy_lint! { - /// **What it does:** Checks for binding a unit value. - /// - /// **Why is this bad?** A unit value cannot usefully be used anywhere. So - /// binding one is kind of pointless. - /// - /// **Known problems:** None. - /// - /// **Example:** - /// ```rust - /// let x = { - /// 1; - /// }; - /// ``` - pub LET_UNIT_VALUE, - pedantic, - "creating a `let` binding to a value of unit type, which usually can't be used afterwards" -} - -declare_lint_pass!(LetUnitValue => [LET_UNIT_VALUE]); - -impl<'tcx> LateLintPass<'tcx> for LetUnitValue { - fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { - if let StmtKind::Local(ref local) = stmt.kind { - if is_unit(cx.typeck_results().pat_ty(&local.pat)) { - if in_external_macro(cx.sess(), stmt.span) || local.pat.span.from_expansion() { - return; - } - if higher::is_from_for_desugar(local) { - return; - } - span_lint_and_then( - cx, - LET_UNIT_VALUE, - stmt.span, - "this let-binding has unit value", - |diag| { - if let Some(expr) = &local.init { - let snip = snippet_with_macro_callsite(cx, expr.span, "()"); - diag.span_suggestion( - stmt.span, - "omit the `let` binding", - format!("{};", snip), - Applicability::MachineApplicable, // snippet - ); - } - }, - ); - } - } - } -} - -declare_clippy_lint! { - /// **What it does:** Checks for comparisons to unit. This includes all binary - /// comparisons (like `==` and `<`) and asserts. - /// - /// **Why is this bad?** Unit is always equal to itself, and thus is just a - /// clumsily written constant. Mostly this happens when someone accidentally - /// adds semicolons at the end of the operands. - /// - /// **Known problems:** None. - /// - /// **Example:** - /// ```rust - /// # fn foo() {}; - /// # fn bar() {}; - /// # fn baz() {}; - /// if { - /// foo(); - /// } == { - /// bar(); - /// } { - /// baz(); - /// } - /// ``` - /// is equal to - /// ```rust - /// # fn foo() {}; - /// # fn bar() {}; - /// # fn baz() {}; - /// { - /// foo(); - /// bar(); - /// baz(); - /// } - /// ``` - /// - /// For asserts: - /// ```rust - /// # fn foo() {}; - /// # fn bar() {}; - /// assert_eq!({ foo(); }, { bar(); }); - /// ``` - /// will always succeed - pub UNIT_CMP, - correctness, - "comparing unit values" -} - -declare_lint_pass!(UnitCmp => [UNIT_CMP]); - -impl<'tcx> LateLintPass<'tcx> for UnitCmp { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if expr.span.from_expansion() { - if let Some(callee) = expr.span.source_callee() { - if let ExpnKind::Macro(MacroKind::Bang, symbol) = callee.kind { - if let ExprKind::Binary(ref cmp, ref left, _) = expr.kind { - let op = cmp.node; - if op.is_comparison() && is_unit(cx.typeck_results().expr_ty(left)) { - let result = match &*symbol.as_str() { - "assert_eq" | "debug_assert_eq" => "succeed", - "assert_ne" | "debug_assert_ne" => "fail", - _ => return, - }; - span_lint( - cx, - UNIT_CMP, - expr.span, - &format!( - "`{}` of unit values detected. This will always {}", - symbol.as_str(), - result - ), - ); - } - } - } - } - return; - } - if let ExprKind::Binary(ref cmp, ref left, _) = expr.kind { - let op = cmp.node; - if op.is_comparison() && is_unit(cx.typeck_results().expr_ty(left)) { - let result = match op { - BinOpKind::Eq | BinOpKind::Le | BinOpKind::Ge => "true", - _ => "false", - }; - span_lint( - cx, - UNIT_CMP, - expr.span, - &format!( - "{}-comparison of unit values detected. This will always be {}", - op.as_str(), - result - ), - ); - } - } - } -} - -declare_clippy_lint! { - /// **What it does:** Checks for passing a unit value as an argument to a function without using a - /// unit literal (`()`). - /// - /// **Why is this bad?** This is likely the result of an accidental semicolon. - /// - /// **Known problems:** None. - /// - /// **Example:** - /// ```rust,ignore - /// foo({ - /// let a = bar(); - /// baz(a); - /// }) - /// ``` - pub UNIT_ARG, - complexity, - "passing unit to a function" -} - -declare_lint_pass!(UnitArg => [UNIT_ARG]); - -impl<'tcx> LateLintPass<'tcx> for UnitArg { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if expr.span.from_expansion() { - return; - } - - // apparently stuff in the desugaring of `?` can trigger this - // so check for that here - // only the calls to `Try::from_error` is marked as desugared, - // so we need to check both the current Expr and its parent. - if is_questionmark_desugar_marked_call(expr) { - return; - } - if_chain! { - let map = &cx.tcx.hir(); - let opt_parent_node = map.find(map.get_parent_node(expr.hir_id)); - if let Some(hir::Node::Expr(parent_expr)) = opt_parent_node; - if is_questionmark_desugar_marked_call(parent_expr); - then { - return; - } - } - - match expr.kind { - ExprKind::Call(_, args) | ExprKind::MethodCall(_, _, args, _) => { - let args_to_recover = args - .iter() - .filter(|arg| { - if is_unit(cx.typeck_results().expr_ty(arg)) && !is_unit_literal(arg) { - !matches!( - &arg.kind, - ExprKind::Match(.., MatchSource::TryDesugar) | ExprKind::Path(..) - ) - } else { - false - } - }) - .collect::<Vec<_>>(); - if !args_to_recover.is_empty() { - lint_unit_args(cx, expr, &args_to_recover); - } - }, - _ => (), - } - } -} - -fn fmt_stmts_and_call( - cx: &LateContext<'_>, - call_expr: &Expr<'_>, - call_snippet: &str, - args_snippets: &[impl AsRef<str>], - non_empty_block_args_snippets: &[impl AsRef<str>], -) -> String { - let call_expr_indent = indent_of(cx, call_expr.span).unwrap_or(0); - let call_snippet_with_replacements = args_snippets - .iter() - .fold(call_snippet.to_owned(), |acc, arg| acc.replacen(arg.as_ref(), "()", 1)); - - let mut stmts_and_call = non_empty_block_args_snippets - .iter() - .map(|it| it.as_ref().to_owned()) - .collect::<Vec<_>>(); - stmts_and_call.push(call_snippet_with_replacements); - stmts_and_call = stmts_and_call - .into_iter() - .map(|v| reindent_multiline(v.into(), true, Some(call_expr_indent)).into_owned()) - .collect(); - - let mut stmts_and_call_snippet = stmts_and_call.join(&format!("{}{}", ";\n", " ".repeat(call_expr_indent))); - // expr is not in a block statement or result expression position, wrap in a block - let parent_node = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(call_expr.hir_id)); - if !matches!(parent_node, Some(Node::Block(_))) && !matches!(parent_node, Some(Node::Stmt(_))) { - let block_indent = call_expr_indent + 4; - stmts_and_call_snippet = - reindent_multiline(stmts_and_call_snippet.into(), true, Some(block_indent)).into_owned(); - stmts_and_call_snippet = format!( - "{{\n{}{}\n{}}}", - " ".repeat(block_indent), - &stmts_and_call_snippet, - " ".repeat(call_expr_indent) - ); - } - stmts_and_call_snippet -} - -fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Expr<'_>]) { - let mut applicability = Applicability::MachineApplicable; - let (singular, plural) = if args_to_recover.len() > 1 { - ("", "s") - } else { - ("a ", "") - }; - span_lint_and_then( - cx, - UNIT_ARG, - expr.span, - &format!("passing {}unit value{} to a function", singular, plural), - |db| { - let mut or = ""; - args_to_recover - .iter() - .filter_map(|arg| { - if_chain! { - if let ExprKind::Block(block, _) = arg.kind; - if block.expr.is_none(); - if let Some(last_stmt) = block.stmts.iter().last(); - if let StmtKind::Semi(last_expr) = last_stmt.kind; - if let Some(snip) = snippet_opt(cx, last_expr.span); - then { - Some(( - last_stmt.span, - snip, - )) - } - else { - None - } - } - }) - .for_each(|(span, sugg)| { - db.span_suggestion( - span, - "remove the semicolon from the last statement in the block", - sugg, - Applicability::MaybeIncorrect, - ); - or = "or "; - applicability = Applicability::MaybeIncorrect; - }); - - let arg_snippets: Vec<String> = args_to_recover - .iter() - .filter_map(|arg| snippet_opt(cx, arg.span)) - .collect(); - let arg_snippets_without_empty_blocks: Vec<String> = args_to_recover - .iter() - .filter(|arg| !is_empty_block(arg)) - .filter_map(|arg| snippet_opt(cx, arg.span)) - .collect(); - - if let Some(call_snippet) = snippet_opt(cx, expr.span) { - let sugg = fmt_stmts_and_call( - cx, - expr, - &call_snippet, - &arg_snippets, - &arg_snippets_without_empty_blocks, - ); - - if arg_snippets_without_empty_blocks.is_empty() { - db.multipart_suggestion( - &format!("use {}unit literal{} instead", singular, plural), - args_to_recover - .iter() - .map(|arg| (arg.span, "()".to_string())) - .collect::<Vec<_>>(), - applicability, - ); - } else { - let plural = arg_snippets_without_empty_blocks.len() > 1; - let empty_or_s = if plural { "s" } else { "" }; - let it_or_them = if plural { "them" } else { "it" }; - db.span_suggestion( - expr.span, - &format!( - "{}move the expression{} in front of the call and replace {} with the unit literal `()`", - or, empty_or_s, it_or_them - ), - sugg, - applicability, - ); - } - } - }, - ); -} - -fn is_empty_block(expr: &Expr<'_>) -> bool { - matches!( - expr.kind, - ExprKind::Block( - Block { - stmts: &[], - expr: None, - .. - }, - _, - ) - ) -} - -fn is_questionmark_desugar_marked_call(expr: &Expr<'_>) -> bool { - use rustc_span::hygiene::DesugaringKind; - if let ExprKind::Call(ref callee, _) = expr.kind { - callee.span.is_desugaring(DesugaringKind::QuestionMark) - } else { - false - } -} - -fn is_unit(ty: Ty<'_>) -> bool { - matches!(ty.kind(), ty::Tuple(slice) if slice.is_empty()) -} - -fn is_unit_literal(expr: &Expr<'_>) -> bool { - matches!(expr.kind, ExprKind::Tup(ref slice) if slice.is_empty()) -} - -declare_clippy_lint! { /// **What it does:** Checks for types used in structs, parameters and `let` /// declarations above a certain complexity threshold. /// @@ -839,7 +452,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeComplexity { TraitItemKind::Const(ref ty, _) | TraitItemKind::Type(_, Some(ref ty)) => self.check_type(cx, ty), TraitItemKind::Fn(FnSig { ref decl, .. }, TraitFn::Required(_)) => self.check_fndecl(cx, decl), // methods with default impl are covered by check_fn - _ => (), + TraitItemKind::Type(..) | TraitItemKind::Fn(_, TraitFn::Provided(_)) => (), } } @@ -847,7 +460,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeComplexity { match item.kind { ImplItemKind::Const(ref ty, _) | ImplItemKind::TyAlias(ref ty) => self.check_type(cx, ty), // methods are covered by check_fn - _ => (), + ImplItemKind::Fn(..) => (), } } @@ -911,7 +524,7 @@ impl<'tcx> Visitor<'tcx> for TypeComplexityVisitor { // function types bring a lot of overhead TyKind::BareFn(ref bare) if bare.abi == Abi::Rust => (50 * self.nest, 1), - TyKind::TraitObject(ref param_bounds, ..) => { + TyKind::TraitObject(ref param_bounds, _, _) => { let has_lifetime_parameters = param_bounds.iter().any(|bound| { bound .bound_generic_params @@ -1005,7 +618,7 @@ fn detect_absurd_comparison<'tcx>( ) -> Option<(ExtremeExpr<'tcx>, AbsurdComparisonResult)> { use crate::types::AbsurdComparisonResult::{AlwaysFalse, AlwaysTrue, InequalityImpossible}; use crate::types::ExtremeType::{Maximum, Minimum}; - use crate::utils::comparisons::{normalize_comparison, Rel}; + use clippy_utils::comparisons::{normalize_comparison, Rel}; // absurd comparison only makes sense on primitive types // primitive types don't implement comparison operators with each other @@ -1247,7 +860,7 @@ fn upcast_comparison_bounds_err<'tcx>( rhs: &'tcx Expr<'_>, invert: bool, ) { - use crate::utils::comparisons::Rel; + use clippy_utils::comparisons::Rel; if let Some((lb, ub)) = lhs_bounds { if let Some(norm_rhs_val) = node_as_const_fullint(cx, rhs) { diff --git a/src/tools/clippy/clippy_lints/src/types/option_option.rs b/src/tools/clippy/clippy_lints/src/types/option_option.rs index dc5db963b4e..b2692c48076 100644 --- a/src/tools/clippy/clippy_lints/src/types/option_option.rs +++ b/src/tools/clippy/clippy_lints/src/types/option_option.rs @@ -1,9 +1,9 @@ +use clippy_utils::diagnostics::span_lint; +use clippy_utils::is_ty_param_diagnostic_item; use rustc_hir::{self as hir, def_id::DefId, QPath}; use rustc_lint::LateContext; use rustc_span::symbol::sym; -use crate::utils::{is_ty_param_diagnostic_item, span_lint}; - use super::OPTION_OPTION; pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool { diff --git a/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs b/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs index e34b95147e1..ef629a35d10 100644 --- a/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs +++ b/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs @@ -1,12 +1,11 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::{get_qpath_generic_tys, is_ty_param_diagnostic_item}; use rustc_errors::Applicability; use rustc_hir::{self as hir, def_id::DefId, QPath, TyKind}; use rustc_lint::LateContext; use rustc_span::symbol::sym; -use crate::utils::{ - get_qpath_generic_tys, is_ty_param_diagnostic_item, snippet_with_applicability, span_lint_and_sugg, -}; - use super::RC_BUFFER; pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool { diff --git a/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs b/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs index 5da6db179c4..c0c1f340583 100644 --- a/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs +++ b/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs @@ -1,13 +1,11 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::{get_qpath_generic_tys, is_ty_param_diagnostic_item, is_ty_param_lang_item}; use rustc_errors::Applicability; use rustc_hir::{self as hir, def_id::DefId, LangItem, QPath, TyKind}; use rustc_lint::LateContext; use rustc_span::symbol::sym; -use crate::utils::{ - get_qpath_generic_tys, is_ty_param_diagnostic_item, is_ty_param_lang_item, snippet_with_applicability, - span_lint_and_sugg, -}; - use super::{utils, REDUNDANT_ALLOCATION}; pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool { diff --git a/src/tools/clippy/clippy_lints/src/types/utils.rs b/src/tools/clippy/clippy_lints/src/types/utils.rs index 4d64748f998..45f891ed718 100644 --- a/src/tools/clippy/clippy_lints/src/types/utils.rs +++ b/src/tools/clippy/clippy_lints/src/types/utils.rs @@ -1,11 +1,9 @@ +use clippy_utils::last_path_segment; +use if_chain::if_chain; use rustc_hir::{GenericArg, QPath, TyKind}; use rustc_lint::LateContext; use rustc_span::source_map::Span; -use crate::utils::last_path_segment; - -use if_chain::if_chain; - pub(super) fn match_borrows_parameter(_cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option<Span> { let last = last_path_segment(qpath); if_chain! { diff --git a/src/tools/clippy/clippy_lints/src/types/vec_box.rs b/src/tools/clippy/clippy_lints/src/types/vec_box.rs index 2530cc133c6..d2c373db261 100644 --- a/src/tools/clippy/clippy_lints/src/types/vec_box.rs +++ b/src/tools/clippy/clippy_lints/src/types/vec_box.rs @@ -1,3 +1,7 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::last_path_segment; +use clippy_utils::source::snippet; +use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{self as hir, def_id::DefId, GenericArg, QPath, TyKind}; use rustc_lint::LateContext; @@ -6,10 +10,6 @@ use rustc_span::symbol::sym; use rustc_target::abi::LayoutOf; use rustc_typeck::hir_ty_to_ty; -use if_chain::if_chain; - -use crate::utils::{last_path_segment, snippet, span_lint_and_sugg}; - use super::VEC_BOX; pub(super) fn check( diff --git a/src/tools/clippy/clippy_lints/src/undropped_manually_drops.rs b/src/tools/clippy/clippy_lints/src/undropped_manually_drops.rs index 5443f1601fc..b6749069176 100644 --- a/src/tools/clippy/clippy_lints/src/undropped_manually_drops.rs +++ b/src/tools/clippy/clippy_lints/src/undropped_manually_drops.rs @@ -1,4 +1,6 @@ -use crate::utils::{is_type_lang_item, match_function_call, paths, span_lint_and_help}; +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::ty::is_type_lang_item; +use clippy_utils::{match_function_call, paths}; use rustc_hir::{lang_items, Expr}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/src/tools/clippy/clippy_lints/src/unicode.rs b/src/tools/clippy/clippy_lints/src/unicode.rs index 93d59cc7fcd..d81e31f5a21 100644 --- a/src/tools/clippy/clippy_lints/src/unicode.rs +++ b/src/tools/clippy/clippy_lints/src/unicode.rs @@ -1,4 +1,6 @@ -use crate::utils::{is_allowed, snippet, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_allowed; +use clippy_utils::source::snippet; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, HirId}; diff --git a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs index c6ae8b9b598..4c13941f665 100644 --- a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs +++ b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs @@ -1,4 +1,5 @@ -use crate::utils::{get_trait_def_id, paths, span_lint, span_lint_and_help}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; +use clippy_utils::{get_trait_def_id, paths}; use if_chain::if_chain; use rustc_hir::def_id::DefId; use rustc_hir::{Expr, ExprKind, StmtKind}; @@ -43,7 +44,7 @@ fn get_trait_predicates_for_trait_id<'tcx>( for (pred, _) in generics.predicates { if_chain! { if let PredicateKind::Trait(poly_trait_pred, _) = pred.kind().skip_binder(); - let trait_pred = cx.tcx.erase_late_bound_regions(ty::Binder::bind(poly_trait_pred)); + let trait_pred = cx.tcx.erase_late_bound_regions(pred.kind().rebind(poly_trait_pred)); if let Some(trait_def_id) = trait_id; if trait_def_id == trait_pred.trait_ref.def_id; then { @@ -57,12 +58,12 @@ fn get_trait_predicates_for_trait_id<'tcx>( fn get_projection_pred<'tcx>( cx: &LateContext<'tcx>, generics: GenericPredicates<'tcx>, - pred: TraitPredicate<'tcx>, + trait_pred: TraitPredicate<'tcx>, ) -> Option<ProjectionPredicate<'tcx>> { generics.predicates.iter().find_map(|(proj_pred, _)| { - if let ty::PredicateKind::Projection(proj_pred) = proj_pred.kind().skip_binder() { - let projection_pred = cx.tcx.erase_late_bound_regions(ty::Binder::bind(proj_pred)); - if projection_pred.projection_ty.substs == pred.trait_ref.substs { + if let ty::PredicateKind::Projection(pred) = proj_pred.kind().skip_binder() { + let projection_pred = cx.tcx.erase_late_bound_regions(proj_pred.kind().rebind(pred)); + if projection_pred.projection_ty.substs == trait_pred.trait_ref.substs { return Some(projection_pred); } } diff --git a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs new file mode 100644 index 00000000000..8698a718bbd --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs @@ -0,0 +1,39 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::higher; +use clippy_utils::source::snippet_with_macro_callsite; +use rustc_errors::Applicability; +use rustc_hir::{Stmt, StmtKind}; +use rustc_lint::{LateContext, LintContext}; +use rustc_middle::lint::in_external_macro; + +use super::LET_UNIT_VALUE; + +pub(super) fn check(cx: &LateContext<'_>, stmt: &Stmt<'_>) { + if let StmtKind::Local(ref local) = stmt.kind { + if cx.typeck_results().pat_ty(&local.pat).is_unit() { + if in_external_macro(cx.sess(), stmt.span) || local.pat.span.from_expansion() { + return; + } + if higher::is_from_for_desugar(local) { + return; + } + span_lint_and_then( + cx, + LET_UNIT_VALUE, + stmt.span, + "this let-binding has unit value", + |diag| { + if let Some(expr) = &local.init { + let snip = snippet_with_macro_callsite(cx, expr.span, "()"); + diag.span_suggestion( + stmt.span, + "omit the `let` binding", + format!("{};", snip), + Applicability::MachineApplicable, // snippet + ); + } + }, + ); + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/unit_types/mod.rs b/src/tools/clippy/clippy_lints/src/unit_types/mod.rs new file mode 100644 index 00000000000..64420a03933 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/unit_types/mod.rs @@ -0,0 +1,107 @@ +mod let_unit_value; +mod unit_arg; +mod unit_cmp; +mod utils; + +use rustc_hir::{Expr, Stmt}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// **What it does:** Checks for binding a unit value. + /// + /// **Why is this bad?** A unit value cannot usefully be used anywhere. So + /// binding one is kind of pointless. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```rust + /// let x = { + /// 1; + /// }; + /// ``` + pub LET_UNIT_VALUE, + pedantic, + "creating a `let` binding to a value of unit type, which usually can't be used afterwards" +} + +declare_clippy_lint! { + /// **What it does:** Checks for comparisons to unit. This includes all binary + /// comparisons (like `==` and `<`) and asserts. + /// + /// **Why is this bad?** Unit is always equal to itself, and thus is just a + /// clumsily written constant. Mostly this happens when someone accidentally + /// adds semicolons at the end of the operands. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```rust + /// # fn foo() {}; + /// # fn bar() {}; + /// # fn baz() {}; + /// if { + /// foo(); + /// } == { + /// bar(); + /// } { + /// baz(); + /// } + /// ``` + /// is equal to + /// ```rust + /// # fn foo() {}; + /// # fn bar() {}; + /// # fn baz() {}; + /// { + /// foo(); + /// bar(); + /// baz(); + /// } + /// ``` + /// + /// For asserts: + /// ```rust + /// # fn foo() {}; + /// # fn bar() {}; + /// assert_eq!({ foo(); }, { bar(); }); + /// ``` + /// will always succeed + pub UNIT_CMP, + correctness, + "comparing unit values" +} + +declare_clippy_lint! { + /// **What it does:** Checks for passing a unit value as an argument to a function without using a + /// unit literal (`()`). + /// + /// **Why is this bad?** This is likely the result of an accidental semicolon. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```rust,ignore + /// foo({ + /// let a = bar(); + /// baz(a); + /// }) + /// ``` + pub UNIT_ARG, + complexity, + "passing unit to a function" +} + +declare_lint_pass!(UnitTypes => [LET_UNIT_VALUE, UNIT_CMP, UNIT_ARG]); + +impl LateLintPass<'_> for UnitTypes { + fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) { + let_unit_value::check(cx, stmt); + } + + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + unit_cmp::check(cx, expr); + unit_arg::check(cx, expr); + } +} diff --git a/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs b/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs new file mode 100644 index 00000000000..925ab577099 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs @@ -0,0 +1,207 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::{self as hir, Block, Expr, ExprKind, MatchSource, Node, StmtKind}; +use rustc_lint::LateContext; + +use super::{utils, UNIT_ARG}; + +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { + if expr.span.from_expansion() { + return; + } + + // apparently stuff in the desugaring of `?` can trigger this + // so check for that here + // only the calls to `Try::from_error` is marked as desugared, + // so we need to check both the current Expr and its parent. + if is_questionmark_desugar_marked_call(expr) { + return; + } + if_chain! { + let map = &cx.tcx.hir(); + let opt_parent_node = map.find(map.get_parent_node(expr.hir_id)); + if let Some(hir::Node::Expr(parent_expr)) = opt_parent_node; + if is_questionmark_desugar_marked_call(parent_expr); + then { + return; + } + } + + match expr.kind { + ExprKind::Call(_, args) | ExprKind::MethodCall(_, _, args, _) => { + let args_to_recover = args + .iter() + .filter(|arg| { + if cx.typeck_results().expr_ty(arg).is_unit() && !utils::is_unit_literal(arg) { + !matches!( + &arg.kind, + ExprKind::Match(.., MatchSource::TryDesugar) | ExprKind::Path(..) + ) + } else { + false + } + }) + .collect::<Vec<_>>(); + if !args_to_recover.is_empty() { + lint_unit_args(cx, expr, &args_to_recover); + } + }, + _ => (), + } +} + +fn is_questionmark_desugar_marked_call(expr: &Expr<'_>) -> bool { + use rustc_span::hygiene::DesugaringKind; + if let ExprKind::Call(ref callee, _) = expr.kind { + callee.span.is_desugaring(DesugaringKind::QuestionMark) + } else { + false + } +} + +fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Expr<'_>]) { + let mut applicability = Applicability::MachineApplicable; + let (singular, plural) = if args_to_recover.len() > 1 { + ("", "s") + } else { + ("a ", "") + }; + span_lint_and_then( + cx, + UNIT_ARG, + expr.span, + &format!("passing {}unit value{} to a function", singular, plural), + |db| { + let mut or = ""; + args_to_recover + .iter() + .filter_map(|arg| { + if_chain! { + if let ExprKind::Block(block, _) = arg.kind; + if block.expr.is_none(); + if let Some(last_stmt) = block.stmts.iter().last(); + if let StmtKind::Semi(last_expr) = last_stmt.kind; + if let Some(snip) = snippet_opt(cx, last_expr.span); + then { + Some(( + last_stmt.span, + snip, + )) + } + else { + None + } + } + }) + .for_each(|(span, sugg)| { + db.span_suggestion( + span, + "remove the semicolon from the last statement in the block", + sugg, + Applicability::MaybeIncorrect, + ); + or = "or "; + applicability = Applicability::MaybeIncorrect; + }); + + let arg_snippets: Vec<String> = args_to_recover + .iter() + .filter_map(|arg| snippet_opt(cx, arg.span)) + .collect(); + let arg_snippets_without_empty_blocks: Vec<String> = args_to_recover + .iter() + .filter(|arg| !is_empty_block(arg)) + .filter_map(|arg| snippet_opt(cx, arg.span)) + .collect(); + + if let Some(call_snippet) = snippet_opt(cx, expr.span) { + let sugg = fmt_stmts_and_call( + cx, + expr, + &call_snippet, + &arg_snippets, + &arg_snippets_without_empty_blocks, + ); + + if arg_snippets_without_empty_blocks.is_empty() { + db.multipart_suggestion( + &format!("use {}unit literal{} instead", singular, plural), + args_to_recover + .iter() + .map(|arg| (arg.span, "()".to_string())) + .collect::<Vec<_>>(), + applicability, + ); + } else { + let plural = arg_snippets_without_empty_blocks.len() > 1; + let empty_or_s = if plural { "s" } else { "" }; + let it_or_them = if plural { "them" } else { "it" }; + db.span_suggestion( + expr.span, + &format!( + "{}move the expression{} in front of the call and replace {} with the unit literal `()`", + or, empty_or_s, it_or_them + ), + sugg, + applicability, + ); + } + } + }, + ); +} + +fn is_empty_block(expr: &Expr<'_>) -> bool { + matches!( + expr.kind, + ExprKind::Block( + Block { + stmts: &[], + expr: None, + .. + }, + _, + ) + ) +} + +fn fmt_stmts_and_call( + cx: &LateContext<'_>, + call_expr: &Expr<'_>, + call_snippet: &str, + args_snippets: &[impl AsRef<str>], + non_empty_block_args_snippets: &[impl AsRef<str>], +) -> String { + let call_expr_indent = indent_of(cx, call_expr.span).unwrap_or(0); + let call_snippet_with_replacements = args_snippets + .iter() + .fold(call_snippet.to_owned(), |acc, arg| acc.replacen(arg.as_ref(), "()", 1)); + + let mut stmts_and_call = non_empty_block_args_snippets + .iter() + .map(|it| it.as_ref().to_owned()) + .collect::<Vec<_>>(); + stmts_and_call.push(call_snippet_with_replacements); + stmts_and_call = stmts_and_call + .into_iter() + .map(|v| reindent_multiline(v.into(), true, Some(call_expr_indent)).into_owned()) + .collect(); + + let mut stmts_and_call_snippet = stmts_and_call.join(&format!("{}{}", ";\n", " ".repeat(call_expr_indent))); + // expr is not in a block statement or result expression position, wrap in a block + let parent_node = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(call_expr.hir_id)); + if !matches!(parent_node, Some(Node::Block(_))) && !matches!(parent_node, Some(Node::Stmt(_))) { + let block_indent = call_expr_indent + 4; + stmts_and_call_snippet = + reindent_multiline(stmts_and_call_snippet.into(), true, Some(block_indent)).into_owned(); + stmts_and_call_snippet = format!( + "{{\n{}{}\n{}}}", + " ".repeat(block_indent), + &stmts_and_call_snippet, + " ".repeat(call_expr_indent) + ); + } + stmts_and_call_snippet +} diff --git a/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs b/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs new file mode 100644 index 00000000000..b3077dec5d8 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs @@ -0,0 +1,56 @@ +use clippy_utils::diagnostics::span_lint; +use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_span::hygiene::{ExpnKind, MacroKind}; + +use super::UNIT_CMP; + +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { + if expr.span.from_expansion() { + if let Some(callee) = expr.span.source_callee() { + if let ExpnKind::Macro(MacroKind::Bang, symbol) = callee.kind { + if let ExprKind::Binary(ref cmp, ref left, _) = expr.kind { + let op = cmp.node; + if op.is_comparison() && cx.typeck_results().expr_ty(left).is_unit() { + let result = match &*symbol.as_str() { + "assert_eq" | "debug_assert_eq" => "succeed", + "assert_ne" | "debug_assert_ne" => "fail", + _ => return, + }; + span_lint( + cx, + UNIT_CMP, + expr.span, + &format!( + "`{}` of unit values detected. This will always {}", + symbol.as_str(), + result + ), + ); + } + } + } + } + return; + } + + if let ExprKind::Binary(ref cmp, ref left, _) = expr.kind { + let op = cmp.node; + if op.is_comparison() && cx.typeck_results().expr_ty(left).is_unit() { + let result = match op { + BinOpKind::Eq | BinOpKind::Le | BinOpKind::Ge => "true", + _ => "false", + }; + span_lint( + cx, + UNIT_CMP, + expr.span, + &format!( + "{}-comparison of unit values detected. This will always be {}", + op.as_str(), + result + ), + ); + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/unit_types/utils.rs b/src/tools/clippy/clippy_lints/src/unit_types/utils.rs new file mode 100644 index 00000000000..4e194a05e8d --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/unit_types/utils.rs @@ -0,0 +1,5 @@ +use rustc_hir::{Expr, ExprKind}; + +pub(super) fn is_unit_literal(expr: &Expr<'_>) -> bool { + matches!(expr.kind, ExprKind::Tup(ref slice) if slice.is_empty()) +} diff --git a/src/tools/clippy/clippy_lints/src/unnamed_address.rs b/src/tools/clippy/clippy_lints/src/unnamed_address.rs index 9582c162e77..d5bc3de6698 100644 --- a/src/tools/clippy/clippy_lints/src/unnamed_address.rs +++ b/src/tools/clippy/clippy_lints/src/unnamed_address.rs @@ -1,4 +1,5 @@ -use crate::utils::{match_def_path, paths, span_lint, span_lint_and_help}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; +use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs b/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs index 00a707107bc..6becff9662a 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs @@ -1,5 +1,6 @@ -use crate::utils; -use crate::utils::sugg::Sugg; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::sugg::Sugg; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath}; @@ -8,6 +9,7 @@ use rustc_middle::ty::{self, subst::GenericArgKind}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; use rustc_span::symbol::Ident; +use std::iter; declare_clippy_lint! { /// **What it does:** @@ -78,17 +80,15 @@ fn mirrored_exprs( mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident) }, // Two arrays with mirrored contents - (ExprKind::Array(left_exprs), ExprKind::Array(right_exprs)) => left_exprs - .iter() - .zip(right_exprs.iter()) - .all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident)), + (ExprKind::Array(left_exprs), ExprKind::Array(right_exprs)) => { + iter::zip(*left_exprs, *right_exprs) + .all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident)) + } // The two exprs are function calls. // Check to see that the function itself and its arguments are mirrored (ExprKind::Call(left_expr, left_args), ExprKind::Call(right_expr, right_args)) => { mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident) - && left_args - .iter() - .zip(right_args.iter()) + && iter::zip(*left_args, *right_args) .all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident)) }, // The two exprs are method calls. @@ -99,16 +99,14 @@ fn mirrored_exprs( ExprKind::MethodCall(right_segment, _, right_args, _), ) => { left_segment.ident == right_segment.ident - && left_args - .iter() - .zip(right_args.iter()) + && iter::zip(*left_args, *right_args) .all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident)) - }, + } // Two tuples with mirrored contents - (ExprKind::Tup(left_exprs), ExprKind::Tup(right_exprs)) => left_exprs - .iter() - .zip(right_exprs.iter()) - .all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident)), + (ExprKind::Tup(left_exprs), ExprKind::Tup(right_exprs)) => { + iter::zip(*left_exprs, *right_exprs) + .all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident)) + } // Two binary ops, which are the same operation and which have mirrored arguments (ExprKind::Binary(left_op, left_left, left_right), ExprKind::Binary(right_op, right_left, right_right)) => { left_op.node == right_op.node @@ -145,9 +143,7 @@ fn mirrored_exprs( }, )), ) => { - (left_segments - .iter() - .zip(right_segments.iter()) + (iter::zip(*left_segments, *right_segments) .all(|(left, right)| left.ident == right.ident) && left_segments .iter() @@ -176,7 +172,7 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<LintTrigger> { if let name = name_ident.ident.name.to_ident_string(); if name == "sort_by" || name == "sort_unstable_by"; if let [vec, Expr { kind: ExprKind::Closure(_, _, closure_body_id, _, _), .. }] = args; - if utils::is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(vec), sym::vec_type); + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(vec), sym::vec_type); if let closure_body = cx.tcx.hir().body(*closure_body_id); if let &[ Param { pat: Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, ..}, @@ -232,7 +228,7 @@ fn expr_borrows(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { impl LateLintPass<'_> for UnnecessarySortBy { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { match detect_lint(cx, expr) { - Some(LintTrigger::SortByKey(trigger)) => utils::span_lint_and_sugg( + Some(LintTrigger::SortByKey(trigger)) => span_lint_and_sugg( cx, UNNECESSARY_SORT_BY, expr.span, @@ -255,7 +251,7 @@ impl LateLintPass<'_> for UnnecessarySortBy { Applicability::MachineApplicable }, ), - Some(LintTrigger::Sort(trigger)) => utils::span_lint_and_sugg( + Some(LintTrigger::Sort(trigger)) => span_lint_and_sugg( cx, UNNECESSARY_SORT_BY, expr.span, diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs index 8e076397c11..c2be457e9dc 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs @@ -1,7 +1,6 @@ -use crate::utils::{ - contains_return, in_macro, match_qpath, paths, return_ty, snippet, span_lint_and_then, - visitors::find_all_ret_expressions, -}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::snippet; +use clippy_utils::{contains_return, in_macro, match_qpath, paths, return_ty, visitors::find_all_ret_expressions}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; @@ -72,7 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { } }, FnKind::Closure => return, - _ => (), + FnKind::Method(..) => (), } // Abort if the method is implementing a trait or of it a trait method. diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs index 5826e9a4aa5..2b9479365c6 100644 --- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs @@ -1,7 +1,8 @@ #![allow(clippy::wildcard_imports, clippy::enum_glob_use)] -use crate::utils::ast_utils::{eq_field_pat, eq_id, eq_pat, eq_path}; -use crate::utils::{over, span_lint_and_then}; +use clippy_utils::ast_utils::{eq_field_pat, eq_id, eq_pat, eq_path}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::over; use rustc_ast::mut_visit::*; use rustc_ast::ptr::P; use rustc_ast::{self as ast, Pat, PatKind, PatKind::*, DUMMY_NODE_ID}; diff --git a/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs b/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs index 154082a0fdb..16ad9d2dfd3 100644 --- a/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs +++ b/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint; +use clippy_utils::diagnostics::span_lint; use rustc_ast::ast::{Item, ItemKind, UseTree, UseTreeKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs index 43166d26787..9990052e114 100644 --- a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs +++ b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_try, match_trait_method, paths, span_lint}; +use clippy_utils::diagnostics::span_lint; +use clippy_utils::{is_try, match_trait_method, paths}; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/src/tools/clippy/clippy_lints/src/unused_self.rs b/src/tools/clippy/clippy_lints/src/unused_self.rs index 812482cf5cf..aef4ce75915 100644 --- a/src/tools/clippy/clippy_lints/src/unused_self.rs +++ b/src/tools/clippy/clippy_lints/src/unused_self.rs @@ -1,11 +1,10 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::visitors::LocalUsedVisitor; use if_chain::if_chain; use rustc_hir::{Impl, ImplItem, ImplItemKind, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::span_lint_and_help; -use crate::utils::visitors::LocalUsedVisitor; - declare_clippy_lint! { /// **What it does:** Checks methods that contain a `self` argument but don't use it /// diff --git a/src/tools/clippy/clippy_lints/src/unused_unit.rs b/src/tools/clippy/clippy_lints/src/unused_unit.rs index a31cd5fda84..329ea49024b 100644 --- a/src/tools/clippy/clippy_lints/src/unused_unit.rs +++ b/src/tools/clippy/clippy_lints/src/unused_unit.rs @@ -1,3 +1,5 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::position_before_rarrow; use if_chain::if_chain; use rustc_ast::ast; use rustc_ast::visit::FnKind; @@ -7,8 +9,6 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::BytePos; -use crate::utils::{position_before_rarrow, span_lint_and_sugg}; - declare_clippy_lint! { /// **What it does:** Checks for unit (`()`) expressions that can be removed. /// diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs index 2fb0463c5a6..fb29acca18a 100644 --- a/src/tools/clippy/clippy_lints/src/unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/unwrap.rs @@ -1,6 +1,6 @@ -use crate::utils::{ - differing_macro_contexts, is_type_diagnostic_item, span_lint_and_then, usage::is_potentially_mutated, -}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{differing_macro_contexts, usage::is_potentially_mutated}; use if_chain::if_chain; use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, NestedVisitorMap, Visitor}; use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, Path, QPath, UnOp}; diff --git a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs index 8cb7429849d..0d745813beb 100644 --- a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs +++ b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs @@ -1,6 +1,10 @@ -use crate::utils::{is_type_diagnostic_item, method_chain_args, return_ty, span_lint_and_then}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{method_chain_args, return_ty}; use if_chain::if_chain; use rustc_hir as hir; +use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; +use rustc_hir::{Expr, ImplItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::map::Map; use rustc_middle::ty; @@ -66,9 +70,6 @@ impl<'tcx> LateLintPass<'tcx> for UnwrapInResult { } } -use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; -use rustc_hir::{Expr, ImplItemKind}; - struct FindExpectUnwrap<'a, 'tcx> { lcx: &'a LateContext<'tcx>, typeck_results: &'tcx ty::TypeckResults<'tcx>, diff --git a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs index 0470e1dbbb8..a6d29d36862 100644 --- a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs +++ b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs @@ -1,7 +1,7 @@ -use crate::utils::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_sugg; use if_chain::if_chain; use itertools::Itertools; -use rustc_ast::ast::{Item, ItemKind, Variant}; +use rustc_ast::ast::{Item, ItemKind, Variant, VisibilityKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; @@ -81,7 +81,7 @@ fn check_ident(cx: &EarlyContext<'_>, ident: &Ident, be_aggressive: bool) { // assume that two-letter words are some kind of valid abbreviation like FP for false positive // (and don't warn) if (ident.chars().all(|c| c.is_ascii_uppercase()) && ident.len() > 2) - // otherwise, warn if we have SOmeTHING lIKE THIs but only warn with the aggressive + // otherwise, warn if we have SOmeTHING lIKE THIs but only warn with the aggressive // upper-case-acronyms-aggressive config option enabled || (be_aggressive && ident != &corrected) { @@ -105,6 +105,8 @@ impl EarlyLintPass for UpperCaseAcronyms { it.kind, ItemKind::TyAlias(..) | ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Trait(..) ); + // do not lint public items + if !matches!(it.vis.kind, VisibilityKind::Public); then { check_ident(cx, &it.ident, self.upper_case_acronyms_aggressive); } diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs index f0523cec621..116cb8b1e1c 100644 --- a/src/tools/clippy/clippy_lints/src/use_self.rs +++ b/src/tools/clippy/clippy_lints/src/use_self.rs @@ -1,6 +1,7 @@ -use crate::utils::{in_macro, meets_msrv, snippet_opt, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_opt; +use clippy_utils::{in_macro, meets_msrv}; use if_chain::if_chain; - use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def::DefKind; diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs index c5334853986..3e1b69e676b 100644 --- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs +++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs @@ -1,8 +1,8 @@ -use crate::utils::sugg::Sugg; -use crate::utils::{ - get_parent_expr, is_type_diagnostic_item, match_def_path, match_trait_method, paths, snippet, - snippet_with_macro_callsite, span_lint_and_help, span_lint_and_sugg, -}; +use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; +use clippy_utils::source::{snippet, snippet_with_macro_callsite}; +use clippy_utils::sugg::Sugg; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{get_parent_expr, match_def_path, match_trait_method, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, HirId, MatchSource}; diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index c5761480080..a92c987014f 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -1,7 +1,7 @@ //! A group of attributes that can be attached to Rust code in order //! to generate a clippy lint detecting said code automatically. -use crate::utils::get_attr; +use clippy_utils::get_attr; use rustc_ast::ast::{LitFloatType, LitKind}; use rustc_ast::walk_list; use rustc_data_structures::fx::FxHashMap; diff --git a/src/tools/clippy/clippy_lints/src/utils/inspector.rs b/src/tools/clippy/clippy_lints/src/utils/inspector.rs index 64ee9e65bb1..6fd3c9d7dec 100644 --- a/src/tools/clippy/clippy_lints/src/utils/inspector.rs +++ b/src/tools/clippy/clippy_lints/src/utils/inspector.rs @@ -1,6 +1,6 @@ //! checks for attributes -use crate::utils::get_attr; +use clippy_utils::get_attr; use rustc_ast::ast::{Attribute, InlineAsmTemplatePiece}; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass, LintContext}; diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs index 0a347516c3a..c496ff1fb24 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs @@ -1,8 +1,8 @@ use crate::consts::{constant_simple, Constant}; -use crate::utils::{ - is_expn_of, match_def_path, match_qpath, match_type, method_calls, path_to_res, paths, run_lints, snippet, - span_lint, span_lint_and_help, span_lint_and_sugg, SpanlessEq, -}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg}; +use clippy_utils::source::snippet; +use clippy_utils::ty::match_type; +use clippy_utils::{is_expn_of, match_def_path, match_qpath, method_calls, path_to_res, paths, run_lints, SpanlessEq}; use if_chain::if_chain; use rustc_ast::ast::{Crate as AstCrate, ItemKind, LitKind, ModKind, NodeId}; use rustc_ast::visit::FnKind; diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs index be9a07f8d7c..d8b31344e6d 100644 --- a/src/tools/clippy/clippy_lints/src/utils/mod.rs +++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs @@ -3,5 +3,3 @@ pub mod conf; pub mod inspector; #[cfg(feature = "internal-lints")] pub mod internal_lints; - -pub use clippy_utils::*; diff --git a/src/tools/clippy/clippy_lints/src/vec.rs b/src/tools/clippy/clippy_lints/src/vec.rs index c132e4de4f6..1af9583887f 100644 --- a/src/tools/clippy/clippy_lints/src/vec.rs +++ b/src/tools/clippy/clippy_lints/src/vec.rs @@ -1,6 +1,9 @@ use crate::consts::{constant, Constant}; use crate::rustc_target::abi::LayoutOf; -use crate::utils::{higher, is_copy, snippet_with_applicability, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::higher; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::is_copy; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind}; diff --git a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs index 8d111f98add..8b696ed1c84 100644 --- a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs +++ b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs @@ -1,6 +1,7 @@ -use crate::utils::{ - is_type_diagnostic_item, match_def_path, path_to_local, path_to_local_id, paths, snippet, span_lint_and_sugg, -}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{match_def_path, path_to_local, path_to_local_id, paths}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; diff --git a/src/tools/clippy/clippy_lints/src/vec_resize_to_zero.rs b/src/tools/clippy/clippy_lints/src/vec_resize_to_zero.rs index d2494b321ef..e035d3c5cad 100644 --- a/src/tools/clippy/clippy_lints/src/vec_resize_to_zero.rs +++ b/src/tools/clippy/clippy_lints/src/vec_resize_to_zero.rs @@ -1,15 +1,14 @@ -use crate::utils::span_lint_and_then; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; +use rustc_ast::LitKind; use rustc_errors::Applicability; +use rustc_hir as hir; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Spanned; -use crate::utils::{match_def_path, paths}; -use rustc_ast::LitKind; -use rustc_hir as hir; - declare_clippy_lint! { /// **What it does:** Finds occurrences of `Vec::resize(0, an_int)` /// diff --git a/src/tools/clippy/clippy_lints/src/verbose_file_reads.rs b/src/tools/clippy/clippy_lints/src/verbose_file_reads.rs index 32574d9d6c9..ec209b30951 100644 --- a/src/tools/clippy/clippy_lints/src/verbose_file_reads.rs +++ b/src/tools/clippy/clippy_lints/src/verbose_file_reads.rs @@ -1,4 +1,6 @@ -use crate::utils::{match_type, paths, span_lint_and_help}; +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::paths; +use clippy_utils::ty::match_type; use if_chain::if_chain; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/wildcard_dependencies.rs b/src/tools/clippy/clippy_lints/src/wildcard_dependencies.rs index cd1864f461d..60c3489a449 100644 --- a/src/tools/clippy/clippy_lints/src/wildcard_dependencies.rs +++ b/src/tools/clippy/clippy_lints/src/wildcard_dependencies.rs @@ -1,4 +1,5 @@ -use crate::utils::{run_lints, span_lint}; +use clippy_utils::diagnostics::span_lint; +use clippy_utils::run_lints; use rustc_hir::{hir_id::CRATE_HIR_ID, Crate}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs index 094b1a42346..51c1117d206 100644 --- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs +++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs @@ -1,4 +1,6 @@ -use crate::utils::{in_macro, snippet, snippet_with_applicability, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::in_macro; +use clippy_utils::source::{snippet, snippet_with_applicability}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{ diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs index 553e6b000eb..12a47a6b703 100644 --- a/src/tools/clippy/clippy_lints/src/write.rs +++ b/src/tools/clippy/clippy_lints/src/write.rs @@ -1,20 +1,19 @@ use std::borrow::Cow; -use std::ops::Range; - -use crate::utils::{snippet_with_applicability, span_lint, span_lint_and_sugg, span_lint_and_then}; -use if_chain::if_chain; -use rustc_ast::ast::{ - Expr, ExprKind, ImplKind, Item, ItemKind, LitKind, MacCall, StrLit, StrStyle, -}; -use rustc_ast::token; +use std::iter; +use std::ops::{Deref, Range}; + +use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::source::{snippet_opt, snippet_with_applicability}; +use rustc_ast::ast::{Expr, ExprKind, ImplKind, Item, ItemKind, MacCall, Path, StrLit, StrStyle}; +use rustc_ast::token::{self, LitKind}; use rustc_ast::tokenstream::TokenStream; use rustc_errors::Applicability; use rustc_lexer::unescape::{self, EscapeError}; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_parse::parser; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::symbol::kw; -use rustc_span::{sym, BytePos, Span}; +use rustc_span::symbol::{kw, Symbol}; +use rustc_span::{sym, BytePos, Span, DUMMY_SP}; declare_clippy_lint! { /// **What it does:** This lint warns when you use `println!("")` to @@ -355,7 +354,120 @@ fn newline_span(fmtstr: &StrLit) -> Span { sp.with_lo(newline_sp_hi - newline_sp_len).with_hi(newline_sp_hi) } +/// Stores a list of replacement spans for each argument, but only if all the replacements used an +/// empty format string. +#[derive(Default)] +struct SimpleFormatArgs { + unnamed: Vec<Vec<Span>>, + named: Vec<(Symbol, Vec<Span>)>, +} +impl SimpleFormatArgs { + fn get_unnamed(&self) -> impl Iterator<Item = &[Span]> { + self.unnamed.iter().map(|x| match x.as_slice() { + // Ignore the dummy span added from out of order format arguments. + [DUMMY_SP] => &[], + x => x, + }) + } + + fn get_named(&self, n: &Path) -> &[Span] { + self.named.iter().find(|x| *n == x.0).map_or(&[], |x| x.1.as_slice()) + } + + fn push(&mut self, arg: rustc_parse_format::Argument<'_>, span: Span) { + use rustc_parse_format::{ + AlignUnknown, ArgumentImplicitlyIs, ArgumentIs, ArgumentNamed, CountImplied, FormatSpec, + }; + + const SIMPLE: FormatSpec<'_> = FormatSpec { + fill: None, + align: AlignUnknown, + flags: 0, + precision: CountImplied, + precision_span: None, + width: CountImplied, + width_span: None, + ty: "", + ty_span: None, + }; + + match arg.position { + ArgumentIs(n) | ArgumentImplicitlyIs(n) => { + if self.unnamed.len() <= n { + // Use a dummy span to mark all unseen arguments. + self.unnamed.resize_with(n, || vec![DUMMY_SP]); + if arg.format == SIMPLE { + self.unnamed.push(vec![span]); + } else { + self.unnamed.push(Vec::new()); + } + } else { + let args = &mut self.unnamed[n]; + match (args.as_mut_slice(), arg.format == SIMPLE) { + // A non-empty format string has been seen already. + ([], _) => (), + // Replace the dummy span, if it exists. + ([dummy @ DUMMY_SP], true) => *dummy = span, + ([_, ..], true) => args.push(span), + ([_, ..], false) => *args = Vec::new(), + } + } + }, + ArgumentNamed(n) => { + if let Some(x) = self.named.iter_mut().find(|x| x.0 == n) { + match x.1.as_slice() { + // A non-empty format string has been seen already. + [] => (), + [_, ..] if arg.format == SIMPLE => x.1.push(span), + [_, ..] => x.1 = Vec::new(), + } + } else if arg.format == SIMPLE { + self.named.push((n, vec![span])); + } else { + self.named.push((n, Vec::new())); + } + }, + }; + } +} + impl Write { + /// Parses a format string into a collection of spans for each argument. This only keeps track + /// of empty format arguments. Will also lint usages of debug format strings outside of debug + /// impls. + fn parse_fmt_string(&self, cx: &EarlyContext<'_>, str_lit: &StrLit) -> Option<SimpleFormatArgs> { + use rustc_parse_format::{ParseMode, Parser, Piece}; + + let str_sym = str_lit.symbol_unescaped.as_str(); + let style = match str_lit.style { + StrStyle::Cooked => None, + StrStyle::Raw(n) => Some(n as usize), + }; + + let mut parser = Parser::new(&str_sym, style, snippet_opt(cx, str_lit.span), false, ParseMode::Format); + let mut args = SimpleFormatArgs::default(); + + while let Some(arg) = parser.next() { + let arg = match arg { + Piece::String(_) => continue, + Piece::NextArgument(arg) => arg, + }; + let span = parser + .arg_places + .last() + .map_or(DUMMY_SP, |&x| str_lit.span.from_inner(x)); + + if !self.in_debug_impl && arg.format.ty == "?" { + // FIXME: modify rustc's fmt string parser to give us the current span + span_lint(cx, USE_DEBUG, span, "use of `Debug`-based formatting"); + } + + args.push(arg, span); + } + + parser.errors.is_empty().then(move || args) + } + /// Checks the arguments of `print[ln]!` and `write[ln]!` calls. It will return a tuple of two /// `Option`s. The first `Option` of the tuple is the macro's format string. It includes /// the contents of the string, whether it's a raw string, and the span of the literal in the @@ -376,124 +488,97 @@ impl Write { /// (Some("string to write: {}"), Some(buf)) /// ``` #[allow(clippy::too_many_lines)] - fn check_tts<'a>( - &self, - cx: &EarlyContext<'a>, - tts: TokenStream, - is_write: bool, - ) -> (Option<StrLit>, Option<Expr>) { - use rustc_parse_format::{ - AlignUnknown, ArgumentImplicitlyIs, ArgumentIs, ArgumentNamed, CountImplied, - FormatSpec, ParseMode, Parser, Piece, - }; - + fn check_tts<'a>(&self, cx: &EarlyContext<'a>, tts: TokenStream, is_write: bool) -> (Option<StrLit>, Option<Expr>) { let mut parser = parser::Parser::new(&cx.sess.parse_sess, tts, false, None); - let mut expr: Option<Expr> = None; - if is_write { - expr = match parser.parse_expr().map_err(|mut err| err.cancel()) { - Ok(p) => Some(p.into_inner()), - Err(_) => return (None, None), - }; - // might be `writeln!(foo)` - if parser.expect(&token::Comma).map_err(|mut err| err.cancel()).is_err() { - return (None, expr); + let expr = if is_write { + match parser + .parse_expr() + .map(rustc_ast::ptr::P::into_inner) + .map_err(|mut e| e.cancel()) + { + // write!(e, ...) + Ok(p) if parser.eat(&token::Comma) => Some(p), + // write!(e) or error + e => return (None, e.ok()), } - } + } else { + None + }; let fmtstr = match parser.parse_str_lit() { Ok(fmtstr) => fmtstr, Err(_) => return (None, expr), }; - let tmp = fmtstr.symbol.as_str(); - let mut args = vec![]; - let mut fmt_parser = Parser::new(&tmp, None, None, false, ParseMode::Format); - while let Some(piece) = fmt_parser.next() { - if !fmt_parser.errors.is_empty() { - return (None, expr); - } - if let Piece::NextArgument(arg) = piece { - if !self.in_debug_impl && arg.format.ty == "?" { - // FIXME: modify rustc's fmt string parser to give us the current span - span_lint( - cx, - USE_DEBUG, - parser.prev_token.span, - "use of `Debug`-based formatting", - ); - } - args.push(arg); - } - } + + let args = match self.parse_fmt_string(cx, &fmtstr) { + Some(args) => args, + None => return (Some(fmtstr), expr), + }; + let lint = if is_write { WRITE_LITERAL } else { PRINT_LITERAL }; - let mut idx = 0; + let mut unnamed_args = args.get_unnamed(); loop { - const SIMPLE: FormatSpec<'_> = FormatSpec { - fill: None, - align: AlignUnknown, - flags: 0, - precision: CountImplied, - precision_span: None, - width: CountImplied, - width_span: None, - ty: "", - ty_span: None, - }; if !parser.eat(&token::Comma) { return (Some(fmtstr), expr); } + + let comma_span = parser.prev_token.span; let token_expr = if let Ok(expr) = parser.parse_expr().map_err(|mut err| err.cancel()) { expr } else { return (Some(fmtstr), None); }; - match &token_expr.kind { - ExprKind::Lit(lit) - if !matches!(lit.kind, LitKind::Int(..) | LitKind::Float(..)) => - { - let mut all_simple = true; - let mut seen = false; - for arg in &args { - match arg.position { - ArgumentImplicitlyIs(n) | ArgumentIs(n) => { - if n == idx { - all_simple &= arg.format == SIMPLE; - seen = true; - } - } - ArgumentNamed(_) => {} - } - } - if all_simple && seen { - span_lint(cx, lint, token_expr.span, "literal with an empty format string"); - } - idx += 1; - } - ExprKind::Assign(lhs, rhs, _) => { - if_chain! { - if let ExprKind::Lit(ref lit) = rhs.kind; - if !matches!(lit.kind, LitKind::Int(..) | LitKind::Float(..)); - if let ExprKind::Path(_, p) = &lhs.kind; - then { - let mut all_simple = true; - let mut seen = false; - for arg in &args { - match arg.position { - ArgumentImplicitlyIs(_) | ArgumentIs(_) => {}, - ArgumentNamed(name) => { - if *p == name { - seen = true; - all_simple &= arg.format == SIMPLE; - } - }, - } - } - if all_simple && seen { - span_lint(cx, lint, rhs.span, "literal with an empty format string"); - } - } - } + let (fmt_spans, lit) = match &token_expr.kind { + ExprKind::Lit(lit) => (unnamed_args.next().unwrap_or(&[]), lit), + ExprKind::Assign(lhs, rhs, _) => match (&lhs.kind, &rhs.kind) { + (ExprKind::Path(_, p), ExprKind::Lit(lit)) => (args.get_named(p), lit), + _ => continue, + }, + _ => { + unnamed_args.next(); + continue; + }, + }; + + let replacement: String = match lit.token.kind { + LitKind::Integer | LitKind::Float | LitKind::Err => continue, + LitKind::StrRaw(_) | LitKind::ByteStrRaw(_) if matches!(fmtstr.style, StrStyle::Raw(_)) => { + lit.token.symbol.as_str().replace("{", "{{").replace("}", "}}") + }, + LitKind::Str | LitKind::ByteStr if matches!(fmtstr.style, StrStyle::Cooked) => { + lit.token.symbol.as_str().replace("{", "{{").replace("}", "}}") + }, + LitKind::StrRaw(_) | LitKind::Str | LitKind::ByteStrRaw(_) | LitKind::ByteStr => continue, + LitKind::Byte | LitKind::Char => match &*lit.token.symbol.as_str() { + "\"" if matches!(fmtstr.style, StrStyle::Cooked) => "\\\"", + "\"" if matches!(fmtstr.style, StrStyle::Raw(0)) => continue, + "\\\\" if matches!(fmtstr.style, StrStyle::Raw(_)) => "\\", + "\\'" => "'", + "{" => "{{", + "}" => "}}", + x if matches!(fmtstr.style, StrStyle::Raw(_)) && x.starts_with('\\') => continue, + x => x, } - _ => idx += 1, + .into(), + LitKind::Bool => lit.token.symbol.as_str().deref().into(), + }; + + if !fmt_spans.is_empty() { + span_lint_and_then( + cx, + lint, + token_expr.span, + "literal with an empty format string", + |diag| { + diag.multipart_suggestion( + "try this", + iter::once((comma_span.to(token_expr.span), String::new())) + .chain(fmt_spans.iter().cloned().zip(iter::repeat(replacement))) + .collect(), + Applicability::MachineApplicable, + ); + }, + ); } } } @@ -524,17 +609,11 @@ impl Write { cx, PRINT_WITH_NEWLINE, mac.span(), - &format!( - "using `{}!()` with a format string that ends in a single newline", - name - ), + &format!("using `{}!()` with a format string that ends in a single newline", name), |err| { err.multipart_suggestion( &format!("use `{}!` instead", suggested), - vec![ - (mac.path.span, suggested), - (newline_span(&fmt_str), String::new()), - ], + vec![(mac.path.span, suggested), (newline_span(&fmt_str), String::new())], Applicability::MachineApplicable, ); }, diff --git a/src/tools/clippy/clippy_lints/src/zero_div_zero.rs b/src/tools/clippy/clippy_lints/src/zero_div_zero.rs index 11d96e15ff1..3b4890ad560 100644 --- a/src/tools/clippy/clippy_lints/src/zero_div_zero.rs +++ b/src/tools/clippy/clippy_lints/src/zero_div_zero.rs @@ -1,5 +1,5 @@ use crate::consts::{constant_simple, Constant}; -use crate::utils::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_help; use if_chain::if_chain; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs index adf7077e650..2abd033e2a0 100644 --- a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs +++ b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs @@ -1,3 +1,6 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::paths; +use clippy_utils::ty::{is_normalizable, is_type_diagnostic_item, match_type}; use if_chain::if_chain; use rustc_hir::{self as hir, HirId, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; @@ -7,8 +10,6 @@ use rustc_span::sym; use rustc_target::abi::LayoutOf as _; use rustc_typeck::hir_ty_to_ty; -use crate::utils::{is_normalizable, is_type_diagnostic_item, match_type, paths, span_lint_and_help}; - declare_clippy_lint! { /// **What it does:** Checks for maps with zero-sized value types anywhere in the code. /// diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml index 9e07f140cf1..d04c5f889dd 100644 --- a/src/tools/clippy/clippy_utils/Cargo.toml +++ b/src/tools/clippy/clippy_utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_utils" -version = "0.1.52" +version = "0.1.53" authors = ["The Rust Clippy Developers"] edition = "2018" publish = false @@ -10,8 +10,6 @@ if_chain = "1.0.0" itertools = "0.9" regex-syntax = "0.6" serde = { version = "1.0", features = ["derive"] } -smallvec = { version = "1", features = ["union"] } -toml = "0.5.3" unicode-normalization = "0.1" rustc-semver="1.1.0" diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs index e202b5061a6..eaea3e636f9 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs @@ -169,9 +169,9 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { (Path(lq, lp), Path(rq, rp)) => both(lq, rq, |l, r| eq_qself(l, r)) && eq_path(lp, rp), (MacCall(l), MacCall(r)) => eq_mac_call(l, r), (Struct(lse), Struct(rse)) => { - eq_path(&lse.path, &rse.path) && - eq_struct_rest(&lse.rest, &rse.rest) && - unordered_over(&lse.fields, &rse.fields, |l, r| eq_field(l, r)) + eq_path(&lse.path, &rse.path) + && eq_struct_rest(&lse.rest, &rse.rest) + && unordered_over(&lse.fields, &rse.fields, |l, r| eq_field(l, r)) }, _ => false, } @@ -409,7 +409,7 @@ pub fn eq_use_tree(l: &UseTree, r: &UseTree) -> bool { } pub fn eq_anon_const(l: &AnonConst, r: &AnonConst) -> bool { - eq_expr(&l.value, &r.value) + eq_expr(&l.value, &r.value) } pub fn eq_use_tree_kind(l: &UseTreeKind, r: &UseTreeKind) -> bool { diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index ebe896b7ae8..8af10ebe777 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -15,6 +15,7 @@ use rustc_span::symbol::Symbol; use std::cmp::Ordering::{self, Equal}; use std::convert::TryInto; use std::hash::{Hash, Hasher}; +use std::iter; /// A `LitKind`-like enum to fold constant `Expr`s into. #[derive(Debug, Clone)] @@ -139,12 +140,12 @@ impl Constant { (&Self::F64(l), &Self::F64(r)) => l.partial_cmp(&r), (&Self::F32(l), &Self::F32(r)) => l.partial_cmp(&r), (&Self::Bool(ref l), &Self::Bool(ref r)) => Some(l.cmp(r)), - (&Self::Tuple(ref l), &Self::Tuple(ref r)) | (&Self::Vec(ref l), &Self::Vec(ref r)) => l - .iter() - .zip(r.iter()) - .map(|(li, ri)| Self::partial_cmp(tcx, cmp_type, li, ri)) - .find(|r| r.map_or(true, |o| o != Ordering::Equal)) - .unwrap_or_else(|| Some(l.len().cmp(&r.len()))), + (&Self::Tuple(ref l), &Self::Tuple(ref r)) | (&Self::Vec(ref l), &Self::Vec(ref r)) => { + iter::zip(l, r) + .map(|(li, ri)| Self::partial_cmp(tcx, cmp_type, li, ri)) + .find(|r| r.map_or(true, |o| o != Ordering::Equal)) + .unwrap_or_else(|| Some(l.len().cmp(&r.len()))) + } (&Self::Repeat(ref lv, ref ls), &Self::Repeat(ref rv, ref rs)) => { match Self::partial_cmp(tcx, cmp_type, lv, rv) { Some(Equal) => Some(ls.cmp(rs)), diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs index 269be217c2d..e9c9cb12b9d 100644 --- a/src/tools/clippy/clippy_utils/src/diagnostics.rs +++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs @@ -8,14 +8,16 @@ use std::env; fn docs_link(diag: &mut DiagnosticBuilder<'_>, lint: &'static Lint) { if env::var("CLIPPY_DISABLE_DOCS_LINKS").is_err() { - diag.help(&format!( - "for further information visit https://rust-lang.github.io/rust-clippy/{}/index.html#{}", - &option_env!("RUST_RELEASE_NUM").map_or("master".to_string(), |n| { - // extract just major + minor version and ignore patch versions - format!("rust-{}", n.rsplitn(2, '.').nth(1).unwrap()) - }), - lint.name_lower().replacen("clippy::", "", 1) - )); + if let Some(lint) = lint.name_lower().strip_prefix("clippy::") { + diag.help(&format!( + "for further information visit https://rust-lang.github.io/rust-clippy/{}/index.html#{}", + &option_env!("RUST_RELEASE_NUM").map_or("master".to_string(), |n| { + // extract just major + minor version and ignore patch versions + format!("rust-{}", n.rsplitn(2, '.').nth(1).unwrap()) + }), + lint + )); + } } } diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs index 8013c4e4fcb..88b115a63d7 100644 --- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs +++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs @@ -9,7 +9,8 @@ //! - or-fun-call //! - option-if-let-else -use crate::{is_ctor_or_promotable_const_function, is_type_diagnostic_item}; +use crate::is_ctor_or_promotable_const_function; +use crate::ty::is_type_diagnostic_item; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit; diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 7f7d9c5f56a..618d33545a4 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -1,12 +1,13 @@ use crate::consts::{constant_context, constant_simple}; -use crate::{differing_macro_contexts, snippet_opt}; +use crate::differing_macro_contexts; +use crate::source::snippet_opt; use rustc_ast::ast::InlineAsmTemplatePiece; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir::def::Res; use rustc_hir::{ - BinOpKind, Block, BlockCheckMode, BodyId, BorrowKind, CaptureBy, Expr, ExprKind, ExprField, PatField, FnRetTy, - GenericArg, GenericArgs, Guard, HirId, InlineAsmOperand, Lifetime, LifetimeName, ParamName, Pat, PatKind, Path, + BinOpKind, Block, BlockCheckMode, BodyId, BorrowKind, CaptureBy, Expr, ExprField, ExprKind, FnRetTy, GenericArg, + GenericArgs, Guard, HirId, InlineAsmOperand, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path, PathSegment, QPath, Stmt, StmtKind, Ty, TyKind, TypeBinding, }; use rustc_lexer::{tokenize, TokenKind}; @@ -79,10 +80,6 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { pub fn eq_path_segments(&mut self, left: &[PathSegment<'_>], right: &[PathSegment<'_>]) -> bool { self.inter_expr().eq_path_segments(left, right) } - - pub fn eq_ty_kind(&mut self, left: &TyKind<'_>, right: &TyKind<'_>) -> bool { - self.inter_expr().eq_ty_kind(left, right) - } } struct HirEqInterExpr<'a, 'b, 'tcx> { @@ -251,7 +248,7 @@ impl HirEqInterExpr<'_, '_, '_> { (&ExprKind::Struct(ref l_path, ref lf, ref lo), &ExprKind::Struct(ref r_path, ref rf, ref ro)) => { self.eq_qpath(l_path, r_path) && both(lo, ro, |l, r| self.eq_expr(l, r)) - && over(lf, rf, |l, r| self.eq_field(l, r)) + && over(lf, rf, |l, r| self.eq_expr_field(l, r)) }, (&ExprKind::Tup(l_tup), &ExprKind::Tup(r_tup)) => self.eq_exprs(l_tup, r_tup), (&ExprKind::Unary(l_op, ref le), &ExprKind::Unary(r_op, ref re)) => l_op == r_op && self.eq_expr(le, re), @@ -266,7 +263,7 @@ impl HirEqInterExpr<'_, '_, '_> { over(left, right, |l, r| self.eq_expr(l, r)) } - fn eq_field(&mut self, left: &ExprField<'_>, right: &ExprField<'_>) -> bool { + fn eq_expr_field(&mut self, left: &ExprField<'_>, right: &ExprField<'_>) -> bool { left.ident.name == right.ident.name && self.eq_expr(&left.expr, &right.expr) } @@ -290,7 +287,7 @@ impl HirEqInterExpr<'_, '_, '_> { left.name == right.name } - fn eq_fieldpat(&mut self, left: &PatField<'_>, right: &PatField<'_>) -> bool { + fn eq_pat_field(&mut self, left: &PatField<'_>, right: &PatField<'_>) -> bool { let (PatField { ident: li, pat: lp, .. }, PatField { ident: ri, pat: rp, .. }) = (&left, &right); li.name == ri.name && self.eq_pat(lp, rp) } @@ -300,7 +297,7 @@ impl HirEqInterExpr<'_, '_, '_> { match (&left.kind, &right.kind) { (&PatKind::Box(ref l), &PatKind::Box(ref r)) => self.eq_pat(l, r), (&PatKind::Struct(ref lp, ref la, ..), &PatKind::Struct(ref rp, ref ra, ..)) => { - self.eq_qpath(lp, rp) && over(la, ra, |l, r| self.eq_fieldpat(l, r)) + self.eq_qpath(lp, rp) && over(la, ra, |l, r| self.eq_pat_field(l, r)) }, (&PatKind::TupleStruct(ref lp, ref la, ls), &PatKind::TupleStruct(ref rp, ref ra, rs)) => { self.eq_qpath(lp, rp) && over(la, ra, |l, r| self.eq_pat(l, r)) && ls == rs @@ -377,13 +374,9 @@ impl HirEqInterExpr<'_, '_, '_> { left.ident.name == right.ident.name && both(&left.args, &right.args, |l, r| self.eq_path_parameters(l, r)) } - fn eq_ty(&mut self, left: &Ty<'_>, right: &Ty<'_>) -> bool { - self.eq_ty_kind(&left.kind, &right.kind) - } - #[allow(clippy::similar_names)] - fn eq_ty_kind(&mut self, left: &TyKind<'_>, right: &TyKind<'_>) -> bool { - match (left, right) { + fn eq_ty(&mut self, left: &Ty<'_>, right: &Ty<'_>) -> bool { + match (&left.kind, &right.kind) { (&TyKind::Slice(ref l_vec), &TyKind::Slice(ref r_vec)) => self.eq_ty(l_vec, r_vec), (&TyKind::Array(ref lt, ref ll_id), &TyKind::Array(ref rt, ref rl_id)) => { let cx = self.inner.cx; diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 7d3584333af..6b235875c20 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1,5 +1,6 @@ #![feature(box_patterns)] #![feature(in_band_lifetimes)] +#![feature(iter_zip)] #![cfg_attr(bootstrap, feature(or_patterns))] #![feature(rustc_private)] #![recursion_limit = "512"] @@ -32,7 +33,7 @@ pub mod attrs; pub mod camel_case; pub mod comparisons; pub mod consts; -mod diagnostics; +pub mod diagnostics; pub mod eager_or_lazy; pub mod higher; mod hir_utils; @@ -40,51 +41,47 @@ pub mod numeric_literal; pub mod paths; pub mod ptr; pub mod qualify_min_const_fn; +pub mod source; pub mod sugg; +pub mod ty; pub mod usage; pub mod visitors; pub use self::attrs::*; -pub use self::diagnostics::*; pub use self::hir_utils::{both, eq_expr_value, over, SpanlessEq, SpanlessHash}; -use std::borrow::Cow; use std::collections::hash_map::Entry; use std::hash::BuildHasherDefault; use if_chain::if_chain; -use rustc_ast::ast::{self, Attribute, BorrowKind, LitKind, Mutability}; +use rustc_ast::ast::{self, Attribute, BorrowKind, LitKind}; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; -use rustc_hir::Node; use rustc_hir::{ - def, Arm, Block, Body, Constness, Expr, ExprKind, FnDecl, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, Item, - ItemKind, LangItem, MatchSource, Param, Pat, PatKind, Path, PathSegment, QPath, TraitItem, TraitItemKind, TraitRef, - TyKind, Unsafety, + def, Arm, BindingAnnotation, Block, Body, Constness, Expr, ExprKind, FieldDef, FnDecl, ForeignItem, GenericArgs, + GenericParam, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, LangItem, Lifetime, Local, MacroDef, + MatchSource, Mod, Node, Param, Pat, PatKind, Path, PathSegment, QPath, Stmt, TraitItem, TraitItemKind, TraitRef, + TyKind, Variant, Visibility, }; -use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, Level, Lint, LintContext}; use rustc_middle::hir::exports::Export; use rustc_middle::hir::map::Map; -use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; -use rustc_middle::ty::{self, layout::IntegerExt, DefIdTree, IntTy, Ty, TyCtxt, TypeFoldable, UintTy}; +use rustc_middle::ty as rustc_ty; +use rustc_middle::ty::{layout::IntegerExt, DefIdTree, Ty, TyCtxt, TypeFoldable}; use rustc_semver::RustcVersion; use rustc_session::Session; -use rustc_span::hygiene::{self, ExpnKind, MacroKind}; +use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::original_sp; use rustc_span::sym; -use rustc_span::symbol::{kw, Symbol}; -use rustc_span::{BytePos, Pos, Span, SyntaxContext, DUMMY_SP}; +use rustc_span::symbol::{kw, Ident, Symbol}; +use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::Integer; -use rustc_trait_selection::traits::query::normalize::AtExt; -use smallvec::SmallVec; use crate::consts::{constant, Constant}; -use std::collections::HashMap; +use crate::ty::is_recursively_primitive_type; pub fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option<Span>) -> Option<RustcVersion> { if let Ok(version) = RustcVersion::parse(msrv) { @@ -137,6 +134,58 @@ pub fn differing_macro_contexts(lhs: Span, rhs: Span) -> bool { rhs.ctxt() != lhs.ctxt() } +/// If the given expression is a local binding, find the initializer expression. +/// If that initializer expression is another local binding, find its initializer again. +/// This process repeats as long as possible (but usually no more than once). Initializer +/// expressions with adjustments are ignored. If this is not desired, use [`find_binding_init`] +/// instead. +/// +/// Examples: +/// ```ignore +/// let abc = 1; +/// // ^ output +/// let def = abc; +/// dbg!(def) +/// // ^^^ input +/// +/// // or... +/// let abc = 1; +/// let def = abc + 2; +/// // ^^^^^^^ output +/// dbg!(def) +/// // ^^^ input +/// ``` +pub fn expr_or_init<'a, 'b, 'tcx: 'b>(cx: &LateContext<'tcx>, mut expr: &'a Expr<'b>) -> &'a Expr<'b> { + while let Some(init) = path_to_local(expr) + .and_then(|id| find_binding_init(cx, id)) + .filter(|init| cx.typeck_results().expr_adjustments(init).is_empty()) + { + expr = init; + } + expr +} + +/// Finds the initializer expression for a local binding. Returns `None` if the binding is mutable. +/// By only considering immutable bindings, we guarantee that the returned expression represents the +/// value of the binding wherever it is referenced. +/// +/// Example: For `let x = 1`, if the `HirId` of `x` is provided, the `Expr` `1` is returned. +/// Note: If you have an expression that references a binding `x`, use `path_to_local` to get the +/// canonical binding `HirId`. +pub fn find_binding_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Expr<'tcx>> { + let hir = cx.tcx.hir(); + if_chain! { + if let Some(Node::Binding(pat)) = hir.find(hir_id); + if matches!(pat.kind, PatKind::Binding(BindingAnnotation::Unannotated, ..)); + let parent = hir.get_parent_node(hir_id); + if let Some(Node::Local(local)) = hir.find(parent); + then { + return local.init; + } + } + None +} + /// Returns `true` if the given `NodeId` is inside a constant context /// /// # Example @@ -184,54 +233,11 @@ pub fn in_macro(span: Span) -> bool { } } -// If the snippet is empty, it's an attribute that was inserted during macro -// expansion and we want to ignore those, because they could come from external -// sources that the user has no control over. -// For some reason these attributes don't have any expansion info on them, so -// we have to check it this way until there is a better way. -pub fn is_present_in_source<T: LintContext>(cx: &T, span: Span) -> bool { - if let Some(snippet) = snippet_opt(cx, span) { - if snippet.is_empty() { - return false; - } - } - true -} - /// Checks if given pattern is a wildcard (`_`) pub fn is_wild<'tcx>(pat: &impl std::ops::Deref<Target = Pat<'tcx>>) -> bool { matches!(pat.kind, PatKind::Wild) } -/// Checks if type is struct, enum or union type with the given def path. -/// -/// If the type is a diagnostic item, use `is_type_diagnostic_item` instead. -/// If you change the signature, remember to update the internal lint `MatchTypeOnDiagItem` -pub fn match_type(cx: &LateContext<'_>, ty: Ty<'_>, path: &[&str]) -> bool { - match ty.kind() { - ty::Adt(adt, _) => match_def_path(cx, adt.did, path), - _ => false, - } -} - -/// Checks if the type is equal to a diagnostic item -/// -/// If you change the signature, remember to update the internal lint `MatchTypeOnDiagItem` -pub fn is_type_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symbol) -> bool { - match ty.kind() { - ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(diag_item, adt.did), - _ => false, - } -} - -/// Checks if the type is equal to a lang item -pub fn is_type_lang_item(cx: &LateContext<'_>, ty: Ty<'_>, lang_item: hir::LangItem) -> bool { - match ty.kind() { - ty::Adt(adt, _) => cx.tcx.lang_items().require(lang_item).unwrap() == adt.did, - _ => false, - } -} - /// Checks if the first type parameter is a lang item. pub fn is_ty_param_lang_item(cx: &LateContext<'_>, qpath: &QPath<'tcx>, item: LangItem) -> Option<&'tcx hir::Ty<'tcx>> { let ty = get_qpath_generic_tys(qpath).next()?; @@ -266,34 +272,37 @@ pub fn is_ty_param_diagnostic_item( } } -/// Return `true` if the passed `typ` is `isize` or `usize`. -pub fn is_isize_or_usize(typ: Ty<'_>) -> bool { - matches!(typ.kind(), ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize)) -} - /// Checks if the method call given in `expr` belongs to the given trait. +/// This is a deprecated function, consider using [`is_trait_method`]. pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str]) -> bool { let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap(); let trt_id = cx.tcx.trait_of_item(def_id); trt_id.map_or(false, |trt_id| match_def_path(cx, trt_id, path)) } -/// Checks if the method call given in `expr` belongs to a trait or other container with a given +/// Checks if the method call given in `def_id` belongs to a trait or other container with a given /// diagnostic item pub fn is_diagnostic_assoc_item(cx: &LateContext<'_>, def_id: DefId, diag_item: Symbol) -> bool { cx.tcx .opt_associated_item(def_id) .and_then(|associated_item| match associated_item.container { - ty::TraitContainer(assoc_def_id) => Some(assoc_def_id), - ty::ImplContainer(assoc_def_id) => match cx.tcx.type_of(assoc_def_id).kind() { - ty::Adt(adt, _) => Some(adt.did), - ty::Slice(_) => cx.tcx.get_diagnostic_item(sym::slice), // this isn't perfect but it works + rustc_ty::TraitContainer(assoc_def_id) => Some(assoc_def_id), + rustc_ty::ImplContainer(assoc_def_id) => match cx.tcx.type_of(assoc_def_id).kind() { + rustc_ty::Adt(adt, _) => Some(adt.did), + rustc_ty::Slice(_) => cx.tcx.get_diagnostic_item(sym::slice), // this isn't perfect but it works _ => None, }, }) .map_or(false, |assoc_def_id| cx.tcx.is_diagnostic_item(diag_item, assoc_def_id)) } +/// Checks if the method call given in `expr` belongs to the given trait. +pub fn is_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) -> bool { + cx.typeck_results() + .type_dependent_def_id(expr.hir_id) + .map_or(false, |did| is_diagnostic_assoc_item(cx, did, diag_item)) +} + /// Checks if an expression references a variable of the given name. pub fn match_var(expr: &Expr<'_>, var: Symbol) -> bool { if let ExprKind::Path(QPath::Resolved(None, ref path)) = expr.kind { @@ -479,26 +488,6 @@ pub fn get_trait_def_id(cx: &LateContext<'_>, path: &[&str]) -> Option<DefId> { } } -/// Checks whether a type implements a trait. -/// See also `get_trait_def_id`. -pub fn implements_trait<'tcx>( - cx: &LateContext<'tcx>, - ty: Ty<'tcx>, - trait_id: DefId, - ty_params: &[GenericArg<'tcx>], -) -> bool { - // Do not check on infer_types to avoid panic in evaluate_obligation. - if ty.has_infer_types() { - return false; - } - let ty = cx.tcx.erase_regions(ty); - if ty.has_escaping_bound_vars() { - return false; - } - let ty_params = cx.tcx.mk_substs(ty_params.iter()); - cx.tcx.type_implements_trait((trait_id, ty, ty_params, cx.param_env)) -} - /// Gets the `hir::TraitRef` of the trait the given method is implemented for. /// /// Use this if you want to find the `TraitRef` of the `Add` trait in this example: @@ -526,26 +515,6 @@ pub fn trait_ref_of_method<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Optio None } -/// Checks whether this type implements `Drop`. -pub fn has_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - match ty.ty_adt_def() { - Some(def) => def.has_dtor(cx.tcx), - None => false, - } -} - -/// Checks whether a type can be partially moved. -pub fn can_partially_move_ty(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - if has_drop(cx, ty) || is_copy(cx, ty) { - return false; - } - match ty.kind() { - ty::Param(_) => false, - ty::Adt(def, subs) => def.all_fields().any(|f| !is_copy(cx, f.ty(cx.tcx, subs))), - _ => true, - } -} - /// Returns the method names and argument list of nested method call expressions that make up /// `expr`. method/span lists are sorted with the most recent call first. pub fn method_calls<'tcx>( @@ -727,206 +696,6 @@ pub fn find_macro_calls(names: &[&str], body: &Body<'_>) -> Vec<Span> { fmc.result } -/// Converts a span to a code snippet if available, otherwise use default. -/// -/// This is useful if you want to provide suggestions for your lint or more generally, if you want -/// to convert a given `Span` to a `str`. -/// -/// # Example -/// ```rust,ignore -/// snippet(cx, expr.span, "..") -/// ``` -pub fn snippet<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> { - snippet_opt(cx, span).map_or_else(|| Cow::Borrowed(default), From::from) -} - -/// Same as `snippet`, but it adapts the applicability level by following rules: -/// -/// - Applicability level `Unspecified` will never be changed. -/// - If the span is inside a macro, change the applicability level to `MaybeIncorrect`. -/// - If the default value is used and the applicability level is `MachineApplicable`, change it to -/// `HasPlaceholders` -pub fn snippet_with_applicability<'a, T: LintContext>( - cx: &T, - span: Span, - default: &'a str, - applicability: &mut Applicability, -) -> Cow<'a, str> { - if *applicability != Applicability::Unspecified && span.from_expansion() { - *applicability = Applicability::MaybeIncorrect; - } - snippet_opt(cx, span).map_or_else( - || { - if *applicability == Applicability::MachineApplicable { - *applicability = Applicability::HasPlaceholders; - } - Cow::Borrowed(default) - }, - From::from, - ) -} - -/// Same as `snippet`, but should only be used when it's clear that the input span is -/// not a macro argument. -pub fn snippet_with_macro_callsite<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> { - snippet(cx, span.source_callsite(), default) -} - -/// Converts a span to a code snippet. Returns `None` if not available. -pub fn snippet_opt<T: LintContext>(cx: &T, span: Span) -> Option<String> { - cx.sess().source_map().span_to_snippet(span).ok() -} - -/// Converts a span (from a block) to a code snippet if available, otherwise use default. -/// -/// This trims the code of indentation, except for the first line. Use it for blocks or block-like -/// things which need to be printed as such. -/// -/// The `indent_relative_to` arg can be used, to provide a span, where the indentation of the -/// resulting snippet of the given span. -/// -/// # Example -/// -/// ```rust,ignore -/// snippet_block(cx, block.span, "..", None) -/// // where, `block` is the block of the if expr -/// if x { -/// y; -/// } -/// // will return the snippet -/// { -/// y; -/// } -/// ``` -/// -/// ```rust,ignore -/// snippet_block(cx, block.span, "..", Some(if_expr.span)) -/// // where, `block` is the block of the if expr -/// if x { -/// y; -/// } -/// // will return the snippet -/// { -/// y; -/// } // aligned with `if` -/// ``` -/// Note that the first line of the snippet always has 0 indentation. -pub fn snippet_block<'a, T: LintContext>( - cx: &T, - span: Span, - default: &'a str, - indent_relative_to: Option<Span>, -) -> Cow<'a, str> { - let snip = snippet(cx, span, default); - let indent = indent_relative_to.and_then(|s| indent_of(cx, s)); - reindent_multiline(snip, true, indent) -} - -/// Same as `snippet_block`, but adapts the applicability level by the rules of -/// `snippet_with_applicability`. -pub fn snippet_block_with_applicability<'a, T: LintContext>( - cx: &T, - span: Span, - default: &'a str, - indent_relative_to: Option<Span>, - applicability: &mut Applicability, -) -> Cow<'a, str> { - let snip = snippet_with_applicability(cx, span, default, applicability); - let indent = indent_relative_to.and_then(|s| indent_of(cx, s)); - reindent_multiline(snip, true, indent) -} - -/// Same as `snippet_with_applicability`, but first walks the span up to the given context. This -/// will result in the macro call, rather then the expansion, if the span is from a child context. -/// If the span is not from a child context, it will be used directly instead. -/// -/// e.g. Given the expression `&vec![]`, getting a snippet from the span for `vec![]` as a HIR node -/// would result in `box []`. If given the context of the address of expression, this function will -/// correctly get a snippet of `vec![]`. -pub fn snippet_with_context( - cx: &LateContext<'_>, - span: Span, - outer: SyntaxContext, - default: &'a str, - applicability: &mut Applicability, -) -> Cow<'a, str> { - let outer_span = hygiene::walk_chain(span, outer); - let span = if outer_span.ctxt() == outer { - outer_span - } else { - // The span is from a macro argument, and the outer context is the macro using the argument - if *applicability != Applicability::Unspecified { - *applicability = Applicability::MaybeIncorrect; - } - // TODO: get the argument span. - span - }; - - snippet_with_applicability(cx, span, default, applicability) -} - -/// Returns a new Span that extends the original Span to the first non-whitespace char of the first -/// line. -/// -/// ```rust,ignore -/// let x = (); -/// // ^^ -/// // will be converted to -/// let x = (); -/// // ^^^^^^^^^^ -/// ``` -pub fn first_line_of_span<T: LintContext>(cx: &T, span: Span) -> Span { - first_char_in_first_line(cx, span).map_or(span, |first_char_pos| span.with_lo(first_char_pos)) -} - -fn first_char_in_first_line<T: LintContext>(cx: &T, span: Span) -> Option<BytePos> { - let line_span = line_span(cx, span); - snippet_opt(cx, line_span).and_then(|snip| { - snip.find(|c: char| !c.is_whitespace()) - .map(|pos| line_span.lo() + BytePos::from_usize(pos)) - }) -} - -/// Returns the indentation of the line of a span -/// -/// ```rust,ignore -/// let x = (); -/// // ^^ -- will return 0 -/// let x = (); -/// // ^^ -- will return 4 -/// ``` -pub fn indent_of<T: LintContext>(cx: &T, span: Span) -> Option<usize> { - snippet_opt(cx, line_span(cx, span)).and_then(|snip| snip.find(|c: char| !c.is_whitespace())) -} - -/// Returns the positon just before rarrow -/// -/// ```rust,ignore -/// fn into(self) -> () {} -/// ^ -/// // in case of unformatted code -/// fn into2(self)-> () {} -/// ^ -/// fn into3(self) -> () {} -/// ^ -/// ``` -pub fn position_before_rarrow(s: &str) -> Option<usize> { - s.rfind("->").map(|rpos| { - let mut rpos = rpos; - let chars: Vec<char> = s.chars().collect(); - while rpos > 1 { - if let Some(c) = chars.get(rpos - 1) { - if c.is_whitespace() { - rpos -= 1; - continue; - } - } - break; - } - rpos - }) -} - /// Extends the span to the beginning of the spans line, incl. whitespaces. /// /// ```rust,ignore @@ -944,81 +713,52 @@ fn line_span<T: LintContext>(cx: &T, span: Span) -> Span { Span::new(line_start, span.hi(), span.ctxt()) } -/// Like `snippet_block`, but add braces if the expr is not an `ExprKind::Block`. -/// Also takes an `Option<String>` which can be put inside the braces. -pub fn expr_block<'a, T: LintContext>( - cx: &T, - expr: &Expr<'_>, - option: Option<String>, - default: &'a str, - indent_relative_to: Option<Span>, -) -> Cow<'a, str> { - let code = snippet_block(cx, expr.span, default, indent_relative_to); - let string = option.unwrap_or_default(); - if expr.span.from_expansion() { - Cow::Owned(format!("{{ {} }}", snippet_with_macro_callsite(cx, expr.span, default))) - } else if let ExprKind::Block(_, _) = expr.kind { - Cow::Owned(format!("{}{}", code, string)) - } else if string.is_empty() { - Cow::Owned(format!("{{ {} }}", code)) - } else { - Cow::Owned(format!("{{\n{};\n{}\n}}", code, string)) +/// Gets the span of the node, if there is one. +pub fn get_node_span(node: Node<'_>) -> Option<Span> { + match node { + Node::Param(Param { span, .. }) + | Node::Item(Item { span, .. }) + | Node::ForeignItem(ForeignItem { span, .. }) + | Node::TraitItem(TraitItem { span, .. }) + | Node::ImplItem(ImplItem { span, .. }) + | Node::Variant(Variant { span, .. }) + | Node::Field(FieldDef { span, .. }) + | Node::Expr(Expr { span, .. }) + | Node::Stmt(Stmt { span, .. }) + | Node::PathSegment(PathSegment { + ident: Ident { span, .. }, + .. + }) + | Node::Ty(hir::Ty { span, .. }) + | Node::TraitRef(TraitRef { + path: Path { span, .. }, + .. + }) + | Node::Binding(Pat { span, .. }) + | Node::Pat(Pat { span, .. }) + | Node::Arm(Arm { span, .. }) + | Node::Block(Block { span, .. }) + | Node::Local(Local { span, .. }) + | Node::MacroDef(MacroDef { span, .. }) + | Node::Lifetime(Lifetime { span, .. }) + | Node::GenericParam(GenericParam { span, .. }) + | Node::Visibility(Visibility { span, .. }) + | Node::Crate(Mod { inner: span, .. }) => Some(*span), + Node::Ctor(_) | Node::AnonConst(_) => None, } } -/// Reindent a multiline string with possibility of ignoring the first line. -#[allow(clippy::needless_pass_by_value)] -pub fn reindent_multiline(s: Cow<'_, str>, ignore_first: bool, indent: Option<usize>) -> Cow<'_, str> { - let s_space = reindent_multiline_inner(&s, ignore_first, indent, ' '); - let s_tab = reindent_multiline_inner(&s_space, ignore_first, indent, '\t'); - reindent_multiline_inner(&s_tab, ignore_first, indent, ' ').into() -} - -fn reindent_multiline_inner(s: &str, ignore_first: bool, indent: Option<usize>, ch: char) -> String { - let x = s - .lines() - .skip(ignore_first as usize) - .filter_map(|l| { - if l.is_empty() { - None - } else { - // ignore empty lines - Some(l.char_indices().find(|&(_, x)| x != ch).unwrap_or((l.len(), ch)).0) - } - }) - .min() - .unwrap_or(0); - let indent = indent.unwrap_or(0); - s.lines() - .enumerate() - .map(|(i, l)| { - if (ignore_first && i == 0) || l.is_empty() { - l.to_owned() - } else if x > indent { - l.split_at(x - indent).1.to_owned() - } else { - " ".repeat(indent - x) + l - } - }) - .collect::<Vec<String>>() - .join("\n") +/// Gets the parent node, if any. +pub fn get_parent_node(tcx: TyCtxt<'_>, id: HirId) -> Option<Node<'_>> { + tcx.hir().parent_iter(id).next().map(|(_, node)| node) } /// Gets the parent expression, if any –- this is useful to constrain a lint. pub fn get_parent_expr<'tcx>(cx: &LateContext<'tcx>, e: &Expr<'_>) -> Option<&'tcx Expr<'tcx>> { - let map = &cx.tcx.hir(); - let hir_id = e.hir_id; - let parent_id = map.get_parent_node(hir_id); - if hir_id == parent_id { - return None; + match get_parent_node(cx.tcx, e.hir_id) { + Some(Node::Expr(parent)) => Some(parent), + _ => None, } - map.find(parent_id).and_then(|node| { - if let Node::Expr(parent) = node { - Some(parent) - } else { - None - } - }) } pub fn get_enclosing_block<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Block<'tcx>> { @@ -1058,24 +798,24 @@ pub fn get_parent_as_impl(tcx: TyCtxt<'_>, id: HirId) -> Option<&Impl<'_>> { } } -/// Returns the base type for HIR references and pointers. -pub fn walk_ptrs_hir_ty<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> { - match ty.kind { - TyKind::Ptr(ref mut_ty) | TyKind::Rptr(_, ref mut_ty) => walk_ptrs_hir_ty(&mut_ty.ty), - _ => ty, - } -} - -/// Returns the base type for references and raw pointers, and count reference -/// depth. -pub fn walk_ptrs_ty_depth(ty: Ty<'_>) -> (Ty<'_>, usize) { - fn inner(ty: Ty<'_>, depth: usize) -> (Ty<'_>, usize) { - match ty.kind() { - ty::Ref(_, ty, _) => inner(ty, depth + 1), - _ => (ty, depth), - } +/// Checks if the given expression is the else clause in the expression `if let .. {} else {}` +pub fn is_else_clause_of_if_let_else(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool { + let map = tcx.hir(); + let mut iter = map.parent_iter(expr.hir_id); + let arm_id = match iter.next() { + Some((id, Node::Arm(..))) => id, + _ => return false, + }; + match iter.next() { + Some(( + _, + Node::Expr(Expr { + kind: ExprKind::Match(_, [_, else_arm], kind), + .. + }), + )) => else_arm.hir_id == arm_id && matches!(kind, MatchSource::IfLetDesugar { .. }), + _ => false, } - inner(ty, 0) } /// Checks whether the given expression is a constant integer of the given value. @@ -1173,26 +913,6 @@ pub fn return_ty<'tcx>(cx: &LateContext<'tcx>, fn_item: hir::HirId) -> Ty<'tcx> cx.tcx.erase_late_bound_regions(ret_ty) } -/// Walks into `ty` and returns `true` if any inner type is the same as `other_ty` -pub fn contains_ty(ty: Ty<'_>, other_ty: Ty<'_>) -> bool { - ty.walk().any(|inner| match inner.unpack() { - GenericArgKind::Type(inner_ty) => ty::TyS::same_type(other_ty, inner_ty), - GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false, - }) -} - -/// Returns `true` if the given type is an `unsafe` function. -pub fn type_is_unsafe_function<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - match ty.kind() { - ty::FnDef(..) | ty::FnPtr(_) => ty.fn_sig(cx.tcx).unsafety() == Unsafety::Unsafe, - _ => false, - } -} - -pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - ty.is_copy_modulo_regions(cx.tcx.at(DUMMY_SP), cx.param_env) -} - /// Checks if an expression is constructing a tuple-like enum variant or struct pub fn is_ctor_or_promotable_const_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { if let ExprKind::Call(ref fun, _) = expr.kind { @@ -1241,11 +961,13 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { }, PatKind::Slice(ref head, ref middle, ref tail) => { match &cx.typeck_results().node_type(pat.hir_id).kind() { - ty::Slice(..) => { + rustc_ty::Slice(..) => { // [..] is the only irrefutable slice pattern. !head.is_empty() || middle.is_none() || !tail.is_empty() }, - ty::Array(..) => are_refutable(cx, head.iter().chain(middle).chain(tail.iter()).map(|pat| &**pat)), + rustc_ty::Array(..) => { + are_refutable(cx, head.iter().chain(middle).chain(tail.iter()).map(|pat| &**pat)) + }, _ => { // unreachable!() true @@ -1255,6 +977,16 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { } } +/// If the pattern is an `or` pattern, call the function once for each sub pattern. Otherwise, call +/// the function once on the given pattern. +pub fn recurse_or_patterns<'tcx, F: FnMut(&'tcx Pat<'tcx>)>(pat: &'tcx Pat<'tcx>, mut f: F) { + if let PatKind::Or(pats) = pat.kind { + pats.iter().cloned().for_each(f) + } else { + f(pat) + } +} + /// Checks for the `#[automatically_derived]` attribute all `#[derive]`d /// implementations have. pub fn is_automatically_derived(attrs: &[ast::Attribute]) -> bool { @@ -1357,64 +1089,31 @@ pub fn strip_pat_refs<'hir>(mut pat: &'hir Pat<'hir>) -> &'hir Pat<'hir> { pat } -pub fn int_bits(tcx: TyCtxt<'_>, ity: ty::IntTy) -> u64 { +pub fn int_bits(tcx: TyCtxt<'_>, ity: rustc_ty::IntTy) -> u64 { Integer::from_int_ty(&tcx, ity).size().bits() } #[allow(clippy::cast_possible_wrap)] /// Turn a constant int byte representation into an i128 -pub fn sext(tcx: TyCtxt<'_>, u: u128, ity: ty::IntTy) -> i128 { +pub fn sext(tcx: TyCtxt<'_>, u: u128, ity: rustc_ty::IntTy) -> i128 { let amt = 128 - int_bits(tcx, ity); ((u as i128) << amt) >> amt } #[allow(clippy::cast_sign_loss)] /// clip unused bytes -pub fn unsext(tcx: TyCtxt<'_>, u: i128, ity: ty::IntTy) -> u128 { +pub fn unsext(tcx: TyCtxt<'_>, u: i128, ity: rustc_ty::IntTy) -> u128 { let amt = 128 - int_bits(tcx, ity); ((u as u128) << amt) >> amt } /// clip unused bytes -pub fn clip(tcx: TyCtxt<'_>, u: u128, ity: ty::UintTy) -> u128 { +pub fn clip(tcx: TyCtxt<'_>, u: u128, ity: rustc_ty::UintTy) -> u128 { let bits = Integer::from_uint_ty(&tcx, ity).size().bits(); let amt = 128 - bits; (u << amt) >> amt } -/// Removes block comments from the given `Vec` of lines. -/// -/// # Examples -/// -/// ```rust,ignore -/// without_block_comments(vec!["/*", "foo", "*/"]); -/// // => vec![] -/// -/// without_block_comments(vec!["bar", "/*", "foo", "*/"]); -/// // => vec!["bar"] -/// ``` -pub fn without_block_comments(lines: Vec<&str>) -> Vec<&str> { - let mut without = vec![]; - - let mut nest_level = 0; - - for line in lines { - if line.contains("/*") { - nest_level += 1; - continue; - } else if line.contains("*/") { - nest_level -= 1; - continue; - } - - if nest_level == 0 { - without.push(line); - } - } - - without -} - pub fn any_parent_is_automatically_derived(tcx: TyCtxt<'_>, node: HirId) -> bool { let map = &tcx.hir(); let mut prev_enclosing_node = None; @@ -1429,47 +1128,6 @@ pub fn any_parent_is_automatically_derived(tcx: TyCtxt<'_>, node: HirId) -> bool false } -/// Returns true if ty has `iter` or `iter_mut` methods -pub fn has_iter_method(cx: &LateContext<'_>, probably_ref_ty: Ty<'_>) -> Option<Symbol> { - // FIXME: instead of this hard-coded list, we should check if `<adt>::iter` - // exists and has the desired signature. Unfortunately FnCtxt is not exported - // so we can't use its `lookup_method` method. - let into_iter_collections: &[Symbol] = &[ - sym::vec_type, - sym::option_type, - sym::result_type, - sym::BTreeMap, - sym::BTreeSet, - sym::vecdeque_type, - sym::LinkedList, - sym::BinaryHeap, - sym::hashset_type, - sym::hashmap_type, - sym::PathBuf, - sym::Path, - sym::Receiver, - ]; - - let ty_to_check = match probably_ref_ty.kind() { - ty::Ref(_, ty_to_check, _) => ty_to_check, - _ => probably_ref_ty, - }; - - let def_id = match ty_to_check.kind() { - ty::Array(..) => return Some(sym::array), - ty::Slice(..) => return Some(sym::slice), - ty::Adt(adt, _) => adt.did, - _ => return None, - }; - - for &name in into_iter_collections { - if cx.tcx.is_diagnostic_item(name, def_id) { - return Some(cx.tcx.item_name(def_id)); - } - } - None -} - /// Matches a function call with the given path and returns the arguments. /// /// Usage: @@ -1494,51 +1152,6 @@ pub fn match_function_call<'tcx>( None } -// FIXME: Per https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/infer/at/struct.At.html#method.normalize -// this function can be removed once the `normalizie` method does not panic when normalization does -// not succeed -/// Checks if `Ty` is normalizable. This function is useful -/// to avoid crashes on `layout_of`. -pub fn is_normalizable<'tcx>(cx: &LateContext<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { - is_normalizable_helper(cx, param_env, ty, &mut HashMap::new()) -} - -fn is_normalizable_helper<'tcx>( - cx: &LateContext<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, - cache: &mut HashMap<Ty<'tcx>, bool>, -) -> bool { - if let Some(&cached_result) = cache.get(ty) { - return cached_result; - } - // prevent recursive loops, false-negative is better than endless loop leading to stack overflow - cache.insert(ty, false); - let result = cx.tcx.infer_ctxt().enter(|infcx| { - let cause = rustc_middle::traits::ObligationCause::dummy(); - if infcx.at(&cause, param_env).normalize(ty).is_ok() { - match ty.kind() { - ty::Adt(def, substs) => def.variants.iter().all(|variant| { - variant - .fields - .iter() - .all(|field| is_normalizable_helper(cx, param_env, field.ty(cx.tcx, substs), cache)) - }), - _ => ty.walk().all(|generic_arg| match generic_arg.unpack() { - GenericArgKind::Type(inner_ty) if inner_ty != ty => { - is_normalizable_helper(cx, param_env, inner_ty, cache) - }, - _ => true, // if inner_ty == ty, we've already checked it - }), - } - } else { - false - } - }); - cache.insert(ty, result); - result -} - pub fn match_def_path<'tcx>(cx: &LateContext<'tcx>, did: DefId, syms: &[&str]) -> bool { // We have to convert `syms` to `&[Symbol]` here because rustc's `match_def_path` // accepts only that. We should probably move to Symbols in Clippy as well. @@ -1568,11 +1181,9 @@ pub fn match_panic_def_id(cx: &LateContext<'_>, did: DefId) -> bool { /// sequence of `if/else`. /// E.g., this returns `([a, b], [c, d, e])` for the expression /// `if a { c } else if b { d } else { e }`. -pub fn if_sequence<'tcx>( - mut expr: &'tcx Expr<'tcx>, -) -> (SmallVec<[&'tcx Expr<'tcx>; 1]>, SmallVec<[&'tcx Block<'tcx>; 1]>) { - let mut conds = SmallVec::new(); - let mut blocks: SmallVec<[&Block<'_>; 1]> = SmallVec::new(); +pub fn if_sequence<'tcx>(mut expr: &'tcx Expr<'tcx>) -> (Vec<&'tcx Expr<'tcx>>, Vec<&'tcx Block<'tcx>>) { + let mut conds = Vec::new(); + let mut blocks: Vec<&Block<'_>> = Vec::new(); while let ExprKind::If(ref cond, ref then_expr, ref else_expr) = expr.kind { conds.push(&**cond); @@ -1624,44 +1235,6 @@ pub fn must_use_attr(attrs: &[Attribute]) -> Option<&Attribute> { attr_by_name(attrs, "must_use") } -// Returns whether the type has #[must_use] attribute -pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - match ty.kind() { - ty::Adt(ref adt, _) => must_use_attr(&cx.tcx.get_attrs(adt.did)).is_some(), - ty::Foreign(ref did) => must_use_attr(&cx.tcx.get_attrs(*did)).is_some(), - ty::Slice(ref ty) - | ty::Array(ref ty, _) - | ty::RawPtr(ty::TypeAndMut { ref ty, .. }) - | ty::Ref(_, ref ty, _) => { - // for the Array case we don't need to care for the len == 0 case - // because we don't want to lint functions returning empty arrays - is_must_use_ty(cx, *ty) - }, - ty::Tuple(ref substs) => substs.types().any(|ty| is_must_use_ty(cx, ty)), - ty::Opaque(ref def_id, _) => { - for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) { - if let ty::PredicateKind::Trait(trait_predicate, _) = predicate.kind().skip_binder() { - if must_use_attr(&cx.tcx.get_attrs(trait_predicate.trait_ref.def_id)).is_some() { - return true; - } - } - } - false - }, - ty::Dynamic(binder, _) => { - for predicate in binder.iter() { - if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() { - if must_use_attr(&cx.tcx.get_attrs(trait_ref.def_id)).is_some() { - return true; - } - } - } - false - }, - _ => false, - } -} - // check if expr is calling method or function with #[must_use] attribute pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { let did = match expr.kind { @@ -1756,18 +1329,6 @@ pub fn run_lints(cx: &LateContext<'_>, lints: &[&'static Lint], id: HirId) -> bo }) } -/// Returns true iff the given type is a primitive (a bool or char, any integer or floating-point -/// number type, a str, or an array, slice, or tuple of those types). -pub fn is_recursively_primitive_type(ty: Ty<'_>) -> bool { - match ty.kind() { - ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => true, - ty::Ref(_, inner, _) if *inner.kind() == ty::Str => true, - ty::Array(inner_type, _) | ty::Slice(inner_type) => is_recursively_primitive_type(inner_type), - ty::Tuple(inner_types) => inner_types.types().all(is_recursively_primitive_type), - _ => false, - } -} - /// Returns Option<String> where String is a textual representation of the type encapsulated in the /// slice iff the given expression is a slice of primitives (as defined in the /// `is_recursively_primitive_type` function) and None otherwise. @@ -1775,9 +1336,9 @@ pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<S let expr_type = cx.typeck_results().expr_ty_adjusted(expr); let expr_kind = expr_type.kind(); let is_primitive = match expr_kind { - ty::Slice(element_type) => is_recursively_primitive_type(element_type), - ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), &ty::Slice(_)) => { - if let ty::Slice(element_type) = inner_ty.kind() { + rustc_ty::Slice(element_type) => is_recursively_primitive_type(element_type), + rustc_ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), &rustc_ty::Slice(_)) => { + if let rustc_ty::Slice(element_type) = inner_ty.kind() { is_recursively_primitive_type(element_type) } else { unreachable!() @@ -1790,9 +1351,9 @@ pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<S // if we have wrappers like Array, Slice or Tuple, print these // and get the type enclosed in the slice ref match expr_type.peel_refs().walk().nth(1).unwrap().expect_ty().kind() { - ty::Slice(..) => return Some("slice".into()), - ty::Array(..) => return Some("array".into()), - ty::Tuple(..) => return Some("tuple".into()), + rustc_ty::Slice(..) => return Some("slice".into()), + rustc_ty::Array(..) => return Some("array".into()), + rustc_ty::Tuple(..) => return Some("tuple".into()), _ => { // is_recursively_primitive_type() should have taken care // of the rest and we can rely on the type that is found @@ -1876,32 +1437,6 @@ pub fn peel_hir_expr_refs(expr: &'a Expr<'a>) -> (&'a Expr<'a>, usize) { f(expr, 0) } -/// Peels off all references on the type. Returns the underlying type and the number of references -/// removed. -pub fn peel_mid_ty_refs(ty: Ty<'_>) -> (Ty<'_>, usize) { - fn peel(ty: Ty<'_>, count: usize) -> (Ty<'_>, usize) { - if let ty::Ref(_, ty, _) = ty.kind() { - peel(ty, count + 1) - } else { - (ty, count) - } - } - peel(ty, 0) -} - -/// Peels off all references on the type.Returns the underlying type, the number of references -/// removed, and whether the pointer is ultimately mutable or not. -pub fn peel_mid_ty_refs_is_mutable(ty: Ty<'_>) -> (Ty<'_>, usize, Mutability) { - fn f(ty: Ty<'_>, count: usize, mutability: Mutability) -> (Ty<'_>, usize, Mutability) { - match ty.kind() { - ty::Ref(_, ty, Mutability::Mut) => f(ty, count + 1, mutability), - ty::Ref(_, ty, Mutability::Not) => f(ty, count + 1, Mutability::Not), - _ => (ty, count, mutability), - } - } - f(ty, 0, Mutability::Mut) -} - #[macro_export] macro_rules! unwrap_cargo_metadata { ($cx: ident, $lint: ident, $deps: expr) => {{ @@ -1955,100 +1490,3 @@ pub fn is_some_ctor(cx: &LateContext<'_>, res: Res) -> bool { } false } - -#[cfg(test)] -mod test { - use super::{reindent_multiline, without_block_comments}; - - #[test] - fn test_reindent_multiline_single_line() { - assert_eq!("", reindent_multiline("".into(), false, None)); - assert_eq!("...", reindent_multiline("...".into(), false, None)); - assert_eq!("...", reindent_multiline(" ...".into(), false, None)); - assert_eq!("...", reindent_multiline("\t...".into(), false, None)); - assert_eq!("...", reindent_multiline("\t\t...".into(), false, None)); - } - - #[test] - #[rustfmt::skip] - fn test_reindent_multiline_block() { - assert_eq!("\ - if x { - y - } else { - z - }", reindent_multiline(" if x { - y - } else { - z - }".into(), false, None)); - assert_eq!("\ - if x { - \ty - } else { - \tz - }", reindent_multiline(" if x { - \ty - } else { - \tz - }".into(), false, None)); - } - - #[test] - #[rustfmt::skip] - fn test_reindent_multiline_empty_line() { - assert_eq!("\ - if x { - y - - } else { - z - }", reindent_multiline(" if x { - y - - } else { - z - }".into(), false, None)); - } - - #[test] - #[rustfmt::skip] - fn test_reindent_multiline_lines_deeper() { - assert_eq!("\ - if x { - y - } else { - z - }", reindent_multiline("\ - if x { - y - } else { - z - }".into(), true, Some(8))); - } - - #[test] - fn test_without_block_comments_lines_without_block_comments() { - let result = without_block_comments(vec!["/*", "", "*/"]); - println!("result: {:?}", result); - assert!(result.is_empty()); - - let result = without_block_comments(vec!["", "/*", "", "*/", "#[crate_type = \"lib\"]", "/*", "", "*/", ""]); - assert_eq!(result, vec!["", "#[crate_type = \"lib\"]", ""]); - - let result = without_block_comments(vec!["/* rust", "", "*/"]); - assert!(result.is_empty()); - - let result = without_block_comments(vec!["/* one-line comment */"]); - assert!(result.is_empty()); - - let result = without_block_comments(vec!["/* nested", "/* multi-line", "comment", "*/", "test", "*/"]); - assert!(result.is_empty()); - - let result = without_block_comments(vec!["/* nested /* inline /* comment */ test */ */"]); - assert!(result.is_empty()); - - let result = without_block_comments(vec!["foo", "bar", "baz"]); - assert_eq!(result, vec!["foo", "bar", "baz"]); - } -} diff --git a/src/tools/clippy/clippy_utils/src/numeric_literal.rs b/src/tools/clippy/clippy_utils/src/numeric_literal.rs index d02603d7702..268bc5b3205 100644 --- a/src/tools/clippy/clippy_utils/src/numeric_literal.rs +++ b/src/tools/clippy/clippy_utils/src/numeric_literal.rs @@ -1,4 +1,5 @@ use rustc_ast::ast::{Lit, LitFloatType, LitIntType, LitKind}; +use std::iter; #[derive(Debug, PartialEq, Copy, Clone)] pub enum Radix { @@ -192,7 +193,7 @@ impl<'a> NumericLiteral<'a> { } } - for (c, i) in digits.zip((0..group_size).cycle()) { + for (c, i) in iter::zip(digits, (0..group_size).cycle()) { if i == 0 { output.push('_'); } diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs index 560614efc74..11a446e42a4 100644 --- a/src/tools/clippy/clippy_utils/src/paths.rs +++ b/src/tools/clippy/clippy_utils/src/paths.rs @@ -61,7 +61,6 @@ pub const IO_READ: [&str; 3] = ["std", "io", "Read"]; pub const IO_WRITE: [&str; 3] = ["std", "io", "Write"]; pub const IPADDR_V4: [&str; 4] = ["std", "net", "IpAddr", "V4"]; pub const IPADDR_V6: [&str; 4] = ["std", "net", "IpAddr", "V6"]; -pub const ITERATOR: [&str; 5] = ["core", "iter", "traits", "iterator", "Iterator"]; #[cfg(feature = "internal-lints")] pub const KW_MODULE: [&str; 3] = ["rustc_span", "symbol", "kw"]; #[cfg(feature = "internal-lints")] diff --git a/src/tools/clippy/clippy_utils/src/ptr.rs b/src/tools/clippy/clippy_utils/src/ptr.rs index df6143edbca..5885cc83560 100644 --- a/src/tools/clippy/clippy_utils/src/ptr.rs +++ b/src/tools/clippy/clippy_utils/src/ptr.rs @@ -1,4 +1,5 @@ -use crate::{get_pat_name, match_var, snippet}; +use crate::source::snippet; +use crate::{get_pat_name, match_var}; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc_hir::{Body, BodyId, Expr, ExprKind, Param}; use rustc_lint::LateContext; diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs new file mode 100644 index 00000000000..2d794d48dc5 --- /dev/null +++ b/src/tools/clippy/clippy_utils/src/source.rs @@ -0,0 +1,420 @@ +//! Utils for extracting, inspecting or transforming source code + +#![allow(clippy::module_name_repetitions)] + +use crate::line_span; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LintContext}; +use rustc_span::hygiene; +use rustc_span::{BytePos, Pos, Span, SyntaxContext}; +use std::borrow::Cow; + +/// Like `snippet_block`, but add braces if the expr is not an `ExprKind::Block`. +/// Also takes an `Option<String>` which can be put inside the braces. +pub fn expr_block<'a, T: LintContext>( + cx: &T, + expr: &Expr<'_>, + option: Option<String>, + default: &'a str, + indent_relative_to: Option<Span>, +) -> Cow<'a, str> { + let code = snippet_block(cx, expr.span, default, indent_relative_to); + let string = option.unwrap_or_default(); + if expr.span.from_expansion() { + Cow::Owned(format!("{{ {} }}", snippet_with_macro_callsite(cx, expr.span, default))) + } else if let ExprKind::Block(_, _) = expr.kind { + Cow::Owned(format!("{}{}", code, string)) + } else if string.is_empty() { + Cow::Owned(format!("{{ {} }}", code)) + } else { + Cow::Owned(format!("{{\n{};\n{}\n}}", code, string)) + } +} + +/// Returns a new Span that extends the original Span to the first non-whitespace char of the first +/// line. +/// +/// ```rust,ignore +/// let x = (); +/// // ^^ +/// // will be converted to +/// let x = (); +/// // ^^^^^^^^^^ +/// ``` +pub fn first_line_of_span<T: LintContext>(cx: &T, span: Span) -> Span { + first_char_in_first_line(cx, span).map_or(span, |first_char_pos| span.with_lo(first_char_pos)) +} + +fn first_char_in_first_line<T: LintContext>(cx: &T, span: Span) -> Option<BytePos> { + let line_span = line_span(cx, span); + snippet_opt(cx, line_span).and_then(|snip| { + snip.find(|c: char| !c.is_whitespace()) + .map(|pos| line_span.lo() + BytePos::from_usize(pos)) + }) +} + +/// Returns the indentation of the line of a span +/// +/// ```rust,ignore +/// let x = (); +/// // ^^ -- will return 0 +/// let x = (); +/// // ^^ -- will return 4 +/// ``` +pub fn indent_of<T: LintContext>(cx: &T, span: Span) -> Option<usize> { + snippet_opt(cx, line_span(cx, span)).and_then(|snip| snip.find(|c: char| !c.is_whitespace())) +} + +// If the snippet is empty, it's an attribute that was inserted during macro +// expansion and we want to ignore those, because they could come from external +// sources that the user has no control over. +// For some reason these attributes don't have any expansion info on them, so +// we have to check it this way until there is a better way. +pub fn is_present_in_source<T: LintContext>(cx: &T, span: Span) -> bool { + if let Some(snippet) = snippet_opt(cx, span) { + if snippet.is_empty() { + return false; + } + } + true +} + +/// Returns the positon just before rarrow +/// +/// ```rust,ignore +/// fn into(self) -> () {} +/// ^ +/// // in case of unformatted code +/// fn into2(self)-> () {} +/// ^ +/// fn into3(self) -> () {} +/// ^ +/// ``` +pub fn position_before_rarrow(s: &str) -> Option<usize> { + s.rfind("->").map(|rpos| { + let mut rpos = rpos; + let chars: Vec<char> = s.chars().collect(); + while rpos > 1 { + if let Some(c) = chars.get(rpos - 1) { + if c.is_whitespace() { + rpos -= 1; + continue; + } + } + break; + } + rpos + }) +} + +/// Reindent a multiline string with possibility of ignoring the first line. +#[allow(clippy::needless_pass_by_value)] +pub fn reindent_multiline(s: Cow<'_, str>, ignore_first: bool, indent: Option<usize>) -> Cow<'_, str> { + let s_space = reindent_multiline_inner(&s, ignore_first, indent, ' '); + let s_tab = reindent_multiline_inner(&s_space, ignore_first, indent, '\t'); + reindent_multiline_inner(&s_tab, ignore_first, indent, ' ').into() +} + +fn reindent_multiline_inner(s: &str, ignore_first: bool, indent: Option<usize>, ch: char) -> String { + let x = s + .lines() + .skip(ignore_first as usize) + .filter_map(|l| { + if l.is_empty() { + None + } else { + // ignore empty lines + Some(l.char_indices().find(|&(_, x)| x != ch).unwrap_or((l.len(), ch)).0) + } + }) + .min() + .unwrap_or(0); + let indent = indent.unwrap_or(0); + s.lines() + .enumerate() + .map(|(i, l)| { + if (ignore_first && i == 0) || l.is_empty() { + l.to_owned() + } else if x > indent { + l.split_at(x - indent).1.to_owned() + } else { + " ".repeat(indent - x) + l + } + }) + .collect::<Vec<String>>() + .join("\n") +} + +/// Converts a span to a code snippet if available, otherwise use default. +/// +/// This is useful if you want to provide suggestions for your lint or more generally, if you want +/// to convert a given `Span` to a `str`. +/// +/// # Example +/// ```rust,ignore +/// snippet(cx, expr.span, "..") +/// ``` +pub fn snippet<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> { + snippet_opt(cx, span).map_or_else(|| Cow::Borrowed(default), From::from) +} + +/// Same as `snippet`, but it adapts the applicability level by following rules: +/// +/// - Applicability level `Unspecified` will never be changed. +/// - If the span is inside a macro, change the applicability level to `MaybeIncorrect`. +/// - If the default value is used and the applicability level is `MachineApplicable`, change it to +/// `HasPlaceholders` +pub fn snippet_with_applicability<'a, T: LintContext>( + cx: &T, + span: Span, + default: &'a str, + applicability: &mut Applicability, +) -> Cow<'a, str> { + if *applicability != Applicability::Unspecified && span.from_expansion() { + *applicability = Applicability::MaybeIncorrect; + } + snippet_opt(cx, span).map_or_else( + || { + if *applicability == Applicability::MachineApplicable { + *applicability = Applicability::HasPlaceholders; + } + Cow::Borrowed(default) + }, + From::from, + ) +} + +/// Same as `snippet`, but should only be used when it's clear that the input span is +/// not a macro argument. +pub fn snippet_with_macro_callsite<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> { + snippet(cx, span.source_callsite(), default) +} + +/// Converts a span to a code snippet. Returns `None` if not available. +pub fn snippet_opt<T: LintContext>(cx: &T, span: Span) -> Option<String> { + cx.sess().source_map().span_to_snippet(span).ok() +} + +/// Converts a span (from a block) to a code snippet if available, otherwise use default. +/// +/// This trims the code of indentation, except for the first line. Use it for blocks or block-like +/// things which need to be printed as such. +/// +/// The `indent_relative_to` arg can be used, to provide a span, where the indentation of the +/// resulting snippet of the given span. +/// +/// # Example +/// +/// ```rust,ignore +/// snippet_block(cx, block.span, "..", None) +/// // where, `block` is the block of the if expr +/// if x { +/// y; +/// } +/// // will return the snippet +/// { +/// y; +/// } +/// ``` +/// +/// ```rust,ignore +/// snippet_block(cx, block.span, "..", Some(if_expr.span)) +/// // where, `block` is the block of the if expr +/// if x { +/// y; +/// } +/// // will return the snippet +/// { +/// y; +/// } // aligned with `if` +/// ``` +/// Note that the first line of the snippet always has 0 indentation. +pub fn snippet_block<'a, T: LintContext>( + cx: &T, + span: Span, + default: &'a str, + indent_relative_to: Option<Span>, +) -> Cow<'a, str> { + let snip = snippet(cx, span, default); + let indent = indent_relative_to.and_then(|s| indent_of(cx, s)); + reindent_multiline(snip, true, indent) +} + +/// Same as `snippet_block`, but adapts the applicability level by the rules of +/// `snippet_with_applicability`. +pub fn snippet_block_with_applicability<'a, T: LintContext>( + cx: &T, + span: Span, + default: &'a str, + indent_relative_to: Option<Span>, + applicability: &mut Applicability, +) -> Cow<'a, str> { + let snip = snippet_with_applicability(cx, span, default, applicability); + let indent = indent_relative_to.and_then(|s| indent_of(cx, s)); + reindent_multiline(snip, true, indent) +} + +/// Same as `snippet_with_applicability`, but first walks the span up to the given context. This +/// will result in the macro call, rather then the expansion, if the span is from a child context. +/// If the span is not from a child context, it will be used directly instead. +/// +/// e.g. Given the expression `&vec![]`, getting a snippet from the span for `vec![]` as a HIR node +/// would result in `box []`. If given the context of the address of expression, this function will +/// correctly get a snippet of `vec![]`. +/// +/// This will also return whether or not the snippet is a macro call. +pub fn snippet_with_context( + cx: &LateContext<'_>, + span: Span, + outer: SyntaxContext, + default: &'a str, + applicability: &mut Applicability, +) -> (Cow<'a, str>, bool) { + let outer_span = hygiene::walk_chain(span, outer); + let (span, is_macro_call) = if outer_span.ctxt() == outer { + (outer_span, span.ctxt() != outer) + } else { + // The span is from a macro argument, and the outer context is the macro using the argument + if *applicability != Applicability::Unspecified { + *applicability = Applicability::MaybeIncorrect; + } + // TODO: get the argument span. + (span, false) + }; + + ( + snippet_with_applicability(cx, span, default, applicability), + is_macro_call, + ) +} + +/// Removes block comments from the given `Vec` of lines. +/// +/// # Examples +/// +/// ```rust,ignore +/// without_block_comments(vec!["/*", "foo", "*/"]); +/// // => vec![] +/// +/// without_block_comments(vec!["bar", "/*", "foo", "*/"]); +/// // => vec!["bar"] +/// ``` +pub fn without_block_comments(lines: Vec<&str>) -> Vec<&str> { + let mut without = vec![]; + + let mut nest_level = 0; + + for line in lines { + if line.contains("/*") { + nest_level += 1; + continue; + } else if line.contains("*/") { + nest_level -= 1; + continue; + } + + if nest_level == 0 { + without.push(line); + } + } + + without +} + +#[cfg(test)] +mod test { + use super::{reindent_multiline, without_block_comments}; + + #[test] + fn test_reindent_multiline_single_line() { + assert_eq!("", reindent_multiline("".into(), false, None)); + assert_eq!("...", reindent_multiline("...".into(), false, None)); + assert_eq!("...", reindent_multiline(" ...".into(), false, None)); + assert_eq!("...", reindent_multiline("\t...".into(), false, None)); + assert_eq!("...", reindent_multiline("\t\t...".into(), false, None)); + } + + #[test] + #[rustfmt::skip] + fn test_reindent_multiline_block() { + assert_eq!("\ + if x { + y + } else { + z + }", reindent_multiline(" if x { + y + } else { + z + }".into(), false, None)); + assert_eq!("\ + if x { + \ty + } else { + \tz + }", reindent_multiline(" if x { + \ty + } else { + \tz + }".into(), false, None)); + } + + #[test] + #[rustfmt::skip] + fn test_reindent_multiline_empty_line() { + assert_eq!("\ + if x { + y + + } else { + z + }", reindent_multiline(" if x { + y + + } else { + z + }".into(), false, None)); + } + + #[test] + #[rustfmt::skip] + fn test_reindent_multiline_lines_deeper() { + assert_eq!("\ + if x { + y + } else { + z + }", reindent_multiline("\ + if x { + y + } else { + z + }".into(), true, Some(8))); + } + + #[test] + fn test_without_block_comments_lines_without_block_comments() { + let result = without_block_comments(vec!["/*", "", "*/"]); + println!("result: {:?}", result); + assert!(result.is_empty()); + + let result = without_block_comments(vec!["", "/*", "", "*/", "#[crate_type = \"lib\"]", "/*", "", "*/", ""]); + assert_eq!(result, vec!["", "#[crate_type = \"lib\"]", ""]); + + let result = without_block_comments(vec!["/* rust", "", "*/"]); + assert!(result.is_empty()); + + let result = without_block_comments(vec!["/* one-line comment */"]); + assert!(result.is_empty()); + + let result = without_block_comments(vec!["/* nested", "/* multi-line", "comment", "*/", "test", "*/"]); + assert!(result.is_empty()); + + let result = without_block_comments(vec!["/* nested /* inline /* comment */ test */ */"]); + assert!(result.is_empty()); + + let result = without_block_comments(vec!["foo", "bar", "baz"]); + assert_eq!(result, vec!["foo", "bar", "baz"]); + } +} diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index d4f6f4281d3..b2fe4317154 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -1,7 +1,8 @@ //! Contains utility functions to generate suggestions. #![deny(clippy::missing_docs_in_private_items)] -use crate::{higher, snippet, snippet_opt, snippet_with_macro_callsite}; +use crate::higher; +use crate::source::{snippet, snippet_opt, snippet_with_macro_callsite}; use rustc_ast::util::parser::AssocOp; use rustc_ast::{ast, token}; use rustc_ast_pretty::pprust::token_kind_to_string; diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs new file mode 100644 index 00000000000..807cfbc4c7f --- /dev/null +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -0,0 +1,305 @@ +//! Util methods for [`rustc_middle::ty`] + +#![allow(clippy::module_name_repetitions)] + +use std::collections::HashMap; + +use rustc_ast::ast::Mutability; +use rustc_hir as hir; +use rustc_hir::def_id::DefId; +use rustc_hir::{TyKind, Unsafety}; +use rustc_infer::infer::TyCtxtInferExt; +use rustc_lint::LateContext; +use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; +use rustc_middle::ty::{self, AdtDef, IntTy, Ty, TypeFoldable, UintTy}; +use rustc_span::sym; +use rustc_span::symbol::Symbol; +use rustc_span::DUMMY_SP; +use rustc_trait_selection::traits::query::normalize::AtExt; + +use crate::{match_def_path, must_use_attr}; + +pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { + ty.is_copy_modulo_regions(cx.tcx.at(DUMMY_SP), cx.param_env) +} + +/// Checks whether a type can be partially moved. +pub fn can_partially_move_ty(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { + if has_drop(cx, ty) || is_copy(cx, ty) { + return false; + } + match ty.kind() { + ty::Param(_) => false, + ty::Adt(def, subs) => def.all_fields().any(|f| !is_copy(cx, f.ty(cx.tcx, subs))), + _ => true, + } +} + +/// Walks into `ty` and returns `true` if any inner type is the same as `other_ty` +pub fn contains_ty(ty: Ty<'_>, other_ty: Ty<'_>) -> bool { + ty.walk().any(|inner| match inner.unpack() { + GenericArgKind::Type(inner_ty) => ty::TyS::same_type(other_ty, inner_ty), + GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false, + }) +} + +/// Walks into `ty` and returns `true` if any inner type is an instance of the given adt +/// constructor. +pub fn contains_adt_constructor(ty: Ty<'_>, adt: &AdtDef) -> bool { + ty.walk().any(|inner| match inner.unpack() { + GenericArgKind::Type(inner_ty) => inner_ty.ty_adt_def() == Some(adt), + GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false, + }) +} + +/// Returns true if ty has `iter` or `iter_mut` methods +pub fn has_iter_method(cx: &LateContext<'_>, probably_ref_ty: Ty<'_>) -> Option<Symbol> { + // FIXME: instead of this hard-coded list, we should check if `<adt>::iter` + // exists and has the desired signature. Unfortunately FnCtxt is not exported + // so we can't use its `lookup_method` method. + let into_iter_collections: &[Symbol] = &[ + sym::vec_type, + sym::option_type, + sym::result_type, + sym::BTreeMap, + sym::BTreeSet, + sym::vecdeque_type, + sym::LinkedList, + sym::BinaryHeap, + sym::hashset_type, + sym::hashmap_type, + sym::PathBuf, + sym::Path, + sym::Receiver, + ]; + + let ty_to_check = match probably_ref_ty.kind() { + ty::Ref(_, ty_to_check, _) => ty_to_check, + _ => probably_ref_ty, + }; + + let def_id = match ty_to_check.kind() { + ty::Array(..) => return Some(sym::array), + ty::Slice(..) => return Some(sym::slice), + ty::Adt(adt, _) => adt.did, + _ => return None, + }; + + for &name in into_iter_collections { + if cx.tcx.is_diagnostic_item(name, def_id) { + return Some(cx.tcx.item_name(def_id)); + } + } + None +} + +/// Checks whether a type implements a trait. +/// See also `get_trait_def_id`. +pub fn implements_trait<'tcx>( + cx: &LateContext<'tcx>, + ty: Ty<'tcx>, + trait_id: DefId, + ty_params: &[GenericArg<'tcx>], +) -> bool { + // Do not check on infer_types to avoid panic in evaluate_obligation. + if ty.has_infer_types() { + return false; + } + let ty = cx.tcx.erase_regions(ty); + if ty.has_escaping_bound_vars() { + return false; + } + let ty_params = cx.tcx.mk_substs(ty_params.iter()); + cx.tcx.type_implements_trait((trait_id, ty, ty_params, cx.param_env)) +} + +/// Checks whether this type implements `Drop`. +pub fn has_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { + match ty.ty_adt_def() { + Some(def) => def.has_dtor(cx.tcx), + None => false, + } +} + +// Returns whether the type has #[must_use] attribute +pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { + match ty.kind() { + ty::Adt(ref adt, _) => must_use_attr(&cx.tcx.get_attrs(adt.did)).is_some(), + ty::Foreign(ref did) => must_use_attr(&cx.tcx.get_attrs(*did)).is_some(), + ty::Slice(ref ty) + | ty::Array(ref ty, _) + | ty::RawPtr(ty::TypeAndMut { ref ty, .. }) + | ty::Ref(_, ref ty, _) => { + // for the Array case we don't need to care for the len == 0 case + // because we don't want to lint functions returning empty arrays + is_must_use_ty(cx, *ty) + }, + ty::Tuple(ref substs) => substs.types().any(|ty| is_must_use_ty(cx, ty)), + ty::Opaque(ref def_id, _) => { + for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) { + if let ty::PredicateKind::Trait(trait_predicate, _) = predicate.kind().skip_binder() { + if must_use_attr(&cx.tcx.get_attrs(trait_predicate.trait_ref.def_id)).is_some() { + return true; + } + } + } + false + }, + ty::Dynamic(binder, _) => { + for predicate in binder.iter() { + if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() { + if must_use_attr(&cx.tcx.get_attrs(trait_ref.def_id)).is_some() { + return true; + } + } + } + false + }, + _ => false, + } +} + +// FIXME: Per https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/infer/at/struct.At.html#method.normalize +// this function can be removed once the `normalizie` method does not panic when normalization does +// not succeed +/// Checks if `Ty` is normalizable. This function is useful +/// to avoid crashes on `layout_of`. +pub fn is_normalizable<'tcx>(cx: &LateContext<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { + is_normalizable_helper(cx, param_env, ty, &mut HashMap::new()) +} + +fn is_normalizable_helper<'tcx>( + cx: &LateContext<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, + cache: &mut HashMap<Ty<'tcx>, bool>, +) -> bool { + if let Some(&cached_result) = cache.get(ty) { + return cached_result; + } + // prevent recursive loops, false-negative is better than endless loop leading to stack overflow + cache.insert(ty, false); + let result = cx.tcx.infer_ctxt().enter(|infcx| { + let cause = rustc_middle::traits::ObligationCause::dummy(); + if infcx.at(&cause, param_env).normalize(ty).is_ok() { + match ty.kind() { + ty::Adt(def, substs) => def.variants.iter().all(|variant| { + variant + .fields + .iter() + .all(|field| is_normalizable_helper(cx, param_env, field.ty(cx.tcx, substs), cache)) + }), + _ => ty.walk().all(|generic_arg| match generic_arg.unpack() { + GenericArgKind::Type(inner_ty) if inner_ty != ty => { + is_normalizable_helper(cx, param_env, inner_ty, cache) + }, + _ => true, // if inner_ty == ty, we've already checked it + }), + } + } else { + false + } + }); + cache.insert(ty, result); + result +} + +/// Returns true iff the given type is a primitive (a bool or char, any integer or floating-point +/// number type, a str, or an array, slice, or tuple of those types). +pub fn is_recursively_primitive_type(ty: Ty<'_>) -> bool { + match ty.kind() { + ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => true, + ty::Ref(_, inner, _) if *inner.kind() == ty::Str => true, + ty::Array(inner_type, _) | ty::Slice(inner_type) => is_recursively_primitive_type(inner_type), + ty::Tuple(inner_types) => inner_types.types().all(is_recursively_primitive_type), + _ => false, + } +} + +/// Checks if the type is equal to a diagnostic item +/// +/// If you change the signature, remember to update the internal lint `MatchTypeOnDiagItem` +pub fn is_type_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symbol) -> bool { + match ty.kind() { + ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(diag_item, adt.did), + _ => false, + } +} + +/// Checks if the type is equal to a lang item +pub fn is_type_lang_item(cx: &LateContext<'_>, ty: Ty<'_>, lang_item: hir::LangItem) -> bool { + match ty.kind() { + ty::Adt(adt, _) => cx.tcx.lang_items().require(lang_item).unwrap() == adt.did, + _ => false, + } +} + +/// Return `true` if the passed `typ` is `isize` or `usize`. +pub fn is_isize_or_usize(typ: Ty<'_>) -> bool { + matches!(typ.kind(), ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize)) +} + +/// Checks if type is struct, enum or union type with the given def path. +/// +/// If the type is a diagnostic item, use `is_type_diagnostic_item` instead. +/// If you change the signature, remember to update the internal lint `MatchTypeOnDiagItem` +pub fn match_type(cx: &LateContext<'_>, ty: Ty<'_>, path: &[&str]) -> bool { + match ty.kind() { + ty::Adt(adt, _) => match_def_path(cx, adt.did, path), + _ => false, + } +} + +/// Peels off all references on the type. Returns the underlying type and the number of references +/// removed. +pub fn peel_mid_ty_refs(ty: Ty<'_>) -> (Ty<'_>, usize) { + fn peel(ty: Ty<'_>, count: usize) -> (Ty<'_>, usize) { + if let ty::Ref(_, ty, _) = ty.kind() { + peel(ty, count + 1) + } else { + (ty, count) + } + } + peel(ty, 0) +} + +/// Peels off all references on the type.Returns the underlying type, the number of references +/// removed, and whether the pointer is ultimately mutable or not. +pub fn peel_mid_ty_refs_is_mutable(ty: Ty<'_>) -> (Ty<'_>, usize, Mutability) { + fn f(ty: Ty<'_>, count: usize, mutability: Mutability) -> (Ty<'_>, usize, Mutability) { + match ty.kind() { + ty::Ref(_, ty, Mutability::Mut) => f(ty, count + 1, mutability), + ty::Ref(_, ty, Mutability::Not) => f(ty, count + 1, Mutability::Not), + _ => (ty, count, mutability), + } + } + f(ty, 0, Mutability::Mut) +} + +/// Returns `true` if the given type is an `unsafe` function. +pub fn type_is_unsafe_function<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { + match ty.kind() { + ty::FnDef(..) | ty::FnPtr(_) => ty.fn_sig(cx.tcx).unsafety() == Unsafety::Unsafe, + _ => false, + } +} + +/// Returns the base type for HIR references and pointers. +pub fn walk_ptrs_hir_ty<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> { + match ty.kind { + TyKind::Ptr(ref mut_ty) | TyKind::Rptr(_, ref mut_ty) => walk_ptrs_hir_ty(&mut_ty.ty), + _ => ty, + } +} + +/// Returns the base type for references and raw pointers, and count reference +/// depth. +pub fn walk_ptrs_ty_depth(ty: Ty<'_>) -> (Ty<'_>, usize) { + fn inner(ty: Ty<'_>, depth: usize) -> (Ty<'_>, usize) { + match ty.kind() { + ty::Ref(_, ty, _) => inner(ty, depth + 1), + _ => (ty, depth), + } + } + inner(ty, 0) +} diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs index 0b1ab6b7ea1..54f110988d7 100644 --- a/src/tools/clippy/clippy_utils/src/usage.rs +++ b/src/tools/clippy/clippy_utils/src/usage.rs @@ -7,8 +7,8 @@ use rustc_hir::intravisit::{NestedVisitorMap, Visitor}; use rustc_hir::{Expr, ExprKind, HirId, Path}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; -use rustc_middle::mir::FakeReadCause; use rustc_middle::hir::map::Map; +use rustc_middle::mir::FakeReadCause; use rustc_middle::ty; use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; @@ -79,7 +79,7 @@ impl<'tcx> Delegate<'tcx> for MutVarsDelegate { self.update(&cmt) } - fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause, _:HirId) { } + fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause, _: HirId) {} } pub struct ParamBindingIdCollector { diff --git a/src/tools/clippy/doc/basics.md b/src/tools/clippy/doc/basics.md index c56e84e2e32..5226875cc21 100644 --- a/src/tools/clippy/doc/basics.md +++ b/src/tools/clippy/doc/basics.md @@ -88,8 +88,8 @@ cargo dev fmt cargo dev update_lints # create a new lint and register it cargo dev new_lint -# (experimental) Setup Clippy to work with rust-analyzer -cargo dev ra_setup +# (experimental) Setup Clippy to work with IntelliJ-Rust +cargo dev ide_setup ``` ## lintcheck diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain index c52a7f2e743..c2821f31fd7 100644 --- a/src/tools/clippy/rust-toolchain +++ b/src/tools/clippy/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2021-03-11" +channel = "nightly-2021-03-25" components = ["llvm-tools-preview", "rustc-dev", "rust-src"] diff --git a/src/tools/clippy/tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.rs b/src/tools/clippy/tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.rs index 735909887ac..c6659edacc3 100644 --- a/src/tools/clippy/tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.rs +++ b/src/tools/clippy/tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.rs @@ -20,4 +20,9 @@ enum Flags { // `GccLlvmSomething` struct GCCLLVMSomething; +// don't warn on public items +pub struct MIXEDCapital; + +pub struct FULLCAPITAL; + fn main() {} diff --git a/src/tools/clippy/tests/ui/def_id_nocore.stderr b/src/tools/clippy/tests/ui/def_id_nocore.stderr index ed87a50547d..702684f6b43 100644 --- a/src/tools/clippy/tests/ui/def_id_nocore.stderr +++ b/src/tools/clippy/tests/ui/def_id_nocore.stderr @@ -1,10 +1,11 @@ -error: methods called `as_*` usually take self by reference or self by mutable reference; consider choosing a less ambiguous name +error: methods called `as_*` usually take `self` by reference or `self` by mutable reference --> $DIR/def_id_nocore.rs:26:19 | LL | pub fn as_ref(self) -> &'static str { | ^^^^ | = note: `-D clippy::wrong-self-convention` implied by `-D warnings` + = help: consider choosing a less ambiguous name error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/dereference.stderr b/src/tools/clippy/tests/ui/dereference.stderr deleted file mode 100644 index d26b462a433..00000000000 --- a/src/tools/clippy/tests/ui/dereference.stderr +++ /dev/null @@ -1,70 +0,0 @@ -error: explicit deref method call - --> $DIR/dereference.rs:30:19 - | -LL | let b: &str = a.deref(); - | ^^^^^^^^^ help: try this: `&*a` - | - = note: `-D clippy::explicit-deref-methods` implied by `-D warnings` - -error: explicit deref_mut method call - --> $DIR/dereference.rs:32:23 - | -LL | let b: &mut str = a.deref_mut(); - | ^^^^^^^^^^^^^ help: try this: `&mut *a` - -error: explicit deref method call - --> $DIR/dereference.rs:35:39 - | -LL | let b: String = format!("{}, {}", a.deref(), a.deref()); - | ^^^^^^^^^ help: try this: `&*a` - -error: explicit deref method call - --> $DIR/dereference.rs:35:50 - | -LL | let b: String = format!("{}, {}", a.deref(), a.deref()); - | ^^^^^^^^^ help: try this: `&*a` - -error: explicit deref method call - --> $DIR/dereference.rs:37:20 - | -LL | println!("{}", a.deref()); - | ^^^^^^^^^ help: try this: `&*a` - -error: explicit deref method call - --> $DIR/dereference.rs:40:11 - | -LL | match a.deref() { - | ^^^^^^^^^ help: try this: `&*a` - -error: explicit deref method call - --> $DIR/dereference.rs:44:28 - | -LL | let b: String = concat(a.deref()); - | ^^^^^^^^^ help: try this: `&*a` - -error: explicit deref method call - --> $DIR/dereference.rs:46:13 - | -LL | let b = just_return(a).deref(); - | ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&*just_return(a)` - -error: explicit deref method call - --> $DIR/dereference.rs:48:28 - | -LL | let b: String = concat(just_return(a).deref()); - | ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&*just_return(a)` - -error: explicit deref method call - --> $DIR/dereference.rs:50:19 - | -LL | let b: &str = a.deref().deref(); - | ^^^^^^^^^^^^^^^^^ help: try this: `&*a.deref()` - -error: explicit deref method call - --> $DIR/dereference.rs:53:13 - | -LL | let b = opt_a.unwrap().deref(); - | ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&*opt_a.unwrap()` - -error: aborting due to 11 previous errors - diff --git a/src/tools/clippy/tests/ui/dereference.fixed b/src/tools/clippy/tests/ui/explicit_deref_methods.fixed index 459ca91b93b..51d0468e47c 100644 --- a/src/tools/clippy/tests/ui/dereference.fixed +++ b/src/tools/clippy/tests/ui/explicit_deref_methods.fixed @@ -29,7 +29,7 @@ fn main() { let b: &str = &*a; - let b: &mut str = &mut *a; + let b: &mut str = &mut **a; // both derefs should get linted here let b: String = format!("{}, {}", &*a, &*a); @@ -43,11 +43,11 @@ fn main() { let b: String = concat(&*a); - let b = &*just_return(a); + let b = just_return(a); - let b: String = concat(&*just_return(a)); + let b: String = concat(just_return(a)); - let b: &str = &*a.deref(); + let b: &str = &**a; let opt_a = Some(a.clone()); let b = &*opt_a.unwrap(); @@ -76,6 +76,8 @@ fn main() { } let b: &str = expr_deref!(a); + let b: &str = expr_deref!(&*a); + // The struct does not implement Deref trait #[derive(Copy, Clone)] struct NoLint(u32); diff --git a/src/tools/clippy/tests/ui/dereference.rs b/src/tools/clippy/tests/ui/explicit_deref_methods.rs index 8dc5272e67f..680664bd4f6 100644 --- a/src/tools/clippy/tests/ui/dereference.rs +++ b/src/tools/clippy/tests/ui/explicit_deref_methods.rs @@ -76,6 +76,8 @@ fn main() { } let b: &str = expr_deref!(a); + let b: &str = expr_deref!(a.deref()); + // The struct does not implement Deref trait #[derive(Copy, Clone)] struct NoLint(u32); diff --git a/src/tools/clippy/tests/ui/explicit_deref_methods.stderr b/src/tools/clippy/tests/ui/explicit_deref_methods.stderr new file mode 100644 index 00000000000..8035d77d18d --- /dev/null +++ b/src/tools/clippy/tests/ui/explicit_deref_methods.stderr @@ -0,0 +1,76 @@ +error: explicit `deref` method call + --> $DIR/explicit_deref_methods.rs:30:19 + | +LL | let b: &str = a.deref(); + | ^^^^^^^^^ help: try this: `&*a` + | + = note: `-D clippy::explicit-deref-methods` implied by `-D warnings` + +error: explicit `deref_mut` method call + --> $DIR/explicit_deref_methods.rs:32:23 + | +LL | let b: &mut str = a.deref_mut(); + | ^^^^^^^^^^^^^ help: try this: `&mut **a` + +error: explicit `deref` method call + --> $DIR/explicit_deref_methods.rs:35:39 + | +LL | let b: String = format!("{}, {}", a.deref(), a.deref()); + | ^^^^^^^^^ help: try this: `&*a` + +error: explicit `deref` method call + --> $DIR/explicit_deref_methods.rs:35:50 + | +LL | let b: String = format!("{}, {}", a.deref(), a.deref()); + | ^^^^^^^^^ help: try this: `&*a` + +error: explicit `deref` method call + --> $DIR/explicit_deref_methods.rs:37:20 + | +LL | println!("{}", a.deref()); + | ^^^^^^^^^ help: try this: `&*a` + +error: explicit `deref` method call + --> $DIR/explicit_deref_methods.rs:40:11 + | +LL | match a.deref() { + | ^^^^^^^^^ help: try this: `&*a` + +error: explicit `deref` method call + --> $DIR/explicit_deref_methods.rs:44:28 + | +LL | let b: String = concat(a.deref()); + | ^^^^^^^^^ help: try this: `&*a` + +error: explicit `deref` method call + --> $DIR/explicit_deref_methods.rs:46:13 + | +LL | let b = just_return(a).deref(); + | ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `just_return(a)` + +error: explicit `deref` method call + --> $DIR/explicit_deref_methods.rs:48:28 + | +LL | let b: String = concat(just_return(a).deref()); + | ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `just_return(a)` + +error: explicit `deref` method call + --> $DIR/explicit_deref_methods.rs:50:19 + | +LL | let b: &str = a.deref().deref(); + | ^^^^^^^^^^^^^^^^^ help: try this: `&**a` + +error: explicit `deref` method call + --> $DIR/explicit_deref_methods.rs:53:13 + | +LL | let b = opt_a.unwrap().deref(); + | ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&*opt_a.unwrap()` + +error: explicit `deref` method call + --> $DIR/explicit_deref_methods.rs:79:31 + | +LL | let b: &str = expr_deref!(a.deref()); + | ^^^^^^^^^ help: try this: `&*a` + +error: aborting due to 12 previous errors + diff --git a/src/tools/clippy/tests/ui/field_reassign_with_default.rs b/src/tools/clippy/tests/ui/field_reassign_with_default.rs index 9fc208f5332..1368c5d7984 100644 --- a/src/tools/clippy/tests/ui/field_reassign_with_default.rs +++ b/src/tools/clippy/tests/ui/field_reassign_with_default.rs @@ -136,6 +136,13 @@ fn main() { // Don't lint in external macros field_reassign_with_default!(); + + // be sure suggestion is correct with generics + let mut a: Wrapper<bool> = Default::default(); + a.i = true; + + let mut a: WrapperMulti<i32, i64> = Default::default(); + a.i = 42; } mod m { @@ -145,3 +152,14 @@ mod m { b: u64, } } + +#[derive(Default)] +struct Wrapper<T> { + i: T, +} + +#[derive(Default)] +struct WrapperMulti<T, U> { + i: T, + j: U, +} diff --git a/src/tools/clippy/tests/ui/field_reassign_with_default.stderr b/src/tools/clippy/tests/ui/field_reassign_with_default.stderr index 2f0f28f7bb7..dd7c0360bb1 100644 --- a/src/tools/clippy/tests/ui/field_reassign_with_default.stderr +++ b/src/tools/clippy/tests/ui/field_reassign_with_default.stderr @@ -83,5 +83,29 @@ note: consider initializing the variable with `C { i: vec![1], ..Default::defaul LL | let mut a: C = C::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 7 previous errors +error: field assignment outside of initializer for an instance created with Default::default() + --> $DIR/field_reassign_with_default.rs:142:5 + | +LL | a.i = true; + | ^^^^^^^^^^^ + | +note: consider initializing the variable with `Wrapper::<bool> { i: true }` and removing relevant reassignments + --> $DIR/field_reassign_with_default.rs:141:5 + | +LL | let mut a: Wrapper<bool> = Default::default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: field assignment outside of initializer for an instance created with Default::default() + --> $DIR/field_reassign_with_default.rs:145:5 + | +LL | a.i = 42; + | ^^^^^^^^^ + | +note: consider initializing the variable with `WrapperMulti::<i32, i64> { i: 42, ..Default::default() }` and removing relevant reassignments + --> $DIR/field_reassign_with_default.rs:144:5 + | +LL | let mut a: WrapperMulti<i32, i64> = Default::default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 9 previous errors diff --git a/src/tools/clippy/tests/ui/if_then_some_else_none.rs b/src/tools/clippy/tests/ui/if_then_some_else_none.rs new file mode 100644 index 00000000000..54789bf9320 --- /dev/null +++ b/src/tools/clippy/tests/ui/if_then_some_else_none.rs @@ -0,0 +1,104 @@ +#![warn(clippy::if_then_some_else_none)] +#![feature(custom_inner_attributes)] + +fn main() { + // Should issue an error. + let _ = if foo() { + println!("true!"); + Some("foo") + } else { + None + }; + + // Should issue an error when macros are used. + let _ = if matches!(true, true) { + println!("true!"); + Some(matches!(true, false)) + } else { + None + }; + + // Should issue an error. Binary expression `o < 32` should be parenthesized. + let x = Some(5); + let _ = x.and_then(|o| if o < 32 { Some(o) } else { None }); + + // Should issue an error. Unary expression `!x` should be parenthesized. + let x = true; + let _ = if !x { Some(0) } else { None }; + + // Should not issue an error since the `else` block has a statement besides `None`. + let _ = if foo() { + println!("true!"); + Some("foo") + } else { + eprintln!("false..."); + None + }; + + // Should not issue an error since there are more than 2 blocks in the if-else chain. + let _ = if foo() { + println!("foo true!"); + Some("foo") + } else if bar() { + println!("bar true!"); + Some("bar") + } else { + None + }; + + let _ = if foo() { + println!("foo true!"); + Some("foo") + } else { + bar().then(|| { + println!("bar true!"); + "bar" + }) + }; + + // Should not issue an error since the `then` block has `None`, not `Some`. + let _ = if foo() { None } else { Some("foo is false") }; + + // Should not issue an error since the `else` block doesn't use `None` directly. + let _ = if foo() { Some("foo is true") } else { into_none() }; + + // Should not issue an error since the `then` block doesn't use `Some` directly. + let _ = if foo() { into_some("foo") } else { None }; +} + +fn _msrv_1_49() { + #![clippy::msrv = "1.49"] + // `bool::then` was stabilized in 1.50. Do not lint this + let _ = if foo() { + println!("true!"); + Some(149) + } else { + None + }; +} + +fn _msrv_1_50() { + #![clippy::msrv = "1.50"] + let _ = if foo() { + println!("true!"); + Some(150) + } else { + None + }; +} + +fn foo() -> bool { + unimplemented!() +} + +fn bar() -> bool { + unimplemented!() +} + +fn into_some<T>(v: T) -> Option<T> { + Some(v) +} + +fn into_none<T>() -> Option<T> { + None +} diff --git a/src/tools/clippy/tests/ui/if_then_some_else_none.stderr b/src/tools/clippy/tests/ui/if_then_some_else_none.stderr new file mode 100644 index 00000000000..8cb22d569f4 --- /dev/null +++ b/src/tools/clippy/tests/ui/if_then_some_else_none.stderr @@ -0,0 +1,61 @@ +error: this could be simplified with `bool::then` + --> $DIR/if_then_some_else_none.rs:6:13 + | +LL | let _ = if foo() { + | _____________^ +LL | | println!("true!"); +LL | | Some("foo") +LL | | } else { +LL | | None +LL | | }; + | |_____^ + | + = note: `-D clippy::if-then-some-else-none` implied by `-D warnings` + = help: consider using `bool::then` like: `foo().then(|| { /* snippet */ "foo" })` + +error: this could be simplified with `bool::then` + --> $DIR/if_then_some_else_none.rs:14:13 + | +LL | let _ = if matches!(true, true) { + | _____________^ +LL | | println!("true!"); +LL | | Some(matches!(true, false)) +LL | | } else { +LL | | None +LL | | }; + | |_____^ + | + = help: consider using `bool::then` like: `matches!(true, true).then(|| { /* snippet */ matches!(true, false) })` + +error: this could be simplified with `bool::then` + --> $DIR/if_then_some_else_none.rs:23:28 + | +LL | let _ = x.and_then(|o| if o < 32 { Some(o) } else { None }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using `bool::then` like: `(o < 32).then(|| o)` + +error: this could be simplified with `bool::then` + --> $DIR/if_then_some_else_none.rs:27:13 + | +LL | let _ = if !x { Some(0) } else { None }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using `bool::then` like: `(!x).then(|| 0)` + +error: this could be simplified with `bool::then` + --> $DIR/if_then_some_else_none.rs:82:13 + | +LL | let _ = if foo() { + | _____________^ +LL | | println!("true!"); +LL | | Some(150) +LL | | } else { +LL | | None +LL | | }; + | |_____^ + | + = help: consider using `bool::then` like: `foo().then(|| { /* snippet */ 150 })` + +error: aborting due to 5 previous errors + diff --git a/src/tools/clippy/tests/ui/inconsistent_struct_constructor.stderr b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.stderr index d7abe44f254..d021bb19579 100644 --- a/src/tools/clippy/tests/ui/inconsistent_struct_constructor.stderr +++ b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.stderr @@ -1,4 +1,4 @@ -error: inconsistent struct constructor +error: struct constructor field order is inconsistent with struct definition field order --> $DIR/inconsistent_struct_constructor.rs:25:9 | LL | Foo { y, x, z }; @@ -6,7 +6,7 @@ LL | Foo { y, x, z }; | = note: `-D clippy::inconsistent-struct-constructor` implied by `-D warnings` -error: inconsistent struct constructor +error: struct constructor field order is inconsistent with struct definition field order --> $DIR/inconsistent_struct_constructor.rs:43:9 | LL | / Foo { diff --git a/src/tools/clippy/tests/ui/manual_flatten.rs b/src/tools/clippy/tests/ui/manual_flatten.rs index cff68eca933..b5bd35a6878 100644 --- a/src/tools/clippy/tests/ui/manual_flatten.rs +++ b/src/tools/clippy/tests/ui/manual_flatten.rs @@ -1,4 +1,5 @@ #![warn(clippy::manual_flatten)] +#![allow(clippy::useless_vec)] fn main() { // Test for loop over implicitly adjusted `Iterator` with `if let` expression @@ -69,6 +70,27 @@ fn main() { } } + let vec_of_ref = vec![&Some(1)]; + for n in &vec_of_ref { + if let Some(n) = n { + println!("{:?}", n); + } + } + + let vec_of_ref = &vec_of_ref; + for n in vec_of_ref { + if let Some(n) = n { + println!("{:?}", n); + } + } + + let slice_of_ref = &[&Some(1)]; + for n in slice_of_ref { + if let Some(n) = n { + println!("{:?}", n); + } + } + // Using manual flatten should not trigger the lint for n in vec![Some(1), Some(2), Some(3)].iter().flatten() { println!("{}", n); diff --git a/src/tools/clippy/tests/ui/manual_flatten.stderr b/src/tools/clippy/tests/ui/manual_flatten.stderr index 855dd9130e2..be5f8a1d818 100644 --- a/src/tools/clippy/tests/ui/manual_flatten.stderr +++ b/src/tools/clippy/tests/ui/manual_flatten.stderr @@ -1,5 +1,5 @@ error: unnecessary `if let` since only the `Some` variant of the iterator element is used - --> $DIR/manual_flatten.rs:6:5 + --> $DIR/manual_flatten.rs:7:5 | LL | for n in x { | ^ - help: try: `x.into_iter().flatten()` @@ -13,7 +13,7 @@ LL | | } | = note: `-D clippy::manual-flatten` implied by `-D warnings` help: ...and remove the `if let` statement in the for loop - --> $DIR/manual_flatten.rs:7:9 + --> $DIR/manual_flatten.rs:8:9 | LL | / if let Some(y) = n { LL | | println!("{}", y); @@ -21,7 +21,7 @@ LL | | } | |_________^ error: unnecessary `if let` since only the `Ok` variant of the iterator element is used - --> $DIR/manual_flatten.rs:14:5 + --> $DIR/manual_flatten.rs:15:5 | LL | for n in y.clone() { | ^ --------- help: try: `y.clone().into_iter().flatten()` @@ -34,7 +34,7 @@ LL | | } | |_____^ | help: ...and remove the `if let` statement in the for loop - --> $DIR/manual_flatten.rs:15:9 + --> $DIR/manual_flatten.rs:16:9 | LL | / if let Ok(n) = n { LL | | println!("{}", n); @@ -42,7 +42,7 @@ LL | | }; | |_________^ error: unnecessary `if let` since only the `Ok` variant of the iterator element is used - --> $DIR/manual_flatten.rs:21:5 + --> $DIR/manual_flatten.rs:22:5 | LL | for n in &y { | ^ -- help: try: `y.iter().flatten()` @@ -55,7 +55,7 @@ LL | | } | |_____^ | help: ...and remove the `if let` statement in the for loop - --> $DIR/manual_flatten.rs:22:9 + --> $DIR/manual_flatten.rs:23:9 | LL | / if let Ok(n) = n { LL | | println!("{}", n); @@ -63,7 +63,7 @@ LL | | } | |_________^ error: unnecessary `if let` since only the `Ok` variant of the iterator element is used - --> $DIR/manual_flatten.rs:31:5 + --> $DIR/manual_flatten.rs:32:5 | LL | for n in z { | ^ - help: try: `z.into_iter().flatten()` @@ -76,7 +76,7 @@ LL | | } | |_____^ | help: ...and remove the `if let` statement in the for loop - --> $DIR/manual_flatten.rs:32:9 + --> $DIR/manual_flatten.rs:33:9 | LL | / if let Ok(n) = n { LL | | println!("{}", n); @@ -84,7 +84,7 @@ LL | | } | |_________^ error: unnecessary `if let` since only the `Some` variant of the iterator element is used - --> $DIR/manual_flatten.rs:40:5 + --> $DIR/manual_flatten.rs:41:5 | LL | for n in z { | ^ - help: try: `z.flatten()` @@ -97,12 +97,75 @@ LL | | } | |_____^ | help: ...and remove the `if let` statement in the for loop - --> $DIR/manual_flatten.rs:41:9 + --> $DIR/manual_flatten.rs:42:9 | LL | / if let Some(m) = n { LL | | println!("{}", m); LL | | } | |_________^ -error: aborting due to 5 previous errors +error: unnecessary `if let` since only the `Some` variant of the iterator element is used + --> $DIR/manual_flatten.rs:74:5 + | +LL | for n in &vec_of_ref { + | ^ ----------- help: try: `vec_of_ref.iter().copied().flatten()` + | _____| + | | +LL | | if let Some(n) = n { +LL | | println!("{:?}", n); +LL | | } +LL | | } + | |_____^ + | +help: ...and remove the `if let` statement in the for loop + --> $DIR/manual_flatten.rs:75:9 + | +LL | / if let Some(n) = n { +LL | | println!("{:?}", n); +LL | | } + | |_________^ + +error: unnecessary `if let` since only the `Some` variant of the iterator element is used + --> $DIR/manual_flatten.rs:81:5 + | +LL | for n in vec_of_ref { + | ^ ---------- help: try: `vec_of_ref.into_iter().copied().flatten()` + | _____| + | | +LL | | if let Some(n) = n { +LL | | println!("{:?}", n); +LL | | } +LL | | } + | |_____^ + | +help: ...and remove the `if let` statement in the for loop + --> $DIR/manual_flatten.rs:82:9 + | +LL | / if let Some(n) = n { +LL | | println!("{:?}", n); +LL | | } + | |_________^ + +error: unnecessary `if let` since only the `Some` variant of the iterator element is used + --> $DIR/manual_flatten.rs:88:5 + | +LL | for n in slice_of_ref { + | ^ ------------ help: try: `slice_of_ref.into_iter().copied().flatten()` + | _____| + | | +LL | | if let Some(n) = n { +LL | | println!("{:?}", n); +LL | | } +LL | | } + | |_____^ + | +help: ...and remove the `if let` statement in the for loop + --> $DIR/manual_flatten.rs:89:9 + | +LL | / if let Some(n) = n { +LL | | println!("{:?}", n); +LL | | } + | |_________^ + +error: aborting due to 8 previous errors diff --git a/src/tools/clippy/tests/ui/manual_map_option.fixed b/src/tools/clippy/tests/ui/manual_map_option.fixed index 9222aaf6c78..acb6a580ceb 100644 --- a/src/tools/clippy/tests/ui/manual_map_option.fixed +++ b/src/tools/clippy/tests/ui/manual_map_option.fixed @@ -128,4 +128,9 @@ fn main() { None => None, }; } + + // #6847 + if Some(0).is_some() { + Some(0) + } else { Some(0).map(|x| x + 1) }; } diff --git a/src/tools/clippy/tests/ui/manual_map_option.rs b/src/tools/clippy/tests/ui/manual_map_option.rs index 1ccb450619c..3299e617707 100644 --- a/src/tools/clippy/tests/ui/manual_map_option.rs +++ b/src/tools/clippy/tests/ui/manual_map_option.rs @@ -186,4 +186,13 @@ fn main() { None => None, }; } + + // #6847 + if let Some(_) = Some(0) { + Some(0) + } else if let Some(x) = Some(0) { + Some(x + 1) + } else { + None + }; } diff --git a/src/tools/clippy/tests/ui/manual_map_option.stderr b/src/tools/clippy/tests/ui/manual_map_option.stderr index d9f86eecd93..048ccfb9582 100644 --- a/src/tools/clippy/tests/ui/manual_map_option.stderr +++ b/src/tools/clippy/tests/ui/manual_map_option.stderr @@ -172,5 +172,24 @@ LL | | None => None, LL | | }; | |_____^ help: try this: `option_env!("").map(String::from)` -error: aborting due to 19 previous errors +error: redundant pattern matching, consider using `is_some()` + --> $DIR/manual_map_option.rs:191:12 + | +LL | if let Some(_) = Some(0) { + | -------^^^^^^^---------- help: try this: `if Some(0).is_some()` + | + = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` + +error: manual implementation of `Option::map` + --> $DIR/manual_map_option.rs:193:12 + | +LL | } else if let Some(x) = Some(0) { + | ____________^ +LL | | Some(x + 1) +LL | | } else { +LL | | None +LL | | }; + | |_____^ help: try this: `{ Some(0).map(|x| x + 1) }` + +error: aborting due to 21 previous errors diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or.fixed b/src/tools/clippy/tests/ui/manual_unwrap_or.fixed index 81d903c15d3..f1d3252230b 100644 --- a/src/tools/clippy/tests/ui/manual_unwrap_or.fixed +++ b/src/tools/clippy/tests/ui/manual_unwrap_or.fixed @@ -136,4 +136,19 @@ fn result_unwrap_or() { }; } +// don't lint in const fn +const fn const_fn_option_unwrap_or() { + match Some(1) { + Some(s) => s, + None => 0, + }; +} + +const fn const_fn_result_unwrap_or() { + match Ok::<&str, &str>("Alice") { + Ok(s) => s, + Err(_) => "Bob", + }; +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or.rs b/src/tools/clippy/tests/ui/manual_unwrap_or.rs index 16105d379c3..c9eee25a5b1 100644 --- a/src/tools/clippy/tests/ui/manual_unwrap_or.rs +++ b/src/tools/clippy/tests/ui/manual_unwrap_or.rs @@ -175,4 +175,19 @@ fn result_unwrap_or() { }; } +// don't lint in const fn +const fn const_fn_option_unwrap_or() { + match Some(1) { + Some(s) => s, + None => 0, + }; +} + +const fn const_fn_result_unwrap_or() { + match Ok::<&str, &str>("Alice") { + Ok(s) => s, + Err(_) => "Bob", + }; +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/match_single_binding2.fixed b/src/tools/clippy/tests/ui/match_single_binding2.fixed new file mode 100644 index 00000000000..e73a85b73d7 --- /dev/null +++ b/src/tools/clippy/tests/ui/match_single_binding2.fixed @@ -0,0 +1,37 @@ +// run-rustfix + +#![warn(clippy::match_single_binding)] +#![allow(unused_variables)] + +fn main() { + // Lint (additional curly braces needed, see #6572) + struct AppendIter<I> + where + I: Iterator, + { + inner: Option<(I, <I as Iterator>::Item)>, + } + + #[allow(dead_code)] + fn size_hint<I: Iterator>(iter: &AppendIter<I>) -> (usize, Option<usize>) { + match &iter.inner { + Some((iter, _item)) => { + let (min, max) = iter.size_hint(); + (min.saturating_add(1), max.and_then(|max| max.checked_add(1))) + }, + None => (0, Some(0)), + } + } + + // Lint (no additional curly braces needed) + let opt = Some((5, 2)); + let get_tup = || -> (i32, i32) { (1, 2) }; + match opt { + #[rustfmt::skip] + Some((first, _second)) => { + let (a, b) = get_tup(); + println!("a {:?} and b {:?}", a, b); + }, + None => println!("nothing"), + } +} diff --git a/src/tools/clippy/tests/ui/match_single_binding2.rs b/src/tools/clippy/tests/ui/match_single_binding2.rs new file mode 100644 index 00000000000..7362cb390e5 --- /dev/null +++ b/src/tools/clippy/tests/ui/match_single_binding2.rs @@ -0,0 +1,37 @@ +// run-rustfix + +#![warn(clippy::match_single_binding)] +#![allow(unused_variables)] + +fn main() { + // Lint (additional curly braces needed, see #6572) + struct AppendIter<I> + where + I: Iterator, + { + inner: Option<(I, <I as Iterator>::Item)>, + } + + #[allow(dead_code)] + fn size_hint<I: Iterator>(iter: &AppendIter<I>) -> (usize, Option<usize>) { + match &iter.inner { + Some((iter, _item)) => match iter.size_hint() { + (min, max) => (min.saturating_add(1), max.and_then(|max| max.checked_add(1))), + }, + None => (0, Some(0)), + } + } + + // Lint (no additional curly braces needed) + let opt = Some((5, 2)); + let get_tup = || -> (i32, i32) { (1, 2) }; + match opt { + #[rustfmt::skip] + Some((first, _second)) => { + match get_tup() { + (a, b) => println!("a {:?} and b {:?}", a, b), + } + }, + None => println!("nothing"), + } +} diff --git a/src/tools/clippy/tests/ui/match_single_binding2.stderr b/src/tools/clippy/tests/ui/match_single_binding2.stderr new file mode 100644 index 00000000000..bc18d191aa3 --- /dev/null +++ b/src/tools/clippy/tests/ui/match_single_binding2.stderr @@ -0,0 +1,34 @@ +error: this match could be written as a `let` statement + --> $DIR/match_single_binding2.rs:18:36 + | +LL | Some((iter, _item)) => match iter.size_hint() { + | ____________________________________^ +LL | | (min, max) => (min.saturating_add(1), max.and_then(|max| max.checked_add(1))), +LL | | }, + | |_____________^ + | + = note: `-D clippy::match-single-binding` implied by `-D warnings` +help: consider using `let` statement + | +LL | Some((iter, _item)) => { +LL | let (min, max) = iter.size_hint(); +LL | (min.saturating_add(1), max.and_then(|max| max.checked_add(1))) +LL | }, + | + +error: this match could be written as a `let` statement + --> $DIR/match_single_binding2.rs:31:13 + | +LL | / match get_tup() { +LL | | (a, b) => println!("a {:?} and b {:?}", a, b), +LL | | } + | |_____________^ + | +help: consider using `let` statement + | +LL | let (a, b) = get_tup(); +LL | println!("a {:?} and b {:?}", a, b); + | + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.fixed b/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.fixed index 519200977a7..d99f9af3faf 100644 --- a/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.fixed +++ b/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.fixed @@ -15,6 +15,16 @@ enum Color { Blue, Rgb(u8, u8, u8), } +impl Color { + fn f(self) { + match self { + Self::Red => (), + Self::Green => (), + Self::Blue => (), + Self::Rgb(..) => (), + }; + } +} fn main() { let f = Foo::A; @@ -56,4 +66,46 @@ fn main() { Color::Rgb(255, _, _) => {}, _ => {}, } + + // References shouldn't change anything + match &color { + &Color::Red => (), + Color::Green => (), + &Color::Rgb(..) => (), + Color::Blue => (), + } + + use self::Color as C; + + match color { + C::Red => (), + C::Green => (), + C::Rgb(..) => (), + C::Blue => (), + } + + match color { + C::Red => (), + Color::Green => (), + Color::Rgb(..) => (), + Color::Blue => (), + } + + match Some(0) { + Some(0) => 0, + Some(_) => 1, + _ => 2, + }; + + #[non_exhaustive] + enum Bar { + A, + B, + C, + } + match Bar::A { + Bar::A => (), + Bar::B => (), + _ => (), + }; } diff --git a/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.rs b/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.rs index 1df917e085c..1752a95de4b 100644 --- a/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.rs +++ b/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.rs @@ -15,6 +15,16 @@ enum Color { Blue, Rgb(u8, u8, u8), } +impl Color { + fn f(self) { + match self { + Self::Red => (), + Self::Green => (), + Self::Blue => (), + _ => (), + }; + } +} fn main() { let f = Foo::A; @@ -56,4 +66,46 @@ fn main() { Color::Rgb(255, _, _) => {}, _ => {}, } + + // References shouldn't change anything + match &color { + &Color::Red => (), + Color::Green => (), + &Color::Rgb(..) => (), + &_ => (), + } + + use self::Color as C; + + match color { + C::Red => (), + C::Green => (), + C::Rgb(..) => (), + _ => (), + } + + match color { + C::Red => (), + Color::Green => (), + Color::Rgb(..) => (), + _ => (), + } + + match Some(0) { + Some(0) => 0, + Some(_) => 1, + _ => 2, + }; + + #[non_exhaustive] + enum Bar { + A, + B, + C, + } + match Bar::A { + Bar::A => (), + Bar::B => (), + _ => (), + }; } diff --git a/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.stderr b/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.stderr index 82790aa9e80..34538dea8e5 100644 --- a/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.stderr +++ b/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.stderr @@ -1,28 +1,52 @@ -error: wildcard match will miss any future added variants - --> $DIR/match_wildcard_for_single_variants.rs:24:9 +error: wildcard matches only a single variant and will also match any future added variants + --> $DIR/match_wildcard_for_single_variants.rs:24:13 | -LL | _ => {}, - | ^ help: try this: `Foo::C` +LL | _ => (), + | ^ help: try this: `Self::Rgb(..)` | = note: `-D clippy::match-wildcard-for-single-variants` implied by `-D warnings` -error: wildcard match will miss any future added variants +error: wildcard matches only a single variant and will also match any future added variants --> $DIR/match_wildcard_for_single_variants.rs:34:9 | LL | _ => {}, + | ^ help: try this: `Foo::C` + +error: wildcard matches only a single variant and will also match any future added variants + --> $DIR/match_wildcard_for_single_variants.rs:44:9 + | +LL | _ => {}, | ^ help: try this: `Color::Blue` -error: wildcard match will miss any future added variants - --> $DIR/match_wildcard_for_single_variants.rs:42:9 +error: wildcard matches only a single variant and will also match any future added variants + --> $DIR/match_wildcard_for_single_variants.rs:52:9 | LL | _ => {}, | ^ help: try this: `Color::Blue` -error: wildcard match will miss any future added variants - --> $DIR/match_wildcard_for_single_variants.rs:48:9 +error: wildcard matches only a single variant and will also match any future added variants + --> $DIR/match_wildcard_for_single_variants.rs:58:9 | LL | _ => {}, | ^ help: try this: `Color::Blue` -error: aborting due to 4 previous errors +error: wildcard matches only a single variant and will also match any future added variants + --> $DIR/match_wildcard_for_single_variants.rs:75:9 + | +LL | &_ => (), + | ^^ help: try this: `Color::Blue` + +error: wildcard matches only a single variant and will also match any future added variants + --> $DIR/match_wildcard_for_single_variants.rs:84:9 + | +LL | _ => (), + | ^ help: try this: `C::Blue` + +error: wildcard matches only a single variant and will also match any future added variants + --> $DIR/match_wildcard_for_single_variants.rs:91:9 + | +LL | _ => (), + | ^ help: try this: `Color::Blue` + +error: aborting due to 8 previous errors diff --git a/src/tools/clippy/tests/ui/mem_replace.fixed b/src/tools/clippy/tests/ui/mem_replace.fixed index 54e962e7116..3b6224254a0 100644 --- a/src/tools/clippy/tests/ui/mem_replace.fixed +++ b/src/tools/clippy/tests/ui/mem_replace.fixed @@ -7,6 +7,7 @@ clippy::mem_replace_with_default )] +use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque}; use std::mem; fn replace_option_with_none() { @@ -19,9 +20,37 @@ fn replace_option_with_none() { fn replace_with_default() { let mut s = String::from("foo"); let _ = std::mem::take(&mut s); + let s = &mut String::from("foo"); let _ = std::mem::take(s); let _ = std::mem::take(s); + + let mut v = vec![123]; + let _ = std::mem::take(&mut v); + let _ = std::mem::take(&mut v); + let _ = std::mem::take(&mut v); + let _ = std::mem::take(&mut v); + + let mut hash_map: HashMap<i32, i32> = HashMap::new(); + let _ = std::mem::take(&mut hash_map); + + let mut btree_map: BTreeMap<i32, i32> = BTreeMap::new(); + let _ = std::mem::take(&mut btree_map); + + let mut vd: VecDeque<i32> = VecDeque::new(); + let _ = std::mem::take(&mut vd); + + let mut hash_set: HashSet<&str> = HashSet::new(); + let _ = std::mem::take(&mut hash_set); + + let mut btree_set: BTreeSet<&str> = BTreeSet::new(); + let _ = std::mem::take(&mut btree_set); + + let mut list: LinkedList<i32> = LinkedList::new(); + let _ = std::mem::take(&mut list); + + let mut binary_heap: BinaryHeap<i32> = BinaryHeap::new(); + let _ = std::mem::take(&mut binary_heap); } fn main() { diff --git a/src/tools/clippy/tests/ui/mem_replace.rs b/src/tools/clippy/tests/ui/mem_replace.rs index 60f52781071..0a36db9e921 100644 --- a/src/tools/clippy/tests/ui/mem_replace.rs +++ b/src/tools/clippy/tests/ui/mem_replace.rs @@ -7,6 +7,7 @@ clippy::mem_replace_with_default )] +use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque}; use std::mem; fn replace_option_with_none() { @@ -19,9 +20,37 @@ fn replace_option_with_none() { fn replace_with_default() { let mut s = String::from("foo"); let _ = std::mem::replace(&mut s, String::default()); + let s = &mut String::from("foo"); let _ = std::mem::replace(s, String::default()); let _ = std::mem::replace(s, Default::default()); + + let mut v = vec![123]; + let _ = std::mem::replace(&mut v, Vec::default()); + let _ = std::mem::replace(&mut v, Default::default()); + let _ = std::mem::replace(&mut v, Vec::new()); + let _ = std::mem::replace(&mut v, vec![]); + + let mut hash_map: HashMap<i32, i32> = HashMap::new(); + let _ = std::mem::replace(&mut hash_map, HashMap::new()); + + let mut btree_map: BTreeMap<i32, i32> = BTreeMap::new(); + let _ = std::mem::replace(&mut btree_map, BTreeMap::new()); + + let mut vd: VecDeque<i32> = VecDeque::new(); + let _ = std::mem::replace(&mut vd, VecDeque::new()); + + let mut hash_set: HashSet<&str> = HashSet::new(); + let _ = std::mem::replace(&mut hash_set, HashSet::new()); + + let mut btree_set: BTreeSet<&str> = BTreeSet::new(); + let _ = std::mem::replace(&mut btree_set, BTreeSet::new()); + + let mut list: LinkedList<i32> = LinkedList::new(); + let _ = std::mem::replace(&mut list, LinkedList::new()); + + let mut binary_heap: BinaryHeap<i32> = BinaryHeap::new(); + let _ = std::mem::replace(&mut binary_heap, BinaryHeap::new()); } fn main() { diff --git a/src/tools/clippy/tests/ui/mem_replace.stderr b/src/tools/clippy/tests/ui/mem_replace.stderr index 245d33aa4f2..f8aa1538bff 100644 --- a/src/tools/clippy/tests/ui/mem_replace.stderr +++ b/src/tools/clippy/tests/ui/mem_replace.stderr @@ -1,5 +1,5 @@ error: replacing an `Option` with `None` - --> $DIR/mem_replace.rs:14:13 + --> $DIR/mem_replace.rs:15:13 | LL | let _ = mem::replace(&mut an_option, None); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `an_option.take()` @@ -7,13 +7,13 @@ LL | let _ = mem::replace(&mut an_option, None); = note: `-D clippy::mem-replace-option-with-none` implied by `-D warnings` error: replacing an `Option` with `None` - --> $DIR/mem_replace.rs:16:13 + --> $DIR/mem_replace.rs:17:13 | LL | let _ = mem::replace(an_option, None); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `an_option.take()` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> $DIR/mem_replace.rs:21:13 + --> $DIR/mem_replace.rs:22:13 | LL | let _ = std::mem::replace(&mut s, String::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut s)` @@ -21,16 +21,82 @@ LL | let _ = std::mem::replace(&mut s, String::default()); = note: `-D clippy::mem-replace-with-default` implied by `-D warnings` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> $DIR/mem_replace.rs:23:13 + --> $DIR/mem_replace.rs:25:13 | LL | let _ = std::mem::replace(s, String::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(s)` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> $DIR/mem_replace.rs:24:13 + --> $DIR/mem_replace.rs:26:13 | LL | let _ = std::mem::replace(s, Default::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(s)` -error: aborting due to 5 previous errors +error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` + --> $DIR/mem_replace.rs:29:13 + | +LL | let _ = std::mem::replace(&mut v, Vec::default()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut v)` + +error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` + --> $DIR/mem_replace.rs:30:13 + | +LL | let _ = std::mem::replace(&mut v, Default::default()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut v)` + +error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` + --> $DIR/mem_replace.rs:31:13 + | +LL | let _ = std::mem::replace(&mut v, Vec::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut v)` + +error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` + --> $DIR/mem_replace.rs:32:13 + | +LL | let _ = std::mem::replace(&mut v, vec![]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut v)` + +error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` + --> $DIR/mem_replace.rs:35:13 + | +LL | let _ = std::mem::replace(&mut hash_map, HashMap::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut hash_map)` + +error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` + --> $DIR/mem_replace.rs:38:13 + | +LL | let _ = std::mem::replace(&mut btree_map, BTreeMap::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut btree_map)` + +error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` + --> $DIR/mem_replace.rs:41:13 + | +LL | let _ = std::mem::replace(&mut vd, VecDeque::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut vd)` + +error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` + --> $DIR/mem_replace.rs:44:13 + | +LL | let _ = std::mem::replace(&mut hash_set, HashSet::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut hash_set)` + +error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` + --> $DIR/mem_replace.rs:47:13 + | +LL | let _ = std::mem::replace(&mut btree_set, BTreeSet::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut btree_set)` + +error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` + --> $DIR/mem_replace.rs:50:13 + | +LL | let _ = std::mem::replace(&mut list, LinkedList::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut list)` + +error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` + --> $DIR/mem_replace.rs:53:13 + | +LL | let _ = std::mem::replace(&mut binary_heap, BinaryHeap::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut binary_heap)` + +error: aborting due to 16 previous errors diff --git a/src/tools/clippy/tests/ui/needless_question_mark.fixed b/src/tools/clippy/tests/ui/needless_question_mark.fixed index 71fb3565224..fd8433870bb 100644 --- a/src/tools/clippy/tests/ui/needless_question_mark.fixed +++ b/src/tools/clippy/tests/ui/needless_question_mark.fixed @@ -167,3 +167,28 @@ mod question_mark_both { needless_question_mark_result(); } } + +// #6921 if a macro wraps an expr in Some( ) and the ? is in the macro use, +// the suggestion fails to apply; do not lint +macro_rules! some_in_macro { + ($expr:expr) => { + || -> _ { Some($expr) }() + }; +} + +pub fn test1() { + let x = Some(3); + let _x = some_in_macro!(x?); +} + +// this one is ok because both the ? and the Some are both inside the macro def +macro_rules! some_and_qmark_in_macro { + ($expr:expr) => { + || -> Option<_> { Some($expr) }() + }; +} + +pub fn test2() { + let x = Some(3); + let _x = some_and_qmark_in_macro!(x?); +} diff --git a/src/tools/clippy/tests/ui/needless_question_mark.rs b/src/tools/clippy/tests/ui/needless_question_mark.rs index e31f6f48fa7..36d45ac7e03 100644 --- a/src/tools/clippy/tests/ui/needless_question_mark.rs +++ b/src/tools/clippy/tests/ui/needless_question_mark.rs @@ -167,3 +167,28 @@ mod question_mark_both { needless_question_mark_result(); } } + +// #6921 if a macro wraps an expr in Some( ) and the ? is in the macro use, +// the suggestion fails to apply; do not lint +macro_rules! some_in_macro { + ($expr:expr) => { + || -> _ { Some($expr) }() + }; +} + +pub fn test1() { + let x = Some(3); + let _x = some_in_macro!(x?); +} + +// this one is ok because both the ? and the Some are both inside the macro def +macro_rules! some_and_qmark_in_macro { + ($expr:expr) => { + || -> Option<_> { Some(Some($expr)?) }() + }; +} + +pub fn test2() { + let x = Some(3); + let _x = some_and_qmark_in_macro!(x?); +} diff --git a/src/tools/clippy/tests/ui/needless_question_mark.stderr b/src/tools/clippy/tests/ui/needless_question_mark.stderr index 983c56031d8..7cbf1e505ad 100644 --- a/src/tools/clippy/tests/ui/needless_question_mark.stderr +++ b/src/tools/clippy/tests/ui/needless_question_mark.stderr @@ -84,5 +84,16 @@ error: question mark operator is useless here LL | Ok(to.magic?) // should be triggered | ^^^^^^^^^^^^^ help: try: `to.magic` -error: aborting due to 14 previous errors +error: question mark operator is useless here + --> $DIR/needless_question_mark.rs:187:27 + | +LL | || -> Option<_> { Some(Some($expr)?) }() + | ^^^^^^^^^^^^^^^^^^ help: try: `Some($expr)` +... +LL | let _x = some_and_qmark_in_macro!(x?); + | ---------------------------- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 15 previous errors diff --git a/src/tools/clippy/tests/ui/new_ret_no_self.rs b/src/tools/clippy/tests/ui/new_ret_no_self.rs index e82873629a5..2f315ffe298 100644 --- a/src/tools/clippy/tests/ui/new_ret_no_self.rs +++ b/src/tools/clippy/tests/ui/new_ret_no_self.rs @@ -340,3 +340,13 @@ mod issue5435 { } } } + +// issue #1724 +struct RetOtherSelf<T>(T); +struct RetOtherSelfWrapper<T>(T); + +impl RetOtherSelf<T> { + fn new(t: T) -> RetOtherSelf<RetOtherSelfWrapper<T>> { + RetOtherSelf(RetOtherSelfWrapper(t)) + } +} diff --git a/src/tools/clippy/tests/ui/new_without_default.rs b/src/tools/clippy/tests/ui/new_without_default.rs index 3b6041823d8..64659b63f46 100644 --- a/src/tools/clippy/tests/ui/new_without_default.rs +++ b/src/tools/clippy/tests/ui/new_without_default.rs @@ -159,4 +159,19 @@ impl NewNotEqualToDerive { } } +// see #6933 +pub struct FooGenerics<T>(std::marker::PhantomData<T>); +impl<T> FooGenerics<T> { + pub fn new() -> Self { + Self(Default::default()) + } +} + +pub struct BarGenerics<T>(std::marker::PhantomData<T>); +impl<T: Copy> BarGenerics<T> { + pub fn new() -> Self { + Self(Default::default()) + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/new_without_default.stderr b/src/tools/clippy/tests/ui/new_without_default.stderr index e529e441eb7..973836f75a9 100644 --- a/src/tools/clippy/tests/ui/new_without_default.stderr +++ b/src/tools/clippy/tests/ui/new_without_default.stderr @@ -43,7 +43,7 @@ LL | | } | help: try this | -LL | impl Default for LtKo<'c> { +LL | impl<'c> Default for LtKo<'c> { LL | fn default() -> Self { LL | Self::new() LL | } @@ -67,5 +67,39 @@ LL | } LL | } | -error: aborting due to 4 previous errors +error: you should consider adding a `Default` implementation for `FooGenerics<T>` + --> $DIR/new_without_default.rs:165:5 + | +LL | / pub fn new() -> Self { +LL | | Self(Default::default()) +LL | | } + | |_____^ + | +help: try this + | +LL | impl<T> Default for FooGenerics<T> { +LL | fn default() -> Self { +LL | Self::new() +LL | } +LL | } + | + +error: you should consider adding a `Default` implementation for `BarGenerics<T>` + --> $DIR/new_without_default.rs:172:5 + | +LL | / pub fn new() -> Self { +LL | | Self(Default::default()) +LL | | } + | |_____^ + | +help: try this + | +LL | impl<T: Copy> Default for BarGenerics<T> { +LL | fn default() -> Self { +LL | Self::new() +LL | } +LL | } + | + +error: aborting due to 6 previous errors diff --git a/src/tools/clippy/tests/ui/or_fun_call.fixed b/src/tools/clippy/tests/ui/or_fun_call.fixed index 64347cae5da..4390ff7dc30 100644 --- a/src/tools/clippy/tests/ui/or_fun_call.fixed +++ b/src/tools/clippy/tests/ui/or_fun_call.fixed @@ -120,6 +120,9 @@ fn test_or_with_ctors() { let slice = &["foo"][..]; let _ = opt.ok_or(slice.len()); + + let string = "foo"; + let _ = opt.ok_or(string.len()); } // Issue 4514 - early return @@ -132,4 +135,18 @@ fn f() -> Option<()> { Some(()) } +mod issue6675 { + unsafe fn foo() { + let mut s = "test".to_owned(); + None.unwrap_or_else(|| s.as_mut_vec()); + } + + fn bar() { + let mut s = "test".to_owned(); + None.unwrap_or_else(|| unsafe { s.as_mut_vec() }); + #[rustfmt::skip] + None.unwrap_or_else(|| unsafe { s.as_mut_vec() }); + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/or_fun_call.rs b/src/tools/clippy/tests/ui/or_fun_call.rs index 7faab0017b2..75908c974cc 100644 --- a/src/tools/clippy/tests/ui/or_fun_call.rs +++ b/src/tools/clippy/tests/ui/or_fun_call.rs @@ -120,6 +120,9 @@ fn test_or_with_ctors() { let slice = &["foo"][..]; let _ = opt.ok_or(slice.len()); + + let string = "foo"; + let _ = opt.ok_or(string.len()); } // Issue 4514 - early return @@ -132,4 +135,18 @@ fn f() -> Option<()> { Some(()) } +mod issue6675 { + unsafe fn foo() { + let mut s = "test".to_owned(); + None.unwrap_or(s.as_mut_vec()); + } + + fn bar() { + let mut s = "test".to_owned(); + None.unwrap_or(unsafe { s.as_mut_vec() }); + #[rustfmt::skip] + None.unwrap_or( unsafe { s.as_mut_vec() } ); + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/or_fun_call.stderr b/src/tools/clippy/tests/ui/or_fun_call.stderr index 1e2bfd490e0..9905029ce91 100644 --- a/src/tools/clippy/tests/ui/or_fun_call.stderr +++ b/src/tools/clippy/tests/ui/or_fun_call.stderr @@ -114,5 +114,23 @@ error: use of `or` followed by a function call LL | .or(Some(Bar(b, Duration::from_secs(2)))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some(Bar(b, Duration::from_secs(2))))` -error: aborting due to 19 previous errors +error: use of `unwrap_or` followed by a function call + --> $DIR/or_fun_call.rs:141:14 + | +LL | None.unwrap_or(s.as_mut_vec()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| s.as_mut_vec())` + +error: use of `unwrap_or` followed by a function call + --> $DIR/or_fun_call.rs:146:14 + | +LL | None.unwrap_or(unsafe { s.as_mut_vec() }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| unsafe { s.as_mut_vec() })` + +error: use of `unwrap_or` followed by a function call + --> $DIR/or_fun_call.rs:148:14 + | +LL | None.unwrap_or( unsafe { s.as_mut_vec() } ); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| unsafe { s.as_mut_vec() })` + +error: aborting due to 22 previous errors diff --git a/src/tools/clippy/tests/ui/print.stderr b/src/tools/clippy/tests/ui/print.stderr index 208d9532628..1754c418381 100644 --- a/src/tools/clippy/tests/ui/print.stderr +++ b/src/tools/clippy/tests/ui/print.stderr @@ -1,8 +1,8 @@ error: use of `Debug`-based formatting - --> $DIR/print.rs:11:19 + --> $DIR/print.rs:11:20 | LL | write!(f, "{:?}", 43.1415) - | ^^^^^^ + | ^^^^ | = note: `-D clippy::use-debug` implied by `-D warnings` @@ -33,10 +33,10 @@ LL | print!("Hello {:?}", "World"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of `Debug`-based formatting - --> $DIR/print.rs:28:12 + --> $DIR/print.rs:28:19 | LL | print!("Hello {:?}", "World"); - | ^^^^^^^^^^^^ + | ^^^^ error: use of `print!` --> $DIR/print.rs:30:5 @@ -45,10 +45,10 @@ LL | print!("Hello {:#?}", "#orld"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of `Debug`-based formatting - --> $DIR/print.rs:30:12 + --> $DIR/print.rs:30:19 | LL | print!("Hello {:#?}", "#orld"); - | ^^^^^^^^^^^^^ + | ^^^^^ error: aborting due to 8 previous errors diff --git a/src/tools/clippy/tests/ui/print_literal.stderr b/src/tools/clippy/tests/ui/print_literal.stderr index e284aece236..54a4084c89e 100644 --- a/src/tools/clippy/tests/ui/print_literal.stderr +++ b/src/tools/clippy/tests/ui/print_literal.stderr @@ -5,66 +5,120 @@ LL | print!("Hello {}", "world"); | ^^^^^^^ | = note: `-D clippy::print-literal` implied by `-D warnings` +help: try this + | +LL | print!("Hello world"); + | ^^^^^-- error: literal with an empty format string --> $DIR/print_literal.rs:26:36 | LL | println!("Hello {} {}", world, "world"); | ^^^^^^^ + | +help: try this + | +LL | println!("Hello {} world", world); + | ^^^^^ -- error: literal with an empty format string --> $DIR/print_literal.rs:27:26 | LL | println!("Hello {}", "world"); | ^^^^^^^ + | +help: try this + | +LL | println!("Hello world"); + | ^^^^^-- error: literal with an empty format string --> $DIR/print_literal.rs:32:25 | LL | println!("{0} {1}", "hello", "world"); | ^^^^^^^ + | +help: try this + | +LL | println!("hello {1}", "world"); + | ^^^^^ -- error: literal with an empty format string --> $DIR/print_literal.rs:32:34 | LL | println!("{0} {1}", "hello", "world"); | ^^^^^^^ + | +help: try this + | +LL | println!("{0} world", "hello"); + | ^^^^^ -- error: literal with an empty format string --> $DIR/print_literal.rs:33:25 | LL | println!("{1} {0}", "hello", "world"); | ^^^^^^^ + | +help: try this + | +LL | println!("{1} hello", "world"); + | ^^^^^-- error: literal with an empty format string --> $DIR/print_literal.rs:33:34 | LL | println!("{1} {0}", "hello", "world"); | ^^^^^^^ + | +help: try this + | +LL | println!("world {0}", "hello"); + | ^^^^^ -- error: literal with an empty format string - --> $DIR/print_literal.rs:36:35 + --> $DIR/print_literal.rs:36:29 | LL | println!("{foo} {bar}", foo = "hello", bar = "world"); - | ^^^^^^^ + | ^^^^^^^^^^^^^ + | +help: try this + | +LL | println!("hello {bar}", bar = "world"); + | ^^^^^ -- error: literal with an empty format string - --> $DIR/print_literal.rs:36:50 + --> $DIR/print_literal.rs:36:44 | LL | println!("{foo} {bar}", foo = "hello", bar = "world"); - | ^^^^^^^ + | ^^^^^^^^^^^^^ + | +help: try this + | +LL | println!("{foo} world", foo = "hello"); + | ^^^^^ -- error: literal with an empty format string - --> $DIR/print_literal.rs:37:35 + --> $DIR/print_literal.rs:37:29 | LL | println!("{bar} {foo}", foo = "hello", bar = "world"); - | ^^^^^^^ + | ^^^^^^^^^^^^^ + | +help: try this + | +LL | println!("{bar} hello", bar = "world"); + | ^^^^^-- error: literal with an empty format string - --> $DIR/print_literal.rs:37:50 + --> $DIR/print_literal.rs:37:44 | LL | println!("{bar} {foo}", foo = "hello", bar = "world"); - | ^^^^^^^ + | ^^^^^^^^^^^^^ + | +help: try this + | +LL | println!("world {foo}", foo = "hello"); + | ^^^^^ -- error: aborting due to 11 previous errors diff --git a/src/tools/clippy/tests/ui/search_is_some.rs b/src/tools/clippy/tests/ui/search_is_some.rs index f0dc3b3d06b..72bc6ef35d3 100644 --- a/src/tools/clippy/tests/ui/search_is_some.rs +++ b/src/tools/clippy/tests/ui/search_is_some.rs @@ -1,8 +1,9 @@ // aux-build:option_helpers.rs +#![warn(clippy::search_is_some)] +#![allow(dead_code)] extern crate option_helpers; use option_helpers::IteratorFalsePositives; -#[warn(clippy::search_is_some)] #[rustfmt::skip] fn main() { let v = vec![3, 2, 1, 0, -1, -2, -3]; @@ -36,3 +37,37 @@ fn main() { // `Pattern` that is not a string let _ = "hello world".find(|c: char| c == 'o' || c == 'l').is_some(); } + +#[rustfmt::skip] +fn is_none() { + let v = vec![3, 2, 1, 0, -1, -2, -3]; + let y = &&42; + + + // Check `find().is_none()`, multi-line case. + let _ = v.iter().find(|&x| { + *x < 0 + } + ).is_none(); + + // Check `position().is_none()`, multi-line case. + let _ = v.iter().position(|&x| { + x < 0 + } + ).is_none(); + + // Check `rposition().is_none()`, multi-line case. + let _ = v.iter().rposition(|&x| { + x < 0 + } + ).is_none(); + + // Check that we don't lint if the caller is not an `Iterator` or string + let falsepos = IteratorFalsePositives { foo: 0 }; + let _ = falsepos.find().is_none(); + let _ = falsepos.position().is_none(); + let _ = falsepos.rposition().is_none(); + // check that we don't lint if `find()` is called with + // `Pattern` that is not a string + let _ = "hello world".find(|c: char| c == 'o' || c == 'l').is_none(); +} diff --git a/src/tools/clippy/tests/ui/search_is_some.stderr b/src/tools/clippy/tests/ui/search_is_some.stderr index c601f568c60..f3c758e451e 100644 --- a/src/tools/clippy/tests/ui/search_is_some.stderr +++ b/src/tools/clippy/tests/ui/search_is_some.stderr @@ -1,5 +1,5 @@ error: called `is_some()` after searching an `Iterator` with `find` - --> $DIR/search_is_some.rs:13:13 + --> $DIR/search_is_some.rs:14:13 | LL | let _ = v.iter().find(|&x| { | _____________^ @@ -12,7 +12,7 @@ LL | | ).is_some(); = help: this is more succinctly expressed by calling `any()` error: called `is_some()` after searching an `Iterator` with `position` - --> $DIR/search_is_some.rs:19:13 + --> $DIR/search_is_some.rs:20:13 | LL | let _ = v.iter().position(|&x| { | _____________^ @@ -24,7 +24,7 @@ LL | | ).is_some(); = help: this is more succinctly expressed by calling `any()` error: called `is_some()` after searching an `Iterator` with `rposition` - --> $DIR/search_is_some.rs:25:13 + --> $DIR/search_is_some.rs:26:13 | LL | let _ = v.iter().rposition(|&x| { | _____________^ @@ -35,5 +35,41 @@ LL | | ).is_some(); | = help: this is more succinctly expressed by calling `any()` -error: aborting due to 3 previous errors +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some.rs:48:13 + | +LL | let _ = v.iter().find(|&x| { + | _____________^ +LL | | *x < 0 +LL | | } +LL | | ).is_none(); + | |______________________________^ + | + = help: this is more succinctly expressed by calling `any()` with negation + +error: called `is_none()` after searching an `Iterator` with `position` + --> $DIR/search_is_some.rs:54:13 + | +LL | let _ = v.iter().position(|&x| { + | _____________^ +LL | | x < 0 +LL | | } +LL | | ).is_none(); + | |______________________________^ + | + = help: this is more succinctly expressed by calling `any()` with negation + +error: called `is_none()` after searching an `Iterator` with `rposition` + --> $DIR/search_is_some.rs:60:13 + | +LL | let _ = v.iter().rposition(|&x| { + | _____________^ +LL | | x < 0 +LL | | } +LL | | ).is_none(); + | |______________________________^ + | + = help: this is more succinctly expressed by calling `any()` with negation + +error: aborting due to 6 previous errors diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable.fixed b/src/tools/clippy/tests/ui/search_is_some_fixable.fixed index dc3f290e562..62ff16f67f4 100644 --- a/src/tools/clippy/tests/ui/search_is_some_fixable.fixed +++ b/src/tools/clippy/tests/ui/search_is_some_fixable.fixed @@ -1,5 +1,5 @@ // run-rustfix - +#![allow(dead_code)] #![warn(clippy::search_is_some)] fn main() { @@ -33,3 +33,36 @@ fn main() { let _ = s1[2..].contains(&s2); let _ = s1[2..].contains(&s2[2..]); } + +fn is_none() { + let v = vec![3, 2, 1, 0, -1, -2, -3]; + let y = &&42; + + // Check `find().is_none()`, single-line case. + let _ = !v.iter().any(|x| *x < 0); + let _ = !(0..1).any(|x| **y == x); // one dereference less + let _ = !(0..1).any(|x| x == 0); + let _ = !v.iter().any(|x| *x == 0); + + // Check `position().is_none()`, single-line case. + let _ = !v.iter().any(|&x| x < 0); + + // Check `rposition().is_none()`, single-line case. + let _ = !v.iter().any(|&x| x < 0); + + let s1 = String::from("hello world"); + let s2 = String::from("world"); + + // caller of `find()` is a `&`static str` + let _ = !"hello world".contains("world"); + let _ = !"hello world".contains(&s2); + let _ = !"hello world".contains(&s2[2..]); + // caller of `find()` is a `String` + let _ = !s1.contains("world"); + let _ = !s1.contains(&s2); + let _ = !s1.contains(&s2[2..]); + // caller of `find()` is slice of `String` + let _ = !s1[2..].contains("world"); + let _ = !s1[2..].contains(&s2); + let _ = !s1[2..].contains(&s2[2..]); +} diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable.rs b/src/tools/clippy/tests/ui/search_is_some_fixable.rs index 146cf5adf1b..8407f716647 100644 --- a/src/tools/clippy/tests/ui/search_is_some_fixable.rs +++ b/src/tools/clippy/tests/ui/search_is_some_fixable.rs @@ -1,5 +1,5 @@ // run-rustfix - +#![allow(dead_code)] #![warn(clippy::search_is_some)] fn main() { @@ -33,3 +33,36 @@ fn main() { let _ = s1[2..].find(&s2).is_some(); let _ = s1[2..].find(&s2[2..]).is_some(); } + +fn is_none() { + let v = vec![3, 2, 1, 0, -1, -2, -3]; + let y = &&42; + + // Check `find().is_none()`, single-line case. + let _ = v.iter().find(|&x| *x < 0).is_none(); + let _ = (0..1).find(|x| **y == *x).is_none(); // one dereference less + let _ = (0..1).find(|x| *x == 0).is_none(); + let _ = v.iter().find(|x| **x == 0).is_none(); + + // Check `position().is_none()`, single-line case. + let _ = v.iter().position(|&x| x < 0).is_none(); + + // Check `rposition().is_none()`, single-line case. + let _ = v.iter().rposition(|&x| x < 0).is_none(); + + let s1 = String::from("hello world"); + let s2 = String::from("world"); + + // caller of `find()` is a `&`static str` + let _ = "hello world".find("world").is_none(); + let _ = "hello world".find(&s2).is_none(); + let _ = "hello world".find(&s2[2..]).is_none(); + // caller of `find()` is a `String` + let _ = s1.find("world").is_none(); + let _ = s1.find(&s2).is_none(); + let _ = s1.find(&s2[2..]).is_none(); + // caller of `find()` is slice of `String` + let _ = s1[2..].find("world").is_none(); + let _ = s1[2..].find(&s2).is_none(); + let _ = s1[2..].find(&s2[2..]).is_none(); +} diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable.stderr b/src/tools/clippy/tests/ui/search_is_some_fixable.stderr index 23c1d9a901b..bd1b6955a97 100644 --- a/src/tools/clippy/tests/ui/search_is_some_fixable.stderr +++ b/src/tools/clippy/tests/ui/search_is_some_fixable.stderr @@ -90,5 +90,95 @@ error: called `is_some()` after calling `find()` on a string LL | let _ = s1[2..].find(&s2[2..]).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])` -error: aborting due to 15 previous errors +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable.rs:42:13 + | +LL | let _ = v.iter().find(|&x| *x < 0).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x| *x < 0)` + +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable.rs:43:13 + | +LL | let _ = (0..1).find(|x| **y == *x).is_none(); // one dereference less + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(0..1).any(|x| **y == x)` + +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable.rs:44:13 + | +LL | let _ = (0..1).find(|x| *x == 0).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(0..1).any(|x| x == 0)` + +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable.rs:45:13 + | +LL | let _ = v.iter().find(|x| **x == 0).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x| *x == 0)` + +error: called `is_none()` after searching an `Iterator` with `position` + --> $DIR/search_is_some_fixable.rs:48:13 + | +LL | let _ = v.iter().position(|&x| x < 0).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|&x| x < 0)` + +error: called `is_none()` after searching an `Iterator` with `rposition` + --> $DIR/search_is_some_fixable.rs:51:13 + | +LL | let _ = v.iter().rposition(|&x| x < 0).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|&x| x < 0)` + +error: called `is_none()` after calling `find()` on a string + --> $DIR/search_is_some_fixable.rs:57:13 + | +LL | let _ = "hello world".find("world").is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!"hello world".contains("world")` + +error: called `is_none()` after calling `find()` on a string + --> $DIR/search_is_some_fixable.rs:58:13 + | +LL | let _ = "hello world".find(&s2).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!"hello world".contains(&s2)` + +error: called `is_none()` after calling `find()` on a string + --> $DIR/search_is_some_fixable.rs:59:13 + | +LL | let _ = "hello world".find(&s2[2..]).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!"hello world".contains(&s2[2..])` + +error: called `is_none()` after calling `find()` on a string + --> $DIR/search_is_some_fixable.rs:61:13 + | +LL | let _ = s1.find("world").is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1.contains("world")` + +error: called `is_none()` after calling `find()` on a string + --> $DIR/search_is_some_fixable.rs:62:13 + | +LL | let _ = s1.find(&s2).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1.contains(&s2)` + +error: called `is_none()` after calling `find()` on a string + --> $DIR/search_is_some_fixable.rs:63:13 + | +LL | let _ = s1.find(&s2[2..]).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1.contains(&s2[2..])` + +error: called `is_none()` after calling `find()` on a string + --> $DIR/search_is_some_fixable.rs:65:13 + | +LL | let _ = s1[2..].find("world").is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1[2..].contains("world")` + +error: called `is_none()` after calling `find()` on a string + --> $DIR/search_is_some_fixable.rs:66:13 + | +LL | let _ = s1[2..].find(&s2).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1[2..].contains(&s2)` + +error: called `is_none()` after calling `find()` on a string + --> $DIR/search_is_some_fixable.rs:67:13 + | +LL | let _ = s1[2..].find(&s2[2..]).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1[2..].contains(&s2[2..])` + +error: aborting due to 30 previous errors diff --git a/src/tools/clippy/tests/ui/string_lit_as_bytes.fixed b/src/tools/clippy/tests/ui/string_lit_as_bytes.fixed index ccf8f61c4a9..dd22bfa5c53 100644 --- a/src/tools/clippy/tests/ui/string_lit_as_bytes.fixed +++ b/src/tools/clippy/tests/ui/string_lit_as_bytes.fixed @@ -8,10 +8,16 @@ fn str_lit_as_bytes() { let bs = br###"raw string with 3# plus " ""###; + let bs = b"lit to string".to_vec(); + let bs = b"lit to owned".to_vec(); + // no warning, because these cannot be written as byte string literals: let ubs = "☃".as_bytes(); let ubs = "hello there! this is a very long string".as_bytes(); + let ubs = "☃".to_string().into_bytes(); + let ubs = "this is also too long and shouldn't be fixed".to_string().into_bytes(); + let strify = stringify!(foobar).as_bytes(); let current_version = env!("CARGO_PKG_VERSION").as_bytes(); diff --git a/src/tools/clippy/tests/ui/string_lit_as_bytes.rs b/src/tools/clippy/tests/ui/string_lit_as_bytes.rs index 178df08e249..d2a710ed6b8 100644 --- a/src/tools/clippy/tests/ui/string_lit_as_bytes.rs +++ b/src/tools/clippy/tests/ui/string_lit_as_bytes.rs @@ -8,10 +8,16 @@ fn str_lit_as_bytes() { let bs = r###"raw string with 3# plus " ""###.as_bytes(); + let bs = "lit to string".to_string().into_bytes(); + let bs = "lit to owned".to_owned().into_bytes(); + // no warning, because these cannot be written as byte string literals: let ubs = "☃".as_bytes(); let ubs = "hello there! this is a very long string".as_bytes(); + let ubs = "☃".to_string().into_bytes(); + let ubs = "this is also too long and shouldn't be fixed".to_string().into_bytes(); + let strify = stringify!(foobar).as_bytes(); let current_version = env!("CARGO_PKG_VERSION").as_bytes(); diff --git a/src/tools/clippy/tests/ui/string_lit_as_bytes.stderr b/src/tools/clippy/tests/ui/string_lit_as_bytes.stderr index 99c512354d5..e0ddb070b50 100644 --- a/src/tools/clippy/tests/ui/string_lit_as_bytes.stderr +++ b/src/tools/clippy/tests/ui/string_lit_as_bytes.stderr @@ -12,17 +12,29 @@ error: calling `as_bytes()` on a string literal LL | let bs = r###"raw string with 3# plus " ""###.as_bytes(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `br###"raw string with 3# plus " ""###` +error: calling `into_bytes()` on a string literal + --> $DIR/string_lit_as_bytes.rs:11:14 + | +LL | let bs = "lit to string".to_string().into_bytes(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"lit to string".to_vec()` + +error: calling `into_bytes()` on a string literal + --> $DIR/string_lit_as_bytes.rs:12:14 + | +LL | let bs = "lit to owned".to_owned().into_bytes(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"lit to owned".to_vec()` + error: calling `as_bytes()` on `include_str!(..)` - --> $DIR/string_lit_as_bytes.rs:19:22 + --> $DIR/string_lit_as_bytes.rs:25:22 | LL | let includestr = include_str!("entry_unfixable.rs").as_bytes(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `include_bytes!(..)` instead: `include_bytes!("entry_unfixable.rs")` error: calling `as_bytes()` on a string literal - --> $DIR/string_lit_as_bytes.rs:21:13 + --> $DIR/string_lit_as_bytes.rs:27:13 | LL | let _ = "string with newline/t/n".as_bytes(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"string with newline/t/n"` -error: aborting due to 4 previous errors +error: aborting due to 6 previous errors diff --git a/src/tools/clippy/tests/ui/suspicious_map.rs b/src/tools/clippy/tests/ui/suspicious_map.rs index d838d8fde21..3a2a10cf09e 100644 --- a/src/tools/clippy/tests/ui/suspicious_map.rs +++ b/src/tools/clippy/tests/ui/suspicious_map.rs @@ -2,4 +2,31 @@ fn main() { let _ = (0..3).map(|x| x + 2).count(); + + let f = |x| x + 1; + let _ = (0..3).map(f).count(); +} + +fn negative() { + // closure with side effects + let mut sum = 0; + let _ = (0..3).map(|x| sum += x).count(); + + // closure variable with side effects + let ext_closure = |x| sum += x; + let _ = (0..3).map(ext_closure).count(); + + // closure that returns unit + let _ = (0..3) + .map(|x| { + // do nothing + }) + .count(); + + // external function + let _ = (0..3).map(do_something).count(); +} + +fn do_something<T>(t: T) -> String { + unimplemented!() } diff --git a/src/tools/clippy/tests/ui/suspicious_map.stderr b/src/tools/clippy/tests/ui/suspicious_map.stderr index e1b4ba40376..8c3f36584a5 100644 --- a/src/tools/clippy/tests/ui/suspicious_map.stderr +++ b/src/tools/clippy/tests/ui/suspicious_map.stderr @@ -7,5 +7,13 @@ LL | let _ = (0..3).map(|x| x + 2).count(); = note: `-D clippy::suspicious-map` implied by `-D warnings` = help: make sure you did not confuse `map` with `filter` or `for_each` -error: aborting due to previous error +error: this call to `map()` won't have an effect on the call to `count()` + --> $DIR/suspicious_map.rs:7:13 + | +LL | let _ = (0..3).map(f).count(); + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: make sure you did not confuse `map` with `filter` or `for_each` + +error: aborting due to 2 previous errors diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.stderr b/src/tools/clippy/tests/ui/unnecessary_cast.stderr index 8981d13e8ea..70aa448af68 100644 --- a/src/tools/clippy/tests/ui/unnecessary_cast.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_cast.stderr @@ -1,22 +1,22 @@ -error: casting to the same type is unnecessary (`i32` -> `i32`) +error: casting integer literal to `i32` is unnecessary --> $DIR/unnecessary_cast.rs:6:5 | LL | 1i32 as i32; - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ help: try: `1_i32` | = note: `-D clippy::unnecessary-cast` implied by `-D warnings` -error: casting to the same type is unnecessary (`f32` -> `f32`) +error: casting float literal to `f32` is unnecessary --> $DIR/unnecessary_cast.rs:7:5 | LL | 1f32 as f32; - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ help: try: `1_f32` error: casting to the same type is unnecessary (`bool` -> `bool`) --> $DIR/unnecessary_cast.rs:8:5 | LL | false as bool; - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ help: try: `false` error: aborting due to 3 previous errors diff --git a/src/tools/clippy/tests/ui/upper_case_acronyms.rs b/src/tools/clippy/tests/ui/upper_case_acronyms.rs index 735909887ac..8c09c6f5b23 100644 --- a/src/tools/clippy/tests/ui/upper_case_acronyms.rs +++ b/src/tools/clippy/tests/ui/upper_case_acronyms.rs @@ -20,4 +20,8 @@ enum Flags { // `GccLlvmSomething` struct GCCLLVMSomething; +// public items must not be linted +pub struct NOWARNINGHERE; +pub struct ALSONoWarningHERE; + fn main() {} diff --git a/src/tools/clippy/tests/ui/use_self.fixed b/src/tools/clippy/tests/ui/use_self.fixed index b94d5448d92..1282befdfb3 100644 --- a/src/tools/clippy/tests/ui/use_self.fixed +++ b/src/tools/clippy/tests/ui/use_self.fixed @@ -75,13 +75,13 @@ mod lifetimes { mod issue2894 { trait IntoBytes { - fn to_bytes(&self) -> Vec<u8>; + fn to_bytes(self) -> Vec<u8>; } // This should not be linted impl IntoBytes for u8 { - fn to_bytes(&self) -> Vec<u8> { - vec![*self] + fn to_bytes(self) -> Vec<u8> { + vec![self] } } } diff --git a/src/tools/clippy/tests/ui/use_self.rs b/src/tools/clippy/tests/ui/use_self.rs index ac99c6d9d7b..7aaac7b2414 100644 --- a/src/tools/clippy/tests/ui/use_self.rs +++ b/src/tools/clippy/tests/ui/use_self.rs @@ -75,13 +75,13 @@ mod lifetimes { mod issue2894 { trait IntoBytes { - fn to_bytes(&self) -> Vec<u8>; + fn to_bytes(self) -> Vec<u8>; } // This should not be linted impl IntoBytes for u8 { - fn to_bytes(&self) -> Vec<u8> { - vec![*self] + fn to_bytes(self) -> Vec<u8> { + vec![self] } } } diff --git a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed index c266f684a36..fd754e4c794 100644 --- a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed +++ b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed @@ -77,7 +77,7 @@ fn main() { let error_kind = ErrorKind::NotFound; match error_kind { ErrorKind::NotFound => {}, - std::io::ErrorKind::PermissionDenied | std::io::ErrorKind::ConnectionRefused | std::io::ErrorKind::ConnectionReset | std::io::ErrorKind::ConnectionAborted | std::io::ErrorKind::NotConnected | std::io::ErrorKind::AddrInUse | std::io::ErrorKind::AddrNotAvailable | std::io::ErrorKind::BrokenPipe | std::io::ErrorKind::AlreadyExists | std::io::ErrorKind::WouldBlock | std::io::ErrorKind::InvalidInput | std::io::ErrorKind::InvalidData | std::io::ErrorKind::TimedOut | std::io::ErrorKind::WriteZero | std::io::ErrorKind::Interrupted | std::io::ErrorKind::Other | std::io::ErrorKind::UnexpectedEof | _ => {}, + ErrorKind::PermissionDenied | ErrorKind::ConnectionRefused | ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::NotConnected | ErrorKind::AddrInUse | ErrorKind::AddrNotAvailable | ErrorKind::BrokenPipe | ErrorKind::AlreadyExists | ErrorKind::WouldBlock | ErrorKind::InvalidInput | ErrorKind::InvalidData | ErrorKind::TimedOut | ErrorKind::WriteZero | ErrorKind::Interrupted | ErrorKind::Other | ErrorKind::UnexpectedEof | _ => {}, } match error_kind { ErrorKind::NotFound => {}, diff --git a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr index 0da2b68ba0b..a513a62c748 100644 --- a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr +++ b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr @@ -1,4 +1,4 @@ -error: wildcard match will miss any future added variants +error: wildcard match will also match any future added variants --> $DIR/wildcard_enum_match_arm.rs:39:9 | LL | _ => eprintln!("Not red"), @@ -10,29 +10,29 @@ note: the lint level is defined here LL | #![deny(clippy::wildcard_enum_match_arm)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: wildcard match will miss any future added variants +error: wildcard match will also match any future added variants --> $DIR/wildcard_enum_match_arm.rs:43:9 | LL | _not_red => eprintln!("Not red"), | ^^^^^^^^ help: try this: `_not_red @ Color::Green | _not_red @ Color::Blue | _not_red @ Color::Rgb(..) | _not_red @ Color::Cyan` -error: wildcard match will miss any future added variants +error: wildcard match will also match any future added variants --> $DIR/wildcard_enum_match_arm.rs:47:9 | LL | not_red => format!("{:?}", not_red), | ^^^^^^^ help: try this: `not_red @ Color::Green | not_red @ Color::Blue | not_red @ Color::Rgb(..) | not_red @ Color::Cyan` -error: wildcard match will miss any future added variants +error: wildcard match will also match any future added variants --> $DIR/wildcard_enum_match_arm.rs:63:9 | LL | _ => "No red", | ^ help: try this: `Color::Red | Color::Green | Color::Blue | Color::Rgb(..) | Color::Cyan` -error: match on non-exhaustive enum doesn't explicitly match all known variants +error: wildcard matches known variants and will also match future added variants --> $DIR/wildcard_enum_match_arm.rs:80:9 | LL | _ => {}, - | ^ help: try this: `std::io::ErrorKind::PermissionDenied | std::io::ErrorKind::ConnectionRefused | std::io::ErrorKind::ConnectionReset | std::io::ErrorKind::ConnectionAborted | std::io::ErrorKind::NotConnected | std::io::ErrorKind::AddrInUse | std::io::ErrorKind::AddrNotAvailable | std::io::ErrorKind::BrokenPipe | std::io::ErrorKind::AlreadyExists | std::io::ErrorKind::WouldBlock | std::io::ErrorKind::InvalidInput | std::io::ErrorKind::InvalidData | std::io::ErrorKind::TimedOut | std::io::ErrorKind::WriteZero | std::io::ErrorKind::Interrupted | std::io::ErrorKind::Other | std::io::ErrorKind::UnexpectedEof | _` + | ^ help: try this: `ErrorKind::PermissionDenied | ErrorKind::ConnectionRefused | ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::NotConnected | ErrorKind::AddrInUse | ErrorKind::AddrNotAvailable | ErrorKind::BrokenPipe | ErrorKind::AlreadyExists | ErrorKind::WouldBlock | ErrorKind::InvalidInput | ErrorKind::InvalidData | ErrorKind::TimedOut | ErrorKind::WriteZero | ErrorKind::Interrupted | ErrorKind::Other | ErrorKind::UnexpectedEof | _` error: aborting due to 5 previous errors diff --git a/src/tools/clippy/tests/ui/write_literal.stderr b/src/tools/clippy/tests/ui/write_literal.stderr index e54d89ecf29..507a78e8280 100644 --- a/src/tools/clippy/tests/ui/write_literal.stderr +++ b/src/tools/clippy/tests/ui/write_literal.stderr @@ -5,66 +5,120 @@ LL | write!(&mut v, "Hello {}", "world"); | ^^^^^^^ | = note: `-D clippy::write-literal` implied by `-D warnings` +help: try this + | +LL | write!(&mut v, "Hello world"); + | ^^^^^-- error: literal with an empty format string --> $DIR/write_literal.rs:31:44 | LL | writeln!(&mut v, "Hello {} {}", world, "world"); | ^^^^^^^ + | +help: try this + | +LL | writeln!(&mut v, "Hello {} world", world); + | ^^^^^ -- error: literal with an empty format string --> $DIR/write_literal.rs:32:34 | LL | writeln!(&mut v, "Hello {}", "world"); | ^^^^^^^ + | +help: try this + | +LL | writeln!(&mut v, "Hello world"); + | ^^^^^-- error: literal with an empty format string --> $DIR/write_literal.rs:37:33 | LL | writeln!(&mut v, "{0} {1}", "hello", "world"); | ^^^^^^^ + | +help: try this + | +LL | writeln!(&mut v, "hello {1}", "world"); + | ^^^^^ -- error: literal with an empty format string --> $DIR/write_literal.rs:37:42 | LL | writeln!(&mut v, "{0} {1}", "hello", "world"); | ^^^^^^^ + | +help: try this + | +LL | writeln!(&mut v, "{0} world", "hello"); + | ^^^^^ -- error: literal with an empty format string --> $DIR/write_literal.rs:38:33 | LL | writeln!(&mut v, "{1} {0}", "hello", "world"); | ^^^^^^^ + | +help: try this + | +LL | writeln!(&mut v, "{1} hello", "world"); + | ^^^^^-- error: literal with an empty format string --> $DIR/write_literal.rs:38:42 | LL | writeln!(&mut v, "{1} {0}", "hello", "world"); | ^^^^^^^ + | +help: try this + | +LL | writeln!(&mut v, "world {0}", "hello"); + | ^^^^^ -- error: literal with an empty format string - --> $DIR/write_literal.rs:41:43 + --> $DIR/write_literal.rs:41:37 | LL | writeln!(&mut v, "{foo} {bar}", foo = "hello", bar = "world"); - | ^^^^^^^ + | ^^^^^^^^^^^^^ + | +help: try this + | +LL | writeln!(&mut v, "hello {bar}", bar = "world"); + | ^^^^^ -- error: literal with an empty format string - --> $DIR/write_literal.rs:41:58 + --> $DIR/write_literal.rs:41:52 | LL | writeln!(&mut v, "{foo} {bar}", foo = "hello", bar = "world"); - | ^^^^^^^ + | ^^^^^^^^^^^^^ + | +help: try this + | +LL | writeln!(&mut v, "{foo} world", foo = "hello"); + | ^^^^^ -- error: literal with an empty format string - --> $DIR/write_literal.rs:42:43 + --> $DIR/write_literal.rs:42:37 | LL | writeln!(&mut v, "{bar} {foo}", foo = "hello", bar = "world"); - | ^^^^^^^ + | ^^^^^^^^^^^^^ + | +help: try this + | +LL | writeln!(&mut v, "{bar} hello", bar = "world"); + | ^^^^^-- error: literal with an empty format string - --> $DIR/write_literal.rs:42:58 + --> $DIR/write_literal.rs:42:52 | LL | writeln!(&mut v, "{bar} {foo}", foo = "hello", bar = "world"); - | ^^^^^^^ + | ^^^^^^^^^^^^^ + | +help: try this + | +LL | writeln!(&mut v, "world {foo}", foo = "hello"); + | ^^^^^ -- error: aborting due to 11 previous errors diff --git a/src/tools/clippy/tests/ui/write_literal_2.rs b/src/tools/clippy/tests/ui/write_literal_2.rs new file mode 100644 index 00000000000..f341e8215e1 --- /dev/null +++ b/src/tools/clippy/tests/ui/write_literal_2.rs @@ -0,0 +1,27 @@ +#![allow(unused_must_use)] +#![warn(clippy::write_literal)] + +use std::io::Write; + +fn main() { + let mut v = Vec::new(); + + writeln!(&mut v, "{}", "{hello}"); + writeln!(&mut v, r"{}", r"{hello}"); + writeln!(&mut v, "{}", '\''); + writeln!(&mut v, "{}", '"'); + writeln!(&mut v, r"{}", '"'); // don't lint + writeln!(&mut v, r"{}", '\''); + writeln!( + &mut v, + "some {}", + "hello \ + world!" + ); + writeln!( + &mut v, + "some {}\ + {} \\ {}", + "1", "2", "3", + ); +} diff --git a/src/tools/clippy/tests/ui/write_literal_2.stderr b/src/tools/clippy/tests/ui/write_literal_2.stderr new file mode 100644 index 00000000000..0aa1b55e58c --- /dev/null +++ b/src/tools/clippy/tests/ui/write_literal_2.stderr @@ -0,0 +1,107 @@ +error: literal with an empty format string + --> $DIR/write_literal_2.rs:9:28 + | +LL | writeln!(&mut v, "{}", "{hello}"); + | ^^^^^^^^^ + | + = note: `-D clippy::write-literal` implied by `-D warnings` +help: try this + | +LL | writeln!(&mut v, "{{hello}}"); + | ^^^^^^^^^-- + +error: literal with an empty format string + --> $DIR/write_literal_2.rs:10:29 + | +LL | writeln!(&mut v, r"{}", r"{hello}"); + | ^^^^^^^^^^ + | +help: try this + | +LL | writeln!(&mut v, r"{{hello}}"); + | ^^^^^^^^^-- + +error: literal with an empty format string + --> $DIR/write_literal_2.rs:11:28 + | +LL | writeln!(&mut v, "{}", '/''); + | ^^^^ + | +help: try this + | +LL | writeln!(&mut v, "'"); + | ^-- + +error: literal with an empty format string + --> $DIR/write_literal_2.rs:12:28 + | +LL | writeln!(&mut v, "{}", '"'); + | ^^^ + | +help: try this + | +LL | writeln!(&mut v, "/""); + | ^^-- + +error: literal with an empty format string + --> $DIR/write_literal_2.rs:14:29 + | +LL | writeln!(&mut v, r"{}", '/''); + | ^^^^ + | +help: try this + | +LL | writeln!(&mut v, r"'"); + | ^-- + +error: literal with an empty format string + --> $DIR/write_literal_2.rs:18:9 + | +LL | / "hello / +LL | | world!" + | |_______________^ + | +help: try this + | +LL | "some hello / +LL | world!" + | + +error: literal with an empty format string + --> $DIR/write_literal_2.rs:25:9 + | +LL | "1", "2", "3", + | ^^^ + | +help: try this + | +LL | "some 1/ +LL | {} / {}", "2", "3", + | + +error: literal with an empty format string + --> $DIR/write_literal_2.rs:25:14 + | +LL | "1", "2", "3", + | ^^^ + | +help: try this + | +LL | 2 / {}", +LL | "1", "3", + | + +error: literal with an empty format string + --> $DIR/write_literal_2.rs:25:19 + | +LL | "1", "2", "3", + | ^^^ + | +help: try this + | +LL | {} / 3", +LL | "1", "2", + | + +error: aborting due to 9 previous errors + diff --git a/src/tools/clippy/tests/ui/wrong_self_convention.rs b/src/tools/clippy/tests/ui/wrong_self_convention.rs index 6cfc0fcb4ca..ba9e19a1722 100644 --- a/src/tools/clippy/tests/ui/wrong_self_convention.rs +++ b/src/tools/clippy/tests/ui/wrong_self_convention.rs @@ -163,3 +163,35 @@ mod issue6307 { fn to_mut(&mut self); } } + +mod issue6727 { + trait ToU64 { + fn to_u64(self) -> u64; + fn to_u64_v2(&self) -> u64; + } + + #[derive(Clone, Copy)] + struct FooCopy; + + impl ToU64 for FooCopy { + fn to_u64(self) -> u64 { + 1 + } + // trigger lint + fn to_u64_v2(&self) -> u64 { + 1 + } + } + + struct FooNoCopy; + + impl ToU64 for FooNoCopy { + // trigger lint + fn to_u64(self) -> u64 { + 2 + } + fn to_u64_v2(&self) -> u64 { + 2 + } + } +} diff --git a/src/tools/clippy/tests/ui/wrong_self_convention.stderr b/src/tools/clippy/tests/ui/wrong_self_convention.stderr index 32bd9075bd5..1d58a12ac79 100644 --- a/src/tools/clippy/tests/ui/wrong_self_convention.stderr +++ b/src/tools/clippy/tests/ui/wrong_self_convention.stderr @@ -1,148 +1,195 @@ -error: methods called `from_*` usually take no self; consider choosing a less ambiguous name +error: methods called `from_*` usually take no `self` --> $DIR/wrong_self_convention.rs:18:17 | LL | fn from_i32(self) {} | ^^^^ | = note: `-D clippy::wrong-self-convention` implied by `-D warnings` + = help: consider choosing a less ambiguous name -error: methods called `from_*` usually take no self; consider choosing a less ambiguous name +error: methods called `from_*` usually take no `self` --> $DIR/wrong_self_convention.rs:24:21 | LL | pub fn from_i64(self) {} | ^^^^ + | + = help: consider choosing a less ambiguous name -error: methods called `as_*` usually take self by reference or self by mutable reference; consider choosing a less ambiguous name +error: methods called `as_*` usually take `self` by reference or `self` by mutable reference --> $DIR/wrong_self_convention.rs:36:15 | LL | fn as_i32(self) {} | ^^^^ + | + = help: consider choosing a less ambiguous name -error: methods called `into_*` usually take self by value; consider choosing a less ambiguous name +error: methods called `into_*` usually take `self` by value --> $DIR/wrong_self_convention.rs:38:17 | LL | fn into_i32(&self) {} | ^^^^^ + | + = help: consider choosing a less ambiguous name -error: methods called `is_*` usually take self by reference or no self; consider choosing a less ambiguous name +error: methods called `is_*` usually take `self` by reference or no `self` --> $DIR/wrong_self_convention.rs:40:15 | LL | fn is_i32(self) {} | ^^^^ + | + = help: consider choosing a less ambiguous name -error: methods called `to_*` usually take self by reference; consider choosing a less ambiguous name +error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference --> $DIR/wrong_self_convention.rs:42:15 | LL | fn to_i32(self) {} | ^^^^ + | + = help: consider choosing a less ambiguous name -error: methods called `from_*` usually take no self; consider choosing a less ambiguous name +error: methods called `from_*` usually take no `self` --> $DIR/wrong_self_convention.rs:44:17 | LL | fn from_i32(self) {} | ^^^^ + | + = help: consider choosing a less ambiguous name -error: methods called `as_*` usually take self by reference or self by mutable reference; consider choosing a less ambiguous name +error: methods called `as_*` usually take `self` by reference or `self` by mutable reference --> $DIR/wrong_self_convention.rs:46:19 | LL | pub fn as_i64(self) {} | ^^^^ + | + = help: consider choosing a less ambiguous name -error: methods called `into_*` usually take self by value; consider choosing a less ambiguous name +error: methods called `into_*` usually take `self` by value --> $DIR/wrong_self_convention.rs:47:21 | LL | pub fn into_i64(&self) {} | ^^^^^ + | + = help: consider choosing a less ambiguous name -error: methods called `is_*` usually take self by reference or no self; consider choosing a less ambiguous name +error: methods called `is_*` usually take `self` by reference or no `self` --> $DIR/wrong_self_convention.rs:48:19 | LL | pub fn is_i64(self) {} | ^^^^ + | + = help: consider choosing a less ambiguous name -error: methods called `to_*` usually take self by reference; consider choosing a less ambiguous name +error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference --> $DIR/wrong_self_convention.rs:49:19 | LL | pub fn to_i64(self) {} | ^^^^ + | + = help: consider choosing a less ambiguous name -error: methods called `from_*` usually take no self; consider choosing a less ambiguous name +error: methods called `from_*` usually take no `self` --> $DIR/wrong_self_convention.rs:50:21 | LL | pub fn from_i64(self) {} | ^^^^ + | + = help: consider choosing a less ambiguous name -error: methods called `as_*` usually take self by reference or self by mutable reference; consider choosing a less ambiguous name +error: methods called `as_*` usually take `self` by reference or `self` by mutable reference --> $DIR/wrong_self_convention.rs:95:19 | LL | fn as_i32(self) {} | ^^^^ + | + = help: consider choosing a less ambiguous name -error: methods called `into_*` usually take self by value; consider choosing a less ambiguous name +error: methods called `into_*` usually take `self` by value --> $DIR/wrong_self_convention.rs:98:25 | LL | fn into_i32_ref(&self) {} | ^^^^^ + | + = help: consider choosing a less ambiguous name -error: methods called `is_*` usually take self by reference or no self; consider choosing a less ambiguous name +error: methods called `is_*` usually take `self` by reference or no `self` --> $DIR/wrong_self_convention.rs:100:19 | LL | fn is_i32(self) {} | ^^^^ - -error: methods called `to_*` usually take self by reference; consider choosing a less ambiguous name - --> $DIR/wrong_self_convention.rs:102:19 | -LL | fn to_i32(self) {} - | ^^^^ + = help: consider choosing a less ambiguous name -error: methods called `from_*` usually take no self; consider choosing a less ambiguous name +error: methods called `from_*` usually take no `self` --> $DIR/wrong_self_convention.rs:104:21 | LL | fn from_i32(self) {} | ^^^^ + | + = help: consider choosing a less ambiguous name -error: methods called `as_*` usually take self by reference or self by mutable reference; consider choosing a less ambiguous name +error: methods called `as_*` usually take `self` by reference or `self` by mutable reference --> $DIR/wrong_self_convention.rs:119:19 | LL | fn as_i32(self); | ^^^^ + | + = help: consider choosing a less ambiguous name -error: methods called `into_*` usually take self by value; consider choosing a less ambiguous name +error: methods called `into_*` usually take `self` by value --> $DIR/wrong_self_convention.rs:122:25 | LL | fn into_i32_ref(&self); | ^^^^^ + | + = help: consider choosing a less ambiguous name -error: methods called `is_*` usually take self by reference or no self; consider choosing a less ambiguous name +error: methods called `is_*` usually take `self` by reference or no `self` --> $DIR/wrong_self_convention.rs:124:19 | LL | fn is_i32(self); | ^^^^ - -error: methods called `to_*` usually take self by reference; consider choosing a less ambiguous name - --> $DIR/wrong_self_convention.rs:126:19 | -LL | fn to_i32(self); - | ^^^^ + = help: consider choosing a less ambiguous name -error: methods called `from_*` usually take no self; consider choosing a less ambiguous name +error: methods called `from_*` usually take no `self` --> $DIR/wrong_self_convention.rs:128:21 | LL | fn from_i32(self); | ^^^^ + | + = help: consider choosing a less ambiguous name -error: methods called `into_*` usually take self by value; consider choosing a less ambiguous name +error: methods called `into_*` usually take `self` by value --> $DIR/wrong_self_convention.rs:146:25 | LL | fn into_i32_ref(&self); | ^^^^^ + | + = help: consider choosing a less ambiguous name -error: methods called `from_*` usually take no self; consider choosing a less ambiguous name +error: methods called `from_*` usually take no `self` --> $DIR/wrong_self_convention.rs:152:21 | LL | fn from_i32(self); | ^^^^ + | + = help: consider choosing a less ambiguous name + +error: methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value + --> $DIR/wrong_self_convention.rs:181:22 + | +LL | fn to_u64_v2(&self) -> u64 { + | ^^^^^ + | + = help: consider choosing a less ambiguous name + +error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference + --> $DIR/wrong_self_convention.rs:190:19 + | +LL | fn to_u64(self) -> u64 { + | ^^^^ + | + = help: consider choosing a less ambiguous name error: aborting due to 24 previous errors diff --git a/src/tools/clippy/tests/ui/wrong_self_conventions_mut.rs b/src/tools/clippy/tests/ui/wrong_self_conventions_mut.rs new file mode 100644 index 00000000000..486a0d77235 --- /dev/null +++ b/src/tools/clippy/tests/ui/wrong_self_conventions_mut.rs @@ -0,0 +1,30 @@ +// edition:2018 +#![warn(clippy::wrong_self_convention)] +#![allow(dead_code)] + +fn main() {} + +mod issue6758 { + pub enum Test<T> { + One(T), + Many(Vec<T>), + } + + impl<T> Test<T> { + // If a method starts with `to_` and not ends with `_mut` it should expect `&self` + pub fn to_many(&mut self) -> Option<&mut [T]> { + match self { + Self::Many(data) => Some(data), + _ => None, + } + } + + // If a method starts with `to_` and ends with `_mut` it should expect `&mut self` + pub fn to_many_mut(&self) -> Option<&[T]> { + match self { + Self::Many(data) => Some(data), + _ => None, + } + } + } +} diff --git a/src/tools/clippy/tests/ui/wrong_self_conventions_mut.stderr b/src/tools/clippy/tests/ui/wrong_self_conventions_mut.stderr new file mode 100644 index 00000000000..6ce37c59491 --- /dev/null +++ b/src/tools/clippy/tests/ui/wrong_self_conventions_mut.stderr @@ -0,0 +1,19 @@ +error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference + --> $DIR/wrong_self_conventions_mut.rs:15:24 + | +LL | pub fn to_many(&mut self) -> Option<&mut [T]> { + | ^^^^^^^^^ + | + = note: `-D clippy::wrong-self-convention` implied by `-D warnings` + = help: consider choosing a less ambiguous name + +error: methods with the following characteristics: (`to_*` and `*_mut`) usually take `self` by mutable reference + --> $DIR/wrong_self_conventions_mut.rs:23:28 + | +LL | pub fn to_many_mut(&self) -> Option<&[T]> { + | ^^^^^ + | + = help: consider choosing a less ambiguous name + +error: aborting due to 2 previous errors + diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index ff0d845be93..83ea676e8f4 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -973,7 +973,11 @@ fn parse_normalization_string(line: &mut &str) -> Option<String> { } pub fn extract_llvm_version(version: &str) -> Option<u32> { - let version_without_suffix = version.trim_end_matches("git").split('-').next().unwrap(); + let pat = |c: char| !c.is_ascii_digit() && c != '.'; + let version_without_suffix = match version.find(pat) { + Some(pos) => &version[..pos], + None => version, + }; let components: Vec<u32> = version_without_suffix .split('.') .map(|s| s.parse().expect("Malformed version component")) diff --git a/src/tools/compiletest/src/tests.rs b/src/tools/compiletest/src/tests.rs index ea9bc1c1a5b..233f2e648dc 100644 --- a/src/tools/compiletest/src/tests.rs +++ b/src/tools/compiletest/src/tests.rs @@ -68,4 +68,8 @@ fn test_extract_llvm_version() { assert_eq!(extract_llvm_version("9.0.1-rust-1.43.0-dev"), Some(90001)); assert_eq!(extract_llvm_version("9.3.1-rust-1.43.0-dev"), Some(90301)); assert_eq!(extract_llvm_version("10.0.0-rust"), Some(100000)); + assert_eq!(extract_llvm_version("11.1.0"), Some(110100)); + assert_eq!(extract_llvm_version("12.0.0libcxx"), Some(120000)); + assert_eq!(extract_llvm_version("12.0.0-rc3"), Some(120000)); + assert_eq!(extract_llvm_version("13.0.0git"), Some(130000)); } diff --git a/src/tools/jsondocck/Cargo.toml b/src/tools/jsondocck/Cargo.toml index 97052ef58d6..a6efc4c9a6b 100644 --- a/src/tools/jsondocck/Cargo.toml +++ b/src/tools/jsondocck/Cargo.toml @@ -12,3 +12,4 @@ lazy_static = "1.4" shlex = "0.1" serde = "1.0" serde_json = "1.0" +fs-err = "2.5.0" diff --git a/src/tools/jsondocck/src/cache.rs b/src/tools/jsondocck/src/cache.rs index 8a6a911321c..a188750c56a 100644 --- a/src/tools/jsondocck/src/cache.rs +++ b/src/tools/jsondocck/src/cache.rs @@ -1,8 +1,10 @@ use crate::error::CkError; use serde_json::Value; use std::collections::HashMap; +use std::io; use std::path::{Path, PathBuf}; -use std::{fs, io}; + +use fs_err as fs; #[derive(Debug)] pub struct Cache { @@ -31,7 +33,11 @@ impl Cache { self.last_path = Some(resolve.clone()); resolve } else { - self.last_path.as_ref().unwrap().clone() + self.last_path + .as_ref() + // FIXME: Point to a line number + .expect("No last path set. Make sure to specify a full path before using `-`") + .clone() } } diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs index bcb3f6922ef..216890d59ad 100644 --- a/src/tools/jsondocck/src/main.rs +++ b/src/tools/jsondocck/src/main.rs @@ -239,7 +239,20 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { let val = cache.get_value(&command.args[0])?; let results = select(&val, &command.args[1]).unwrap(); let pat = string_to_value(&command.args[2], cache); - results.len() == 1 && results[0] == pat.as_ref() + let is = results.len() == 1 && results[0] == pat.as_ref(); + if !command.negated && !is { + return Err(CkError::FailedCheck( + format!( + "{} matched to {:?}, but expected {:?}", + &command.args[1], + results, + pat.as_ref() + ), + command, + )); + } else { + is + } } CommandKind::Set => { // @set <name> = <path> <jsonpath> @@ -299,7 +312,10 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { fn string_to_value<'a>(s: &str, cache: &'a Cache) -> Cow<'a, Value> { if s.starts_with("$") { - Cow::Borrowed(&cache.variables[&s[1..]]) + Cow::Borrowed(&cache.variables.get(&s[1..]).unwrap_or_else(|| { + // FIXME(adotinthevoid): Show line number + panic!("No variable: `{}`. Current state: `{:?}`", &s[1..], cache.variables) + })) } else { Cow::Owned(serde_json::from_str(s).unwrap()) } diff --git a/src/tools/miri b/src/tools/miri -Subproject 12dac5c0f7acd106401aa14fec758f0ff552f67 +Subproject 2cdd1744b896e8129322229f253f95fd7ad491f diff --git a/src/tools/rust-analyzer b/src/tools/rust-analyzer -Subproject 858ad554374a8b1ad67692558a0878391abfdd8 +Subproject bb1d925dab36372c6bd1fb5671bb68ce938ff00 diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 96a02038638..51f48d8f2ec 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -32,7 +32,6 @@ const EXCEPTIONS: &[(&str, &str)] = &[ ("fuchsia-zircon", "BSD-3-Clause"), // rustdoc, rustc, cargo (jobserver & tempdir) ("colored", "MPL-2.0"), // rustfmt ("ordslice", "Apache-2.0"), // rls - ("cloudabi", "BSD-2-Clause"), // (rls -> crossbeam-channel 0.2 -> rand 0.5) ("ryu", "Apache-2.0 OR BSL-1.0"), // rls/cargo/... (because of serde) ("bytesize", "Apache-2.0"), // cargo ("im-rc", "MPL-2.0+"), // cargo @@ -76,7 +75,6 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[ "cfg-if", "chalk-derive", "chalk-ir", - "cloudabi", "cmake", "compiler_builtins", "cpuid-bool", |
