diff --git a/src/tools/clippy/.github/workflows/clippy_mq.yml b/src/tools/clippy/.github/workflows/clippy_mq.yml index ce15a861bb072..c49241bdff1bc 100644 --- a/src/tools/clippy/.github/workflows/clippy_mq.yml +++ b/src/tools/clippy/.github/workflows/clippy_mq.yml @@ -34,7 +34,7 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: persist-credentials: false @@ -94,7 +94,7 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: persist-credentials: false @@ -112,7 +112,7 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: persist-credentials: false @@ -168,7 +168,7 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: persist-credentials: false @@ -179,7 +179,7 @@ jobs: # Download - name: Download target dir - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v6 with: name: binaries path: target/debug diff --git a/src/tools/clippy/.github/workflows/deploy.yml b/src/tools/clippy/.github/workflows/deploy.yml index 48c5bd36dbcd8..872931160c35f 100644 --- a/src/tools/clippy/.github/workflows/deploy.yml +++ b/src/tools/clippy/.github/workflows/deploy.yml @@ -25,13 +25,13 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: # Unsetting this would make so that any malicious package could get our Github Token persist-credentials: false - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ env.TARGET_BRANCH }} path: 'out' diff --git a/src/tools/clippy/.github/workflows/lintcheck.yml b/src/tools/clippy/.github/workflows/lintcheck.yml index 45fd10ae76149..9ce0b7f5fc46b 100644 --- a/src/tools/clippy/.github/workflows/lintcheck.yml +++ b/src/tools/clippy/.github/workflows/lintcheck.yml @@ -24,7 +24,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: fetch-depth: 2 # Unsetting this would make so that any malicious package could get our Github Token @@ -80,7 +80,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: # Unsetting this would make so that any malicious package could get our Github Token persist-credentials: false @@ -113,7 +113,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: # Unsetting this would make so that any malicious package could get our Github Token persist-credentials: false diff --git a/src/tools/clippy/.github/workflows/remark.yml b/src/tools/clippy/.github/workflows/remark.yml index c2cc48ab95116..03641a9aa62f2 100644 --- a/src/tools/clippy/.github/workflows/remark.yml +++ b/src/tools/clippy/.github/workflows/remark.yml @@ -4,6 +4,9 @@ on: merge_group: pull_request: +env: + MDBOOK_VERSION: 0.5.1 + jobs: remark: runs-on: ubuntu-latest @@ -11,7 +14,7 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: # Unsetting this would make so that any malicious package could get our Github Token persist-credentials: false @@ -27,7 +30,7 @@ jobs: - name: Install mdbook run: | mkdir mdbook - curl -Lf https://github.com/rust-lang/mdBook/releases/download/v0.4.43/mdbook-v0.4.43-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=./mdbook + curl -Lf https://github.com/rust-lang/mdBook/releases/download/v${MDBOOK_VERSION}/mdbook-v${MDBOOK_VERSION}-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=./mdbook echo `pwd`/mdbook >> $GITHUB_PATH # Run diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index 6cb2755be0eec..78b81b5b74d69 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md @@ -6314,6 +6314,7 @@ Released 2018-09-13 [`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown [`doc_nested_refdefs`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_nested_refdefs [`doc_overindented_list_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_overindented_list_items +[`doc_paragraphs_missing_punctuation`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_paragraphs_missing_punctuation [`doc_suspicious_footnotes`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_suspicious_footnotes [`double_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_comparisons [`double_ended_iterator_last`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_ended_iterator_last @@ -7121,6 +7122,7 @@ Released 2018-09-13 [`future-size-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#future-size-threshold [`ignore-interior-mutability`]: https://doc.rust-lang.org/clippy/lint_configuration.html#ignore-interior-mutability [`inherent-impl-lint-scope`]: https://doc.rust-lang.org/clippy/lint_configuration.html#inherent-impl-lint-scope +[`large-error-ignored`]: https://doc.rust-lang.org/clippy/lint_configuration.html#large-error-ignored [`large-error-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#large-error-threshold [`lint-commented-code`]: https://doc.rust-lang.org/clippy/lint_configuration.html#lint-commented-code [`literal-representation-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#literal-representation-threshold diff --git a/src/tools/clippy/book/src/continuous_integration/github_actions.md b/src/tools/clippy/book/src/continuous_integration/github_actions.md index 62d32446d9202..bed0f66bab33a 100644 --- a/src/tools/clippy/book/src/continuous_integration/github_actions.md +++ b/src/tools/clippy/book/src/continuous_integration/github_actions.md @@ -15,7 +15,7 @@ jobs: clippy_check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Run Clippy run: cargo clippy --all-targets --all-features ``` diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md index 6569bdabf115a..2e185fb3a086e 100644 --- a/src/tools/clippy/book/src/lint_configuration.md +++ b/src/tools/clippy/book/src/lint_configuration.md @@ -681,6 +681,17 @@ Sets the scope ("crate", "file", or "module") in which duplicate inherent `impl` * [`multiple_inherent_impl`](https://rust-lang.github.io/rust-clippy/master/index.html#multiple_inherent_impl) +## `large-error-ignored` +A list of paths to types that should be ignored as overly large `Err`-variants in a +`Result` returned from a function + +**Default Value:** `[]` + +--- +**Affected lints:** +* [`result_large_err`](https://rust-lang.github.io/rust-clippy/master/index.html#result_large_err) + + ## `large-error-threshold` The maximum size of the `Err`-variant in a `Result` returned from a function diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs index 8cdd99ac44a8e..2e9cf8e91f7d0 100644 --- a/src/tools/clippy/clippy_config/src/conf.rs +++ b/src/tools/clippy/clippy_config/src/conf.rs @@ -666,6 +666,10 @@ define_Conf! { /// Sets the scope ("crate", "file", or "module") in which duplicate inherent `impl` blocks for the same type are linted. #[lints(multiple_inherent_impl)] inherent_impl_lint_scope: InherentImplLintScope = InherentImplLintScope::Crate, + /// A list of paths to types that should be ignored as overly large `Err`-variants in a + /// `Result` returned from a function + #[lints(result_large_err)] + large_error_ignored: Vec = Vec::default(), /// The maximum size of the `Err`-variant in a `Result` returned from a function #[lints(result_large_err)] large_error_threshold: u64 = 128, diff --git a/src/tools/clippy/clippy_lints/src/byte_char_slices.rs b/src/tools/clippy/clippy_lints/src/byte_char_slices.rs index d88c0711b3971..fc9931439e93b 100644 --- a/src/tools/clippy/clippy_lints/src/byte_char_slices.rs +++ b/src/tools/clippy/clippy_lints/src/byte_char_slices.rs @@ -31,8 +31,8 @@ declare_lint_pass!(ByteCharSlice => [BYTE_CHAR_SLICES]); impl EarlyLintPass for ByteCharSlice { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { - if let Some(slice) = is_byte_char_slices(expr) - && !expr.span.from_expansion() + if !expr.span.from_expansion() + && let Some(slice) = is_byte_char_slices(expr) { span_lint_and_sugg( cx, @@ -47,33 +47,28 @@ impl EarlyLintPass for ByteCharSlice { } } +/// Checks whether the slice is that of byte chars, and if so, builds a byte-string out of it fn is_byte_char_slices(expr: &Expr) -> Option { - if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, expr) = &expr.kind { - match &expr.kind { - ExprKind::Array(members) => { - if members.is_empty() { - return None; - } - - members - .iter() - .map(|member| match &member.kind { - ExprKind::Lit(Lit { - kind: LitKind::Byte, - symbol, - .. - }) => Some(symbol.as_str()), - _ => None, - }) - .map(|maybe_quote| match maybe_quote { - Some("\"") => Some("\\\""), - Some("\\'") => Some("'"), - other => other, - }) - .collect::>() - }, - _ => None, - } + if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, expr) = &expr.kind + && let ExprKind::Array(members) = &expr.kind + && !members.is_empty() + { + members + .iter() + .map(|member| match &member.kind { + ExprKind::Lit(Lit { + kind: LitKind::Byte, + symbol, + .. + }) => Some(symbol.as_str()), + _ => None, + }) + .map(|maybe_quote| match maybe_quote { + Some("\"") => Some("\\\""), + Some("\\'") => Some("'"), + other => other, + }) + .collect::>() } else { None } diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs index a754eea311651..4a350dca2993b 100644 --- a/src/tools/clippy/clippy_lints/src/declared_lints.rs +++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs @@ -118,6 +118,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::doc::DOC_MARKDOWN_INFO, crate::doc::DOC_NESTED_REFDEFS_INFO, crate::doc::DOC_OVERINDENTED_LIST_ITEMS_INFO, + crate::doc::DOC_PARAGRAPHS_MISSING_PUNCTUATION_INFO, crate::doc::DOC_SUSPICIOUS_FOOTNOTES_INFO, crate::doc::EMPTY_DOCS_INFO, crate::doc::MISSING_ERRORS_DOC_INFO, @@ -777,7 +778,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::use_self::USE_SELF_INFO, crate::useless_concat::USELESS_CONCAT_INFO, crate::useless_conversion::USELESS_CONVERSION_INFO, - crate::vec::USELESS_VEC_INFO, + crate::useless_vec::USELESS_VEC_INFO, crate::vec_init_then_push::VEC_INIT_THEN_PUSH_INFO, crate::visibility::NEEDLESS_PUB_SELF_INFO, crate::visibility::PUB_WITHOUT_SHORTHAND_INFO, diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index 548f03c9f2059..32fd4afb122e6 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -12,8 +12,8 @@ use rustc_errors::Applicability; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt, walk_ty}; use rustc_hir::{ - self as hir, AmbigArg, BindingMode, Body, BodyId, BorrowKind, Expr, ExprKind, HirId, MatchSource, Mutability, Node, - Pat, PatKind, Path, QPath, TyKind, UnOp, + self as hir, AmbigArg, BindingMode, Body, BodyId, BorrowKind, Expr, ExprKind, HirId, Item, MatchSource, Mutability, + Node, OwnerId, Pat, PatKind, Path, QPath, TyKind, UnOp, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; @@ -27,6 +27,8 @@ declare_clippy_lint! { /// ### What it does /// Checks for explicit `deref()` or `deref_mut()` method calls. /// + /// Doesn't lint inside the implementation of the `Deref` or `DerefMut` traits. + /// /// ### Why is this bad? /// Dereferencing by `&*x` or `&mut *x` is clearer and more concise, /// when not part of a method chain. @@ -169,6 +171,10 @@ pub struct Dereferencing<'tcx> { /// /// e.g. `m!(x) | Foo::Bar(ref x)` ref_locals: FxIndexMap>, + + /// The outermost `impl Deref` we're currently in. While we're in one, + /// `explicit_deref_methods` is deactivated + outermost_deref_impl: Option, } #[derive(Debug)] @@ -246,7 +252,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { // Stop processing sub expressions when a macro call is seen if expr.span.from_expansion() { if let Some((state, data)) = self.state.take() { - report(cx, expr, state, data, cx.typeck_results()); + self.report(cx, expr, state, data, cx.typeck_results()); } return; } @@ -255,7 +261,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { let Some((kind, sub_expr, skip_expr)) = try_parse_ref_op(cx.tcx, typeck, expr) else { // The whole chain of reference operations has been seen if let Some((state, data)) = self.state.take() { - report(cx, expr, state, data, typeck); + self.report(cx, expr, state, data, typeck); } return; }; @@ -263,7 +269,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { if is_from_proc_macro(cx, expr) { if let Some((state, data)) = self.state.take() { - report(cx, expr, state, data, cx.typeck_results()); + self.report(cx, expr, state, data, cx.typeck_results()); } return; } @@ -515,7 +521,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { (Some((State::DerefedBorrow(state), data)), RefOp::AddrOf(mutability)) => { let adjusted_ty = data.adjusted_ty; let stability = state.stability; - report(cx, expr, State::DerefedBorrow(state), data, typeck); + self.report(cx, expr, State::DerefedBorrow(state), data, typeck); if stability.is_deref_stable() { self.state = Some(( State::Borrow { mutability }, @@ -530,7 +536,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { let adjusted_ty = data.adjusted_ty; let stability = state.stability; let for_field_access = state.for_field_access; - report(cx, expr, State::DerefedBorrow(state), data, typeck); + self.report(cx, expr, State::DerefedBorrow(state), data, typeck); if let Some(name) = for_field_access && let sub_expr_ty = typeck.expr_ty(sub_expr) && !ty_contains_field(sub_expr_ty, name) @@ -602,7 +608,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { )); }, - (Some((state, data)), _) => report(cx, expr, state, data, typeck), + (Some((state, data)), _) => self.report(cx, expr, state, data, typeck), } } @@ -673,6 +679,31 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { self.current_body = None; } } + + fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { + // Only check for `impl Deref(Mut)`s if we're not already in one + if !self.in_deref_impl() && is_deref_or_derefmut_impl(cx, item) { + self.outermost_deref_impl = Some(item.owner_id); + } + } + + fn check_item_post(&mut self, _cx: &LateContext<'_>, item: &Item<'_>) { + // Only clear `self.outermost_deref_impl` if we're escaping the _outermost_ `impl Deref(Mut)` + if self.outermost_deref_impl == Some(item.owner_id) { + self.outermost_deref_impl = None; + } + } +} + +fn is_deref_or_derefmut_impl(cx: &LateContext<'_>, item: &Item<'_>) -> bool { + if let hir::ItemKind::Impl(impl_) = item.kind + && let Some(of_trait) = impl_.of_trait + && let Some(trait_id) = of_trait.trait_ref.trait_def_id() + { + cx.tcx.lang_items().deref_trait() == Some(trait_id) || cx.tcx.lang_items().deref_mut_trait() == Some(trait_id) + } else { + false + } } fn try_parse_ref_op<'tcx>( @@ -930,209 +961,11 @@ fn ty_contains_field(ty: Ty<'_>, name: Symbol) -> bool { } } -#[expect(clippy::needless_pass_by_value, clippy::too_many_lines)] -fn report<'tcx>( - cx: &LateContext<'tcx>, - expr: &'tcx Expr<'_>, - state: State, - data: StateData<'tcx>, - typeck: &'tcx TypeckResults<'tcx>, -) { - match state { - State::DerefMethod { - ty_changed_count, - is_ufcs, - mutbl, - } => { - let mut app = Applicability::MachineApplicable; - let (expr_str, expr_is_macro_call) = - snippet_with_context(cx, expr.span, data.first_expr.span.ctxt(), "..", &mut app); - let ty = typeck.expr_ty(expr); - let (_, ref_count, _) = peel_and_count_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 mutbl == Mutability::Not && matches!(ty.kind(), ty::Ref(_, _, Mutability::Mut)) { - "&*" - } else { - "" - } - } else if mutbl == Mutability::Mut { - "&mut " - } else { - "&" - }; - - let expr_str = if !expr_is_macro_call && is_ufcs && cx.precedence(expr) < ExprPrecedence::Prefix { - Cow::Owned(format!("({expr_str})")) - } else { - expr_str - }; - - span_lint_and_sugg( - cx, - EXPLICIT_DEREF_METHODS, - data.first_expr.span, - match mutbl { - Mutability::Not => "explicit `deref` method call", - Mutability::Mut => "explicit `deref_mut` method call", - }, - "try", - format!("{addr_of_str}{deref_str}{expr_str}"), - app, - ); - }, - State::DerefedBorrow(state) => { - // Do not suggest removing a non-mandatory `&` in `&*rawptr` in an `unsafe` context, - // as this may make rustc trigger its `dangerous_implicit_autorefs` lint. - if let ExprKind::AddrOf(BorrowKind::Ref, _, subexpr) = data.first_expr.kind - && let ExprKind::Unary(UnOp::Deref, subsubexpr) = subexpr.kind - && cx.typeck_results().expr_ty_adjusted(subsubexpr).is_raw_ptr() - { - return; - } - - let mut app = Applicability::MachineApplicable; - let (snip, snip_is_macro) = - snippet_with_context(cx, expr.span, data.first_expr.span.ctxt(), "..", &mut app); - span_lint_hir_and_then( - cx, - NEEDLESS_BORROW, - data.first_expr.hir_id, - data.first_expr.span, - state.msg, - |diag| { - let needs_paren = match cx.tcx.parent_hir_node(data.first_expr.hir_id) { - Node::Expr(e) => match e.kind { - ExprKind::Call(callee, _) if callee.hir_id != data.first_expr.hir_id => false, - ExprKind::Call(..) => { - cx.precedence(expr) < ExprPrecedence::Unambiguous - || matches!(expr.kind, ExprKind::Field(..)) - }, - _ => cx.precedence(expr) < cx.precedence(e), - }, - _ => false, - }; - let is_in_tuple = matches!( - get_parent_expr(cx, data.first_expr), - Some(Expr { - kind: ExprKind::Tup(..), - .. - }) - ); - - let sugg = if !snip_is_macro && needs_paren && !has_enclosing_paren(&snip) && !is_in_tuple { - format!("({snip})") - } else { - snip.into() - }; - diag.span_suggestion(data.first_expr.span, "change this to", sugg, app); - }, - ); - }, - State::ExplicitDeref { mutability } => { - if is_block_like(expr) - && let ty::Ref(_, ty, _) = data.adjusted_ty.kind() - && ty.is_sized(cx.tcx, cx.typing_env()) - { - // Rustc bug: auto deref doesn't work on block expression when targeting sized types. - return; - } - - let ty = typeck.expr_ty(expr); - - // `&&[T; N]`, or `&&..&[T; N]` (src) cannot coerce to `&[T]` (dst). - if let ty::Ref(_, dst, _) = data.adjusted_ty.kind() - && dst.is_slice() - { - let (src, n_src_refs, _) = peel_and_count_ty_refs(ty); - if n_src_refs >= 2 && src.is_array() { - return; - } - } - - let (prefix, needs_paren) = match mutability { - Some(mutability) if !ty.is_ref() => { - let prefix = match mutability { - Mutability::Not => "&", - Mutability::Mut => "&mut ", - }; - (prefix, cx.precedence(expr) < ExprPrecedence::Prefix) - }, - None if !ty.is_ref() && data.adjusted_ty.is_ref() => ("&", false), - _ => ("", false), - }; - span_lint_hir_and_then( - cx, - EXPLICIT_AUTO_DEREF, - data.first_expr.hir_id, - data.first_expr.span, - "deref which would be done by auto-deref", - |diag| { - let mut app = Applicability::MachineApplicable; - let (snip, snip_is_macro) = - snippet_with_context(cx, expr.span, data.first_expr.span.ctxt(), "..", &mut app); - let sugg = if !snip_is_macro && needs_paren && !has_enclosing_paren(&snip) { - format!("{prefix}({snip})") - } else { - format!("{prefix}{snip}") - }; - diag.span_suggestion(data.first_expr.span, "try", sugg, app); - }, - ); - }, - State::ExplicitDerefField { - derefs_manually_drop, .. - } => { - let (snip_span, needs_parens) = if matches!(expr.kind, ExprKind::Field(..)) - && (derefs_manually_drop - || adjust_derefs_manually_drop( - typeck.expr_adjustments(data.first_expr), - typeck.expr_ty(data.first_expr), - )) { - // `DerefMut` will not be automatically applied to `ManuallyDrop<_>` - // field expressions when the base type is a union and the parent - // expression is also a field access. - // - // e.g. `&mut x.y.z` where `x` is a union, and accessing `z` requires a - // deref through `ManuallyDrop<_>` will not compile. - let parent_id = cx.tcx.parent_hir_id(expr.hir_id); - if parent_id == data.first_expr.hir_id { - return; - } - (cx.tcx.hir_node(parent_id).expect_expr().span, true) - } else { - (expr.span, false) - }; - span_lint_hir_and_then( - cx, - EXPLICIT_AUTO_DEREF, - data.first_expr.hir_id, - data.first_expr.span, - "deref which would be done by auto-deref", - |diag| { - let mut app = Applicability::MachineApplicable; - let snip = snippet_with_context(cx, snip_span, data.first_expr.span.ctxt(), "..", &mut app).0; - let sugg = if needs_parens { - format!("({snip})") - } else { - snip.into_owned() - }; - diag.span_suggestion(data.first_expr.span, "try", sugg, app); - }, - ); - }, - State::Borrow { .. } | State::Reborrow { .. } => (), +impl<'tcx> Dereferencing<'tcx> { + fn in_deref_impl(&self) -> bool { + self.outermost_deref_impl.is_some() } -} -impl<'tcx> Dereferencing<'tcx> { fn check_local_usage(&mut self, cx: &LateContext<'tcx>, e: &Expr<'tcx>, local: HirId) { if let Some(outer_pat) = self.ref_locals.get_mut(&local) && let Some(pat) = outer_pat @@ -1191,4 +1024,211 @@ impl<'tcx> Dereferencing<'tcx> { } } } + + #[expect(clippy::needless_pass_by_value, clippy::too_many_lines)] + fn report( + &self, + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + state: State, + data: StateData<'tcx>, + typeck: &'tcx TypeckResults<'tcx>, + ) { + match state { + State::DerefMethod { + ty_changed_count, + is_ufcs, + mutbl, + } => { + if self.in_deref_impl() { + // `deref(_mut)` is fine in an `impl Deref(Mut)` + return; + } + let mut app = Applicability::MachineApplicable; + let (expr_str, expr_is_macro_call) = + snippet_with_context(cx, expr.span, data.first_expr.span.ctxt(), "..", &mut app); + let ty = typeck.expr_ty(expr); + let (_, ref_count, _) = peel_and_count_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 mutbl == Mutability::Not && matches!(ty.kind(), ty::Ref(_, _, Mutability::Mut)) { + "&*" + } else { + "" + } + } else if mutbl == Mutability::Mut { + "&mut " + } else { + "&" + }; + + let expr_str = if !expr_is_macro_call && is_ufcs && cx.precedence(expr) < ExprPrecedence::Prefix { + Cow::Owned(format!("({expr_str})")) + } else { + expr_str + }; + + span_lint_and_sugg( + cx, + EXPLICIT_DEREF_METHODS, + data.first_expr.span, + match mutbl { + Mutability::Not => "explicit `deref` method call", + Mutability::Mut => "explicit `deref_mut` method call", + }, + "try", + format!("{addr_of_str}{deref_str}{expr_str}"), + app, + ); + }, + State::DerefedBorrow(state) => { + // Do not suggest removing a non-mandatory `&` in `&*rawptr` in an `unsafe` context, + // as this may make rustc trigger its `dangerous_implicit_autorefs` lint. + if let ExprKind::AddrOf(BorrowKind::Ref, _, subexpr) = data.first_expr.kind + && let ExprKind::Unary(UnOp::Deref, subsubexpr) = subexpr.kind + && cx.typeck_results().expr_ty_adjusted(subsubexpr).is_raw_ptr() + { + return; + } + + let mut app = Applicability::MachineApplicable; + let (snip, snip_is_macro) = + snippet_with_context(cx, expr.span, data.first_expr.span.ctxt(), "..", &mut app); + span_lint_hir_and_then( + cx, + NEEDLESS_BORROW, + data.first_expr.hir_id, + data.first_expr.span, + state.msg, + |diag| { + let needs_paren = match cx.tcx.parent_hir_node(data.first_expr.hir_id) { + Node::Expr(e) => match e.kind { + ExprKind::Call(callee, _) if callee.hir_id != data.first_expr.hir_id => false, + ExprKind::Call(..) => { + cx.precedence(expr) < ExprPrecedence::Unambiguous + || matches!(expr.kind, ExprKind::Field(..)) + }, + _ => cx.precedence(expr) < cx.precedence(e), + }, + _ => false, + }; + let is_in_tuple = matches!( + get_parent_expr(cx, data.first_expr), + Some(Expr { + kind: ExprKind::Tup(..), + .. + }) + ); + + let sugg = if !snip_is_macro && needs_paren && !has_enclosing_paren(&snip) && !is_in_tuple { + format!("({snip})") + } else { + snip.into() + }; + diag.span_suggestion(data.first_expr.span, "change this to", sugg, app); + }, + ); + }, + State::ExplicitDeref { mutability } => { + if is_block_like(expr) + && let ty::Ref(_, ty, _) = data.adjusted_ty.kind() + && ty.is_sized(cx.tcx, cx.typing_env()) + { + // Rustc bug: auto deref doesn't work on block expression when targeting sized types. + return; + } + + let ty = typeck.expr_ty(expr); + + // `&&[T; N]`, or `&&..&[T; N]` (src) cannot coerce to `&[T]` (dst). + if let ty::Ref(_, dst, _) = data.adjusted_ty.kind() + && dst.is_slice() + { + let (src, n_src_refs, _) = peel_and_count_ty_refs(ty); + if n_src_refs >= 2 && src.is_array() { + return; + } + } + + let (prefix, needs_paren) = match mutability { + Some(mutability) if !ty.is_ref() => { + let prefix = match mutability { + Mutability::Not => "&", + Mutability::Mut => "&mut ", + }; + (prefix, cx.precedence(expr) < ExprPrecedence::Prefix) + }, + None if !ty.is_ref() && data.adjusted_ty.is_ref() => ("&", false), + _ => ("", false), + }; + span_lint_hir_and_then( + cx, + EXPLICIT_AUTO_DEREF, + data.first_expr.hir_id, + data.first_expr.span, + "deref which would be done by auto-deref", + |diag| { + let mut app = Applicability::MachineApplicable; + let (snip, snip_is_macro) = + snippet_with_context(cx, expr.span, data.first_expr.span.ctxt(), "..", &mut app); + let sugg = if !snip_is_macro && needs_paren && !has_enclosing_paren(&snip) { + format!("{prefix}({snip})") + } else { + format!("{prefix}{snip}") + }; + diag.span_suggestion(data.first_expr.span, "try", sugg, app); + }, + ); + }, + State::ExplicitDerefField { + derefs_manually_drop, .. + } => { + let (snip_span, needs_parens) = if matches!(expr.kind, ExprKind::Field(..)) + && (derefs_manually_drop + || adjust_derefs_manually_drop( + typeck.expr_adjustments(data.first_expr), + typeck.expr_ty(data.first_expr), + )) { + // `DerefMut` will not be automatically applied to `ManuallyDrop<_>` + // field expressions when the base type is a union and the parent + // expression is also a field access. + // + // e.g. `&mut x.y.z` where `x` is a union, and accessing `z` requires a + // deref through `ManuallyDrop<_>` will not compile. + let parent_id = cx.tcx.parent_hir_id(expr.hir_id); + if parent_id == data.first_expr.hir_id { + return; + } + (cx.tcx.hir_node(parent_id).expect_expr().span, true) + } else { + (expr.span, false) + }; + span_lint_hir_and_then( + cx, + EXPLICIT_AUTO_DEREF, + data.first_expr.hir_id, + data.first_expr.span, + "deref which would be done by auto-deref", + |diag| { + let mut app = Applicability::MachineApplicable; + let snip = snippet_with_context(cx, snip_span, data.first_expr.span.ctxt(), "..", &mut app).0; + let sugg = if needs_parens { + format!("({snip})") + } else { + snip.into_owned() + }; + diag.span_suggestion(data.first_expr.span, "try", sugg, app); + }, + ); + }, + State::Borrow { .. } | State::Reborrow { .. } => (), + } + } } diff --git a/src/tools/clippy/clippy_lints/src/doc/doc_paragraphs_missing_punctuation.rs b/src/tools/clippy/clippy_lints/src/doc/doc_paragraphs_missing_punctuation.rs new file mode 100644 index 0000000000000..a8f7346376728 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/doc/doc_paragraphs_missing_punctuation.rs @@ -0,0 +1,126 @@ +use rustc_errors::Applicability; +use rustc_lint::LateContext; +use rustc_resolve::rustdoc::main_body_opts; + +use rustc_resolve::rustdoc::pulldown_cmark::{Event, Options, Parser, Tag, TagEnd}; + +use super::{DOC_PARAGRAPHS_MISSING_PUNCTUATION, Fragments}; + +const MSG: &str = "doc paragraphs should end with a terminal punctuation mark"; +const PUNCTUATION_SUGGESTION: char = '.'; + +pub fn check(cx: &LateContext<'_>, doc: &str, fragments: Fragments<'_>) { + for missing_punctuation in is_missing_punctuation(doc) { + match missing_punctuation { + MissingPunctuation::Fixable(offset) => { + // This ignores `#[doc]` attributes, which we do not handle. + if let Some(span) = fragments.span(cx, offset..offset) { + clippy_utils::diagnostics::span_lint_and_sugg( + cx, + DOC_PARAGRAPHS_MISSING_PUNCTUATION, + span, + MSG, + "end the paragraph with some punctuation", + PUNCTUATION_SUGGESTION.to_string(), + Applicability::MaybeIncorrect, + ); + } + }, + MissingPunctuation::Unfixable(offset) => { + // This ignores `#[doc]` attributes, which we do not handle. + if let Some(span) = fragments.span(cx, offset..offset) { + clippy_utils::diagnostics::span_lint_and_help( + cx, + DOC_PARAGRAPHS_MISSING_PUNCTUATION, + span, + MSG, + None, + "end the paragraph with some punctuation", + ); + } + }, + } + } +} + +#[must_use] +/// If punctuation is missing, returns the offset where new punctuation should be inserted. +fn is_missing_punctuation(doc_string: &str) -> Vec { + // The colon is not exactly a terminal punctuation mark, but this is required for paragraphs that + // introduce a table or a list for example. + const TERMINAL_PUNCTUATION_MARKS: &[char] = &['.', '?', '!', '…', ':']; + + let mut no_report_depth = 0; + let mut missing_punctuation = Vec::new(); + let mut current_paragraph = None; + + for (event, offset) in + Parser::new_ext(doc_string, main_body_opts() - Options::ENABLE_SMART_PUNCTUATION).into_offset_iter() + { + match event { + Event::Start( + Tag::CodeBlock(..) + | Tag::FootnoteDefinition(_) + | Tag::Heading { .. } + | Tag::HtmlBlock + | Tag::List(..) + | Tag::Table(_), + ) => { + no_report_depth += 1; + }, + Event::End(TagEnd::FootnoteDefinition) => { + no_report_depth -= 1; + }, + Event::End( + TagEnd::CodeBlock | TagEnd::Heading(_) | TagEnd::HtmlBlock | TagEnd::List(_) | TagEnd::Table, + ) => { + no_report_depth -= 1; + current_paragraph = None; + }, + Event::InlineHtml(_) | Event::Start(Tag::Image { .. }) | Event::End(TagEnd::Image) => { + current_paragraph = None; + }, + Event::End(TagEnd::Paragraph) => { + if let Some(mp) = current_paragraph { + missing_punctuation.push(mp); + } + }, + Event::Code(..) | Event::Start(Tag::Link { .. }) | Event::End(TagEnd::Link) + if no_report_depth == 0 && !offset.is_empty() => + { + if doc_string[..offset.end] + .trim_end() + .ends_with(TERMINAL_PUNCTUATION_MARKS) + { + current_paragraph = None; + } else { + current_paragraph = Some(MissingPunctuation::Fixable(offset.end)); + } + }, + Event::Text(..) if no_report_depth == 0 && !offset.is_empty() => { + let trimmed = doc_string[..offset.end].trim_end(); + if trimmed.ends_with(TERMINAL_PUNCTUATION_MARKS) { + current_paragraph = None; + } else if let Some(t) = trimmed.strip_suffix(|c| c == ')' || c == '"') { + if t.ends_with(TERMINAL_PUNCTUATION_MARKS) { + // Avoid false positives. + current_paragraph = None; + } else { + current_paragraph = Some(MissingPunctuation::Unfixable(offset.end)); + } + } else { + current_paragraph = Some(MissingPunctuation::Fixable(offset.end)); + } + }, + _ => {}, + } + } + + missing_punctuation +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +enum MissingPunctuation { + Fixable(usize), + Unfixable(usize), +} diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs index 1e1d6e69cc91c..120da92da9442 100644 --- a/src/tools/clippy/clippy_lints/src/doc/mod.rs +++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs @@ -27,6 +27,7 @@ use url::Url; mod broken_link; mod doc_comment_double_space_linebreaks; +mod doc_paragraphs_missing_punctuation; mod doc_suspicious_footnotes; mod include_in_doc_without_cfg; mod lazy_continuation; @@ -670,6 +671,33 @@ declare_clippy_lint! { "looks like a link or footnote ref, but with no definition" } +declare_clippy_lint! { + /// ### What it does + /// Checks for doc comments whose paragraphs do not end with a period or another punctuation mark. + /// Various Markdowns constructs are taken into account to avoid false positives. + /// + /// ### Why is this bad? + /// A project may wish to enforce consistent doc comments by making sure paragraphs end with a + /// punctuation mark. + /// + /// ### Example + /// ```no_run + /// /// Returns a random number + /// /// + /// /// It was chosen by a fair dice roll + /// ``` + /// Use instead: + /// ```no_run + /// /// Returns a random number. + /// /// + /// /// It was chosen by a fair dice roll. + /// ``` + #[clippy::version = "1.93.0"] + pub DOC_PARAGRAPHS_MISSING_PUNCTUATION, + restriction, + "missing terminal punctuation in doc comments" +} + pub struct Documentation { valid_idents: FxHashSet, check_private_items: bool, @@ -704,6 +732,7 @@ impl_lint_pass!(Documentation => [ DOC_INCLUDE_WITHOUT_CFG, DOC_COMMENT_DOUBLE_SPACE_LINEBREAKS, DOC_SUSPICIOUS_FOOTNOTES, + DOC_PARAGRAPHS_MISSING_PUNCTUATION, ]); impl EarlyLintPass for Documentation { @@ -875,6 +904,15 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet, attrs: &[ }, ); + doc_paragraphs_missing_punctuation::check( + cx, + &doc, + Fragments { + doc: &doc, + fragments: &fragments, + }, + ); + // NOTE: check_doc uses it own cb function, // to avoid causing duplicated diagnostics for the broken link checker. let mut full_fake_broken_link_callback = |bl: BrokenLink<'_>| -> Option<(CowStr<'_>, CowStr<'_>)> { diff --git a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs index 9b5cd7e1731f3..a92bfd45df0ce 100644 --- a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs +++ b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs @@ -1,4 +1,5 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::is_in_const_context; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::implements_trait; use rustc_errors::Applicability; @@ -40,9 +41,9 @@ declare_clippy_lint! { declare_lint_pass!(PatternEquality => [EQUATABLE_IF_LET]); /// detects if pattern matches just one thing -fn unary_pattern(pat: &Pat<'_>) -> bool { +fn is_unary_pattern(pat: &Pat<'_>) -> bool { fn array_rec(pats: &[Pat<'_>]) -> bool { - pats.iter().all(unary_pattern) + pats.iter().all(is_unary_pattern) } match &pat.kind { PatKind::Missing => unreachable!(), @@ -53,9 +54,9 @@ fn unary_pattern(pat: &Pat<'_>) -> bool { | PatKind::Never | PatKind::Or(_) | PatKind::Err(_) => false, - PatKind::Struct(_, a, etc) => etc.is_none() && a.iter().all(|x| unary_pattern(x.pat)), + PatKind::Struct(_, a, etc) => etc.is_none() && a.iter().all(|x| is_unary_pattern(x.pat)), PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => etc.as_opt_usize().is_none() && array_rec(a), - PatKind::Ref(x, _, _) | PatKind::Box(x) | PatKind::Deref(x) | PatKind::Guard(x, _) => unary_pattern(x), + PatKind::Ref(x, _, _) | PatKind::Box(x) | PatKind::Deref(x) | PatKind::Guard(x, _) => is_unary_pattern(x), PatKind::Expr(_) => true, } } @@ -103,48 +104,63 @@ fn contains_type_mismatch(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { impl<'tcx> LateLintPass<'tcx> for PatternEquality { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if let ExprKind::Let(let_expr) = expr.kind - && unary_pattern(let_expr.pat) + && is_unary_pattern(let_expr.pat) && !expr.span.in_external_macro(cx.sess().source_map()) + && !let_expr.pat.span.from_expansion() + && !let_expr.init.span.from_expansion() { let exp_ty = cx.typeck_results().expr_ty(let_expr.init); let pat_ty = cx.typeck_results().pat_ty(let_expr.pat); - let mut applicability = Applicability::MachineApplicable; - if is_structural_partial_eq(cx, exp_ty, pat_ty) && !contains_type_mismatch(cx, let_expr.pat) { - let pat_str = match let_expr.pat.kind { - PatKind::Struct(..) => format!( - "({})", - snippet_with_context(cx, let_expr.pat.span, expr.span.ctxt(), "..", &mut applicability).0, - ), - _ => snippet_with_context(cx, let_expr.pat.span, expr.span.ctxt(), "..", &mut applicability) - .0 - .to_string(), - }; - span_lint_and_sugg( + let mut app = Applicability::MachineApplicable; + let ctxt = expr.span.ctxt(); + + if is_structural_partial_eq(cx, exp_ty, pat_ty) + && !contains_type_mismatch(cx, let_expr.pat) + // Calls to trait methods (`PartialEq::eq` in this case) aren't stable yet. We could _technically_ + // try looking at whether: + // 1) features `const_trait_impl` and `const_cmp` are enabled + // 2) implementation of `PartialEq for ExpTy` has `fn eq` that is `const` + // + // but that didn't quite work out (see #15482), so we just reject outright in this case + && !is_in_const_context(cx) + { + span_lint_and_then( cx, EQUATABLE_IF_LET, expr.span, "this pattern matching can be expressed using equality", - "try", - format!( - "{} == {pat_str}", - snippet_with_context(cx, let_expr.init.span, expr.span.ctxt(), "..", &mut applicability).0, - ), - applicability, + |diag| { + let pat_str = { + let str = snippet_with_context(cx, let_expr.pat.span, ctxt, "..", &mut app).0; + if let PatKind::Struct(..) = let_expr.pat.kind { + format!("({str})").into() + } else { + str + } + }; + + let sugg = format!( + "{} == {pat_str}", + snippet_with_context(cx, let_expr.init.span, ctxt, "..", &mut app).0, + ); + diag.span_suggestion(expr.span, "try", sugg, app); + }, ); } else { - span_lint_and_sugg( + span_lint_and_then( cx, EQUATABLE_IF_LET, expr.span, "this pattern matching can be expressed using `matches!`", - "try", - format!( - "matches!({}, {})", - snippet_with_context(cx, let_expr.init.span, expr.span.ctxt(), "..", &mut applicability).0, - snippet_with_context(cx, let_expr.pat.span, expr.span.ctxt(), "..", &mut applicability).0, - ), - applicability, + |diag| { + let sugg = format!( + "matches!({}, {})", + snippet_with_context(cx, let_expr.init.span, ctxt, "..", &mut app).0, + snippet_with_context(cx, let_expr.pat.span, ctxt, "..", &mut app).0, + ); + diag.span_suggestion(expr.span, "try", sugg, app); + }, ); } } diff --git a/src/tools/clippy/clippy_lints/src/functions/mod.rs b/src/tools/clippy/clippy_lints/src/functions/mod.rs index 5a40af4219426..bdc366f6878a0 100644 --- a/src/tools/clippy/clippy_lints/src/functions/mod.rs +++ b/src/tools/clippy/clippy_lints/src/functions/mod.rs @@ -485,6 +485,7 @@ pub struct Functions { too_many_arguments_threshold: u64, too_many_lines_threshold: u64, large_error_threshold: u64, + large_error_ignored: DefIdSet, avoid_breaking_exported_api: bool, /// A set of resolved `def_id` of traits that are configured to allow /// function params renaming. @@ -498,6 +499,11 @@ impl Functions { too_many_arguments_threshold: conf.too_many_arguments_threshold, too_many_lines_threshold: conf.too_many_lines_threshold, large_error_threshold: conf.large_error_threshold, + large_error_ignored: conf + .large_error_ignored + .iter() + .flat_map(|ignored_ty| lookup_path_str(tcx, PathNS::Type, ignored_ty)) + .collect(), avoid_breaking_exported_api: conf.avoid_breaking_exported_api, trait_ids: conf .allow_renamed_params_for @@ -554,12 +560,24 @@ impl<'tcx> LateLintPass<'tcx> for Functions { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { must_use::check_item(cx, item); - result::check_item(cx, item, self.large_error_threshold, self.msrv); + result::check_item( + cx, + item, + self.large_error_threshold, + &self.large_error_ignored, + self.msrv, + ); } fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) { must_use::check_impl_item(cx, item); - result::check_impl_item(cx, item, self.large_error_threshold, self.msrv); + result::check_impl_item( + cx, + item, + self.large_error_threshold, + &self.large_error_ignored, + self.msrv, + ); impl_trait_in_params::check_impl_item(cx, item); renamed_function_params::check_impl_item(cx, item, &self.trait_ids); } @@ -568,7 +586,13 @@ impl<'tcx> LateLintPass<'tcx> for Functions { too_many_arguments::check_trait_item(cx, item, self.too_many_arguments_threshold); not_unsafe_ptr_arg_deref::check_trait_item(cx, item); must_use::check_trait_item(cx, item); - result::check_trait_item(cx, item, self.large_error_threshold, self.msrv); + result::check_trait_item( + cx, + item, + self.large_error_threshold, + &self.large_error_ignored, + self.msrv, + ); impl_trait_in_params::check_trait_item(cx, item, self.avoid_breaking_exported_api); ref_option::check_trait_item(cx, item, self.avoid_breaking_exported_api); } diff --git a/src/tools/clippy/clippy_lints/src/functions/result.rs b/src/tools/clippy/clippy_lints/src/functions/result.rs index fb80cc1a63a30..04e15a1d8a0e9 100644 --- a/src/tools/clippy/clippy_lints/src/functions/result.rs +++ b/src/tools/clippy/clippy_lints/src/functions/result.rs @@ -4,6 +4,7 @@ use rustc_errors::Diag; use rustc_hir as hir; use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty::{self, Ty}; +use rustc_span::def_id::DefIdSet; use rustc_span::{Span, sym}; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; @@ -35,7 +36,13 @@ fn result_err_ty<'tcx>( } } -pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::Item<'tcx>, large_err_threshold: u64, msrv: Msrv) { +pub(super) fn check_item<'tcx>( + cx: &LateContext<'tcx>, + item: &hir::Item<'tcx>, + large_err_threshold: u64, + large_err_ignored: &DefIdSet, + msrv: Msrv, +) { if let hir::ItemKind::Fn { ref sig, .. } = item.kind && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.owner_id.def_id, item.span) { @@ -43,7 +50,7 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::Item<'tcx>, l let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); check_result_unit_err(cx, err_ty, fn_header_span, msrv); } - check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold); + check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold, large_err_ignored); } } @@ -51,6 +58,7 @@ pub(super) fn check_impl_item<'tcx>( cx: &LateContext<'tcx>, item: &hir::ImplItem<'tcx>, large_err_threshold: u64, + large_err_ignored: &DefIdSet, msrv: Msrv, ) { // Don't lint if method is a trait's implementation, we can't do anything about those @@ -62,7 +70,7 @@ pub(super) fn check_impl_item<'tcx>( let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); check_result_unit_err(cx, err_ty, fn_header_span, msrv); } - check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold); + check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold, large_err_ignored); } } @@ -70,6 +78,7 @@ pub(super) fn check_trait_item<'tcx>( cx: &LateContext<'tcx>, item: &hir::TraitItem<'tcx>, large_err_threshold: u64, + large_err_ignored: &DefIdSet, msrv: Msrv, ) { if let hir::TraitItemKind::Fn(ref sig, _) = item.kind { @@ -78,7 +87,7 @@ pub(super) fn check_trait_item<'tcx>( if cx.effective_visibilities.is_exported(item.owner_id.def_id) { check_result_unit_err(cx, err_ty, fn_header_span, msrv); } - check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold); + check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold, large_err_ignored); } } } @@ -96,7 +105,18 @@ fn check_result_unit_err(cx: &LateContext<'_>, err_ty: Ty<'_>, fn_header_span: S } } -fn check_result_large_err<'tcx>(cx: &LateContext<'tcx>, err_ty: Ty<'tcx>, hir_ty_span: Span, large_err_threshold: u64) { +fn check_result_large_err<'tcx>( + cx: &LateContext<'tcx>, + err_ty: Ty<'tcx>, + hir_ty_span: Span, + large_err_threshold: u64, + large_err_ignored: &DefIdSet, +) { + if let ty::Adt(adt, _) = err_ty.kind() + && large_err_ignored.contains(&adt.did()) + { + return; + } if let ty::Adt(adt, subst) = err_ty.kind() && let Some(local_def_id) = adt.did().as_local() && let hir::Node::Item(item) = cx.tcx.hir_node_by_def_id(local_def_id) diff --git a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs index d2bc0b6d99354..638a08b096db7 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs @@ -13,7 +13,7 @@ use rustc_session::declare_lint_pass; use rustc_span::Span; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{IntoSpan, SpanRangeExt, snippet}; +use clippy_utils::source::{IntoSpan, SpanRangeExt, snippet, snippet_with_context}; use clippy_utils::sym; declare_clippy_lint! { @@ -335,29 +335,29 @@ impl<'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'_, '_, 'tcx> { return; } - match (self.cx.tcx.get_diagnostic_name(ty_did), method.ident.name) { - (Some(sym::HashMap), sym::new) => { - self.suggestions.insert(e.span, "HashMap::default()".to_string()); + let container_name = match self.cx.tcx.get_diagnostic_name(ty_did) { + Some(sym::HashMap) => "HashMap", + Some(sym::HashSet) => "HashSet", + _ => return, + }; + + match method.ident.name { + sym::new => { + self.suggestions.insert(e.span, format!("{container_name}::default()")); }, - (Some(sym::HashMap), sym::with_capacity) => { - self.suggestions.insert( - e.span, - format!( - "HashMap::with_capacity_and_hasher({}, Default::default())", - snippet(self.cx, args[0].span, "capacity"), - ), + sym::with_capacity => { + let (arg_snippet, _) = snippet_with_context( + self.cx, + args[0].span, + e.span.ctxt(), + "..", + // We can throw-away the applicability here since the whole suggestion is + // marked as `MaybeIncorrect` later. + &mut Applicability::MaybeIncorrect, ); - }, - (Some(sym::HashSet), sym::new) => { - self.suggestions.insert(e.span, "HashSet::default()".to_string()); - }, - (Some(sym::HashSet), sym::with_capacity) => { self.suggestions.insert( e.span, - format!( - "HashSet::with_capacity_and_hasher({}, Default::default())", - snippet(self.cx, args[0].span, "capacity"), - ), + format!("{container_name}::with_capacity_and_hasher({arg_snippet}, Default::default())",), ); }, _ => {}, diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 4542105d3277a..230d83dacc959 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -386,7 +386,7 @@ mod upper_case_acronyms; mod use_self; mod useless_concat; mod useless_conversion; -mod vec; +mod useless_vec; mod vec_init_then_push; mod visibility; mod volatile_composites; @@ -592,7 +592,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co Box::new(move |_| Box::new(transmute::Transmute::new(conf))), Box::new(move |_| Box::new(cognitive_complexity::CognitiveComplexity::new(conf))), Box::new(move |_| Box::new(escape::BoxedLocal::new(conf))), - Box::new(move |_| Box::new(vec::UselessVec::new(conf))), + Box::new(move |_| Box::new(useless_vec::UselessVec::new(conf))), Box::new(move |_| Box::new(panic_unimplemented::PanicUnimplemented::new(conf))), Box::new(|_| Box::new(strings::StringLitAsBytes)), Box::new(|_| Box::new(derive::Derive)), diff --git a/src/tools/clippy/clippy_lints/src/methods/sliced_string_as_bytes.rs b/src/tools/clippy/clippy_lints/src/methods/sliced_string_as_bytes.rs index 4aff194923a6c..fb124f3605b94 100644 --- a/src/tools/clippy/clippy_lints/src/methods/sliced_string_as_bytes.rs +++ b/src/tools/clippy/clippy_lints/src/methods/sliced_string_as_bytes.rs @@ -1,15 +1,21 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::higher; use clippy_utils::res::MaybeDef; use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, LangItem, is_range_literal}; +use rustc_hir::{Expr, ExprKind, LangItem}; use rustc_lint::LateContext; use super::SLICED_STRING_AS_BYTES; +/// Checks if `index` is any type of range except `RangeFull` (i.e. `..`) +fn is_bounded_range_literal(cx: &LateContext<'_>, index: &Expr<'_>) -> bool { + higher::Range::hir(cx, index).is_some_and(|range| Option::or(range.start, range.end).is_some()) +} + pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>) { if let ExprKind::Index(indexed, index, _) = recv.kind - && is_range_literal(index) + && is_bounded_range_literal(cx, index) && let ty = cx.typeck_results().expr_ty(indexed).peel_refs() && (ty.is_str() || ty.is_lang_item(cx, LangItem::String)) { 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 972304d79e751..f852080d0f2a0 100644 --- a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs +++ b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs @@ -4,7 +4,8 @@ use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{implements_trait, peel_and_count_ty_refs, should_call_clone_as_function}; use clippy_utils::{get_parent_expr, peel_blocks, strip_pat_refs}; use rustc_errors::Applicability; -use rustc_hir::{self as hir, LangItem}; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::{self as hir, LangItem, Node}; use rustc_lint::LateContext; use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::{Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor}; @@ -69,14 +70,37 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: Symbo } } + // Add `*` derefs if the expr is used in a ctor, because automatic derefs don't apply in that case. + let deref = if rcv_depth > res_depth { + let parent = cx.tcx.parent_hir_node(expr.hir_id); + match parent { + Node::ExprField(_) => "*".repeat(rcv_depth - res_depth), + Node::Expr(parent) + if let hir::ExprKind::Call(func, _) = parent.kind + && let (_, Some(path)) = func.opt_res_path() + && matches!(path.res, Res::Def(DefKind::Ctor(_, _), _) | Res::SelfCtor(_)) => + { + "*".repeat(rcv_depth - res_depth) + }, + _ => String::new(), + } + } else { + String::new() + }; + let mut applicability = Applicability::MachineApplicable; + let suggestion = format!( + "{deref}{}", + snippet_with_applicability(cx, recvr.span, "..", &mut applicability) + ); + span_lint_and_sugg( cx, USELESS_ASREF, expr.span, format!("this call to `{call_name}` does nothing"), "try", - snippet_with_applicability(cx, recvr.span, "..", &mut applicability).to_string(), + suggestion, applicability, ); } diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs index 1c62caa1c8274..ac221743cfd64 100644 --- a/src/tools/clippy/clippy_lints/src/missing_doc.rs +++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs @@ -1,26 +1,18 @@ -// Note: More specifically this lint is largely inspired (aka copied) from -// *rustc*'s -// [`missing_doc`]. -// -// [`missing_doc`]: https://github.com/rust-lang/rust/blob/cf9cf7c923eb01146971429044f216a3ca905e06/compiler/rustc_lint/src/builtin.rs#L415 -// - use clippy_config::Conf; -use clippy_utils::attrs::is_doc_hidden; use clippy_utils::diagnostics::span_lint; -use clippy_utils::is_from_proc_macro; -use clippy_utils::source::SpanRangeExt; -use rustc_ast::ast::MetaItemInner; -use rustc_hir as hir; -use rustc_hir::Attribute; -use rustc_hir::def::DefKind; +use clippy_utils::{is_doc_hidden, is_from_proc_macro}; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def_id::LocalDefId; -use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::ty::{AssocContainer, Visibility}; +use rustc_hir::{ + AttrArgs, Attribute, Body, BodyId, FieldDef, HirId, ImplItem, Item, ItemKind, Node, TraitItem, Variant, +}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::middle::privacy::Level; +use rustc_middle::ty::Visibility; use rustc_session::impl_lint_pass; use rustc_span::def_id::CRATE_DEF_ID; +use rustc_span::sym; use rustc_span::symbol::kw; -use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does @@ -37,24 +29,27 @@ declare_clippy_lint! { "detects missing documentation for private members" } -macro_rules! note_prev_span_then_ret { - ($prev_span:expr, $span:expr) => {{ - $prev_span = Some($span); - return; - }}; -} - pub struct MissingDoc { /// Whether to **only** check for missing documentation in items visible within the current /// crate. For example, `pub(crate)` items. crate_items_only: bool, /// Whether to allow fields starting with an underscore to skip documentation requirements allow_unused: bool, - /// Stack of whether #[doc(hidden)] is set - /// at each level which has lint attributes. - doc_hidden_stack: Vec, - /// Used to keep tracking of the previous item, field or variants etc, to get the search span. - prev_span: Option, + /// The current number of modules since the crate root. + module_depth: u32, + macro_module_depth: u32, + /// The current level of the attribute stack. + attr_depth: u32, + /// What `attr_depth` level the first `doc(hidden)` attribute was seen. This is zero if the + /// attribute hasn't been seen. + doc_hidden_depth: u32, + /// What `attr_depth` level the first `automatically_derived` attribute was seen. This is zero + /// if the attribute hasn't been seen. + automatically_derived_depth: u32, + /// The id of the first body we've seen. + in_body: Option, + /// The module/crate id an item must be visible at to be linted. + require_visibility_at: Option, } impl MissingDoc { @@ -62,225 +57,241 @@ impl MissingDoc { Self { crate_items_only: conf.missing_docs_in_crate_items, allow_unused: conf.missing_docs_allow_unused, - doc_hidden_stack: vec![false], - prev_span: None, + module_depth: 0, + macro_module_depth: 0, + attr_depth: 0, + doc_hidden_depth: 0, + automatically_derived_depth: 0, + in_body: None, + require_visibility_at: None, } } - fn doc_hidden(&self) -> bool { - *self.doc_hidden_stack.last().expect("empty doc_hidden_stack") - } + fn is_missing_docs(&self, cx: &LateContext<'_>, def_id: LocalDefId, hir_id: HirId) -> bool { + if cx.tcx.sess.opts.test { + return false; + } - fn has_include(meta: Option<&[MetaItemInner]>) -> bool { - if let Some(list) = meta - && let Some(meta) = list.first() - && let Some(name) = meta.ident() - { - name.name == sym::include - } else { - false + match cx.effective_visibilities.effective_vis(def_id) { + None if self.require_visibility_at.is_some() => return false, + None if self.crate_items_only && self.module_depth != 0 => return false, + // `missing_docs` lint uses `Reexported` because rustdoc doesn't render documentation + // for items without a reachable path. + Some(vis) if vis.is_public_at_level(Level::Reexported) => return false, + Some(vis) => { + if self.crate_items_only { + // Use the `Reachable` level since rustdoc will be able to render the documentation + // when building private docs. + let vis = vis.at_level(Level::Reachable); + if !(vis.is_public() || matches!(vis, Visibility::Restricted(id) if id.is_top_level_module())) { + return false; + } + } else if let Some(id) = self.require_visibility_at + && !vis.at_level(Level::Reexported).is_accessible_from(id, cx.tcx) + { + return false; + } + }, + None => {}, } + + !cx.tcx.hir_attrs(hir_id).iter().any(is_doc_attr) } +} - fn check_missing_docs_attrs( - &self, - cx: &LateContext<'_>, - def_id: LocalDefId, - attrs: &[Attribute], - sp: Span, - article: &'static str, - desc: &'static str, - ) { - // If we're building a test harness, then warning about - // documentation is probably not really relevant right now. - if cx.sess().opts.test { - return; +impl_lint_pass!(MissingDoc => [MISSING_DOCS_IN_PRIVATE_ITEMS]); + +impl<'tcx> LateLintPass<'tcx> for MissingDoc { + fn check_attributes(&mut self, _: &LateContext<'tcx>, attrs: &'tcx [Attribute]) { + self.attr_depth += 1; + if self.doc_hidden_depth == 0 && is_doc_hidden(attrs) { + self.doc_hidden_depth = self.attr_depth; } + } - // `#[doc(hidden)]` disables missing_docs check. - if self.doc_hidden() { - return; + fn check_attributes_post(&mut self, _: &LateContext<'tcx>, _: &'tcx [Attribute]) { + self.attr_depth -= 1; + if self.attr_depth < self.doc_hidden_depth { + self.doc_hidden_depth = 0; + } + if self.attr_depth < self.automatically_derived_depth { + self.automatically_derived_depth = 0; } + } - if sp.from_expansion() { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { + if self.doc_hidden_depth != 0 || self.automatically_derived_depth != 0 || self.in_body.is_some() { return; } - if self.crate_items_only && def_id != CRATE_DEF_ID { - let vis = cx.tcx.visibility(def_id); - if vis == Visibility::Public || vis != Visibility::Restricted(CRATE_DEF_ID.into()) { + let span = match item.kind { + // ignore main() + ItemKind::Fn { ident, .. } + if ident.name == sym::main && cx.tcx.local_parent(item.owner_id.def_id) == CRATE_DEF_ID => + { return; - } - } else if def_id != CRATE_DEF_ID && cx.effective_visibilities.is_exported(def_id) { - return; - } + }, + ItemKind::Const(ident, ..) if ident.name == kw::Underscore => return, + ItemKind::Impl { .. } => { + if cx.tcx.is_automatically_derived(item.owner_id.def_id.to_def_id()) { + self.automatically_derived_depth = self.attr_depth; + } + return; + }, + ItemKind::ExternCrate(..) + | ItemKind::ForeignMod { .. } + | ItemKind::GlobalAsm { .. } + | ItemKind::Use(..) => return, - if let Some(parent_def_id) = cx.tcx.opt_parent(def_id.to_def_id()) - && let DefKind::AnonConst - | DefKind::AssocConst - | DefKind::AssocFn - | DefKind::Closure - | DefKind::Const - | DefKind::Fn - | DefKind::InlineConst - | DefKind::Static { .. } - | DefKind::SyntheticCoroutineBody = cx.tcx.def_kind(parent_def_id) - { - // Nested item has no generated documentation, so it doesn't need to be documented. - return; - } + ItemKind::Mod(ident, ..) => { + if item.span.from_expansion() && item.span.eq_ctxt(ident.span) { + self.module_depth += 1; + self.require_visibility_at = cx.tcx.opt_local_parent(item.owner_id.def_id); + self.macro_module_depth = self.module_depth; + return; + } + ident.span + }, - let has_doc = attrs - .iter() - .any(|a| a.doc_str().is_some() || Self::has_include(a.meta_item_list().as_deref())) - || matches!(self.search_span(sp), Some(span) if span_to_snippet_contains_docs(cx, span)); + ItemKind::Const(ident, ..) + | ItemKind::Enum(ident, ..) + | ItemKind::Fn { ident, .. } + | ItemKind::Macro(ident, ..) + | ItemKind::Static(_, ident, ..) + | ItemKind::Struct(ident, ..) + | ItemKind::Trait(_, _, _, ident, ..) + | ItemKind::TraitAlias(_, ident, ..) + | ItemKind::TyAlias(ident, ..) + | ItemKind::Union(ident, ..) => ident.span, + }; - if !has_doc { + if !item.span.from_expansion() + && self.is_missing_docs(cx, item.owner_id.def_id, item.hir_id()) + && !is_from_proc_macro(cx, item) + { + let (article, desc) = cx.tcx.article_and_description(item.owner_id.to_def_id()); span_lint( cx, MISSING_DOCS_IN_PRIVATE_ITEMS, - sp, + span, format!("missing documentation for {article} {desc}"), ); } + if matches!(item.kind, ItemKind::Mod(..)) { + self.module_depth += 1; + } } - /// Return a span to search for doc comments manually. - /// - /// # Example - /// ```ignore - /// fn foo() { ... } - /// ^^^^^^^^^^^^^^^^ prev_span - /// ↑ - /// | search_span | - /// ↓ - /// fn bar() { ... } - /// ^^^^^^^^^^^^^^^^ cur_span - /// ``` - fn search_span(&self, cur_span: Span) -> Option { - let prev_span = self.prev_span?; - let start_pos = if prev_span.contains(cur_span) { - // In case when the prev_span is an entire struct, or enum, - // and the current span is a field, or variant, we need to search from - // the starting pos of the previous span. - prev_span.lo() - } else { - prev_span.hi() - }; - let search_span = cur_span.with_lo(start_pos).with_hi(cur_span.lo()); - Some(search_span) - } -} - -impl_lint_pass!(MissingDoc => [MISSING_DOCS_IN_PRIVATE_ITEMS]); - -impl<'tcx> LateLintPass<'tcx> for MissingDoc { - fn check_attributes(&mut self, _: &LateContext<'tcx>, attrs: &'tcx [Attribute]) { - let doc_hidden = self.doc_hidden() || is_doc_hidden(attrs); - self.doc_hidden_stack.push(doc_hidden); - } - - fn check_attributes_post(&mut self, _: &LateContext<'tcx>, _: &'tcx [Attribute]) { - self.doc_hidden_stack.pop().expect("empty doc_hidden_stack"); - } - - fn check_crate(&mut self, cx: &LateContext<'tcx>) { - let attrs = cx.tcx.hir_attrs(hir::CRATE_HIR_ID); - self.check_missing_docs_attrs(cx, CRATE_DEF_ID, attrs, cx.tcx.def_span(CRATE_DEF_ID), "the", "crate"); - } - - fn check_crate_post(&mut self, _: &LateContext<'tcx>) { - self.prev_span = None; - } - - fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) { - match it.kind { - hir::ItemKind::Fn { ident, .. } => { - // ignore main() - if ident.name == sym::main { - let at_root = cx.tcx.local_parent(it.owner_id.def_id) == CRATE_DEF_ID; - if at_root { - note_prev_span_then_ret!(self.prev_span, it.span); - } - } - }, - hir::ItemKind::Const(ident, ..) => { - if ident.name == kw::Underscore { - note_prev_span_then_ret!(self.prev_span, it.span); - } - }, - hir::ItemKind::Enum(..) - | hir::ItemKind::Macro(..) - | hir::ItemKind::Mod(..) - | hir::ItemKind::Static(..) - | hir::ItemKind::Struct(..) - | hir::ItemKind::Trait(..) - | hir::ItemKind::TraitAlias(..) - | hir::ItemKind::TyAlias(..) - | hir::ItemKind::Union(..) => {}, - hir::ItemKind::ExternCrate(..) - | hir::ItemKind::ForeignMod { .. } - | hir::ItemKind::GlobalAsm { .. } - | hir::ItemKind::Impl { .. } - | hir::ItemKind::Use(..) => note_prev_span_then_ret!(self.prev_span, it.span), + fn check_item_post(&mut self, _: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { + if matches!(item.kind, ItemKind::Mod(..)) + && self.doc_hidden_depth == 0 + && self.automatically_derived_depth == 0 + && self.in_body.is_none() + { + self.module_depth -= 1; + if self.module_depth < self.macro_module_depth { + self.require_visibility_at = None; + } } + } - let (article, desc) = cx.tcx.article_and_description(it.owner_id.to_def_id()); - - let attrs = cx.tcx.hir_attrs(it.hir_id()); - if !is_from_proc_macro(cx, it) { - self.check_missing_docs_attrs(cx, it.owner_id.def_id, attrs, it.span, article, desc); + fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { + if self.doc_hidden_depth == 0 + && self.automatically_derived_depth == 0 + && self.in_body.is_none() + && !item.span.from_expansion() + && self.is_missing_docs(cx, item.owner_id.def_id, item.hir_id()) + && !is_from_proc_macro(cx, item) + { + let (article, desc) = cx.tcx.article_and_description(item.owner_id.to_def_id()); + span_lint( + cx, + MISSING_DOCS_IN_PRIVATE_ITEMS, + item.ident.span, + format!("missing documentation for {article} {desc}"), + ); } - self.prev_span = Some(it.span); } - fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx hir::TraitItem<'_>) { - let (article, desc) = cx.tcx.article_and_description(trait_item.owner_id.to_def_id()); - - let attrs = cx.tcx.hir_attrs(trait_item.hir_id()); - if !is_from_proc_macro(cx, trait_item) { - self.check_missing_docs_attrs(cx, trait_item.owner_id.def_id, attrs, trait_item.span, article, desc); + fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) { + if self.doc_hidden_depth == 0 + && self.automatically_derived_depth == 0 + && self.in_body.is_none() + && let Node::Item(parent) = cx.tcx.parent_hir_node(item.hir_id()) + && let ItemKind::Impl(impl_) = parent.kind + && impl_.of_trait.is_none() + && !item.span.from_expansion() + && self.is_missing_docs(cx, item.owner_id.def_id, item.hir_id()) + && !is_from_proc_macro(cx, item) + { + let (article, desc) = cx.tcx.article_and_description(item.owner_id.to_def_id()); + span_lint( + cx, + MISSING_DOCS_IN_PRIVATE_ITEMS, + item.ident.span, + format!("missing documentation for {article} {desc}"), + ); } - self.prev_span = Some(trait_item.span); } - fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) { - // If the method is an impl for a trait, don't doc. - match cx.tcx.associated_item(impl_item.owner_id).container { - AssocContainer::Trait | AssocContainer::TraitImpl(_) => { - note_prev_span_then_ret!(self.prev_span, impl_item.span); - }, - AssocContainer::InherentImpl => {}, + fn check_body(&mut self, _: &LateContext<'tcx>, body: &Body<'tcx>) { + if self.doc_hidden_depth == 0 && self.automatically_derived_depth == 0 && self.in_body.is_none() { + self.in_body = Some(body.id()); } + } - let (article, desc) = cx.tcx.article_and_description(impl_item.owner_id.to_def_id()); - let attrs = cx.tcx.hir_attrs(impl_item.hir_id()); - if !is_from_proc_macro(cx, impl_item) { - self.check_missing_docs_attrs(cx, impl_item.owner_id.def_id, attrs, impl_item.span, article, desc); + fn check_body_post(&mut self, _: &LateContext<'tcx>, body: &Body<'tcx>) { + if self.in_body == Some(body.id()) { + self.in_body = None; } - self.prev_span = Some(impl_item.span); } - fn check_field_def(&mut self, cx: &LateContext<'tcx>, sf: &'tcx hir::FieldDef<'_>) { - if !(sf.is_positional() - || is_from_proc_macro(cx, sf) - || self.allow_unused && sf.ident.as_str().starts_with('_')) + fn check_field_def(&mut self, cx: &LateContext<'tcx>, field: &'tcx FieldDef<'_>) { + if self.doc_hidden_depth == 0 + && self.automatically_derived_depth == 0 + && self.in_body.is_none() + && !field.is_positional() + && !field.span.from_expansion() + && !(self.allow_unused && field.ident.name.as_str().starts_with('_')) + && self.is_missing_docs(cx, field.def_id, field.hir_id) + && !is_from_proc_macro(cx, field) { - let attrs = cx.tcx.hir_attrs(sf.hir_id); - self.check_missing_docs_attrs(cx, sf.def_id, attrs, sf.span, "a", "struct field"); + span_lint( + cx, + MISSING_DOCS_IN_PRIVATE_ITEMS, + field.ident.span, + "missing documentation for a field", + ); } - self.prev_span = Some(sf.span); } - fn check_variant(&mut self, cx: &LateContext<'tcx>, v: &'tcx hir::Variant<'_>) { - let attrs = cx.tcx.hir_attrs(v.hir_id); - if !is_from_proc_macro(cx, v) { - self.check_missing_docs_attrs(cx, v.def_id, attrs, v.span, "a", "variant"); + fn check_variant(&mut self, cx: &LateContext<'tcx>, variant: &'tcx Variant<'_>) { + if self.doc_hidden_depth == 0 + && self.automatically_derived_depth == 0 + && self.in_body.is_none() + && !variant.span.from_expansion() + && self.is_missing_docs(cx, variant.def_id, variant.hir_id) + && !is_from_proc_macro(cx, variant) + { + span_lint( + cx, + MISSING_DOCS_IN_PRIVATE_ITEMS, + variant.ident.span, + "missing documentation for a variant", + ); } - self.prev_span = Some(v.span); } } -fn span_to_snippet_contains_docs(cx: &LateContext<'_>, search_span: Span) -> bool { - search_span.check_source_text(cx, |src| src.lines().rev().any(|line| line.trim().starts_with("///"))) +fn is_doc_attr(attr: &Attribute) -> bool { + match attr { + Attribute::Parsed(AttributeKind::DocComment { .. }) => true, + Attribute::Unparsed(attr) + if let [ident] = &*attr.path.segments + && ident.name == sym::doc => + { + matches!(attr.args, AttrArgs::Eq { .. }) + }, + _ => false, + } } diff --git a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs index bc5e72270f4e3..80cf081992cc7 100644 --- a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs +++ b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs @@ -1,13 +1,13 @@ use clippy_utils::desugar_await; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::visitors::{Descend, Visitable, for_each_expr}; -use core::ops::ControlFlow::Continue; use hir::def::{DefKind, Res}; use hir::{BlockCheckMode, ExprKind, QPath, UnOp}; -use rustc_ast::Mutability; +use rustc_ast::{BorrowKind, Mutability}; use rustc_hir as hir; +use rustc_hir::intravisit::{Visitor, walk_body, walk_expr}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty; +use rustc_middle::hir::nested_filter; +use rustc_middle::ty::{self, TyCtxt, TypeckResults}; use rustc_session::declare_lint_pass; use rustc_span::{DesugaringKind, Span}; @@ -55,6 +55,13 @@ declare_clippy_lint! { /// unsafe { char::from_u32_unchecked(int_value) } /// } /// ``` + /// + /// ### Note + /// + /// Taking a raw pointer to a union field is always safe and will + /// not be considered unsafe by this lint, even when linting code written + /// with a specified Rust version of 1.91 or earlier (which required + /// using an `unsafe` block). #[clippy::version = "1.69.0"] pub MULTIPLE_UNSAFE_OPS_PER_BLOCK, restriction, @@ -70,8 +77,7 @@ impl<'tcx> LateLintPass<'tcx> for MultipleUnsafeOpsPerBlock { { return; } - let mut unsafe_ops = vec![]; - collect_unsafe_exprs(cx, block, &mut unsafe_ops); + let unsafe_ops = UnsafeExprCollector::collect_unsafe_exprs(cx, block); if unsafe_ops.len() > 1 { span_lint_and_then( cx, @@ -91,25 +97,49 @@ impl<'tcx> LateLintPass<'tcx> for MultipleUnsafeOpsPerBlock { } } -fn collect_unsafe_exprs<'tcx>( - cx: &LateContext<'tcx>, - node: impl Visitable<'tcx>, - unsafe_ops: &mut Vec<(&'static str, Span)>, -) { - for_each_expr(cx, node, |expr| { +struct UnsafeExprCollector<'tcx> { + tcx: TyCtxt<'tcx>, + typeck_results: &'tcx TypeckResults<'tcx>, + unsafe_ops: Vec<(&'static str, Span)>, +} + +impl<'tcx> UnsafeExprCollector<'tcx> { + fn collect_unsafe_exprs(cx: &LateContext<'tcx>, block: &'tcx hir::Block<'tcx>) -> Vec<(&'static str, Span)> { + let mut collector = Self { + tcx: cx.tcx, + typeck_results: cx.typeck_results(), + unsafe_ops: vec![], + }; + collector.visit_block(block); + collector.unsafe_ops + } +} + +impl<'tcx> Visitor<'tcx> for UnsafeExprCollector<'tcx> { + type NestedFilter = nested_filter::OnlyBodies; + + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { match expr.kind { // The `await` itself will desugar to two unsafe calls, but we should ignore those. // Instead, check the expression that is `await`ed _ if let Some(e) = desugar_await(expr) => { - collect_unsafe_exprs(cx, e, unsafe_ops); - return Continue(Descend::No); + return self.visit_expr(e); }, - ExprKind::InlineAsm(_) => unsafe_ops.push(("inline assembly used here", expr.span)), + ExprKind::InlineAsm(_) => self.unsafe_ops.push(("inline assembly used here", expr.span)), + + ExprKind::AddrOf(BorrowKind::Raw, _, mut inner) => { + while let ExprKind::Field(prefix, _) = inner.kind + && self.typeck_results.expr_adjustments(prefix).is_empty() + { + inner = prefix; + } + return self.visit_expr(inner); + }, ExprKind::Field(e, _) => { - if cx.typeck_results().expr_ty(e).is_union() { - unsafe_ops.push(("union field access occurs here", expr.span)); + if self.typeck_results.expr_ty(e).is_union() { + self.unsafe_ops.push(("union field access occurs here", expr.span)); } }, @@ -127,32 +157,32 @@ fn collect_unsafe_exprs<'tcx>( .. }, )) => { - unsafe_ops.push(("access of a mutable static occurs here", expr.span)); + self.unsafe_ops + .push(("access of a mutable static occurs here", expr.span)); }, - ExprKind::Unary(UnOp::Deref, e) if cx.typeck_results().expr_ty_adjusted(e).is_raw_ptr() => { - unsafe_ops.push(("raw pointer dereference occurs here", expr.span)); + ExprKind::Unary(UnOp::Deref, e) if self.typeck_results.expr_ty(e).is_raw_ptr() => { + self.unsafe_ops.push(("raw pointer dereference occurs here", expr.span)); }, ExprKind::Call(path_expr, _) => { - let sig = match *cx.typeck_results().expr_ty(path_expr).kind() { - ty::FnDef(id, _) => cx.tcx.fn_sig(id).skip_binder(), - ty::FnPtr(sig_tys, hdr) => sig_tys.with(hdr), - _ => return Continue(Descend::Yes), + let opt_sig = match *self.typeck_results.expr_ty_adjusted(path_expr).kind() { + ty::FnDef(id, _) => Some(self.tcx.fn_sig(id).skip_binder()), + ty::FnPtr(sig_tys, hdr) => Some(sig_tys.with(hdr)), + _ => None, }; - if sig.safety().is_unsafe() { - unsafe_ops.push(("unsafe function call occurs here", expr.span)); + if opt_sig.is_some_and(|sig| sig.safety().is_unsafe()) { + self.unsafe_ops.push(("unsafe function call occurs here", expr.span)); } }, ExprKind::MethodCall(..) => { - if let Some(sig) = cx - .typeck_results() + let opt_sig = self + .typeck_results .type_dependent_def_id(expr.hir_id) - .map(|def_id| cx.tcx.fn_sig(def_id)) - && sig.skip_binder().safety().is_unsafe() - { - unsafe_ops.push(("unsafe method call occurs here", expr.span)); + .map(|def_id| self.tcx.fn_sig(def_id)); + if opt_sig.is_some_and(|sig| sig.skip_binder().safety().is_unsafe()) { + self.unsafe_ops.push(("unsafe method call occurs here", expr.span)); } }, @@ -173,15 +203,26 @@ fn collect_unsafe_exprs<'tcx>( } )) ) { - unsafe_ops.push(("modification of a mutable static occurs here", expr.span)); - collect_unsafe_exprs(cx, rhs, unsafe_ops); - return Continue(Descend::No); + self.unsafe_ops + .push(("modification of a mutable static occurs here", expr.span)); + return self.visit_expr(rhs); } }, _ => {}, } - Continue::<(), _>(Descend::Yes) - }); + walk_expr(self, expr); + } + + fn visit_body(&mut self, body: &hir::Body<'tcx>) { + let saved_typeck_results = self.typeck_results; + self.typeck_results = self.tcx.typeck_body(body.id()); + walk_body(self, body); + self.typeck_results = saved_typeck_results; + } + + fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { + self.tcx + } } diff --git a/src/tools/clippy/clippy_lints/src/ptr/ptr_arg.rs b/src/tools/clippy/clippy_lints/src/ptr/ptr_arg.rs index fd9230f00a8bd..4bfff64b1bd48 100644 --- a/src/tools/clippy/clippy_lints/src/ptr/ptr_arg.rs +++ b/src/tools/clippy/clippy_lints/src/ptr/ptr_arg.rs @@ -2,7 +2,7 @@ use super::PTR_ARG; use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::res::MaybeResPath; use clippy_utils::source::SpanRangeExt; -use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, sym}; +use clippy_utils::{VEC_METHODS_SHADOWING_SLICE_METHODS, get_expr_use_or_unification_node, is_lint_allowed, sym}; use hir::LifetimeKind; use rustc_abi::ExternAbi; use rustc_errors::Applicability; @@ -23,8 +23,6 @@ use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use std::{fmt, iter}; -use crate::vec::is_allowed_vec_method; - pub(super) fn check_body<'tcx>( cx: &LateContext<'tcx>, body: &Body<'tcx>, @@ -383,7 +381,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &Body<'tcx>, args: &[ // Some methods exist on both `[T]` and `Vec`, such as `len`, where the receiver type // doesn't coerce to a slice and our adjusted type check below isn't enough, // but it would still be valid to call with a slice - if is_allowed_vec_method(use_expr) { + if VEC_METHODS_SHADOWING_SLICE_METHODS.contains(&name) { return; } } diff --git a/src/tools/clippy/clippy_lints/src/time_subtraction.rs b/src/tools/clippy/clippy_lints/src/time_subtraction.rs index dbd4ec77fd5f9..e0fdca97dbeee 100644 --- a/src/tools/clippy/clippy_lints/src/time_subtraction.rs +++ b/src/tools/clippy/clippy_lints/src/time_subtraction.rs @@ -1,5 +1,5 @@ use clippy_config::Conf; -use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::{MaybeDef, MaybeTypeckRes}; use clippy_utils::sugg::Sugg; @@ -109,36 +109,16 @@ impl LateLintPass<'_> for UncheckedTimeSubtraction { && !expr.span.from_expansion() && self.msrv.meets(cx, msrvs::TRY_FROM) { - // For chained subtraction like (instant - dur1) - dur2, avoid suggestions - if is_chained_time_subtraction(cx, lhs) { - span_lint( - cx, - UNCHECKED_TIME_SUBTRACTION, - expr.span, - "unchecked subtraction of a 'Duration' from an 'Instant'", - ); - } else { - // instant - duration - print_unchecked_duration_subtraction_sugg(cx, lhs, rhs, expr); - } + print_unchecked_duration_subtraction_sugg(cx, lhs, rhs, expr); } - } else if lhs_ty.is_diag_item(cx, sym::Duration) + } + // duration - duration + else if lhs_ty.is_diag_item(cx, sym::Duration) && rhs_ty.is_diag_item(cx, sym::Duration) && !expr.span.from_expansion() && self.msrv.meets(cx, msrvs::TRY_FROM) { - // For chained subtraction like (dur1 - dur2) - dur3, avoid suggestions - if is_chained_time_subtraction(cx, lhs) { - span_lint( - cx, - UNCHECKED_TIME_SUBTRACTION, - expr.span, - "unchecked subtraction between 'Duration' values", - ); - } else { - // duration - duration - print_unchecked_duration_subtraction_sugg(cx, lhs, rhs, expr); - } + print_unchecked_duration_subtraction_sugg(cx, lhs, rhs, expr); } } } @@ -191,26 +171,26 @@ fn print_unchecked_duration_subtraction_sugg( right_expr: &Expr<'_>, expr: &Expr<'_>, ) { - let typeck = cx.typeck_results(); - let left_ty = typeck.expr_ty(left_expr); - - let lint_msg = if left_ty.is_diag_item(cx, sym::Instant) { - "unchecked subtraction of a 'Duration' from an 'Instant'" - } else { - "unchecked subtraction between 'Duration' values" - }; - - let mut applicability = Applicability::MachineApplicable; - let left_sugg = Sugg::hir_with_applicability(cx, left_expr, "", &mut applicability); - let right_sugg = Sugg::hir_with_applicability(cx, right_expr, "", &mut applicability); - - span_lint_and_sugg( + span_lint_and_then( cx, UNCHECKED_TIME_SUBTRACTION, expr.span, - lint_msg, - "try", - format!("{}.checked_sub({}).unwrap()", left_sugg.maybe_paren(), right_sugg), - applicability, + "unchecked subtraction of a `Duration`", + |diag| { + // For chained subtraction, like `(dur1 - dur2) - dur3` or `(instant - dur1) - dur2`, + // avoid suggestions + if !is_chained_time_subtraction(cx, left_expr) { + let mut applicability = Applicability::MachineApplicable; + let left_sugg = Sugg::hir_with_applicability(cx, left_expr, "", &mut applicability); + let right_sugg = Sugg::hir_with_applicability(cx, right_expr, "", &mut applicability); + + diag.span_suggestion( + expr.span, + "try", + format!("{}.checked_sub({}).unwrap()", left_sugg.maybe_paren(), right_sugg), + applicability, + ); + } + }, ); } 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 933e25fe98c65..91fce5d5bd68a 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 @@ -17,6 +17,8 @@ pub(super) fn check<'tcx>( arg: &'tcx Expr<'_>, msrv: Msrv, ) -> bool { + let mut applicability = Applicability::MachineApplicable; + let arg_sugg = sugg::Sugg::hir_with_context(cx, arg, e.span.ctxt(), "..", &mut applicability); match (from_ty.kind(), to_ty.kind()) { (ty::RawPtr(from_pointee_ty, from_mutbl), ty::RawPtr(to_pointee_ty, to_mutbl)) => { span_lint_and_then( @@ -25,40 +27,38 @@ pub(super) fn check<'tcx>( e.span, "transmute from a pointer to a pointer", |diag| { - if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) { - if from_mutbl == to_mutbl - && to_pointee_ty.is_sized(cx.tcx, cx.typing_env()) - && msrv.meets(cx, msrvs::POINTER_CAST) - { - diag.span_suggestion_verbose( - e.span, - "use `pointer::cast` instead", - format!("{}.cast::<{to_pointee_ty}>()", arg.maybe_paren()), - Applicability::MaybeIncorrect, - ); - } else if from_pointee_ty == to_pointee_ty - && let Some(method) = match (from_mutbl, to_mutbl) { - (ty::Mutability::Not, ty::Mutability::Mut) => Some("cast_mut"), - (ty::Mutability::Mut, ty::Mutability::Not) => Some("cast_const"), - _ => None, - } - && !from_pointee_ty.has_erased_regions() - && msrv.meets(cx, msrvs::POINTER_CAST_CONSTNESS) - { - diag.span_suggestion_verbose( - e.span, - format!("use `pointer::{method}` instead"), - format!("{}.{method}()", arg.maybe_paren()), - Applicability::MaybeIncorrect, - ); - } else { - diag.span_suggestion_verbose( - e.span, - "use an `as` cast instead", - arg.as_ty(to_ty), - Applicability::MaybeIncorrect, - ); + if from_mutbl == to_mutbl + && to_pointee_ty.is_sized(cx.tcx, cx.typing_env()) + && msrv.meets(cx, msrvs::POINTER_CAST) + { + diag.span_suggestion_verbose( + e.span, + "use `pointer::cast` instead", + format!("{}.cast::<{to_pointee_ty}>()", arg_sugg.maybe_paren()), + Applicability::MaybeIncorrect, + ); + } else if from_pointee_ty == to_pointee_ty + && let Some(method) = match (from_mutbl, to_mutbl) { + (ty::Mutability::Not, ty::Mutability::Mut) => Some("cast_mut"), + (ty::Mutability::Mut, ty::Mutability::Not) => Some("cast_const"), + _ => None, } + && !from_pointee_ty.has_erased_regions() + && msrv.meets(cx, msrvs::POINTER_CAST_CONSTNESS) + { + diag.span_suggestion_verbose( + e.span, + format!("use `pointer::{method}` instead"), + format!("{}.{method}()", arg_sugg.maybe_paren()), + Applicability::MaybeIncorrect, + ); + } else { + diag.span_suggestion_verbose( + e.span, + "use an `as` cast instead", + arg_sugg.as_ty(to_ty), + Applicability::MaybeIncorrect, + ); } }, ); 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 70c2a73ce6ef2..39b1ccdc94268 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,6 +1,5 @@ use super::{TRANSMUTE_BYTES_TO_STR, TRANSMUTE_PTR_TO_PTR}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::snippet; use clippy_utils::{std_or_core, sugg}; use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability}; @@ -17,8 +16,7 @@ pub(super) fn check<'tcx>( arg: &'tcx Expr<'_>, const_context: bool, ) -> bool { - let mut triggered = false; - + let arg_sugg = || sugg::Sugg::hir_with_context(cx, arg, e.span.ctxt(), "..", &mut Applicability::Unspecified); if let (ty::Ref(_, ty_from, from_mutbl), ty::Ref(_, ty_to, to_mutbl)) = (*from_ty.kind(), *to_ty.kind()) { if let ty::Slice(slice_ty) = *ty_from.kind() && ty_to.is_str() @@ -29,8 +27,6 @@ pub(super) fn check<'tcx>( let postfix = if from_mutbl == Mutability::Mut { "_mut" } else { "" }; - let snippet = snippet(cx, arg.span, ".."); - span_lint_and_sugg( cx, TRANSMUTE_BYTES_TO_STR, @@ -38,15 +34,17 @@ pub(super) fn check<'tcx>( format!("transmute from a `{from_ty}` to a `{to_ty}`"), "consider using", if const_context { - format!("{top_crate}::str::from_utf8_unchecked{postfix}({snippet})") + format!("{top_crate}::str::from_utf8_unchecked{postfix}({})", arg_sugg()) } else { - format!("{top_crate}::str::from_utf8{postfix}({snippet}).unwrap()") + format!("{top_crate}::str::from_utf8{postfix}({}).unwrap()", arg_sugg()) }, Applicability::MaybeIncorrect, ); - triggered = true; - } else if (cx.tcx.erase_and_anonymize_regions(from_ty) != cx.tcx.erase_and_anonymize_regions(to_ty)) - && !const_context + + return true; + } + + if (cx.tcx.erase_and_anonymize_regions(from_ty) != cx.tcx.erase_and_anonymize_regions(to_ty)) && !const_context { span_lint_and_then( cx, @@ -54,23 +52,21 @@ pub(super) fn check<'tcx>( e.span, "transmute from a reference to a reference", |diag| { - if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) { - let sugg_paren = arg - .as_ty(Ty::new_ptr(cx.tcx, ty_from, from_mutbl)) - .as_ty(Ty::new_ptr(cx.tcx, ty_to, to_mutbl)); - let sugg = if to_mutbl == Mutability::Mut { - sugg_paren.mut_addr_deref() - } else { - sugg_paren.addr_deref() - }; - diag.span_suggestion(e.span, "try", sugg, Applicability::Unspecified); - } + let sugg_paren = arg_sugg() + .as_ty(Ty::new_ptr(cx.tcx, ty_from, from_mutbl)) + .as_ty(Ty::new_ptr(cx.tcx, ty_to, to_mutbl)); + let sugg = if to_mutbl == Mutability::Mut { + sugg_paren.mut_addr_deref() + } else { + sugg_paren.addr_deref() + }; + diag.span_suggestion(e.span, "try", sugg, Applicability::Unspecified); }, ); - triggered = true; + return true; } } - triggered + false } diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs index 99201a1ca215f..8ed3df8731b3f 100644 --- a/src/tools/clippy/clippy_lints/src/unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/unwrap.rs @@ -1,15 +1,21 @@ +use std::borrow::Cow; +use std::iter; + use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::msrvs::Msrv; use clippy_utils::res::{MaybeDef, MaybeResPath}; +use clippy_utils::source::snippet; use clippy_utils::usage::is_potentially_local_place; use clippy_utils::{can_use_if_let_chains, higher, sym}; +use rustc_abi::FieldIdx; use rustc_errors::Applicability; use rustc_hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn}; use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, Node, UnOp}; -use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceWithHirId}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, Place, PlaceWithHirId}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::nested_filter; +use rustc_middle::hir::place::ProjectionKind; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::impl_lint_pass; @@ -114,11 +120,91 @@ impl UnwrappableKind { } } +#[derive(Clone, Debug, Eq)] +enum Local { + /// `x.field1.field2.field3` + WithFieldAccess { + local_id: HirId, + /// The indices of the field accessed. + /// + /// Stored last-to-first, e.g. for the example above: `[field3, field2, field1]` + field_indices: Vec, + /// The span of the whole expression + span: Span, + }, + /// `x` + Pure { local_id: HirId }, +} + +/// Identical to derived impl, but ignores `span` on [`Local::WithFieldAccess`] +impl PartialEq for Local { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + ( + Self::WithFieldAccess { + local_id: self_local_id, + field_indices: self_field_indices, + .. + }, + Self::WithFieldAccess { + local_id: other_local_id, + field_indices: other_field_indices, + .. + }, + ) => self_local_id == other_local_id && self_field_indices == other_field_indices, + ( + Self::Pure { + local_id: self_local_id, + }, + Self::Pure { + local_id: other_local_id, + }, + ) => self_local_id == other_local_id, + _ => false, + } + } +} + +impl Local { + fn snippet(&self, cx: &LateContext<'_>) -> Cow<'static, str> { + match *self { + Self::WithFieldAccess { span, .. } => snippet(cx.sess(), span, "_"), + Self::Pure { local_id } => cx.tcx.hir_name(local_id).to_string().into(), + } + } + + fn is_potentially_local_place(&self, place: &Place<'_>) -> bool { + match self { + Self::WithFieldAccess { + local_id, + field_indices, + .. + } => { + is_potentially_local_place(*local_id, place) + // If there were projections other than field projections, err on the side of caution and say that they + // _might_ be mutating something. + // + // The reason we use `<=` and not `==` is that a mutation of `struct` or `struct.field1` should count as + // mutation of the child fields such as `struct.field1.field2` + && place.projections.len() <= field_indices.len() + && iter::zip(&place.projections, field_indices.iter().copied().rev()).all(|(proj, field_idx)| { + match proj.kind { + ProjectionKind::Field(f_idx, _) => f_idx == field_idx, + // If this is a projection we don't expect, it _might_ be mutating something + _ => false, + } + }) + }, + Self::Pure { local_id } => is_potentially_local_place(*local_id, place), + } + } +} + /// Contains information about whether a variable can be unwrapped. -#[derive(Copy, Clone, Debug)] +#[derive(Clone, Debug)] struct UnwrapInfo<'tcx> { /// The variable that is checked - local_id: HirId, + local: Local, /// The if itself if_expr: &'tcx Expr<'tcx>, /// The check, like `x.is_ok()` @@ -156,38 +242,77 @@ fn collect_unwrap_info<'tcx>( } } - match expr.kind { - ExprKind::Binary(op, left, right) - if matches!( - (invert, op.node), - (false, BinOpKind::And | BinOpKind::BitAnd) | (true, BinOpKind::Or | BinOpKind::BitOr) - ) => - { - let mut unwrap_info = collect_unwrap_info(cx, if_expr, left, branch, invert, false); - unwrap_info.extend(collect_unwrap_info(cx, if_expr, right, branch, invert, false)); - unwrap_info - }, - ExprKind::Unary(UnOp::Not, expr) => collect_unwrap_info(cx, if_expr, expr, branch, !invert, false), - ExprKind::MethodCall(method_name, receiver, [], _) - if let Some(local_id) = receiver.res_local_id() - && let ty = cx.typeck_results().expr_ty(receiver) - && let name = method_name.ident.name - && let Some((kind, unwrappable)) = option_or_result_call(cx, ty, name) => - { - let safe_to_unwrap = unwrappable != invert; + fn inner<'tcx>( + cx: &LateContext<'tcx>, + if_expr: &'tcx Expr<'_>, + expr: &'tcx Expr<'_>, + branch: &'tcx Expr<'_>, + invert: bool, + is_entire_condition: bool, + out: &mut Vec>, + ) { + match expr.kind { + ExprKind::Binary(op, left, right) + if matches!( + (invert, op.node), + (false, BinOpKind::And | BinOpKind::BitAnd) | (true, BinOpKind::Or | BinOpKind::BitOr) + ) => + { + inner(cx, if_expr, left, branch, invert, false, out); + inner(cx, if_expr, right, branch, invert, false, out); + }, + ExprKind::Unary(UnOp::Not, expr) => inner(cx, if_expr, expr, branch, !invert, false, out), + ExprKind::MethodCall(method_name, receiver, [], _) + if let Some(local) = extract_local(cx, receiver) + && let ty = cx.typeck_results().expr_ty(receiver) + && let name = method_name.ident.name + && let Some((kind, unwrappable)) = option_or_result_call(cx, ty, name) => + { + let safe_to_unwrap = unwrappable != invert; + + out.push(UnwrapInfo { + local, + if_expr, + check: expr, + check_name: name, + branch, + safe_to_unwrap, + kind, + is_entire_condition, + }); + }, + _ => {}, + } + } + + let mut out = vec![]; + inner(cx, if_expr, expr, branch, invert, is_entire_condition, &mut out); + out +} - vec![UnwrapInfo { +/// Extracts either a local used by itself ([`Local::Pure`]), or (one or more levels of) field +/// access to a local ([`Local::WithFieldAccess`]) +fn extract_local(cx: &LateContext<'_>, mut expr: &Expr<'_>) -> Option { + let span = expr.span; + let mut field_indices = vec![]; + while let ExprKind::Field(recv, _) = expr.kind + && let Some(field_idx) = cx.typeck_results().opt_field_index(expr.hir_id) + { + field_indices.push(field_idx); + expr = recv; + } + if let Some(local_id) = expr.res_local_id() { + if field_indices.is_empty() { + Some(Local::Pure { local_id }) + } else { + Some(Local::WithFieldAccess { local_id, - if_expr, - check: expr, - check_name: name, - branch, - safe_to_unwrap, - kind, - is_entire_condition, - }] - }, - _ => vec![], + field_indices, + span, + }) + } + } else { + None } } @@ -198,9 +323,9 @@ fn collect_unwrap_info<'tcx>( /// `is_some` + `unwrap` is equivalent to `if let Some(..) = ..`, which it would not be if /// the option is changed to None between `is_some` and `unwrap`, ditto for `Result`. /// (And also `.as_mut()` is a somewhat common method that is still worth linting on.) -struct MutationVisitor<'tcx> { +struct MutationVisitor<'tcx, 'lcl> { is_mutated: bool, - local_id: HirId, + local: &'lcl Local, tcx: TyCtxt<'tcx>, } @@ -221,10 +346,10 @@ fn is_as_mut_use(tcx: TyCtxt<'_>, expr_id: HirId) -> bool { } } -impl<'tcx> Delegate<'tcx> for MutationVisitor<'tcx> { +impl<'tcx> Delegate<'tcx> for MutationVisitor<'tcx, '_> { fn borrow(&mut self, cat: &PlaceWithHirId<'tcx>, diag_expr_id: HirId, bk: ty::BorrowKind) { if let ty::BorrowKind::Mutable = bk - && is_potentially_local_place(self.local_id, &cat.place) + && self.local.is_potentially_local_place(&cat.place) && !is_as_mut_use(self.tcx, diag_expr_id) { self.is_mutated = true; @@ -232,7 +357,7 @@ impl<'tcx> Delegate<'tcx> for MutationVisitor<'tcx> { } fn mutate(&mut self, cat: &PlaceWithHirId<'tcx>, _: HirId) { - if is_potentially_local_place(self.local_id, &cat.place) { + if self.local.is_potentially_local_place(&cat.place) { self.is_mutated = true; } } @@ -256,7 +381,7 @@ impl<'tcx> UnwrappableVariablesVisitor<'_, 'tcx> { for unwrap_info in collect_unwrap_info(self.cx, if_expr, cond, branch, else_branch, true) { let mut delegate = MutationVisitor { is_mutated: false, - local_id: unwrap_info.local_id, + local: &unwrap_info.local, tcx: self.cx.tcx, }; @@ -318,24 +443,17 @@ impl<'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'_, 'tcx> { // find `unwrap[_err]()` or `expect("...")` calls: if let ExprKind::MethodCall(method_name, self_arg, ..) = expr.kind && let (self_arg, as_ref_kind) = consume_option_as_ref(self_arg) - && let Some(id) = self_arg.res_local_id() + && let Some(local) = extract_local(self.cx, self_arg) && matches!(method_name.ident.name, sym::unwrap | sym::expect | sym::unwrap_err) && let call_to_unwrap = matches!(method_name.ident.name, sym::unwrap | sym::expect) - && let Some(unwrappable) = self.unwrappables.iter() - .find(|u| u.local_id == id) + && let Some(unwrappable) = self.unwrappables.iter().find(|u| u.local == local) // Span contexts should not differ with the conditional branch && let span_ctxt = expr.span.ctxt() && unwrappable.branch.span.ctxt() == span_ctxt && unwrappable.check.span.ctxt() == span_ctxt { if call_to_unwrap == unwrappable.safe_to_unwrap { - let is_entire_condition = unwrappable.is_entire_condition; - let unwrappable_variable_name = self.cx.tcx.hir_name(unwrappable.local_id); - let suggested_pattern = if call_to_unwrap { - unwrappable.kind.success_variant_pattern() - } else { - unwrappable.kind.error_variant_pattern() - }; + let unwrappable_variable_str = unwrappable.local.snippet(self.cx); span_lint_hir_and_then( self.cx, @@ -343,16 +461,21 @@ impl<'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'_, 'tcx> { expr.hir_id, expr.span, format!( - "called `{}` on `{unwrappable_variable_name}` after checking its variant with `{}`", + "called `{}` on `{unwrappable_variable_str}` after checking its variant with `{}`", method_name.ident.name, unwrappable.check_name, ), |diag| { - if is_entire_condition { + if unwrappable.is_entire_condition { diag.span_suggestion( unwrappable.check.span.with_lo(unwrappable.if_expr.span.lo()), "try", format!( - "if let {suggested_pattern} = {borrow_prefix}{unwrappable_variable_name}", + "if let {suggested_pattern} = {borrow_prefix}{unwrappable_variable_str}", + suggested_pattern = if call_to_unwrap { + unwrappable.kind.success_variant_pattern() + } else { + unwrappable.kind.error_variant_pattern() + }, borrow_prefix = match as_ref_kind { Some(AsRefKind::AsRef) => "&", Some(AsRefKind::AsMut) => "&mut ", diff --git a/src/tools/clippy/clippy_lints/src/vec.rs b/src/tools/clippy/clippy_lints/src/useless_vec.rs similarity index 90% rename from src/tools/clippy/clippy_lints/src/vec.rs rename to src/tools/clippy/clippy_lints/src/useless_vec.rs index b87db836869d6..28c339ce2b7d3 100644 --- a/src/tools/clippy/clippy_lints/src/vec.rs +++ b/src/tools/clippy/clippy_lints/src/useless_vec.rs @@ -10,7 +10,7 @@ use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::is_copy; use clippy_utils::visitors::for_each_local_use_after_expr; -use clippy_utils::{get_parent_expr, higher, is_in_test, span_contains_comment, sym}; +use clippy_utils::{VEC_METHODS_SHADOWING_SLICE_METHODS, get_parent_expr, higher, is_in_test, span_contains_comment}; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, LetStmt, Mutability, Node, Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -123,8 +123,16 @@ impl UselessVec { // allow indexing into a vec and some set of allowed method calls that exist on slices, too if let Some(parent) = get_parent_expr(cx, expr) && (adjusts_to_slice(cx, expr) - || matches!(parent.kind, ExprKind::Index(..)) - || is_allowed_vec_method(parent)) + || match parent.kind { + ExprKind::Index(..) => true, + ExprKind::MethodCall(path, _, [], _) => { + // If the given expression is a method call to a `Vec` method that also exists on + // slices, it means that this expression does not actually require a `Vec` and could + // just work with an array. + VEC_METHODS_SHADOWING_SLICE_METHODS.contains(&path.ident.name) + }, + _ => false, + }) { ControlFlow::Continue(()) } else { @@ -144,8 +152,9 @@ impl UselessVec { VecToArray::Impossible }, // search for `for _ in vec![...]` - Node::Expr(Expr { span, .. }) - if span.is_desugaring(DesugaringKind::ForLoop) && self.msrv.meets(cx, msrvs::ARRAY_INTO_ITERATOR) => + Node::Expr(expr) + if expr.span.is_desugaring(DesugaringKind::ForLoop) + && self.msrv.meets(cx, msrvs::ARRAY_INTO_ITERATOR) => { VecToArray::Possible }, @@ -276,9 +285,8 @@ impl SuggestedType { assert!(args_span.is_none_or(|s| !s.from_expansion())); assert!(len_span.is_none_or(|s| !s.from_expansion())); - let maybe_args = args_span - .map(|sp| sp.get_source_text(cx).expect("spans are always crate-local")) - .map_or(String::new(), |x| x.to_owned()); + let maybe_args = args_span.map(|sp| sp.get_source_text(cx).expect("spans are always crate-local")); + let maybe_args = maybe_args.as_deref().unwrap_or_default(); let maybe_len = len_span .map(|sp| sp.get_source_text(cx).expect("spans are always crate-local")) .map(|st| format!("; {st}")) @@ -301,17 +309,6 @@ fn adjusts_to_slice(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { matches!(cx.typeck_results().expr_ty_adjusted(e).kind(), ty::Ref(_, ty, _) if ty.is_slice()) } -/// Checks if the given expression is a method call to a `Vec` method -/// that also exists on slices. If this returns true, it means that -/// this expression does not actually require a `Vec` and could just work with an array. -pub fn is_allowed_vec_method(e: &Expr<'_>) -> bool { - if let ExprKind::MethodCall(path, _, [], _) = e.kind { - matches!(path.ident.name, sym::as_ptr | sym::is_empty | sym::len) - } else { - false - } -} - fn suggest_type(expr: &Expr<'_>) -> SuggestedType { if let ExprKind::AddrOf(BorrowKind::Ref, mutability, _) = expr.kind { // `expr` is `&vec![_]`, so suggest `&[_]` (or `&mut[_]` resp.) diff --git a/src/tools/clippy/clippy_utils/README.md b/src/tools/clippy/clippy_utils/README.md index 6f976094fc2d0..4b1a10a3d9cfa 100644 --- a/src/tools/clippy/clippy_utils/README.md +++ b/src/tools/clippy/clippy_utils/README.md @@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain: ``` -nightly-2025-11-14 +nightly-2025-11-28 ``` diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index 4bdbfc8853662..27b5a57c737d3 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -43,7 +43,7 @@ pub fn eq_pat(l: &Pat, r: &Pat) -> bool { (Range(lf, lt, le), Range(rf, rt, re)) => { eq_expr_opt(lf.as_deref(), rf.as_deref()) && eq_expr_opt(lt.as_deref(), rt.as_deref()) - && eq_range_end(&le.node, &re.node) + && eq_range_end(le.node, re.node) }, (Box(l), Box(r)) => eq_pat(l, r), (Ref(l, l_pin, l_mut), Ref(r, r_pin, r_mut)) => l_pin == r_pin && l_mut == r_mut && eq_pat(l, r), @@ -64,7 +64,7 @@ pub fn eq_pat(l: &Pat, r: &Pat) -> bool { } } -pub fn eq_range_end(l: &RangeEnd, r: &RangeEnd) -> bool { +pub fn eq_range_end(l: RangeEnd, r: RangeEnd) -> bool { match (l, r) { (RangeEnd::Excluded, RangeEnd::Excluded) => true, (RangeEnd::Included(l), RangeEnd::Included(r)) => { diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs index 50d9136b8b4dc..d9254fca9453d 100644 --- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs +++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs @@ -265,7 +265,14 @@ fn item_search_pat(item: &Item<'_>) -> (Pat, Pat) { ItemKind::Trait(_, IsAuto::Yes, ..) => (Pat::Str("auto"), Pat::Str("}")), ItemKind::Trait(..) => (Pat::Str("trait"), Pat::Str("}")), ItemKind::Impl(_) => (Pat::Str("impl"), Pat::Str("}")), - _ => return (Pat::Str(""), Pat::Str("")), + ItemKind::Mod(..) => (Pat::Str("mod"), Pat::Str("")), + ItemKind::Macro(_, def, _) => ( + Pat::Str(if def.macro_rules { "macro_rules" } else { "macro" }), + Pat::Str(""), + ), + ItemKind::TraitAlias(..) => (Pat::Str("trait"), Pat::Str(";")), + ItemKind::GlobalAsm { .. } => return (Pat::Str("global_asm"), Pat::Str("")), + ItemKind::Use(..) => return (Pat::Str(""), Pat::Str("")), }; if item.vis_span.is_empty() { (start_pat, end_pat) diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index c9302b17eb7ec..ed164fcf371b1 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -136,6 +136,9 @@ use crate::res::{MaybeDef, MaybeQPath, MaybeResPath}; use crate::ty::{adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type}; use crate::visitors::for_each_expr_without_closures; +/// Methods on `Vec` that also exists on slices. +pub const VEC_METHODS_SHADOWING_SLICE_METHODS: [Symbol; 3] = [sym::as_ptr, sym::is_empty, sym::len]; + #[macro_export] macro_rules! extract_msrv_attr { () => { diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index 2593df1035277..2ef2afb450711 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -8,7 +8,7 @@ use rustc_ast::util::parser::AssocOp; use rustc_ast::{UnOp, ast}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; -use rustc_hir::{self as hir, Closure, ExprKind, HirId, MutTy, Node, TyKind}; +use rustc_hir::{self as hir, Closure, ExprKind, HirId, MatchSource, MutTy, Node, TyKind}; use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; use rustc_lint::{EarlyContext, LateContext, LintContext}; use rustc_middle::hir::place::ProjectionKind; @@ -146,7 +146,9 @@ impl<'a> Sugg<'a> { | ExprKind::Let(..) | ExprKind::Closure { .. } | ExprKind::Unary(..) - | ExprKind::Match(..) => Sugg::MaybeParen(get_snippet(expr.span)), + | ExprKind::Match(_, _, + MatchSource::Normal | MatchSource::Postfix | MatchSource::ForLoopDesugar + ) => Sugg::MaybeParen(get_snippet(expr.span)), ExprKind::Continue(..) | ExprKind::Yield(..) | ExprKind::Array(..) @@ -169,7 +171,10 @@ impl<'a> Sugg<'a> { | ExprKind::Tup(..) | ExprKind::Use(..) | ExprKind::Err(_) - | ExprKind::UnsafeBinderCast(..) => Sugg::NonParen(get_snippet(expr.span)), + | ExprKind::UnsafeBinderCast(..) + | ExprKind::Match(_, _, + MatchSource::AwaitDesugar | MatchSource::TryDesugar(_) | MatchSource::FormatArgs + ) => Sugg::NonParen(get_snippet(expr.span)), ExprKind::DropTemps(inner) => Self::hir_from_snippet(cx, inner, get_snippet), ExprKind::Assign(lhs, rhs, _) => { Sugg::BinOp(AssocOp::Assign, get_snippet(lhs.span), get_snippet(rhs.span)) diff --git a/src/tools/clippy/rust-toolchain.toml b/src/tools/clippy/rust-toolchain.toml index f6809da98f2b1..5157b79832a39 100644 --- a/src/tools/clippy/rust-toolchain.toml +++ b/src/tools/clippy/rust-toolchain.toml @@ -1,6 +1,6 @@ [toolchain] # begin autogenerated nightly -channel = "nightly-2025-11-14" +channel = "nightly-2025-11-28" # end autogenerated nightly components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] profile = "minimal" diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs index 2fc4abe48fe4a..8693973ef78c7 100644 --- a/src/tools/clippy/src/driver.rs +++ b/src/tools/clippy/src/driver.rs @@ -13,12 +13,12 @@ extern crate rustc_interface; extern crate rustc_session; extern crate rustc_span; -/// See docs in https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc/src/main.rs -/// and https://github.com/rust-lang/rust/pull/146627 for why we need this. +/// See docs in +/// and for why we need this. /// /// FIXME(madsmtm): This is loaded from the sysroot that was built with the other `rustc` crates /// above, instead of via Cargo as you'd normally do. This is currently needed for LTO due to -/// https://github.com/rust-lang/cc-rs/issues/1613. +/// . #[cfg(feature = "jemalloc")] extern crate tikv_jemalloc_sys as _; @@ -191,7 +191,6 @@ fn display_help() { const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/new?template=ice.yml"; -#[expect(clippy::too_many_lines)] pub fn main() { let early_dcx = EarlyDiagCtxt::new(ErrorOutputType::default()); diff --git a/src/tools/clippy/tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.rs b/src/tools/clippy/tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.rs deleted file mode 100644 index 155f680c7b13a..0000000000000 --- a/src/tools/clippy/tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.rs +++ /dev/null @@ -1,26 +0,0 @@ -//! Test file for missing_docs_in_private_items lint with allow_unused configuration -#![warn(clippy::missing_docs_in_private_items)] -#![allow(dead_code)] - -/// A struct with some documented and undocumented fields -struct Test { - /// This field is documented - field1: i32, - _unused: i32, // This should not trigger a warning because it starts with an underscore - field3: i32, //~ missing_docs_in_private_items -} - -struct Test2 { - //~^ missing_docs_in_private_items - _field1: i32, // This should not trigger a warning - _field2: i32, // This should not trigger a warning -} - -struct Test3 { - //~^ missing_docs_in_private_items - /// This field is documented although this is not mandatory - _unused: i32, // This should not trigger a warning because it starts with an underscore - field2: i32, //~ missing_docs_in_private_items -} - -fn main() {} diff --git a/src/tools/clippy/tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.stderr b/src/tools/clippy/tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.stderr deleted file mode 100644 index 8f511883e9005..0000000000000 --- a/src/tools/clippy/tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.stderr +++ /dev/null @@ -1,38 +0,0 @@ -error: missing documentation for a struct field - --> tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.rs:10:5 - | -LL | field3: i32, - | ^^^^^^^^^^^ - | - = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::missing_docs_in_private_items)]` - -error: missing documentation for a struct - --> tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.rs:13:1 - | -LL | / struct Test2 { -LL | | -LL | | _field1: i32, // This should not trigger a warning -LL | | _field2: i32, // This should not trigger a warning -LL | | } - | |_^ - -error: missing documentation for a struct - --> tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.rs:19:1 - | -LL | / struct Test3 { -LL | | -LL | | /// This field is documented although this is not mandatory -LL | | _unused: i32, // This should not trigger a warning because it starts with an underscore -LL | | field2: i32, -LL | | } - | |_^ - -error: missing documentation for a struct field - --> tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.rs:23:5 - | -LL | field2: i32, - | ^^^^^^^^^^^ - -error: aborting due to 4 previous errors - diff --git a/src/tools/clippy/tests/ui-toml/missing_docs_allow_unused/clippy.toml b/src/tools/clippy/tests/ui-toml/missing_docs_in_private_items/allow_unused/clippy.toml similarity index 100% rename from src/tools/clippy/tests/ui-toml/missing_docs_allow_unused/clippy.toml rename to src/tools/clippy/tests/ui-toml/missing_docs_in_private_items/allow_unused/clippy.toml diff --git a/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/clippy.toml b/src/tools/clippy/tests/ui-toml/missing_docs_in_private_items/crate_root/clippy.toml similarity index 100% rename from src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/clippy.toml rename to src/tools/clippy/tests/ui-toml/missing_docs_in_private_items/crate_root/clippy.toml diff --git a/src/tools/clippy/tests/ui-toml/missing_docs_in_private_items/default/clippy.toml b/src/tools/clippy/tests/ui-toml/missing_docs_in_private_items/default/clippy.toml new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/tools/clippy/tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.allow_unused.stderr b/src/tools/clippy/tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.allow_unused.stderr new file mode 100644 index 0000000000000..b686288c7d27f --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.allow_unused.stderr @@ -0,0 +1,644 @@ +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:26:5 + | +LL | f3: u32, + | ^^ + | +note: the lint level is defined here + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:8:9 + | +LL | #![deny(clippy::missing_docs_in_private_items)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:60:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:77:8 + | +LL | fn f3() {} + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:78:11 + | +LL | const C3: u32 = 0; + | ^^ + +error: missing documentation for a function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:117:4 + | +LL | fn fn_crate() {} + | ^^^^^^^^ + +error: missing documentation for a constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:118:7 + | +LL | const CONST_CRATE: u32 = 0; + | ^^^^^^^^^^^ + +error: missing documentation for a static + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:119:8 + | +LL | static STATIC_CRATE: u32 = 0; + | ^^^^^^^^^^^^ + +error: missing documentation for a type alias + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:120:6 + | +LL | type TyAliasCrate = u32; + | ^^^^^^^^^^^^ + +error: missing documentation for a trait alias + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:121:7 + | +LL | trait TraitAliasCrate = Iterator; + | ^^^^^^^^^^^^^^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:122:8 + | +LL | struct StructCrate; + | ^^^^^^^^^^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:124:8 + | +LL | struct StructFieldCrate { + | ^^^^^^^^^^^^^^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:125:9 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:128:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:138:8 + | +LL | struct StructTupleCrate(u32, pub u32); + | ^^^^^^^^^^^^^^^^ + +error: missing documentation for an enum + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:140:6 + | +LL | enum EnumCrate { + | ^^^^^^^^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:141:5 + | +LL | V1, + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:142:5 + | +LL | V2(u32), + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:144:5 + | +LL | V3 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:145:9 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:155:9 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a union + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:161:7 + | +LL | union UnionCrate { + | ^^^^^^^^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:162:9 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:165:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:176:12 + | +LL | pub fn f1() {} + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:177:15 + | +LL | pub const C1: u32 = 0; + | ^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:182:8 + | +LL | fn f3() {} + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:183:11 + | +LL | const C3: u32 = 0; + | ^^ + +error: missing documentation for a trait + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:190:7 + | +LL | trait TraitCrate { + | ^^^^^^^^^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:191:8 + | +LL | fn f1(); + | ^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:192:8 + | +LL | fn f2() {} + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:193:11 + | +LL | const C1: u32; + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:194:11 + | +LL | const C2: u32 = 0; + | ^^ + +error: missing documentation for an associated type + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:195:10 + | +LL | type T1; + | ^^ + +error: missing documentation for a macro + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:216:14 + | +LL | macro_rules! mac_rules_crate { + | ^^^^^^^^^^^^^^^ + +error: missing documentation for a macro + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:220:7 + | +LL | macro mac_crate { + | ^^^^^^^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:238:9 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:241:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:255:5 + | +LL | V1, + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:256:5 + | +LL | V2(u32), + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:258:5 + | +LL | V3 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:259:9 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:269:9 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:276:9 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:279:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:290:12 + | +LL | pub fn f1() {} + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:291:15 + | +LL | pub const C1: u32 = 0; + | ^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:296:8 + | +LL | fn f3() {} + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:297:11 + | +LL | const C3: u32 = 0; + | ^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:305:8 + | +LL | fn f1(); + | ^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:306:8 + | +LL | fn f2() {} + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:307:11 + | +LL | const C1: u32; + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:308:11 + | +LL | const C2: u32 = 0; + | ^^ + +error: missing documentation for an associated type + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:309:10 + | +LL | type T1; + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:541:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:567:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:588:8 + | +LL | fn f3() {} + | ^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:591:12 + | +LL | struct S3 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:592:13 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:595:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for an enum + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:600:10 + | +LL | enum E3 { + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:602:9 + | +LL | V1 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:603:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:609:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:614:11 + | +LL | const C3: u32 = 0; + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:620:13 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:623:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:630:9 + | +LL | V1 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:631:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:637:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a module + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:647:5 + | +LL | mod mod_crate { + | ^^^^^^^^^ + +error: missing documentation for a function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:648:12 + | +LL | pub fn f1() {} + | ^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:651:16 + | +LL | pub struct S1 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:652:13 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:655:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for an enum + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:660:14 + | +LL | pub enum E1 { + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:662:9 + | +LL | V1 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:663:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:669:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:674:15 + | +LL | pub const C1: u32 = 0; + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:680:13 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:683:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:690:9 + | +LL | V1 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:691:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:697:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:705:8 + | +LL | fn f3() {} + | ^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:708:12 + | +LL | struct S3 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:709:13 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:712:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for an enum + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:717:10 + | +LL | enum E3 { + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:719:9 + | +LL | V1 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:720:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:726:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:731:11 + | +LL | const C3: u32 = 0; + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:737:13 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:740:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:747:9 + | +LL | V1 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:748:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:754:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1061:9 + | +LL | f2: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1062:20 + | +LL | pub(crate) f3: u32, + | ^^ + +error: missing documentation for a function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1069:23 + | +LL | pub(crate) fn f2() {} + | ^^ + +error: missing documentation for an enum + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1072:18 + | +LL | pub enum E1 { + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1074:13 + | +LL | V2, + | ^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1077:20 + | +LL | pub struct S2; + | ^^ + +error: missing documentation for a function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1096:18 + | +LL | $(pub fn f2() {}) + | ^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1165:20 + | +LL | pub struct VisFromOutside; + | ^^^^^^^^^^^^^^ + +error: aborting due to 106 previous errors + diff --git a/src/tools/clippy/tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.crate_root.stderr b/src/tools/clippy/tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.crate_root.stderr new file mode 100644 index 0000000000000..e95ce5615cce8 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.crate_root.stderr @@ -0,0 +1,500 @@ +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:26:5 + | +LL | f3: u32, + | ^^ + | +note: the lint level is defined here + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:8:9 + | +LL | #![deny(clippy::missing_docs_in_private_items)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:32:5 + | +LL | _f7: u32, + | ^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:60:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:66:5 + | +LL | _f7: u32, + | ^^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:77:8 + | +LL | fn f3() {} + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:78:11 + | +LL | const C3: u32 = 0; + | ^^ + +error: missing documentation for a function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:117:4 + | +LL | fn fn_crate() {} + | ^^^^^^^^ + +error: missing documentation for a constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:118:7 + | +LL | const CONST_CRATE: u32 = 0; + | ^^^^^^^^^^^ + +error: missing documentation for a static + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:119:8 + | +LL | static STATIC_CRATE: u32 = 0; + | ^^^^^^^^^^^^ + +error: missing documentation for a type alias + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:120:6 + | +LL | type TyAliasCrate = u32; + | ^^^^^^^^^^^^ + +error: missing documentation for a trait alias + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:121:7 + | +LL | trait TraitAliasCrate = Iterator; + | ^^^^^^^^^^^^^^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:122:8 + | +LL | struct StructCrate; + | ^^^^^^^^^^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:124:8 + | +LL | struct StructFieldCrate { + | ^^^^^^^^^^^^^^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:125:9 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:128:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:131:9 + | +LL | pub _f5: u32, + | ^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:134:5 + | +LL | _f7: u32, + | ^^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:138:8 + | +LL | struct StructTupleCrate(u32, pub u32); + | ^^^^^^^^^^^^^^^^ + +error: missing documentation for an enum + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:140:6 + | +LL | enum EnumCrate { + | ^^^^^^^^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:141:5 + | +LL | V1, + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:142:5 + | +LL | V2(u32), + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:144:5 + | +LL | V3 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:145:9 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:155:9 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a union + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:161:7 + | +LL | union UnionCrate { + | ^^^^^^^^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:162:9 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:165:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:168:9 + | +LL | pub _f5: u32, + | ^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:171:5 + | +LL | _f7: u32, + | ^^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:176:12 + | +LL | pub fn f1() {} + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:177:15 + | +LL | pub const C1: u32 = 0; + | ^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:182:8 + | +LL | fn f3() {} + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:183:11 + | +LL | const C3: u32 = 0; + | ^^ + +error: missing documentation for a trait + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:190:7 + | +LL | trait TraitCrate { + | ^^^^^^^^^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:191:8 + | +LL | fn f1(); + | ^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:192:8 + | +LL | fn f2() {} + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:193:11 + | +LL | const C1: u32; + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:194:11 + | +LL | const C2: u32 = 0; + | ^^ + +error: missing documentation for an associated type + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:195:10 + | +LL | type T1; + | ^^ + +error: missing documentation for a macro + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:216:14 + | +LL | macro_rules! mac_rules_crate { + | ^^^^^^^^^^^^^^^ + +error: missing documentation for a macro + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:220:7 + | +LL | macro mac_crate { + | ^^^^^^^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:238:9 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:241:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:244:9 + | +LL | pub _f5: u32, + | ^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:247:5 + | +LL | _f7: u32, + | ^^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:255:5 + | +LL | V1, + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:256:5 + | +LL | V2(u32), + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:258:5 + | +LL | V3 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:259:9 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:269:9 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:276:9 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:279:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:282:9 + | +LL | pub _f5: u32, + | ^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:285:5 + | +LL | _f7: u32, + | ^^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:290:12 + | +LL | pub fn f1() {} + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:291:15 + | +LL | pub const C1: u32 = 0; + | ^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:296:8 + | +LL | fn f3() {} + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:297:11 + | +LL | const C3: u32 = 0; + | ^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:305:8 + | +LL | fn f1(); + | ^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:306:8 + | +LL | fn f2() {} + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:307:11 + | +LL | const C1: u32; + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:308:11 + | +LL | const C2: u32 = 0; + | ^^ + +error: missing documentation for an associated type + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:309:10 + | +LL | type T1; + | ^^ + +error: missing documentation for a module + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:647:5 + | +LL | mod mod_crate { + | ^^^^^^^^^ + +error: missing documentation for a function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:648:12 + | +LL | pub fn f1() {} + | ^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:651:16 + | +LL | pub struct S1 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:652:13 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for an enum + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:660:14 + | +LL | pub enum E1 { + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:662:9 + | +LL | V1 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:663:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:669:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:674:15 + | +LL | pub const C1: u32 = 0; + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:680:13 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:690:9 + | +LL | V1 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:691:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:697:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1062:20 + | +LL | pub(crate) f3: u32, + | ^^ + +error: missing documentation for an enum + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1072:18 + | +LL | pub enum E1 { + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1074:13 + | +LL | V2, + | ^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1077:20 + | +LL | pub struct S2; + | ^^ + +error: missing documentation for a function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1096:18 + | +LL | $(pub fn f2() {}) + | ^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1165:20 + | +LL | pub struct VisFromOutside; + | ^^^^^^^^^^^^^^ + +error: aborting due to 82 previous errors + diff --git a/src/tools/clippy/tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.default.stderr b/src/tools/clippy/tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.default.stderr new file mode 100644 index 0000000000000..44a3d29580ade --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.default.stderr @@ -0,0 +1,704 @@ +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:26:5 + | +LL | f3: u32, + | ^^ + | +note: the lint level is defined here + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:8:9 + | +LL | #![deny(clippy::missing_docs_in_private_items)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:32:5 + | +LL | _f7: u32, + | ^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:60:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:66:5 + | +LL | _f7: u32, + | ^^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:77:8 + | +LL | fn f3() {} + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:78:11 + | +LL | const C3: u32 = 0; + | ^^ + +error: missing documentation for a function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:117:4 + | +LL | fn fn_crate() {} + | ^^^^^^^^ + +error: missing documentation for a constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:118:7 + | +LL | const CONST_CRATE: u32 = 0; + | ^^^^^^^^^^^ + +error: missing documentation for a static + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:119:8 + | +LL | static STATIC_CRATE: u32 = 0; + | ^^^^^^^^^^^^ + +error: missing documentation for a type alias + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:120:6 + | +LL | type TyAliasCrate = u32; + | ^^^^^^^^^^^^ + +error: missing documentation for a trait alias + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:121:7 + | +LL | trait TraitAliasCrate = Iterator; + | ^^^^^^^^^^^^^^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:122:8 + | +LL | struct StructCrate; + | ^^^^^^^^^^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:124:8 + | +LL | struct StructFieldCrate { + | ^^^^^^^^^^^^^^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:125:9 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:128:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:131:9 + | +LL | pub _f5: u32, + | ^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:134:5 + | +LL | _f7: u32, + | ^^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:138:8 + | +LL | struct StructTupleCrate(u32, pub u32); + | ^^^^^^^^^^^^^^^^ + +error: missing documentation for an enum + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:140:6 + | +LL | enum EnumCrate { + | ^^^^^^^^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:141:5 + | +LL | V1, + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:142:5 + | +LL | V2(u32), + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:144:5 + | +LL | V3 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:145:9 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:155:9 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a union + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:161:7 + | +LL | union UnionCrate { + | ^^^^^^^^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:162:9 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:165:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:168:9 + | +LL | pub _f5: u32, + | ^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:171:5 + | +LL | _f7: u32, + | ^^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:176:12 + | +LL | pub fn f1() {} + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:177:15 + | +LL | pub const C1: u32 = 0; + | ^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:182:8 + | +LL | fn f3() {} + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:183:11 + | +LL | const C3: u32 = 0; + | ^^ + +error: missing documentation for a trait + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:190:7 + | +LL | trait TraitCrate { + | ^^^^^^^^^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:191:8 + | +LL | fn f1(); + | ^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:192:8 + | +LL | fn f2() {} + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:193:11 + | +LL | const C1: u32; + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:194:11 + | +LL | const C2: u32 = 0; + | ^^ + +error: missing documentation for an associated type + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:195:10 + | +LL | type T1; + | ^^ + +error: missing documentation for a macro + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:216:14 + | +LL | macro_rules! mac_rules_crate { + | ^^^^^^^^^^^^^^^ + +error: missing documentation for a macro + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:220:7 + | +LL | macro mac_crate { + | ^^^^^^^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:238:9 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:241:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:244:9 + | +LL | pub _f5: u32, + | ^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:247:5 + | +LL | _f7: u32, + | ^^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:255:5 + | +LL | V1, + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:256:5 + | +LL | V2(u32), + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:258:5 + | +LL | V3 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:259:9 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:269:9 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:276:9 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:279:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:282:9 + | +LL | pub _f5: u32, + | ^^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:285:5 + | +LL | _f7: u32, + | ^^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:290:12 + | +LL | pub fn f1() {} + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:291:15 + | +LL | pub const C1: u32 = 0; + | ^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:296:8 + | +LL | fn f3() {} + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:297:11 + | +LL | const C3: u32 = 0; + | ^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:305:8 + | +LL | fn f1(); + | ^^ + +error: missing documentation for an associated function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:306:8 + | +LL | fn f2() {} + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:307:11 + | +LL | const C1: u32; + | ^^ + +error: missing documentation for an associated constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:308:11 + | +LL | const C2: u32 = 0; + | ^^ + +error: missing documentation for an associated type + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:309:10 + | +LL | type T1; + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:541:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:567:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:588:8 + | +LL | fn f3() {} + | ^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:591:12 + | +LL | struct S3 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:592:13 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:595:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for an enum + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:600:10 + | +LL | enum E3 { + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:602:9 + | +LL | V1 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:603:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:609:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:614:11 + | +LL | const C3: u32 = 0; + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:620:13 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:623:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:630:9 + | +LL | V1 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:631:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:637:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a module + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:647:5 + | +LL | mod mod_crate { + | ^^^^^^^^^ + +error: missing documentation for a function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:648:12 + | +LL | pub fn f1() {} + | ^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:651:16 + | +LL | pub struct S1 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:652:13 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:655:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for an enum + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:660:14 + | +LL | pub enum E1 { + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:662:9 + | +LL | V1 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:663:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:669:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:674:15 + | +LL | pub const C1: u32 = 0; + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:680:13 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:683:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:690:9 + | +LL | V1 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:691:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:697:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:705:8 + | +LL | fn f3() {} + | ^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:708:12 + | +LL | struct S3 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:709:13 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:712:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for an enum + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:717:10 + | +LL | enum E3 { + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:719:9 + | +LL | V1 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:720:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:726:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a constant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:731:11 + | +LL | const C3: u32 = 0; + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:737:13 + | +LL | pub f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:740:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:747:9 + | +LL | V1 { + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:748:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:754:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1061:9 + | +LL | f2: u32, + | ^^ + +error: missing documentation for a field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1062:20 + | +LL | pub(crate) f3: u32, + | ^^ + +error: missing documentation for a function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1069:23 + | +LL | pub(crate) fn f2() {} + | ^^ + +error: missing documentation for an enum + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1072:18 + | +LL | pub enum E1 { + | ^^ + +error: missing documentation for a variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1074:13 + | +LL | V2, + | ^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1077:20 + | +LL | pub struct S2; + | ^^ + +error: missing documentation for a function + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1096:18 + | +LL | $(pub fn f2() {}) + | ^^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1165:20 + | +LL | pub struct VisFromOutside; + | ^^^^^^^^^^^^^^ + +error: aborting due to 116 previous errors + diff --git a/src/tools/clippy/tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs b/src/tools/clippy/tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs new file mode 100644 index 0000000000000..0a7730a4ee7f8 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs @@ -0,0 +1,1167 @@ +//@aux-build:../../ui/auxiliary/proc_macros.rs +//@revisions: default crate_root allow_unused +//@[default] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/missing_docs_in_private_items/default +//@[crate_root] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/missing_docs_in_private_items/crate_root +//@[allow_unused] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/missing_docs_in_private_items/allow_unused + +#![feature(decl_macro, trait_alias)] +#![deny(clippy::missing_docs_in_private_items)] +#![allow(non_local_definitions)] + +extern crate proc_macros; +use proc_macros::{external, with_span}; + +fn main() {} + +pub fn fn_pub() {} +pub const CONST_PUB: u32 = 0; +pub static STATIC_PUB: u32 = 0; +pub type TyAliasPub = u32; +pub trait TraitAliasPub = Iterator; +pub struct StructPub; +pub struct StructFieldPub { + pub f1: u32, + /// docs + pub f2: u32, + f3: u32, //~ missing_docs_in_private_items + /// docs + f4: u32, + pub _f5: u32, + /// docs + pub _f6: u32, + _f7: u32, //~[default,crate_root] missing_docs_in_private_items + /// docs + _f8: u32, +} +pub struct StructTuplePub(u32, pub u32); +pub enum EnumPub { + V1, + V2(u32), + V3 { + f1: u32, + /// docs + f2: u32, + }, + /// docs + V4, + /// docs + V5(u32), + /// docs + V6 { + f1: u32, + /// docs + f2: u32, + }, +} +pub union UnionPub { + pub f1: u32, + /// docs + pub f2: u32, + f3: u32, //~ missing_docs_in_private_items + /// docs + f4: u32, + pub _f5: u32, + /// docs + pub _f6: u32, + _f7: u32, //~[default,crate_root] missing_docs_in_private_items + /// docs + _f8: u32, +} +impl StructFieldPub { + pub fn f1() {} + pub const C1: u32 = 0; + /// docs + pub fn f2() {} + /// docs + pub const C2: u32 = 0; + fn f3() {} //~ missing_docs_in_private_items + const C3: u32 = 0; //~ missing_docs_in_private_items + /// docs + fn f4() {} + /// docs + const C4: u32 = 0; +} +pub trait TraitPub { + fn f1(); + fn f2() {} + const C1: u32; + const C2: u32 = 0; + type T1; + /// docs + fn f3(); + /// docs + fn f4() {} + /// docs + const C3: u32; + /// docs + const C4: u32 = 0; + /// docs + type T2; +} +impl TraitPub for StructPub { + fn f1() {} + const C1: u32 = 0; + type T1 = u32; + fn f3() {} + const C3: u32 = 0; + type T2 = u32; +} +#[macro_export] +macro_rules! mac_rules_pub { + () => {}; +} +pub macro mac_pub { + () => {}, +} + +fn fn_crate() {} //~ missing_docs_in_private_items +const CONST_CRATE: u32 = 0; //~ missing_docs_in_private_items +static STATIC_CRATE: u32 = 0; //~ missing_docs_in_private_items +type TyAliasCrate = u32; //~ missing_docs_in_private_items +trait TraitAliasCrate = Iterator; //~ missing_docs_in_private_items +struct StructCrate; //~ missing_docs_in_private_items +//~v missing_docs_in_private_items +struct StructFieldCrate { + pub f1: u32, //~ missing_docs_in_private_items + /// docs + pub f2: u32, + f3: u32, //~ missing_docs_in_private_items + /// docs + f4: u32, + pub _f5: u32, //~[default,crate_root] missing_docs_in_private_items + /// docs + pub _f6: u32, + _f7: u32, //~[default,crate_root] missing_docs_in_private_items + /// docs + _f8: u32, +} +struct StructTupleCrate(u32, pub u32); //~ missing_docs_in_private_items +//~v missing_docs_in_private_items +enum EnumCrate { + V1, //~ missing_docs_in_private_items + V2(u32), //~ missing_docs_in_private_items + //~v missing_docs_in_private_items + V3 { + f1: u32, //~ missing_docs_in_private_items + /// docs + f2: u32, + }, + /// docs + V4, + /// docs + V5(u32), + /// docs + V6 { + f1: u32, //~ missing_docs_in_private_items + /// docs + f2: u32, + }, +} +//~v missing_docs_in_private_items +union UnionCrate { + pub f1: u32, //~ missing_docs_in_private_items + /// docs + pub f2: u32, + f3: u32, //~ missing_docs_in_private_items + /// docs + f4: u32, + pub _f5: u32, //~[default,crate_root] missing_docs_in_private_items + /// docs + pub _f6: u32, + _f7: u32, //~[default,crate_root] missing_docs_in_private_items + /// docs + _f8: u32, +} +impl StructFieldCrate { + pub fn f1() {} //~ missing_docs_in_private_items + pub const C1: u32 = 0; //~ missing_docs_in_private_items + /// docs + pub fn f2() {} + /// docs + pub const C2: u32 = 0; + fn f3() {} //~ missing_docs_in_private_items + const C3: u32 = 0; //~ missing_docs_in_private_items + /// docs + fn f4() {} + /// docs + const C4: u32 = 0; +} +//~v missing_docs_in_private_items +trait TraitCrate { + fn f1(); //~ missing_docs_in_private_items + fn f2() {} //~ missing_docs_in_private_items + const C1: u32; //~ missing_docs_in_private_items + const C2: u32 = 0; //~ missing_docs_in_private_items + type T1; //~ missing_docs_in_private_items + /// docs + fn f3(); + /// docs + fn f4() {} + /// docs + const C3: u32; + /// docs + const C4: u32 = 0; + /// docs + type T2; +} +impl TraitCrate for StructCrate { + fn f1() {} + const C1: u32 = 0; + type T1 = u32; + fn f3() {} + const C3: u32 = 0; + type T2 = u32; +} +//~v missing_docs_in_private_items +macro_rules! mac_rules_crate { + () => {}; +} +//~v missing_docs_in_private_items +macro mac_crate { + () => {}, +} + +/// docs +fn fn_crate_doc() {} +/// docs +const CONST_CRATE_DOC: u32 = 0; +/// docs +static STATIC_CRATE_DOC: u32 = 0; +/// docs +type TyAliasCrateDoc = u32; +/// docs +trait TraitAliasCrateDoc = Iterator; +/// docs +struct StructCrateDoc; +/// docs +struct StructFieldCrateDoc { + pub f1: u32, //~ missing_docs_in_private_items + /// docs + pub f2: u32, + f3: u32, //~ missing_docs_in_private_items + /// docs + f4: u32, + pub _f5: u32, //~[default,crate_root] missing_docs_in_private_items + /// docs + pub _f6: u32, + _f7: u32, //~[default,crate_root] missing_docs_in_private_items + /// docs + _f8: u32, +} +/// docs +struct StructTupleCrateDoc(u32, pub u32); +/// docs +enum EnumCrateDoc { + V1, //~ missing_docs_in_private_items + V2(u32), //~ missing_docs_in_private_items + //~v missing_docs_in_private_items + V3 { + f1: u32, //~ missing_docs_in_private_items + /// docs + f2: u32, + }, + /// docs + V4, + /// docs + V5(u32), + /// docs + V6 { + f1: u32, //~ missing_docs_in_private_items + /// docs + f2: u32, + }, +} +/// docs +union UnionCrateDoc { + pub f1: u32, //~ missing_docs_in_private_items + /// docs + pub f2: u32, + f3: u32, //~ missing_docs_in_private_items + /// docs + f4: u32, + pub _f5: u32, //~[default,crate_root] missing_docs_in_private_items + /// docs + pub _f6: u32, + _f7: u32, //~[default,crate_root] missing_docs_in_private_items + /// docs + _f8: u32, +} +impl StructFieldCrateDoc { + pub fn f1() {} //~ missing_docs_in_private_items + pub const C1: u32 = 0; //~ missing_docs_in_private_items + /// docs + pub fn f2() {} + /// docs + pub const C2: u32 = 0; + fn f3() {} //~ missing_docs_in_private_items + const C3: u32 = 0; //~ missing_docs_in_private_items + /// docs + fn f4() {} + /// docs + const C4: u32 = 0; +} +/// docs +trait TraitCrateDoc { + fn f1(); //~ missing_docs_in_private_items + fn f2() {} //~ missing_docs_in_private_items + const C1: u32; //~ missing_docs_in_private_items + const C2: u32 = 0; //~ missing_docs_in_private_items + type T1; //~ missing_docs_in_private_items + /// docs + fn f3(); + /// docs + fn f4() {} + /// docs + const C3: u32; + /// docs + const C4: u32 = 0; + /// docs + type T2; +} +impl TraitCrate for StructCrateDoc { + fn f1() {} + const C1: u32 = 0; + type T1 = u32; + fn f3() {} + const C3: u32 = 0; + type T2 = u32; +} +/// docs +macro_rules! mac_rules_crate_doc { + () => {}; +} +/// docs +macro mac_crate_doc { + () => {}, +} + +#[doc(hidden)] +fn fn_crate_hidden() {} +#[doc(hidden)] +const CONST_CRATE_HIDDEN: u32 = 0; +#[doc(hidden)] +static STATIC_CRATE_HIDDEN: u32 = 0; +#[doc(hidden)] +type TyAliasCrateHidden = u32; +#[doc(hidden)] +trait TraitAliasCrateHidden = Iterator; +#[doc(hidden)] +struct StructCrateHidden; +#[doc(hidden)] +struct StructFieldCrateHidden { + pub f1: u32, + /// docs + pub f2: u32, + f3: u32, + /// docs + f4: u32, + pub _f5: u32, + /// docs + pub _f6: u32, + _f7: u32, + /// docs + _f8: u32, +} +#[doc(hidden)] +struct StructTupleCrateHidden(u32, pub u32); +#[doc(hidden)] +enum EnumCrateHidden { + V1, + V2(u32), + V3 { + f1: u32, + /// docs + f2: u32, + }, + V4, + V5(u32), + /// docs + V6 { + f1: u32, + /// docs + f2: u32, + }, +} +#[doc(hidden)] +union UnionCrateHidden { + pub f1: u32, + /// docs + pub f2: u32, + f3: u32, + /// docs + f4: u32, + pub _f5: u32, + /// docs + pub _f6: u32, + _f7: u32, + /// docs + _f8: u32, +} +#[doc(hidden)] +impl StructFieldCrateHidden { + pub fn f1() {} + pub const C1: u32 = 0; + /// docs + pub fn f2() {} + /// docs + pub const C2: u32 = 0; + fn f3() {} + const C3: u32 = 0; + /// docs + fn f4() {} + /// docs + const C4: u32 = 0; +} +#[doc(hidden)] +trait TraitCrateHidden { + fn f1(); + fn f2() {} + const C1: u32; + const C2: u32 = 0; + type T1; + /// docs + fn f3(); + /// docs + fn f4() {} + /// docs + const C3: u32; + /// docs + const C4: u32 = 0; + /// docs + type T2; +} +#[doc(hidden)] +macro_rules! mac_rules_crate_hidden { + () => {}; +} +#[doc(hidden)] +macro mac_crate_hidden { + () => {}, +} + +#[expect(clippy::missing_docs_in_private_items)] +fn fn_crate_expect() {} +#[expect(clippy::missing_docs_in_private_items)] +const CONST_CRATE_EXPECT: u32 = 0; +#[expect(clippy::missing_docs_in_private_items)] +static STATIC_CRATE_EXPECT: u32 = 0; +#[expect(clippy::missing_docs_in_private_items)] +type TyAliasCrateExpect = u32; +#[expect(clippy::missing_docs_in_private_items)] +trait TraitAliasCrateExpect = Iterator; +#[expect(clippy::missing_docs_in_private_items)] +struct StructCrateExpect; +#[expect(clippy::missing_docs_in_private_items)] +struct StructFieldCrateExpect { + #[expect(clippy::missing_docs_in_private_items)] + pub f1: u32, + /// docs + pub f2: u32, + #[expect(clippy::missing_docs_in_private_items)] + f3: u32, + /// docs + f4: u32, +} +#[expect(clippy::missing_docs_in_private_items)] +struct StructTupleCrateExpect(u32, pub u32); +#[expect(clippy::missing_docs_in_private_items)] +enum EnumCrateExpect { + #[expect(clippy::missing_docs_in_private_items)] + V1, + #[expect(clippy::missing_docs_in_private_items)] + V2(u32), + #[expect(clippy::missing_docs_in_private_items)] + V3 { + #[expect(clippy::missing_docs_in_private_items)] + f1: u32, + /// docs + f2: u32, + }, + /// docs + V4, + /// docs + V5(u32), + /// docs + V6 { + #[expect(clippy::missing_docs_in_private_items)] + f1: u32, + /// docs + f2: u32, + }, +} +#[expect(clippy::missing_docs_in_private_items)] +union UnionCrateExpect { + #[expect(clippy::missing_docs_in_private_items)] + pub f1: u32, + /// docs + pub f2: u32, + #[expect(clippy::missing_docs_in_private_items)] + f3: u32, + /// docs + f4: u32, +} +impl StructFieldCrateExpect { + #[expect(clippy::missing_docs_in_private_items)] + pub fn f1() {} + #[expect(clippy::missing_docs_in_private_items)] + pub const C1: u32 = 0; + #[expect(clippy::missing_docs_in_private_items)] + fn f2() {} + #[expect(clippy::missing_docs_in_private_items)] + const C2: u32 = 0; +} +#[expect(clippy::missing_docs_in_private_items)] +trait TraitCrateExpect { + #[expect(clippy::missing_docs_in_private_items)] + fn f1(); + #[expect(clippy::missing_docs_in_private_items)] + fn f2() {} + #[expect(clippy::missing_docs_in_private_items)] + const C1: u32; + #[expect(clippy::missing_docs_in_private_items)] + const C2: u32 = 0; + #[expect(clippy::missing_docs_in_private_items)] + type T1; +} +#[expect(clippy::missing_docs_in_private_items)] +macro_rules! mac_rules_crate_expect { + () => {}; +} +#[expect(clippy::missing_docs_in_private_items)] +macro mac_crate_expect { + () => {}, +} + +pub mod mod_pub { + pub fn f1() {} + pub struct S1 { + pub f1: u32, + /// docs + pub f2: u32, + f3: u32, //~[default,allow_unused] missing_docs_in_private_items + /// docs + f4: u32, + } + pub enum E1 { + V1 { + f1: u32, + /// docs + f2: u32, + }, + /// docs + V2 { + f1: u32, + /// docs + f2: u32, + }, + } + pub const C1: u32 = 0; + + /// docs + pub fn f2() {} + /// docs + pub struct S2 { + pub f1: u32, + /// docs + pub f2: u32, + f3: u32, //~[default,allow_unused] missing_docs_in_private_items + /// docs + f4: u32, + } + /// docs + pub enum E2 { + V1 { + f1: u32, + /// docs + f2: u32, + }, + /// docs + V2 { + f1: u32, + /// docs + f2: u32, + }, + } + /// docs + pub const C2: u32 = 0; + + fn f3() {} //~[default,allow_unused] missing_docs_in_private_items + // + //~[default,allow_unused]v missing_docs_in_private_items + struct S3 { + pub f1: u32, //~[default,allow_unused] missing_docs_in_private_items + /// docs + pub f2: u32, + f3: u32, //~[default,allow_unused] missing_docs_in_private_items + /// docs + f4: u32, + } + //~[default,allow_unused]v missing_docs_in_private_items + enum E3 { + //~[default,allow_unused]v missing_docs_in_private_items + V1 { + f1: u32, //~[default,allow_unused] missing_docs_in_private_items + /// docs + f2: u32, + }, + /// docs + V2 { + f1: u32, //~[default,allow_unused] missing_docs_in_private_items + /// docs + f2: u32, + }, + } + const C3: u32 = 0; //~[default,allow_unused] missing_docs_in_private_items + + /// docs + fn f4() {} + /// docs + struct S4 { + pub f1: u32, //~[default,allow_unused] missing_docs_in_private_items + /// docs + pub f2: u32, + f3: u32, //~[default,allow_unused] missing_docs_in_private_items + /// docs + f4: u32, + } + /// docs + enum E4 { + //~[default,allow_unused]v missing_docs_in_private_items + V1 { + f1: u32, //~[default,allow_unused] missing_docs_in_private_items + /// docs + f2: u32, + }, + /// docs + V2 { + f1: u32, //~[default,allow_unused] missing_docs_in_private_items + /// docs + f2: u32, + }, + } + /// docs + const C4: u32 = 0; +} + +//~v missing_docs_in_private_items +mod mod_crate { + pub fn f1() {} //~ missing_docs_in_private_items + // + //~v missing_docs_in_private_items + pub struct S1 { + pub f1: u32, //~ missing_docs_in_private_items + /// docs + pub f2: u32, + f3: u32, //~[default,allow_unused] missing_docs_in_private_items + /// docs + f4: u32, + } + //~v missing_docs_in_private_items + pub enum E1 { + //~v missing_docs_in_private_items + V1 { + f1: u32, //~ missing_docs_in_private_items + /// docs + f2: u32, + }, + /// docs + V2 { + f1: u32, //~ missing_docs_in_private_items + /// docs + f2: u32, + }, + } + pub const C1: u32 = 0; //~ missing_docs_in_private_items + + /// docs + pub fn f2() {} + /// docs + pub struct S2 { + pub f1: u32, //~ missing_docs_in_private_items + /// docs + pub f2: u32, + f3: u32, //~[default,allow_unused] missing_docs_in_private_items + /// docs + f4: u32, + } + /// docs + pub enum E2 { + //~v missing_docs_in_private_items + V1 { + f1: u32, //~ missing_docs_in_private_items + /// docs + f2: u32, + }, + /// docs + V2 { + f1: u32, //~ missing_docs_in_private_items + /// docs + f2: u32, + }, + } + /// docs + pub const C2: u32 = 0; + + fn f3() {} //~[default,allow_unused] missing_docs_in_private_items + // + //~[default,allow_unused]v missing_docs_in_private_items + struct S3 { + pub f1: u32, //~[default,allow_unused] missing_docs_in_private_items + /// docs + pub f2: u32, + f3: u32, //~[default,allow_unused] missing_docs_in_private_items + /// docs + f4: u32, + } + //~[default,allow_unused]v missing_docs_in_private_items + enum E3 { + //~[default,allow_unused]v missing_docs_in_private_items + V1 { + f1: u32, //~[default,allow_unused] missing_docs_in_private_items + /// docs + f2: u32, + }, + /// docs + V2 { + f1: u32, //~[default,allow_unused] missing_docs_in_private_items + /// docs + f2: u32, + }, + } + const C3: u32 = 0; //~[default,allow_unused] missing_docs_in_private_items + + /// docs + fn f4() {} + /// docs + struct S4 { + pub f1: u32, //~[default,allow_unused] missing_docs_in_private_items + /// docs + pub f2: u32, + f3: u32, //~[default,allow_unused] missing_docs_in_private_items + /// docs + f4: u32, + } + /// docs + enum E4 { + //~[default,allow_unused]v missing_docs_in_private_items + V1 { + f1: u32, //~[default,allow_unused] missing_docs_in_private_items + /// docs + f2: u32, + }, + /// docs + V2 { + f1: u32, //~[default,allow_unused] missing_docs_in_private_items + /// docs + f2: u32, + }, + } + /// docs + const C4: u32 = 0; +} + +/// docs +mod mod_crate_doc {} + +#[doc(hidden)] +mod mod_crate_hidden { + pub fn f1() {} + pub struct S1 { + pub f1: u32, + /// docs + pub f2: u32, + f3: u32, + /// docs + f4: u32, + } + pub enum E1 { + V1 { + f1: u32, + /// docs + f2: u32, + }, + /// docs + V2 { + f1: u32, + /// docs + f2: u32, + }, + } + pub const C1: u32 = 0; + + /// docs + pub fn f2() {} + /// docs + pub struct S2 { + pub f1: u32, + /// docs + pub f2: u32, + f3: u32, + /// docs + f4: u32, + } + /// docs + pub enum E2 { + V1 { + f1: u32, + /// docs + f2: u32, + }, + /// docs + V2 { + f1: u32, + /// docs + f2: u32, + }, + } + /// docs + pub const C2: u32 = 0; + + fn f3() {} + struct S3 { + pub f1: u32, + /// docs + pub f2: u32, + f3: u32, + /// docs + f4: u32, + } + enum E3 { + V1 { + f1: u32, + /// docs + f2: u32, + }, + /// docs + V2 { + f1: u32, + /// docs + f2: u32, + }, + } + const C3: u32 = 0; + + /// docs + fn f4() {} + /// docs + struct S4 { + pub f1: u32, + /// docs + pub f2: u32, + f3: u32, + /// docs + f4: u32, + } + /// docs + enum E4 { + V1 { + f1: u32, + /// docs + f2: u32, + }, + /// docs + V2 { + f1: u32, + /// docs + f2: u32, + }, + } + /// docs + const C4: u32 = 0; +} + +#[expect(clippy::missing_docs_in_private_items)] +mod mod_crate_expect {} + +#[doc = "docs"] +mod explicit_doc_attr {} + +with_span! { + sp + fn fn_pm() {} + const CONST_PM: u32 = 0; + static STATIC_PM: u32 = 0; + type TyAliasPm = u32; + trait TraitAliasPm = Iterator; + struct StructPm; + struct StructFieldPm { + pub f1: u32, + f2: u32, + pub _f3: u32, + _f4: u32, + } + struct StructTuplePm(u32, pub u32); + enum EnumPm { + V1, + V2(u32), + V3 { f1: u32, }, + } + union UnionPm { + pub f1: u32, + f2: u32, + pub _f3: u32, + _f4: u32, + } + impl StructFieldPm { + pub fn f1() {} + pub const C1: u32 = 0; + fn f2() {} + const C2: u32 = 0; + } + trait TraitPm { + fn f1(); + fn f2() {} + const C1: u32; + const C2: u32 = 0; + type T1; + } + impl TraitPm for StructPm { + fn f1() {} + const C1: u32 = 0; + type T1 = u32; + } + macro_rules! mac_rules_pm { + () => {}; + } + macro mac_pm { + () => {}, + } + mod mod_pm {} +} + +external! { + fn fn_external() {} + const CONST_EXTERNAL: u32 = 0; + static STATIC_EXTERNAL: u32 = 0; + type TyAliasExternal = u32; + trait TraitAliasExternal = Iterator; + struct StructExternal; + struct StructFieldExternal { + pub f1: u32, + f2: u32, + pub _f3: u32, + _f4: u32, + } + struct StructTupleExternal(u32, pub u32); + enum EnumExternal { + V1, + V2(u32), + V3 { f1: u32, }, + } + union UnionExternal { + pub f1: u32, + f2: u32, + pub _f3: u32, + _f4: u32, + } + impl StructFieldExternal { + pub fn f1() {} + pub const C1: u32 = 0; + fn f2() {} + const C2: u32 = 0; + } + trait TraitExternal { + fn f1(); + fn f2() {} + const C1: u32; + const C2: u32 = 0; + type T1; + } + impl TraitExternal for StructExternal { + fn f1() {} + const C1: u32 = 0; + type T1 = u32; + } + macro_rules! mac_rules_external { + () => {}; + } + macro mac_external { + () => {}, + } + mod mod_external {} +} + +pub const _: () = {}; +const _: () = {}; + +/// docs +fn fn_with_items() { + fn f() {} + type T = u32; + struct S { + f1: u32, + f2: u32, + } + enum E { + V { f: u32 }, + } + impl S { + fn f() {} + const C: u32 = 0; + } + const C: u32 = 0; + static ST: u32 = 0; + trait Tr { + fn f(); + type T; + const C: u32; + } + trait Tr2 = Tr; + mod m {} + macro_rules! m2 { + () => {}; + } + macro m3 { () => {}, } + union U { + f: u32, + } +} +/// docs +const CONST_WITH_ITEMS: () = { + fn f() {} +}; +/// docs +static STATIC_WITH_ITEMS: () = { + fn f() {} +}; +/// docs +trait TraitWithItems { + /// docs + fn f() { + fn f() {} + } + /// docs + const C: () = { + fn f() {} + }; +} +/// docs +struct StructWithItems; +impl StructWithItems { + /// docs + fn f() { + fn f() {} + } + /// docs + const C: () = { + fn f() {} + }; +} +/// docs +type TypeAliasWithItems = [u32; { + fn f() {} + 1 +}]; + +/// docs +mod with_reexports { + pub fn f1_reexport() {} + pub struct S1Reexport { + pub f1: u32, + f2: u32, //~[default,allow_unused] missing_docs_in_private_items + pub(crate) f3: u32, //~ missing_docs_in_private_items + /// docs + f4: u32, + } + + /// docs + mod m1 { + pub(crate) fn f2() {} //~[default,allow_unused] missing_docs_in_private_items + + //~v missing_docs_in_private_items + pub enum E1 { + V1Reexport, + V2, //~ missing_docs_in_private_items + } + + pub struct S2; //~ missing_docs_in_private_items + pub fn f3_reexport() -> S2 { + S2 + } + } + pub use m1::E1::{V1Reexport, V2}; + use m1::f2; + pub use m1::f3_reexport; +} +pub use with_reexports::{S1Reexport, V1Reexport, f1_reexport, f3_reexport}; + +external! { + mod mod_generated { + $(type T = u32;) + struct S { + $(f1: u32,) + f2: u32, + } + pub fn f() {} + $(pub fn f2() {}) //~ missing_docs_in_private_items + #[doc(hidden)] + $(pub fn f3() {}) + } +} + +/// docs +mod mod_with_hidden { + #[doc(hidden)] + pub mod m { + pub struct S { + #[doc(hidden)] + pub f: u32, + } + #[automatically_derived] + impl S { + #[doc(hidden)] + pub fn f() {} + pub const C: () = { + #[automatically_derived] + impl S { + #[doc(hidden)] + pub fn f2() { + mod m { + pub(crate) union U { + pub f: u32, + } + } + } + } + }; + } + } + #[doc(hidden)] + pub(crate) fn f() {} +} + +/// docs +struct WithProject { + /// docs + a: u32, + /// docs + b: u32, +} +with_span! { + span + const _: () = { + // Similar output to pin_project + struct Project<'a> { + $(a: &'a u32), + $(b: &'a u32), + } + impl $(WithProject) { + fn project(&self) -> Project<'_> { + Project { + a: &self.a, + b: &self.b, + } + } + } + }; +} + +external! { + mod mod_mac_with_pub {$( + struct DerivedFromInput; + impl DerivedFromInput { + pub fn foo() {} + } + pub struct VisFromOutside; //~ missing_docs_in_private_items + )} +} diff --git a/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs b/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs deleted file mode 100644 index 6a1d2b51abc8f..0000000000000 --- a/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs +++ /dev/null @@ -1,67 +0,0 @@ -//! this is crate -#![allow(missing_docs)] -#![allow(clippy::struct_field_names)] -#![warn(clippy::missing_docs_in_private_items)] - -/// this is mod -mod my_mod { - /// some docs - fn priv_with_docs() {} - fn priv_no_docs() {} - /// some docs - pub(crate) fn crate_with_docs() {} - pub(crate) fn crate_no_docs() {} - //~^ missing_docs_in_private_items - /// some docs - pub(super) fn super_with_docs() {} - pub(super) fn super_no_docs() {} - //~^ missing_docs_in_private_items - - mod my_sub { - /// some docs - fn sub_priv_with_docs() {} - fn sub_priv_no_docs() {} - /// some docs - pub(crate) fn sub_crate_with_docs() {} - pub(crate) fn sub_crate_no_docs() {} - //~^ missing_docs_in_private_items - /// some docs - pub(super) fn sub_super_with_docs() {} - pub(super) fn sub_super_no_docs() {} - } - - /// some docs - pub(crate) struct CrateStructWithDocs { - /// some docs - pub(crate) crate_field_with_docs: (), - pub(crate) crate_field_no_docs: (), - //~^ missing_docs_in_private_items - /// some docs - priv_field_with_docs: (), - priv_field_no_docs: (), - } - - pub(crate) struct CrateStructNoDocs { - //~^ missing_docs_in_private_items - /// some docs - pub(crate) crate_field_with_docs: (), - pub(crate) crate_field_no_docs: (), - //~^ missing_docs_in_private_items - /// some docs - priv_field_with_docs: (), - priv_field_no_docs: (), - } -} - -/// some docs -type CrateTypedefWithDocs = String; -type CrateTypedefNoDocs = String; -//~^ missing_docs_in_private_items -/// some docs -pub type PubTypedefWithDocs = String; -pub type PubTypedefNoDocs = String; - -fn main() { - my_mod::crate_with_docs(); - my_mod::crate_no_docs(); -} diff --git a/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr b/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr deleted file mode 100644 index 0d70276de42d3..0000000000000 --- a/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr +++ /dev/null @@ -1,53 +0,0 @@ -error: missing documentation for a function - --> tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs:13:5 - | -LL | pub(crate) fn crate_no_docs() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::missing_docs_in_private_items)]` - -error: missing documentation for a function - --> tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs:17:5 - | -LL | pub(super) fn super_no_docs() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: missing documentation for a function - --> tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs:26:9 - | -LL | pub(crate) fn sub_crate_no_docs() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: missing documentation for a struct field - --> tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs:37:9 - | -LL | pub(crate) crate_field_no_docs: (), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: missing documentation for a struct - --> tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs:44:5 - | -LL | / pub(crate) struct CrateStructNoDocs { -LL | | -LL | | /// some docs -LL | | pub(crate) crate_field_with_docs: (), -... | -LL | | priv_field_no_docs: (), -LL | | } - | |_____^ - -error: missing documentation for a struct field - --> tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs:48:9 - | -LL | pub(crate) crate_field_no_docs: (), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: missing documentation for a type alias - --> tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs:58:1 - | -LL | type CrateTypedefNoDocs = String; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 7 previous errors - diff --git a/src/tools/clippy/tests/ui-toml/result_large_err/clippy.toml b/src/tools/clippy/tests/ui-toml/result_large_err/clippy.toml index df505ed9672a6..80eeac0f9870d 100644 --- a/src/tools/clippy/tests/ui-toml/result_large_err/clippy.toml +++ b/src/tools/clippy/tests/ui-toml/result_large_err/clippy.toml @@ -1 +1,2 @@ large-error-threshold = 512 +large-error-ignored = ["result_large_err::IgnoredError", "result_large_err::IgnoredErrorEnum"] diff --git a/src/tools/clippy/tests/ui-toml/result_large_err/result_large_err.rs b/src/tools/clippy/tests/ui-toml/result_large_err/result_large_err.rs index dea4d61a96bfb..170f37db7593e 100644 --- a/src/tools/clippy/tests/ui-toml/result_large_err/result_large_err.rs +++ b/src/tools/clippy/tests/ui-toml/result_large_err/result_large_err.rs @@ -1,4 +1,6 @@ +//@compile-flags: --crate-name result_large_err #![warn(clippy::result_large_err)] +#![allow(clippy::large_enum_variant)] fn f() -> Result<(), [u8; 511]> { todo!() @@ -7,4 +9,22 @@ fn f2() -> Result<(), [u8; 512]> { //~^ ERROR: the `Err`-variant returned from this function is very large todo!() } + +struct IgnoredError { + inner: [u8; 512], +} + +fn f3() -> Result<(), IgnoredError> { + todo!() +} + +enum IgnoredErrorEnum { + V1, + V2 { inner: [u8; 512] }, +} + +fn f4() -> Result<(), IgnoredErrorEnum> { + todo!() +} + fn main() {} diff --git a/src/tools/clippy/tests/ui-toml/result_large_err/result_large_err.stderr b/src/tools/clippy/tests/ui-toml/result_large_err/result_large_err.stderr index 656ce7ab7f2fa..7e5954f885b82 100644 --- a/src/tools/clippy/tests/ui-toml/result_large_err/result_large_err.stderr +++ b/src/tools/clippy/tests/ui-toml/result_large_err/result_large_err.stderr @@ -1,5 +1,5 @@ error: the `Err`-variant returned from this function is very large - --> tests/ui-toml/result_large_err/result_large_err.rs:6:12 + --> tests/ui-toml/result_large_err/result_large_err.rs:8:12 | LL | fn f2() -> Result<(), [u8; 512]> { | ^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index 2d9503c5ac53a..d5040f4a39bfd 100644 --- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -50,6 +50,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect future-size-threshold ignore-interior-mutability inherent-impl-lint-scope + large-error-ignored large-error-threshold lint-commented-code literal-representation-threshold @@ -147,6 +148,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect future-size-threshold ignore-interior-mutability inherent-impl-lint-scope + large-error-ignored large-error-threshold lint-commented-code literal-representation-threshold @@ -244,6 +246,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni future-size-threshold ignore-interior-mutability inherent-impl-lint-scope + large-error-ignored large-error-threshold lint-commented-code literal-representation-threshold diff --git a/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.rs b/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.rs index de699309b16d1..1cd45685609f0 100644 --- a/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.rs +++ b/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.rs @@ -3,7 +3,7 @@ #![warn(clippy::blanket_clippy_restriction_lints)] -//! Test that the whole restriction group is not enabled +//! Test that the whole restriction group is not enabled. #![warn(clippy::restriction)] //~^ blanket_clippy_restriction_lints #![deny(clippy::restriction)] diff --git a/src/tools/clippy/tests/ui/byte_char_slices.fixed b/src/tools/clippy/tests/ui/byte_char_slices.fixed index b0c1b1f034b4d..87934d6362f75 100644 --- a/src/tools/clippy/tests/ui/byte_char_slices.fixed +++ b/src/tools/clippy/tests/ui/byte_char_slices.fixed @@ -1,4 +1,3 @@ -#![allow(unused)] #![warn(clippy::byte_char_slices)] fn main() { diff --git a/src/tools/clippy/tests/ui/byte_char_slices.rs b/src/tools/clippy/tests/ui/byte_char_slices.rs index 0d6953dda97e7..0de7cf66fda89 100644 --- a/src/tools/clippy/tests/ui/byte_char_slices.rs +++ b/src/tools/clippy/tests/ui/byte_char_slices.rs @@ -1,4 +1,3 @@ -#![allow(unused)] #![warn(clippy::byte_char_slices)] fn main() { diff --git a/src/tools/clippy/tests/ui/byte_char_slices.stderr b/src/tools/clippy/tests/ui/byte_char_slices.stderr index 2556aa9c0f76b..c1b7e4ca2f17d 100644 --- a/src/tools/clippy/tests/ui/byte_char_slices.stderr +++ b/src/tools/clippy/tests/ui/byte_char_slices.stderr @@ -1,5 +1,5 @@ error: can be more succinctly written as a byte str - --> tests/ui/byte_char_slices.rs:5:15 + --> tests/ui/byte_char_slices.rs:4:15 | LL | let bad = &[b'a', b'b', b'c']; | ^^^^^^^^^^^^^^^^^^^ help: try: `b"abc"` @@ -8,25 +8,25 @@ LL | let bad = &[b'a', b'b', b'c']; = help: to override `-D warnings` add `#[allow(clippy::byte_char_slices)]` error: can be more succinctly written as a byte str - --> tests/ui/byte_char_slices.rs:7:18 + --> tests/ui/byte_char_slices.rs:6:18 | LL | let quotes = &[b'"', b'H', b'i']; | ^^^^^^^^^^^^^^^^^^^ help: try: `b"\"Hi"` error: can be more succinctly written as a byte str - --> tests/ui/byte_char_slices.rs:9:18 + --> tests/ui/byte_char_slices.rs:8:18 | LL | let quotes = &[b'\'', b'S', b'u', b'p']; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b"'Sup"` error: can be more succinctly written as a byte str - --> tests/ui/byte_char_slices.rs:11:19 + --> tests/ui/byte_char_slices.rs:10:19 | LL | let escapes = &[b'\x42', b'E', b's', b'c']; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b"\x42Esc"` error: useless use of `vec!` - --> tests/ui/byte_char_slices.rs:15:16 + --> tests/ui/byte_char_slices.rs:14:16 | LL | let good = vec![b'a', b'a']; | ^^^^^^^^^^^^^^^^ help: you can use an array directly: `[b'a', b'a']` diff --git a/src/tools/clippy/tests/ui/cast.rs b/src/tools/clippy/tests/ui/cast.rs index fab02bf7b24e4..ff2791c457301 100644 --- a/src/tools/clippy/tests/ui/cast.rs +++ b/src/tools/clippy/tests/ui/cast.rs @@ -582,3 +582,13 @@ mod issue14150 { //~^ cast_possible_wrap } } + +fn issue16045() { + fn f() -> Result<(), ()> { + let val = Ok::<_, ()>(0u8); + _ = val? as i8; + //~^ cast_possible_wrap + + Ok(()) + } +} diff --git a/src/tools/clippy/tests/ui/cast.stderr b/src/tools/clippy/tests/ui/cast.stderr index 8c48855123f93..0ff1dc11c3ac6 100644 --- a/src/tools/clippy/tests/ui/cast.stderr +++ b/src/tools/clippy/tests/ui/cast.stderr @@ -764,5 +764,11 @@ error: casting `u8` to `i8` may wrap around the value LL | _ = 1u8 as i8; | ^^^^^^^^^ -error: aborting due to 94 previous errors +error: casting `u8` to `i8` may wrap around the value + --> tests/ui/cast.rs:589:13 + | +LL | _ = val? as i8; + | ^^^^^^^^^^ help: if this is intentional, use `cast_signed()` instead: `val?.cast_signed()` + +error: aborting due to 95 previous errors diff --git a/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals.rs b/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals.rs index 7d0bcc547a42b..d1db2e67e269d 100644 --- a/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals.rs +++ b/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals.rs @@ -1,27 +1,19 @@ -#![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] -#![allow( - clippy::if_same_then_else, - clippy::branches_sharing_code, - clippy::unnecessary_literal_unwrap -)] +#![warn(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] +#![expect(clippy::branches_sharing_code, clippy::unnecessary_literal_unwrap)] fn test_complex_conditions() { let x: Result<(), ()> = Ok(()); let y: Result<(), ()> = Ok(()); if x.is_ok() && y.is_err() { - // unnecessary x.unwrap(); //~^ unnecessary_unwrap - // will panic x.unwrap_err(); //~^ panicking_unwrap - // will panic y.unwrap(); //~^ panicking_unwrap - // unnecessary y.unwrap_err(); //~^ unnecessary_unwrap } else { @@ -37,45 +29,35 @@ fn test_complex_conditions() { x.unwrap(); y.unwrap(); } else { - // will panic x.unwrap(); //~^ panicking_unwrap - // unnecessary x.unwrap_err(); //~^ unnecessary_unwrap - // will panic y.unwrap(); //~^ panicking_unwrap - // unnecessary y.unwrap_err(); //~^ unnecessary_unwrap } let z: Result<(), ()> = Ok(()); if x.is_ok() && !(y.is_ok() || z.is_err()) { - // unnecessary x.unwrap(); //~^ unnecessary_unwrap - // will panic x.unwrap_err(); //~^ panicking_unwrap - // will panic y.unwrap(); //~^ panicking_unwrap - // unnecessary y.unwrap_err(); //~^ unnecessary_unwrap - // unnecessary z.unwrap(); //~^ unnecessary_unwrap - // will panic z.unwrap_err(); //~^ panicking_unwrap } @@ -85,27 +67,21 @@ fn test_complex_conditions() { y.unwrap(); z.unwrap(); } else { - // will panic x.unwrap(); //~^ panicking_unwrap - // unnecessary x.unwrap_err(); //~^ unnecessary_unwrap - // unnecessary y.unwrap(); //~^ unnecessary_unwrap - // will panic y.unwrap_err(); //~^ panicking_unwrap - // will panic z.unwrap(); //~^ panicking_unwrap - // unnecessary z.unwrap_err(); //~^ unnecessary_unwrap } diff --git a/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals.stderr b/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals.stderr index d3905850c9702..e154e3c35dc9f 100644 --- a/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals.stderr +++ b/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals.stderr @@ -1,21 +1,17 @@ error: called `unwrap` on `x` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/complex_conditionals.rs:13:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:8:9 | LL | if x.is_ok() && y.is_err() { | --------- the check is happening here -LL | // unnecessary LL | x.unwrap(); | ^^^^^^^^^^ | = help: try using `if let` or `match` -note: the lint level is defined here - --> tests/ui/checked_unwrap/complex_conditionals.rs:1:35 - | -LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `-D clippy::unnecessary-unwrap` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_unwrap)]` error: this call to `unwrap_err()` will always panic - --> tests/ui/checked_unwrap/complex_conditionals.rs:17:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:11:9 | LL | if x.is_ok() && y.is_err() { | --------- because of this check @@ -23,14 +19,11 @@ LL | if x.is_ok() && y.is_err() { LL | x.unwrap_err(); | ^^^^^^^^^^^^^^ | -note: the lint level is defined here - --> tests/ui/checked_unwrap/complex_conditionals.rs:1:9 - | -LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] - | ^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `-D clippy::panicking-unwrap` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::panicking_unwrap)]` error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/complex_conditionals.rs:21:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:14:9 | LL | if x.is_ok() && y.is_err() { | ---------- because of this check @@ -39,7 +32,7 @@ LL | y.unwrap(); | ^^^^^^^^^^ error: called `unwrap_err` on `y` after checking its variant with `is_err` - --> tests/ui/checked_unwrap/complex_conditionals.rs:25:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:17:9 | LL | if x.is_ok() && y.is_err() { | ---------- the check is happening here @@ -50,7 +43,7 @@ LL | y.unwrap_err(); = help: try using `if let` or `match` error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/complex_conditionals.rs:41:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:32:9 | LL | if x.is_ok() || y.is_ok() { | --------- because of this check @@ -59,7 +52,7 @@ LL | x.unwrap(); | ^^^^^^^^^^ error: called `unwrap_err` on `x` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/complex_conditionals.rs:45:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:35:9 | LL | if x.is_ok() || y.is_ok() { | --------- the check is happening here @@ -70,7 +63,7 @@ LL | x.unwrap_err(); = help: try using `if let` or `match` error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/complex_conditionals.rs:49:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:38:9 | LL | if x.is_ok() || y.is_ok() { | --------- because of this check @@ -79,7 +72,7 @@ LL | y.unwrap(); | ^^^^^^^^^^ error: called `unwrap_err` on `y` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/complex_conditionals.rs:53:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:41:9 | LL | if x.is_ok() || y.is_ok() { | --------- the check is happening here @@ -90,18 +83,17 @@ LL | y.unwrap_err(); = help: try using `if let` or `match` error: called `unwrap` on `x` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/complex_conditionals.rs:59:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:46:9 | LL | if x.is_ok() && !(y.is_ok() || z.is_err()) { | --------- the check is happening here -LL | // unnecessary LL | x.unwrap(); | ^^^^^^^^^^ | = help: try using `if let` or `match` error: this call to `unwrap_err()` will always panic - --> tests/ui/checked_unwrap/complex_conditionals.rs:63:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:49:9 | LL | if x.is_ok() && !(y.is_ok() || z.is_err()) { | --------- because of this check @@ -110,7 +102,7 @@ LL | x.unwrap_err(); | ^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/complex_conditionals.rs:67:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:52:9 | LL | if x.is_ok() && !(y.is_ok() || z.is_err()) { | --------- because of this check @@ -119,7 +111,7 @@ LL | y.unwrap(); | ^^^^^^^^^^ error: called `unwrap_err` on `y` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/complex_conditionals.rs:71:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:55:9 | LL | if x.is_ok() && !(y.is_ok() || z.is_err()) { | --------- the check is happening here @@ -130,7 +122,7 @@ LL | y.unwrap_err(); = help: try using `if let` or `match` error: called `unwrap` on `z` after checking its variant with `is_err` - --> tests/ui/checked_unwrap/complex_conditionals.rs:75:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:58:9 | LL | if x.is_ok() && !(y.is_ok() || z.is_err()) { | ---------- the check is happening here @@ -141,7 +133,7 @@ LL | z.unwrap(); = help: try using `if let` or `match` error: this call to `unwrap_err()` will always panic - --> tests/ui/checked_unwrap/complex_conditionals.rs:79:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:61:9 | LL | if x.is_ok() && !(y.is_ok() || z.is_err()) { | ---------- because of this check @@ -150,7 +142,7 @@ LL | z.unwrap_err(); | ^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/complex_conditionals.rs:89:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:70:9 | LL | if x.is_ok() || !(y.is_ok() && z.is_err()) { | --------- because of this check @@ -159,7 +151,7 @@ LL | x.unwrap(); | ^^^^^^^^^^ error: called `unwrap_err` on `x` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/complex_conditionals.rs:93:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:73:9 | LL | if x.is_ok() || !(y.is_ok() && z.is_err()) { | --------- the check is happening here @@ -170,7 +162,7 @@ LL | x.unwrap_err(); = help: try using `if let` or `match` error: called `unwrap` on `y` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/complex_conditionals.rs:97:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:76:9 | LL | if x.is_ok() || !(y.is_ok() && z.is_err()) { | --------- the check is happening here @@ -181,7 +173,7 @@ LL | y.unwrap(); = help: try using `if let` or `match` error: this call to `unwrap_err()` will always panic - --> tests/ui/checked_unwrap/complex_conditionals.rs:101:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:79:9 | LL | if x.is_ok() || !(y.is_ok() && z.is_err()) { | --------- because of this check @@ -190,7 +182,7 @@ LL | y.unwrap_err(); | ^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/complex_conditionals.rs:105:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:82:9 | LL | if x.is_ok() || !(y.is_ok() && z.is_err()) { | ---------- because of this check @@ -199,7 +191,7 @@ LL | z.unwrap(); | ^^^^^^^^^^ error: called `unwrap_err` on `z` after checking its variant with `is_err` - --> tests/ui/checked_unwrap/complex_conditionals.rs:109:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:85:9 | LL | if x.is_ok() || !(y.is_ok() && z.is_err()) { | ---------- the check is happening here diff --git a/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.rs b/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.rs index 7635f848cb349..6789e7c262b33 100644 --- a/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.rs +++ b/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.rs @@ -1,19 +1,14 @@ -#![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] -#![allow( - clippy::if_same_then_else, - clippy::branches_sharing_code, - clippy::unnecessary_literal_unwrap -)] //@no-rustfix: has placeholders +#![warn(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] +#![expect(clippy::branches_sharing_code, clippy::unnecessary_literal_unwrap)] + fn test_nested() { fn nested() { let x = Some(()); if x.is_some() { - // unnecessary x.unwrap(); //~^ unnecessary_unwrap } else { - // will panic x.unwrap(); //~^ panicking_unwrap } diff --git a/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.stderr b/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.stderr index 329be4d366210..7e4ef049f4a59 100644 --- a/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.stderr +++ b/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.stderr @@ -1,20 +1,16 @@ error: called `unwrap` on `x` after checking its variant with `is_some` - --> tests/ui/checked_unwrap/complex_conditionals_nested.rs:13:13 + --> tests/ui/checked_unwrap/complex_conditionals_nested.rs:9:13 | LL | if x.is_some() { | -------------- help: try: `if let Some() = x` -LL | // unnecessary LL | x.unwrap(); | ^^^^^^^^^^ | -note: the lint level is defined here - --> tests/ui/checked_unwrap/complex_conditionals_nested.rs:1:35 - | -LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `-D clippy::unnecessary-unwrap` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_unwrap)]` error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/complex_conditionals_nested.rs:17:13 + --> tests/ui/checked_unwrap/complex_conditionals_nested.rs:12:13 | LL | if x.is_some() { | ----------- because of this check @@ -22,11 +18,8 @@ LL | if x.is_some() { LL | x.unwrap(); | ^^^^^^^^^^ | -note: the lint level is defined here - --> tests/ui/checked_unwrap/complex_conditionals_nested.rs:1:9 - | -LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] - | ^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `-D clippy::panicking-unwrap` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::panicking_unwrap)]` error: aborting due to 2 previous errors diff --git a/src/tools/clippy/tests/ui/checked_unwrap/if_let_chains.rs b/src/tools/clippy/tests/ui/checked_unwrap/if_let_chains.rs index cfa7715965cdb..5c20ebb800244 100644 --- a/src/tools/clippy/tests/ui/checked_unwrap/if_let_chains.rs +++ b/src/tools/clippy/tests/ui/checked_unwrap/if_let_chains.rs @@ -1,5 +1,5 @@ //@require-annotations-for-level: ERROR -#![deny(clippy::unnecessary_unwrap)] +#![warn(clippy::unnecessary_unwrap)] #[clippy::msrv = "1.85"] fn if_let_chains_unsupported(a: Option, b: Option) { diff --git a/src/tools/clippy/tests/ui/checked_unwrap/if_let_chains.stderr b/src/tools/clippy/tests/ui/checked_unwrap/if_let_chains.stderr index 8a4137de37a3c..801b074fc277c 100644 --- a/src/tools/clippy/tests/ui/checked_unwrap/if_let_chains.stderr +++ b/src/tools/clippy/tests/ui/checked_unwrap/if_let_chains.stderr @@ -8,11 +8,8 @@ LL | println!("the value of a is {}", a.unwrap()); | ^^^^^^^^^^ | = help: try using `match` -note: the lint level is defined here - --> tests/ui/checked_unwrap/if_let_chains.rs:2:9 - | -LL | #![deny(clippy::unnecessary_unwrap)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `-D clippy::unnecessary-unwrap` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_unwrap)]` error: called `unwrap` on `a` after checking its variant with `is_none` --> tests/ui/checked_unwrap/if_let_chains.rs:20:42 diff --git a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs index bba264080b406..c6476a7507a1d 100644 --- a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs +++ b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs @@ -1,15 +1,15 @@ //@no-rustfix: has placeholders -#![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] -#![allow( +#![warn(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] +#![expect( clippy::if_same_then_else, clippy::branches_sharing_code, - clippy::unnecessary_literal_unwrap + clippy::unnecessary_literal_unwrap, + clippy::self_assignment )] macro_rules! m { ($a:expr) => { if $a.is_some() { - // unnecessary $a.unwrap(); //~^ unnecessary_unwrap } @@ -43,90 +43,71 @@ macro_rules! checks_some { fn main() { let x = Some(()); if x.is_some() { - // unnecessary x.unwrap(); //~^ unnecessary_unwrap - // unnecessary x.expect("an error message"); //~^ unnecessary_unwrap } else { - // will panic x.unwrap(); //~^ panicking_unwrap - // will panic x.expect("an error message"); //~^ panicking_unwrap } if x.is_none() { - // will panic x.unwrap(); //~^ panicking_unwrap } else { - // unnecessary x.unwrap(); //~^ unnecessary_unwrap } m!(x); - // ok checks_in_param!(x.is_some(), x.unwrap()); - // ok checks_unwrap!(x, x.unwrap()); - // ok checks_some!(x.is_some(), x); let mut x: Result<(), ()> = Ok(()); if x.is_ok() { - // unnecessary x.unwrap(); //~^ unnecessary_unwrap - // unnecessary x.expect("an error message"); //~^ unnecessary_unwrap - // will panic x.unwrap_err(); //~^ panicking_unwrap } else { - // will panic x.unwrap(); //~^ panicking_unwrap - // will panic x.expect("an error message"); //~^ panicking_unwrap - // unnecessary x.unwrap_err(); //~^ unnecessary_unwrap } if x.is_err() { - // will panic x.unwrap(); //~^ panicking_unwrap - // unnecessary x.unwrap_err(); //~^ unnecessary_unwrap } else { - // unnecessary x.unwrap(); //~^ unnecessary_unwrap - // will panic x.unwrap_err(); //~^ panicking_unwrap } if x.is_ok() { x = Err(()); - // not unnecessary because of mutation of x + // not unnecessary because of mutation of `x` // it will always panic but the lint is not smart enough to see this (it only // checks if conditions). x.unwrap(); } else { x = Ok(()); - // not unnecessary because of mutation of x + // not unnecessary because of mutation of `x` // it will always panic but the lint is not smart enough to see this (it // only checks if conditions). x.unwrap_err(); @@ -175,13 +156,11 @@ fn issue11371() { //~^ panicking_unwrap } - // This should not lint. Statics are, at the time of writing, not linted on anyway, - // but if at some point they are supported by this lint, it should correctly see that - // `X` is being mutated and not suggest `if let Some(..) = X {}` + // This should not lint and suggest `if let Some(..) = X {}`, as `X` is being mutated static mut X: Option = Some(123); unsafe { + #[expect(static_mut_refs)] if X.is_some() { - //~^ ERROR: creating a shared reference X = None; X.unwrap(); } @@ -299,17 +278,197 @@ fn check_expect() { let x = Some(()); if x.is_some() { #[expect(clippy::unnecessary_unwrap)] - // unnecessary x.unwrap(); #[expect(clippy::unnecessary_unwrap)] - // unnecessary x.expect("an error message"); } else { #[expect(clippy::panicking_unwrap)] - // will panic x.unwrap(); #[expect(clippy::panicking_unwrap)] - // will panic x.expect("an error message"); } } + +fn partial_moves() { + fn borrow_option(_: &Option<()>) {} + + let x = Some(()); + // Using `if let Some(o) = x` won't work here, as `borrow_option` will try to borrow a moved value + if x.is_some() { + borrow_option(&x); + x.unwrap(); + //~^ unnecessary_unwrap + } + // This is fine though, as `if let Some(o) = &x` won't move `x` + if x.is_some() { + borrow_option(&x); + x.as_ref().unwrap(); + //~^ unnecessary_unwrap + } +} + +fn issue15321() { + struct Soption { + option: Option, + other: bool, + } + let mut sopt = Soption { + option: Some(true), + other: true, + }; + // Lint: nothing was mutated + let _res = if sopt.option.is_some() { + sopt.option.unwrap() + //~^ unnecessary_unwrap + } else { + sopt.option.unwrap() + //~^ panicking_unwrap + }; + // Lint: an unrelated field was mutated + let _res = if sopt.option.is_some() { + sopt.other = false; + sopt.option.unwrap() + //~^ unnecessary_unwrap + } else { + sopt.other = false; + sopt.option.unwrap() + //~^ panicking_unwrap + }; + // No lint: the whole local was mutated + let _res = if sopt.option.is_some() { + sopt = sopt; + sopt.option.unwrap() + } else { + sopt.option = None; + sopt.option.unwrap() + }; + // No lint: the field we're looking at was mutated + let _res = if sopt.option.is_some() { + sopt = sopt; + sopt.option.unwrap() + } else { + sopt.option = None; + sopt.option.unwrap() + }; + + struct Toption(Option, bool); + let mut topt = Toption(Some(true), true); + // Lint: nothing was mutated + let _res = if topt.0.is_some() { + topt.0.unwrap() + //~^ unnecessary_unwrap + } else { + topt.0.unwrap() + //~^ panicking_unwrap + }; + // Lint: an unrelated field was mutated + let _res = if topt.0.is_some() { + topt.1 = false; + topt.0.unwrap() + //~^ unnecessary_unwrap + } else { + topt.1 = false; + topt.0.unwrap() + //~^ panicking_unwrap + }; + // No lint: the whole local was mutated + let _res = if topt.0.is_some() { + topt = topt; + topt.0.unwrap() + } else { + topt = topt; + topt.0.unwrap() + }; + // No lint: the field we're looking at was mutated + let _res = if topt.0.is_some() { + topt.0 = None; + topt.0.unwrap() + } else { + topt.0 = None; + topt.0.unwrap() + }; + + // Nested field accesses get linted as well + struct Soption2 { + other: bool, + option: Soption, + } + let mut sopt2 = Soption2 { + other: true, + option: Soption { + option: Some(true), + other: true, + }, + }; + // Lint: no fields were mutated + let _res = if sopt2.option.option.is_some() { + sopt2.option.option.unwrap() + //~^ unnecessary_unwrap + } else { + sopt2.option.option.unwrap() + //~^ panicking_unwrap + }; + // Lint: an unrelated outer field was mutated -- don't get confused by `Soption2.other` having the + // same `FieldIdx` of 1 as `Soption.option` + let _res = if sopt2.option.option.is_some() { + sopt2.other = false; + sopt2.option.option.unwrap() + //~^ unnecessary_unwrap + } else { + sopt2.other = false; + sopt2.option.option.unwrap() + //~^ panicking_unwrap + }; + // Lint: an unrelated inner field was mutated + let _res = if sopt2.option.option.is_some() { + sopt2.option.other = false; + sopt2.option.option.unwrap() + //~^ unnecessary_unwrap + } else { + sopt2.option.other = false; + sopt2.option.option.unwrap() + //~^ panicking_unwrap + }; + // Don't lint: the whole local was mutated + let _res = if sopt2.option.option.is_some() { + sopt2 = sopt2; + sopt2.option.option.unwrap() + } else { + sopt2 = sopt2; + sopt2.option.option.unwrap() + }; + // Don't lint: a parent field of the field we're looking at was mutated, and with that the + // field we're looking at + let _res = if sopt2.option.option.is_some() { + sopt2.option = sopt; + sopt2.option.option.unwrap() + } else { + sopt2.option = sopt; + sopt2.option.option.unwrap() + }; + // Don't lint: the field we're looking at was mutated directly + let _res = if sopt2.option.option.is_some() { + sopt2.option.option = None; + sopt2.option.option.unwrap() + } else { + sopt2.option.option = None; + sopt2.option.option.unwrap() + }; + + // Partial moves + fn borrow_toption(_: &Toption) {} + + // Using `if let Some(o) = topt.0` won't work here, as `borrow_toption` will try to borrow a + // partially moved value + if topt.0.is_some() { + borrow_toption(&topt); + topt.0.unwrap(); + //~^ unnecessary_unwrap + } + // This is fine though, as `if let Some(o) = &topt.0` won't (partially) move `topt` + if topt.0.is_some() { + borrow_toption(&topt); + topt.0.as_ref().unwrap(); + //~^ unnecessary_unwrap + } +} diff --git a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr index 2007a85954137..be979baa9fe4a 100644 --- a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr +++ b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr @@ -1,20 +1,16 @@ error: called `unwrap` on `x` after checking its variant with `is_some` - --> tests/ui/checked_unwrap/simple_conditionals.rs:47:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:46:9 | LL | if x.is_some() { | -------------- help: try: `if let Some() = x` -LL | // unnecessary LL | x.unwrap(); | ^^^^^^^^^^ | -note: the lint level is defined here - --> tests/ui/checked_unwrap/simple_conditionals.rs:2:35 - | -LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `-D clippy::unnecessary-unwrap` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_unwrap)]` error: called `expect` on `x` after checking its variant with `is_some` - --> tests/ui/checked_unwrap/simple_conditionals.rs:51:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:49:9 | LL | if x.is_some() { | -------------- help: try: `if let Some() = x` @@ -23,7 +19,7 @@ LL | x.expect("an error message"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:55:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:52:9 | LL | if x.is_some() { | ----------- because of this check @@ -31,14 +27,11 @@ LL | if x.is_some() { LL | x.unwrap(); | ^^^^^^^^^^ | -note: the lint level is defined here - --> tests/ui/checked_unwrap/simple_conditionals.rs:2:9 - | -LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] - | ^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `-D clippy::panicking-unwrap` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::panicking_unwrap)]` error: this call to `expect()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:59:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:55:9 | LL | if x.is_some() { | ----------- because of this check @@ -47,16 +40,15 @@ LL | x.expect("an error message"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:64:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:59:9 | LL | if x.is_none() { | ----------- because of this check -LL | // will panic LL | x.unwrap(); | ^^^^^^^^^^ error: called `unwrap` on `x` after checking its variant with `is_none` - --> tests/ui/checked_unwrap/simple_conditionals.rs:68:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:62:9 | LL | if x.is_none() { | -------------- help: try: `if let Some() = x` @@ -69,7 +61,6 @@ error: called `unwrap` on `x` after checking its variant with `is_some` | LL | if $a.is_some() { | --------------- help: try: `if let Some() = x` -LL | // unnecessary LL | $a.unwrap(); | ^^^^^^^^^^^ ... @@ -79,16 +70,15 @@ LL | m!(x); = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) error: called `unwrap` on `x` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/simple_conditionals.rs:81:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:71:9 | LL | if x.is_ok() { | ------------ help: try: `if let Ok() = x` -LL | // unnecessary LL | x.unwrap(); | ^^^^^^^^^^ error: called `expect` on `x` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/simple_conditionals.rs:85:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:74:9 | LL | if x.is_ok() { | ------------ help: try: `if let Ok() = x` @@ -97,7 +87,7 @@ LL | x.expect("an error message"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `unwrap_err()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:89:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:77:9 | LL | if x.is_ok() { | --------- because of this check @@ -106,7 +96,7 @@ LL | x.unwrap_err(); | ^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:93:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:80:9 | LL | if x.is_ok() { | --------- because of this check @@ -115,7 +105,7 @@ LL | x.unwrap(); | ^^^^^^^^^^ error: this call to `expect()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:97:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:83:9 | LL | if x.is_ok() { | --------- because of this check @@ -124,7 +114,7 @@ LL | x.expect("an error message"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: called `unwrap_err` on `x` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/simple_conditionals.rs:101:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:86:9 | LL | if x.is_ok() { | ------------ help: try: `if let Err() = x` @@ -133,16 +123,15 @@ LL | x.unwrap_err(); | ^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:106:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:90:9 | LL | if x.is_err() { | ---------- because of this check -LL | // will panic LL | x.unwrap(); | ^^^^^^^^^^ error: called `unwrap_err` on `x` after checking its variant with `is_err` - --> tests/ui/checked_unwrap/simple_conditionals.rs:110:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:93:9 | LL | if x.is_err() { | ------------- help: try: `if let Err() = x` @@ -151,7 +140,7 @@ LL | x.unwrap_err(); | ^^^^^^^^^^^^^^ error: called `unwrap` on `x` after checking its variant with `is_err` - --> tests/ui/checked_unwrap/simple_conditionals.rs:114:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:96:9 | LL | if x.is_err() { | ------------- help: try: `if let Ok() = x` @@ -160,7 +149,7 @@ LL | x.unwrap(); | ^^^^^^^^^^ error: this call to `unwrap_err()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:118:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:99:9 | LL | if x.is_err() { | ---------- because of this check @@ -169,7 +158,7 @@ LL | x.unwrap_err(); | ^^^^^^^^^^^^^^ error: called `unwrap` on `option` after checking its variant with `is_some` - --> tests/ui/checked_unwrap/simple_conditionals.rs:143:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:124:9 | LL | if option.is_some() { | ------------------- help: try: `if let Some() = &option` @@ -177,7 +166,7 @@ LL | option.as_ref().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:146:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:127:9 | LL | if option.is_some() { | ---------------- because of this check @@ -186,7 +175,7 @@ LL | option.as_ref().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: called `unwrap` on `result` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/simple_conditionals.rs:153:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:134:9 | LL | if result.is_ok() { | ----------------- help: try: `if let Ok() = &result` @@ -194,7 +183,7 @@ LL | result.as_ref().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:156:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:137:9 | LL | if result.is_ok() { | -------------- because of this check @@ -203,7 +192,7 @@ LL | result.as_ref().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: called `unwrap` on `option` after checking its variant with `is_some` - --> tests/ui/checked_unwrap/simple_conditionals.rs:162:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:143:9 | LL | if option.is_some() { | ------------------- help: try: `if let Some() = &mut option` @@ -211,7 +200,7 @@ LL | option.as_mut().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:165:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:146:9 | LL | if option.is_some() { | ---------------- because of this check @@ -220,7 +209,7 @@ LL | option.as_mut().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: called `unwrap` on `result` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/simple_conditionals.rs:171:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:152:9 | LL | if result.is_ok() { | ----------------- help: try: `if let Ok() = &mut result` @@ -228,7 +217,7 @@ LL | result.as_mut().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:174:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:155:9 | LL | if result.is_ok() { | -------------- because of this check @@ -237,7 +226,7 @@ LL | result.as_mut().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: called `unwrap` on `option` after checking its variant with `is_some` - --> tests/ui/checked_unwrap/simple_conditionals.rs:205:17 + --> tests/ui/checked_unwrap/simple_conditionals.rs:184:17 | LL | if option.is_some() { | ------------------- help: try: `if let Some() = &option` @@ -245,7 +234,7 @@ LL | let _ = option.as_ref().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:208:17 + --> tests/ui/checked_unwrap/simple_conditionals.rs:187:17 | LL | if option.is_some() { | ---------------- because of this check @@ -254,7 +243,7 @@ LL | let _ = option.as_ref().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: called `unwrap` on `result` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/simple_conditionals.rs:216:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:195:9 | LL | if result.is_ok() { | ----------------- help: try: `if let Ok() = &result` @@ -263,7 +252,7 @@ LL | result.as_ref().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:220:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:199:9 | LL | if result.is_ok() { | -------------- because of this check @@ -272,7 +261,7 @@ LL | result.as_ref().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: called `unwrap` on `x` after checking its variant with `is_some` - --> tests/ui/checked_unwrap/simple_conditionals.rs:246:17 + --> tests/ui/checked_unwrap/simple_conditionals.rs:225:17 | LL | if x.is_some() { | -------------- help: try: `if let Some() = x` @@ -280,7 +269,7 @@ LL | _ = x.unwrap(); | ^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:249:17 + --> tests/ui/checked_unwrap/simple_conditionals.rs:228:17 | LL | if x.is_some() { | ----------- because of this check @@ -289,7 +278,7 @@ LL | _ = x.unwrap(); | ^^^^^^^^^^ error: called `unwrap` on `r` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/simple_conditionals.rs:255:17 + --> tests/ui/checked_unwrap/simple_conditionals.rs:234:17 | LL | if r.is_ok() { | ------------ help: try: `if let Ok() = &r` @@ -297,7 +286,7 @@ LL | _ = r.as_ref().unwrap(); | ^^^^^^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:258:17 + --> tests/ui/checked_unwrap/simple_conditionals.rs:237:17 | LL | if r.is_ok() { | --------- because of this check @@ -306,7 +295,7 @@ LL | _ = r.as_ref().unwrap(); | ^^^^^^^^^^^^^^^^^^^ error: called `unwrap` on `x` after checking its variant with `is_some` - --> tests/ui/checked_unwrap/simple_conditionals.rs:267:17 + --> tests/ui/checked_unwrap/simple_conditionals.rs:246:17 | LL | if x.is_some() { | -------------- help: try: `if let Some() = x` @@ -314,7 +303,7 @@ LL | _ = x.unwrap(); | ^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:270:17 + --> tests/ui/checked_unwrap/simple_conditionals.rs:249:17 | LL | if x.is_some() { | ----------- because of this check @@ -323,7 +312,7 @@ LL | _ = x.unwrap(); | ^^^^^^^^^^ error: called `unwrap` on `option` after checking its variant with `is_some` - --> tests/ui/checked_unwrap/simple_conditionals.rs:280:26 + --> tests/ui/checked_unwrap/simple_conditionals.rs:259:26 | LL | if option.is_some() { | ------------------- help: try: `if let Some() = option` @@ -331,7 +320,7 @@ LL | println!("{:?}", option.unwrap()); | ^^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:283:26 + --> tests/ui/checked_unwrap/simple_conditionals.rs:262:26 | LL | if option.is_some() { | ---------------- because of this check @@ -340,7 +329,7 @@ LL | println!("{:?}", option.unwrap()); | ^^^^^^^^^^^^^^^ error: called `unwrap` on `result` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/simple_conditionals.rs:290:26 + --> tests/ui/checked_unwrap/simple_conditionals.rs:269:26 | LL | if result.is_ok() { | ----------------- help: try: `if let Ok() = result` @@ -348,7 +337,7 @@ LL | println!("{:?}", result.unwrap()); | ^^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:293:26 + --> tests/ui/checked_unwrap/simple_conditionals.rs:272:26 | LL | if result.is_ok() { | -------------- because of this check @@ -356,15 +345,164 @@ LL | if result.is_ok() { LL | println!("{:?}", result.unwrap()); | ^^^^^^^^^^^^^^^ -error: creating a shared reference to mutable static - --> tests/ui/checked_unwrap/simple_conditionals.rs:183:12 +error: called `unwrap` on `x` after checking its variant with `is_some` + --> tests/ui/checked_unwrap/simple_conditionals.rs:299:9 + | +LL | if x.is_some() { + | -------------- help: try: `if let Some() = x` +LL | borrow_option(&x); +LL | x.unwrap(); + | ^^^^^^^^^^ + +error: called `unwrap` on `x` after checking its variant with `is_some` + --> tests/ui/checked_unwrap/simple_conditionals.rs:305:9 + | +LL | if x.is_some() { + | -------------- help: try: `if let Some() = &x` +LL | borrow_option(&x); +LL | x.as_ref().unwrap(); + | ^^^^^^^^^^^^^^^^^^^ + +error: called `unwrap` on `sopt.option` after checking its variant with `is_some` + --> tests/ui/checked_unwrap/simple_conditionals.rs:321:9 + | +LL | let _res = if sopt.option.is_some() { + | ------------------------ help: try: `if let Some() = sopt.option` +LL | sopt.option.unwrap() + | ^^^^^^^^^^^^^^^^^^^^ + +error: this call to `unwrap()` will always panic + --> tests/ui/checked_unwrap/simple_conditionals.rs:324:9 + | +LL | let _res = if sopt.option.is_some() { + | --------------------- because of this check +... +LL | sopt.option.unwrap() + | ^^^^^^^^^^^^^^^^^^^^ + +error: called `unwrap` on `sopt.option` after checking its variant with `is_some` + --> tests/ui/checked_unwrap/simple_conditionals.rs:330:9 + | +LL | let _res = if sopt.option.is_some() { + | ------------------------ help: try: `if let Some() = sopt.option` +LL | sopt.other = false; +LL | sopt.option.unwrap() + | ^^^^^^^^^^^^^^^^^^^^ + +error: this call to `unwrap()` will always panic + --> tests/ui/checked_unwrap/simple_conditionals.rs:334:9 + | +LL | let _res = if sopt.option.is_some() { + | --------------------- because of this check +... +LL | sopt.option.unwrap() + | ^^^^^^^^^^^^^^^^^^^^ + +error: called `unwrap` on `topt.0` after checking its variant with `is_some` + --> tests/ui/checked_unwrap/simple_conditionals.rs:358:9 + | +LL | let _res = if topt.0.is_some() { + | ------------------- help: try: `if let Some() = topt.0` +LL | topt.0.unwrap() + | ^^^^^^^^^^^^^^^ + +error: this call to `unwrap()` will always panic + --> tests/ui/checked_unwrap/simple_conditionals.rs:361:9 + | +LL | let _res = if topt.0.is_some() { + | ---------------- because of this check +... +LL | topt.0.unwrap() + | ^^^^^^^^^^^^^^^ + +error: called `unwrap` on `topt.0` after checking its variant with `is_some` + --> tests/ui/checked_unwrap/simple_conditionals.rs:367:9 + | +LL | let _res = if topt.0.is_some() { + | ------------------- help: try: `if let Some() = topt.0` +LL | topt.1 = false; +LL | topt.0.unwrap() + | ^^^^^^^^^^^^^^^ + +error: this call to `unwrap()` will always panic + --> tests/ui/checked_unwrap/simple_conditionals.rs:371:9 + | +LL | let _res = if topt.0.is_some() { + | ---------------- because of this check +... +LL | topt.0.unwrap() + | ^^^^^^^^^^^^^^^ + +error: called `unwrap` on `sopt2.option.option` after checking its variant with `is_some` + --> tests/ui/checked_unwrap/simple_conditionals.rs:405:9 + | +LL | let _res = if sopt2.option.option.is_some() { + | -------------------------------- help: try: `if let Some() = sopt2.option.option` +LL | sopt2.option.option.unwrap() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: this call to `unwrap()` will always panic + --> tests/ui/checked_unwrap/simple_conditionals.rs:408:9 | -LL | if X.is_some() { - | ^^^^^^^^^^^ shared reference to mutable static +LL | let _res = if sopt2.option.option.is_some() { + | ----------------------------- because of this check +... +LL | sopt2.option.option.unwrap() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: called `unwrap` on `sopt2.option.option` after checking its variant with `is_some` + --> tests/ui/checked_unwrap/simple_conditionals.rs:415:9 | - = note: for more information, see - = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives - = note: `#[deny(static_mut_refs)]` (part of `#[deny(rust_2024_compatibility)]`) on by default +LL | let _res = if sopt2.option.option.is_some() { + | -------------------------------- help: try: `if let Some() = sopt2.option.option` +LL | sopt2.other = false; +LL | sopt2.option.option.unwrap() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: this call to `unwrap()` will always panic + --> tests/ui/checked_unwrap/simple_conditionals.rs:419:9 + | +LL | let _res = if sopt2.option.option.is_some() { + | ----------------------------- because of this check +... +LL | sopt2.option.option.unwrap() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: called `unwrap` on `sopt2.option.option` after checking its variant with `is_some` + --> tests/ui/checked_unwrap/simple_conditionals.rs:425:9 + | +LL | let _res = if sopt2.option.option.is_some() { + | -------------------------------- help: try: `if let Some() = sopt2.option.option` +LL | sopt2.option.other = false; +LL | sopt2.option.option.unwrap() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: this call to `unwrap()` will always panic + --> tests/ui/checked_unwrap/simple_conditionals.rs:429:9 + | +LL | let _res = if sopt2.option.option.is_some() { + | ----------------------------- because of this check +... +LL | sopt2.option.option.unwrap() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: called `unwrap` on `topt.0` after checking its variant with `is_some` + --> tests/ui/checked_unwrap/simple_conditionals.rs:465:9 + | +LL | if topt.0.is_some() { + | ------------------- help: try: `if let Some() = topt.0` +LL | borrow_toption(&topt); +LL | topt.0.unwrap(); + | ^^^^^^^^^^^^^^^ + +error: called `unwrap` on `topt.0` after checking its variant with `is_some` + --> tests/ui/checked_unwrap/simple_conditionals.rs:471:9 + | +LL | if topt.0.is_some() { + | ------------------- help: try: `if let Some() = &topt.0` +LL | borrow_toption(&topt); +LL | topt.0.as_ref().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 40 previous errors +error: aborting due to 57 previous errors diff --git a/src/tools/clippy/tests/ui/doc/doc_paragraphs_missing_punctuation.fixed b/src/tools/clippy/tests/ui/doc/doc_paragraphs_missing_punctuation.fixed new file mode 100644 index 0000000000000..95d65039440b5 --- /dev/null +++ b/src/tools/clippy/tests/ui/doc/doc_paragraphs_missing_punctuation.fixed @@ -0,0 +1,172 @@ +#![feature(custom_inner_attributes)] +#![rustfmt::skip] +#![warn(clippy::doc_paragraphs_missing_punctuation)] + +/// Returns the Answer to the Ultimate Question of Life, the Universe, and Everything. +//~^ doc_paragraphs_missing_punctuation +fn answer() -> i32 { + 42 +} + +/// The `Option` type. +//~^ doc_paragraphs_missing_punctuation +// Triggers even in the presence of another attribute. +#[derive(Debug)] +enum MyOption { + /// No value. + //~^ doc_paragraphs_missing_punctuation + None, + /// Some value of type `T`. + Some(T), +} + +// Triggers correctly even when interleaved with other attributes. +/// A multiline +#[derive(Debug)] +/// doc comment: +/// only the last line triggers the lint. +//~^ doc_paragraphs_missing_punctuation +enum Exceptions { + /// Question marks are fine? + QuestionMark, + /// Exclamation marks are fine! + ExclamationMark, + /// Ellipses are ok too… + Ellipsis, + /// HTML content is however not checked: + /// Raw HTML is allowed as well + RawHtml, + /// The raw HTML exception actually does the right thing to autolinks: + /// . + //~^ doc_paragraphs_missing_punctuation + MarkdownAutolink, + /// This table introduction ends with a colon: + /// + /// | Exception | Note | + /// | -------------- | ----- | + /// | Markdown table | A-ok | + MarkdownTable, + /// Here is a snippet. + //~^ doc_paragraphs_missing_punctuation + /// + /// ``` + /// // Code blocks are no issues. + /// ``` + CodeBlock, +} + +// Check the lint can be expected on a whole enum at once. +#[expect(clippy::doc_paragraphs_missing_punctuation)] +enum Char { + /// U+0000 + Null, + /// U+0001 + StartOfHeading, +} + +// Check the lint can be expected on a single variant without affecting others. +enum Char2 { + #[expect(clippy::doc_paragraphs_missing_punctuation)] + /// U+0000 + Null, + /// U+0001. + //~^ doc_paragraphs_missing_punctuation + StartOfHeading, +} + +mod module { + //! Works on + //! inner attributes too. + //~^ doc_paragraphs_missing_punctuation +} + +enum Trailers { + /// Sometimes the last sentence ends with parentheses (and that's ok). + ParensPassing, + /// (Sometimes the last sentence is in parentheses.) + SentenceInParensPassing, + /// **Sometimes the last sentence is in bold, and that's ok.** + DoubleStarPassing, + /// **But sometimes it is missing a period.** + //~^ doc_paragraphs_missing_punctuation + DoubleStarFailing, + /// _Sometimes the last sentence is in italics, and that's ok._ + UnderscorePassing, + /// _But sometimes it is missing a period._ + //~^ doc_paragraphs_missing_punctuation + UnderscoreFailing, + /// This comment ends with "a quote." + AmericanStyleQuotePassing, + /// This comment ends with "a quote". + BritishStyleQuotePassing, +} + +/// Doc comments can end with an [inline link](#anchor). +//~^ doc_paragraphs_missing_punctuation +struct InlineLink; + +/// Some doc comments contain [link reference definitions][spec]. +//~^ doc_paragraphs_missing_punctuation +/// +/// [spec]: https://spec.commonmark.org/0.31.2/#link-reference-definitions +struct LinkRefDefinition; + +// List items do not always need to end with a period. +enum UnorderedLists { + /// This list has an introductory sentence: + /// + /// - A list item + Dash, + /// + A list item + Plus, + /// * A list item + Star, +} + +enum OrderedLists { + /// 1. A list item + Dot, + /// 42) A list item + Paren, +} + +/// Doc comments with trailing blank lines are supported. +//~^ doc_paragraphs_missing_punctuation +/// +struct TrailingBlankLine; + +/// This doc comment has multiple paragraph. +/// This first paragraph is missing punctuation. +//~^ doc_paragraphs_missing_punctuation +/// +/// The second one as well +/// And it has multiple sentences. +//~^ doc_paragraphs_missing_punctuation +/// +/// Same for this third and last one. +//~^ doc_paragraphs_missing_punctuation +struct MultiParagraphDocComment; + +/// ``` +struct IncompleteBlockCode; + +/// This ends with a code `span`. +//~^ doc_paragraphs_missing_punctuation +struct CodeSpan; + +#[expect(clippy::empty_docs)] +/// +struct EmptyDocComment; + +/** + * Block doc comments work. + * + */ +//~^^^ doc_paragraphs_missing_punctuation +struct BlockDocComment; + +/// Sometimes a doc attribute is used for concatenation +/// ``` +#[doc = ""] +/// ``` +struct DocAttribute; diff --git a/src/tools/clippy/tests/ui/doc/doc_paragraphs_missing_punctuation.rs b/src/tools/clippy/tests/ui/doc/doc_paragraphs_missing_punctuation.rs new file mode 100644 index 0000000000000..35b74d7d13b9e --- /dev/null +++ b/src/tools/clippy/tests/ui/doc/doc_paragraphs_missing_punctuation.rs @@ -0,0 +1,172 @@ +#![feature(custom_inner_attributes)] +#![rustfmt::skip] +#![warn(clippy::doc_paragraphs_missing_punctuation)] + +/// Returns the Answer to the Ultimate Question of Life, the Universe, and Everything +//~^ doc_paragraphs_missing_punctuation +fn answer() -> i32 { + 42 +} + +/// The `Option` type +//~^ doc_paragraphs_missing_punctuation +// Triggers even in the presence of another attribute. +#[derive(Debug)] +enum MyOption { + /// No value + //~^ doc_paragraphs_missing_punctuation + None, + /// Some value of type `T`. + Some(T), +} + +// Triggers correctly even when interleaved with other attributes. +/// A multiline +#[derive(Debug)] +/// doc comment: +/// only the last line triggers the lint +//~^ doc_paragraphs_missing_punctuation +enum Exceptions { + /// Question marks are fine? + QuestionMark, + /// Exclamation marks are fine! + ExclamationMark, + /// Ellipses are ok too… + Ellipsis, + /// HTML content is however not checked: + /// Raw HTML is allowed as well + RawHtml, + /// The raw HTML exception actually does the right thing to autolinks: + /// + //~^ doc_paragraphs_missing_punctuation + MarkdownAutolink, + /// This table introduction ends with a colon: + /// + /// | Exception | Note | + /// | -------------- | ----- | + /// | Markdown table | A-ok | + MarkdownTable, + /// Here is a snippet + //~^ doc_paragraphs_missing_punctuation + /// + /// ``` + /// // Code blocks are no issues. + /// ``` + CodeBlock, +} + +// Check the lint can be expected on a whole enum at once. +#[expect(clippy::doc_paragraphs_missing_punctuation)] +enum Char { + /// U+0000 + Null, + /// U+0001 + StartOfHeading, +} + +// Check the lint can be expected on a single variant without affecting others. +enum Char2 { + #[expect(clippy::doc_paragraphs_missing_punctuation)] + /// U+0000 + Null, + /// U+0001 + //~^ doc_paragraphs_missing_punctuation + StartOfHeading, +} + +mod module { + //! Works on + //! inner attributes too + //~^ doc_paragraphs_missing_punctuation +} + +enum Trailers { + /// Sometimes the last sentence ends with parentheses (and that's ok). + ParensPassing, + /// (Sometimes the last sentence is in parentheses.) + SentenceInParensPassing, + /// **Sometimes the last sentence is in bold, and that's ok.** + DoubleStarPassing, + /// **But sometimes it is missing a period** + //~^ doc_paragraphs_missing_punctuation + DoubleStarFailing, + /// _Sometimes the last sentence is in italics, and that's ok._ + UnderscorePassing, + /// _But sometimes it is missing a period_ + //~^ doc_paragraphs_missing_punctuation + UnderscoreFailing, + /// This comment ends with "a quote." + AmericanStyleQuotePassing, + /// This comment ends with "a quote". + BritishStyleQuotePassing, +} + +/// Doc comments can end with an [inline link](#anchor) +//~^ doc_paragraphs_missing_punctuation +struct InlineLink; + +/// Some doc comments contain [link reference definitions][spec] +//~^ doc_paragraphs_missing_punctuation +/// +/// [spec]: https://spec.commonmark.org/0.31.2/#link-reference-definitions +struct LinkRefDefinition; + +// List items do not always need to end with a period. +enum UnorderedLists { + /// This list has an introductory sentence: + /// + /// - A list item + Dash, + /// + A list item + Plus, + /// * A list item + Star, +} + +enum OrderedLists { + /// 1. A list item + Dot, + /// 42) A list item + Paren, +} + +/// Doc comments with trailing blank lines are supported +//~^ doc_paragraphs_missing_punctuation +/// +struct TrailingBlankLine; + +/// This doc comment has multiple paragraph. +/// This first paragraph is missing punctuation +//~^ doc_paragraphs_missing_punctuation +/// +/// The second one as well +/// And it has multiple sentences +//~^ doc_paragraphs_missing_punctuation +/// +/// Same for this third and last one +//~^ doc_paragraphs_missing_punctuation +struct MultiParagraphDocComment; + +/// ``` +struct IncompleteBlockCode; + +/// This ends with a code `span` +//~^ doc_paragraphs_missing_punctuation +struct CodeSpan; + +#[expect(clippy::empty_docs)] +/// +struct EmptyDocComment; + +/** + * Block doc comments work + * + */ +//~^^^ doc_paragraphs_missing_punctuation +struct BlockDocComment; + +/// Sometimes a doc attribute is used for concatenation +/// ``` +#[doc = ""] +/// ``` +struct DocAttribute; diff --git a/src/tools/clippy/tests/ui/doc/doc_paragraphs_missing_punctuation.stderr b/src/tools/clippy/tests/ui/doc/doc_paragraphs_missing_punctuation.stderr new file mode 100644 index 0000000000000..49aa4e8aeb888 --- /dev/null +++ b/src/tools/clippy/tests/ui/doc/doc_paragraphs_missing_punctuation.stderr @@ -0,0 +1,113 @@ +error: doc paragraphs should end with a terminal punctuation mark + --> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:5:86 + | +LL | /// Returns the Answer to the Ultimate Question of Life, the Universe, and Everything + | ^ help: end the paragraph with some punctuation: `.` + | + = note: `-D clippy::doc-paragraphs-missing-punctuation` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::doc_paragraphs_missing_punctuation)]` + +error: doc paragraphs should end with a terminal punctuation mark + --> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:11:22 + | +LL | /// The `Option` type + | ^ help: end the paragraph with some punctuation: `.` + +error: doc paragraphs should end with a terminal punctuation mark + --> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:16:17 + | +LL | /// No value + | ^ help: end the paragraph with some punctuation: `.` + +error: doc paragraphs should end with a terminal punctuation mark + --> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:27:41 + | +LL | /// only the last line triggers the lint + | ^ help: end the paragraph with some punctuation: `.` + +error: doc paragraphs should end with a terminal punctuation mark + --> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:40:56 + | +LL | /// + | ^ help: end the paragraph with some punctuation: `.` + +error: doc paragraphs should end with a terminal punctuation mark + --> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:49:26 + | +LL | /// Here is a snippet + | ^ help: end the paragraph with some punctuation: `.` + +error: doc paragraphs should end with a terminal punctuation mark + --> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:72:15 + | +LL | /// U+0001 + | ^ help: end the paragraph with some punctuation: `.` + +error: doc paragraphs should end with a terminal punctuation mark + --> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:79:29 + | +LL | //! inner attributes too + | ^ help: end the paragraph with some punctuation: `.` + +error: doc paragraphs should end with a terminal punctuation mark + --> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:90:47 + | +LL | /// **But sometimes it is missing a period** + | ^ help: end the paragraph with some punctuation: `.` + +error: doc paragraphs should end with a terminal punctuation mark + --> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:95:46 + | +LL | /// _But sometimes it is missing a period_ + | ^ help: end the paragraph with some punctuation: `.` + +error: doc paragraphs should end with a terminal punctuation mark + --> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:104:56 + | +LL | /// Doc comments can end with an [inline link](#anchor) + | ^ help: end the paragraph with some punctuation: `.` + +error: doc paragraphs should end with a terminal punctuation mark + --> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:108:65 + | +LL | /// Some doc comments contain [link reference definitions][spec] + | ^ help: end the paragraph with some punctuation: `.` + +error: doc paragraphs should end with a terminal punctuation mark + --> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:133:57 + | +LL | /// Doc comments with trailing blank lines are supported + | ^ help: end the paragraph with some punctuation: `.` + +error: doc paragraphs should end with a terminal punctuation mark + --> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:139:48 + | +LL | /// This first paragraph is missing punctuation + | ^ help: end the paragraph with some punctuation: `.` + +error: doc paragraphs should end with a terminal punctuation mark + --> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:143:34 + | +LL | /// And it has multiple sentences + | ^ help: end the paragraph with some punctuation: `.` + +error: doc paragraphs should end with a terminal punctuation mark + --> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:146:37 + | +LL | /// Same for this third and last one + | ^ help: end the paragraph with some punctuation: `.` + +error: doc paragraphs should end with a terminal punctuation mark + --> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:153:33 + | +LL | /// This ends with a code `span` + | ^ help: end the paragraph with some punctuation: `.` + +error: doc paragraphs should end with a terminal punctuation mark + --> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:162:27 + | +LL | * Block doc comments work + | ^ help: end the paragraph with some punctuation: `.` + +error: aborting due to 18 previous errors + diff --git a/src/tools/clippy/tests/ui/doc/doc_paragraphs_missing_punctuation_unfixable.rs b/src/tools/clippy/tests/ui/doc/doc_paragraphs_missing_punctuation_unfixable.rs new file mode 100644 index 0000000000000..3873f1d1edcfa --- /dev/null +++ b/src/tools/clippy/tests/ui/doc/doc_paragraphs_missing_punctuation_unfixable.rs @@ -0,0 +1,13 @@ +#![feature(custom_inner_attributes)] +#![rustfmt::skip] +#![warn(clippy::doc_paragraphs_missing_punctuation)] +//@no-rustfix + +enum UnfixableTrailers { + /// Sometimes the doc comment ends with parentheses (like this) + //~^ doc_paragraphs_missing_punctuation + EndsWithParens, + /// This comment ends with "a quote" + //~^ doc_paragraphs_missing_punctuation + QuoteFailing, +} diff --git a/src/tools/clippy/tests/ui/doc/doc_paragraphs_missing_punctuation_unfixable.stderr b/src/tools/clippy/tests/ui/doc/doc_paragraphs_missing_punctuation_unfixable.stderr new file mode 100644 index 0000000000000..e8587eace2d6c --- /dev/null +++ b/src/tools/clippy/tests/ui/doc/doc_paragraphs_missing_punctuation_unfixable.stderr @@ -0,0 +1,20 @@ +error: doc paragraphs should end with a terminal punctuation mark + --> tests/ui/doc/doc_paragraphs_missing_punctuation_unfixable.rs:7:68 + | +LL | /// Sometimes the doc comment ends with parentheses (like this) + | ^ + | + = help: end the paragraph with some punctuation + = note: `-D clippy::doc-paragraphs-missing-punctuation` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::doc_paragraphs_missing_punctuation)]` + +error: doc paragraphs should end with a terminal punctuation mark + --> tests/ui/doc/doc_paragraphs_missing_punctuation_unfixable.rs:10:41 + | +LL | /// This comment ends with "a quote" + | ^ + | + = help: end the paragraph with some punctuation + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/ui/equatable_if_let.fixed b/src/tools/clippy/tests/ui/equatable_if_let.fixed index 58fbad64a78da..2cf69cf7b2fdf 100644 --- a/src/tools/clippy/tests/ui/equatable_if_let.fixed +++ b/src/tools/clippy/tests/ui/equatable_if_let.fixed @@ -1,14 +1,6 @@ //@aux-build:proc_macros.rs - -#![allow( - unused_variables, - dead_code, - clippy::derive_partial_eq_without_eq, - clippy::needless_ifs -)] +#![allow(clippy::derive_partial_eq_without_eq, clippy::needless_ifs)] #![warn(clippy::equatable_if_let)] - -extern crate proc_macros; use proc_macros::{external, inline_macros}; use std::cmp::Ordering; @@ -48,7 +40,6 @@ impl PartialEq for NotStructuralEq { } } -#[inline_macros] fn main() { let a = 2; let b = 3; @@ -95,13 +86,6 @@ fn main() { //~^ equatable_if_let if matches!(h, NoPartialEqStruct { a: 2, b: false }) {} //~^ equatable_if_let - - if "abc" == inline!("abc") { - //~^ equatable_if_let - println!("OK"); - } - - external!({ if let 2 = $a {} }); } mod issue8710 { @@ -139,3 +123,92 @@ mod issue8710 { } } } + +#[inline_macros] +fn issue14548() { + if let inline!("abc") = "abc" { + println!("OK"); + } + + let a = 2; + external!({ if let 2 = $a {} }); + + // Don't lint: `==`/`matches!` might be correct for a particular `$($font)|*`, but not in general + macro_rules! m1 { + ($($font:pat_param)|*) => { + if let $($font)|* = "from_expansion" {} + } + } + m1!("foo"); + m1!("Sans" | "Serif" | "Sans Mono"); + m1!(inline!("foo")); + + // Don't lint: the suggestion might be correct for a particular `$from_root_ctxt`, but not in + // general + macro_rules! m2 { + ($from_root_ctxt:pat) => { + if let $from_root_ctxt = "from_expansion" {} + }; + } + m2!("foo"); + m2!("Sans" | "Serif" | "Sans Mono"); + m2!(inline!("foo")); + + // Don't lint: the suggestion might be correct for a particular `$from_root_ctxt`, but not in + // general + macro_rules! m3 { + ($from_root_ctxt:expr) => { + if let "from_expansion" = $from_root_ctxt {} + }; + } + m3!("foo"); + m3!("foo"); + m3!(inline!("foo")); + + // Don't lint: the suggestion might be correct for a particular `$from_root_ctxt`, but not in + // general. Don't get confused by the scrutinee coming from macro invocation + macro_rules! m4 { + ($from_root_ctxt:pat) => { + if let $from_root_ctxt = inline!("from_expansion") {} + }; + } + m4!("foo"); + m4!("Sans" | "Serif" | "Sans Mono"); + m4!(inline!("foo")); + + // Don't lint: the suggestion might be correct for a particular `$from_root_ctxt`, but not in + // general. Don't get confused by the scrutinee coming from macro invocation + macro_rules! m5 { + ($from_root_ctxt:expr) => { + if let inline!("from_expansion") = $from_root_ctxt {} + }; + } + m5!("foo"); + m5!("foo"); + m5!(inline!("foo")); + + // Would be nice to lint: both sides are macro _invocations_, so the suggestion is correct in + // general + if let inline!("foo") = inline!("bar") {} +} + +// PartialEq is not stable in consts yet +fn issue15376() { + enum NonConstEq { + A, + B, + } + impl PartialEq for NonConstEq { + fn eq(&self, _other: &Self) -> bool { + true + } + } + + const N: NonConstEq = NonConstEq::A; + + // `impl PartialEq` is not const, suggest `matches!` + const _: u32 = if matches!(N, NonConstEq::A) { 0 } else { 1 }; + //~^ ERROR: this pattern matching can be expressed using `matches!` + const _: u32 = if matches!(Some(N), Some(NonConstEq::A)) { 0 } else { 1 }; + //~^ ERROR: this pattern matching can be expressed using `matches!` +} diff --git a/src/tools/clippy/tests/ui/equatable_if_let.rs b/src/tools/clippy/tests/ui/equatable_if_let.rs index cca97c76b5094..94302b3dfa652 100644 --- a/src/tools/clippy/tests/ui/equatable_if_let.rs +++ b/src/tools/clippy/tests/ui/equatable_if_let.rs @@ -1,14 +1,6 @@ //@aux-build:proc_macros.rs - -#![allow( - unused_variables, - dead_code, - clippy::derive_partial_eq_without_eq, - clippy::needless_ifs -)] +#![allow(clippy::derive_partial_eq_without_eq, clippy::needless_ifs)] #![warn(clippy::equatable_if_let)] - -extern crate proc_macros; use proc_macros::{external, inline_macros}; use std::cmp::Ordering; @@ -48,7 +40,6 @@ impl PartialEq for NotStructuralEq { } } -#[inline_macros] fn main() { let a = 2; let b = 3; @@ -95,13 +86,6 @@ fn main() { //~^ equatable_if_let if let NoPartialEqStruct { a: 2, b: false } = h {} //~^ equatable_if_let - - if let inline!("abc") = "abc" { - //~^ equatable_if_let - println!("OK"); - } - - external!({ if let 2 = $a {} }); } mod issue8710 { @@ -139,3 +123,92 @@ mod issue8710 { } } } + +#[inline_macros] +fn issue14548() { + if let inline!("abc") = "abc" { + println!("OK"); + } + + let a = 2; + external!({ if let 2 = $a {} }); + + // Don't lint: `==`/`matches!` might be correct for a particular `$($font)|*`, but not in general + macro_rules! m1 { + ($($font:pat_param)|*) => { + if let $($font)|* = "from_expansion" {} + } + } + m1!("foo"); + m1!("Sans" | "Serif" | "Sans Mono"); + m1!(inline!("foo")); + + // Don't lint: the suggestion might be correct for a particular `$from_root_ctxt`, but not in + // general + macro_rules! m2 { + ($from_root_ctxt:pat) => { + if let $from_root_ctxt = "from_expansion" {} + }; + } + m2!("foo"); + m2!("Sans" | "Serif" | "Sans Mono"); + m2!(inline!("foo")); + + // Don't lint: the suggestion might be correct for a particular `$from_root_ctxt`, but not in + // general + macro_rules! m3 { + ($from_root_ctxt:expr) => { + if let "from_expansion" = $from_root_ctxt {} + }; + } + m3!("foo"); + m3!("foo"); + m3!(inline!("foo")); + + // Don't lint: the suggestion might be correct for a particular `$from_root_ctxt`, but not in + // general. Don't get confused by the scrutinee coming from macro invocation + macro_rules! m4 { + ($from_root_ctxt:pat) => { + if let $from_root_ctxt = inline!("from_expansion") {} + }; + } + m4!("foo"); + m4!("Sans" | "Serif" | "Sans Mono"); + m4!(inline!("foo")); + + // Don't lint: the suggestion might be correct for a particular `$from_root_ctxt`, but not in + // general. Don't get confused by the scrutinee coming from macro invocation + macro_rules! m5 { + ($from_root_ctxt:expr) => { + if let inline!("from_expansion") = $from_root_ctxt {} + }; + } + m5!("foo"); + m5!("foo"); + m5!(inline!("foo")); + + // Would be nice to lint: both sides are macro _invocations_, so the suggestion is correct in + // general + if let inline!("foo") = inline!("bar") {} +} + +// PartialEq is not stable in consts yet +fn issue15376() { + enum NonConstEq { + A, + B, + } + impl PartialEq for NonConstEq { + fn eq(&self, _other: &Self) -> bool { + true + } + } + + const N: NonConstEq = NonConstEq::A; + + // `impl PartialEq` is not const, suggest `matches!` + const _: u32 = if let NonConstEq::A = N { 0 } else { 1 }; + //~^ ERROR: this pattern matching can be expressed using `matches!` + const _: u32 = if let Some(NonConstEq::A) = Some(N) { 0 } else { 1 }; + //~^ ERROR: this pattern matching can be expressed using `matches!` +} diff --git a/src/tools/clippy/tests/ui/equatable_if_let.stderr b/src/tools/clippy/tests/ui/equatable_if_let.stderr index dd1832ad68b28..8cc78daa2535c 100644 --- a/src/tools/clippy/tests/ui/equatable_if_let.stderr +++ b/src/tools/clippy/tests/ui/equatable_if_let.stderr @@ -1,5 +1,5 @@ error: this pattern matching can be expressed using equality - --> tests/ui/equatable_if_let.rs:64:8 + --> tests/ui/equatable_if_let.rs:55:8 | LL | if let 2 = a {} | ^^^^^^^^^ help: try: `a == 2` @@ -8,100 +8,106 @@ LL | if let 2 = a {} = help: to override `-D warnings` add `#[allow(clippy::equatable_if_let)]` error: this pattern matching can be expressed using equality - --> tests/ui/equatable_if_let.rs:66:8 + --> tests/ui/equatable_if_let.rs:57:8 | LL | if let Ordering::Greater = a.cmp(&b) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `a.cmp(&b) == Ordering::Greater` error: this pattern matching can be expressed using equality - --> tests/ui/equatable_if_let.rs:68:8 + --> tests/ui/equatable_if_let.rs:59:8 | LL | if let Some(2) = c {} | ^^^^^^^^^^^^^^^ help: try: `c == Some(2)` error: this pattern matching can be expressed using equality - --> tests/ui/equatable_if_let.rs:70:8 + --> tests/ui/equatable_if_let.rs:61:8 | LL | if let Struct { a: 2, b: false } = d {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `d == (Struct { a: 2, b: false })` error: this pattern matching can be expressed using equality - --> tests/ui/equatable_if_let.rs:72:8 + --> tests/ui/equatable_if_let.rs:63:8 | LL | if let Enum::TupleVariant(32, 64) = e {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `e == Enum::TupleVariant(32, 64)` error: this pattern matching can be expressed using equality - --> tests/ui/equatable_if_let.rs:74:8 + --> tests/ui/equatable_if_let.rs:65:8 | LL | if let Enum::RecordVariant { a: 64, b: 32 } = e {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `e == (Enum::RecordVariant { a: 64, b: 32 })` error: this pattern matching can be expressed using equality - --> tests/ui/equatable_if_let.rs:76:8 + --> tests/ui/equatable_if_let.rs:67:8 | LL | if let Enum::UnitVariant = e {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `e == Enum::UnitVariant` error: this pattern matching can be expressed using equality - --> tests/ui/equatable_if_let.rs:78:8 + --> tests/ui/equatable_if_let.rs:69:8 | LL | if let (Enum::UnitVariant, &Struct { a: 2, b: false }) = (e, &d) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(e, &d) == (Enum::UnitVariant, &Struct { a: 2, b: false })` error: this pattern matching can be expressed using `matches!` - --> tests/ui/equatable_if_let.rs:88:8 + --> tests/ui/equatable_if_let.rs:79:8 | LL | if let NotPartialEq::A = f {} | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(f, NotPartialEq::A)` error: this pattern matching can be expressed using equality - --> tests/ui/equatable_if_let.rs:90:8 + --> tests/ui/equatable_if_let.rs:81:8 | LL | if let NotStructuralEq::A = g {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `g == NotStructuralEq::A` error: this pattern matching can be expressed using `matches!` - --> tests/ui/equatable_if_let.rs:92:8 + --> tests/ui/equatable_if_let.rs:83:8 | LL | if let Some(NotPartialEq::A) = Some(f) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(Some(f), Some(NotPartialEq::A))` error: this pattern matching can be expressed using equality - --> tests/ui/equatable_if_let.rs:94:8 + --> tests/ui/equatable_if_let.rs:85:8 | LL | if let Some(NotStructuralEq::A) = Some(g) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(g) == Some(NotStructuralEq::A)` error: this pattern matching can be expressed using `matches!` - --> tests/ui/equatable_if_let.rs:96:8 + --> tests/ui/equatable_if_let.rs:87:8 | LL | if let NoPartialEqStruct { a: 2, b: false } = h {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(h, NoPartialEqStruct { a: 2, b: false })` -error: this pattern matching can be expressed using equality - --> tests/ui/equatable_if_let.rs:99:8 - | -LL | if let inline!("abc") = "abc" { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"abc" == inline!("abc")` - error: this pattern matching can be expressed using `matches!` - --> tests/ui/equatable_if_let.rs:109:12 + --> tests/ui/equatable_if_let.rs:93:12 | LL | if let Some('i') = cs.iter().next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(cs.iter().next(), Some('i'))` error: this pattern matching can be expressed using `matches!` - --> tests/ui/equatable_if_let.rs:117:12 + --> tests/ui/equatable_if_let.rs:101:12 | LL | if let Some(1) = cs.iter().next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(cs.iter().next(), Some(1))` error: this pattern matching can be expressed using `matches!` - --> tests/ui/equatable_if_let.rs:135:12 + --> tests/ui/equatable_if_let.rs:119:12 | LL | if let Some(MyEnum::B) = get_enum() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(get_enum(), Some(MyEnum::B))` -error: aborting due to 17 previous errors +error: this pattern matching can be expressed using `matches!` + --> tests/ui/equatable_if_let.rs:210:23 + | +LL | const _: u32 = if let NonConstEq::A = N { 0 } else { 1 }; + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(N, NonConstEq::A)` + +error: this pattern matching can be expressed using `matches!` + --> tests/ui/equatable_if_let.rs:212:23 + | +LL | const _: u32 = if let Some(NonConstEq::A) = Some(N) { 0 } else { 1 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(Some(N), Some(NonConstEq::A))` + +error: aborting due to 18 previous errors diff --git a/src/tools/clippy/tests/ui/equatable_if_let_const_cmp.fixed b/src/tools/clippy/tests/ui/equatable_if_let_const_cmp.fixed new file mode 100644 index 0000000000000..51dab25ed6d83 --- /dev/null +++ b/src/tools/clippy/tests/ui/equatable_if_let_const_cmp.fixed @@ -0,0 +1,24 @@ +#![warn(clippy::equatable_if_let)] +#![allow(clippy::eq_op)] +#![feature(const_trait_impl, const_cmp)] + +fn issue15376() { + enum ConstEq { + A, + B, + } + impl const PartialEq for ConstEq { + fn eq(&self, _other: &Self) -> bool { + true + } + } + + const C: ConstEq = ConstEq::A; + + // `impl PartialEq` is const... but we still suggest `matches!` for now + // TODO: detect this and suggest `=` + const _: u32 = if matches!(C, ConstEq::A) { 0 } else { 1 }; + //~^ ERROR: this pattern matching can be expressed using `matches!` + const _: u32 = if matches!(Some(C), Some(ConstEq::A)) { 0 } else { 1 }; + //~^ ERROR: this pattern matching can be expressed using `matches!` +} diff --git a/src/tools/clippy/tests/ui/equatable_if_let_const_cmp.rs b/src/tools/clippy/tests/ui/equatable_if_let_const_cmp.rs new file mode 100644 index 0000000000000..b402e05c53de9 --- /dev/null +++ b/src/tools/clippy/tests/ui/equatable_if_let_const_cmp.rs @@ -0,0 +1,24 @@ +#![warn(clippy::equatable_if_let)] +#![allow(clippy::eq_op)] +#![feature(const_trait_impl, const_cmp)] + +fn issue15376() { + enum ConstEq { + A, + B, + } + impl const PartialEq for ConstEq { + fn eq(&self, _other: &Self) -> bool { + true + } + } + + const C: ConstEq = ConstEq::A; + + // `impl PartialEq` is const... but we still suggest `matches!` for now + // TODO: detect this and suggest `=` + const _: u32 = if let ConstEq::A = C { 0 } else { 1 }; + //~^ ERROR: this pattern matching can be expressed using `matches!` + const _: u32 = if let Some(ConstEq::A) = Some(C) { 0 } else { 1 }; + //~^ ERROR: this pattern matching can be expressed using `matches!` +} diff --git a/src/tools/clippy/tests/ui/equatable_if_let_const_cmp.stderr b/src/tools/clippy/tests/ui/equatable_if_let_const_cmp.stderr new file mode 100644 index 0000000000000..ec72e42d64305 --- /dev/null +++ b/src/tools/clippy/tests/ui/equatable_if_let_const_cmp.stderr @@ -0,0 +1,17 @@ +error: this pattern matching can be expressed using `matches!` + --> tests/ui/equatable_if_let_const_cmp.rs:20:23 + | +LL | const _: u32 = if let ConstEq::A = C { 0 } else { 1 }; + | ^^^^^^^^^^^^^^^^^^ help: try: `matches!(C, ConstEq::A)` + | + = note: `-D clippy::equatable-if-let` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::equatable_if_let)]` + +error: this pattern matching can be expressed using `matches!` + --> tests/ui/equatable_if_let_const_cmp.rs:22:23 + | +LL | const _: u32 = if let Some(ConstEq::A) = Some(C) { 0 } else { 1 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(Some(C), Some(ConstEq::A))` + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/ui/explicit_deref_methods.fixed b/src/tools/clippy/tests/ui/explicit_deref_methods.fixed index 97e8e0bafe4fd..6c29630dc3a57 100644 --- a/src/tools/clippy/tests/ui/explicit_deref_methods.fixed +++ b/src/tools/clippy/tests/ui/explicit_deref_methods.fixed @@ -156,3 +156,116 @@ fn main() { let _ = &&mut **&mut x; //~ explicit_deref_methods let _ = &&mut ***(&mut &mut x); //~ explicit_deref_methods } + +mod issue_15392 { + use std::ops::{Deref, DerefMut}; + + struct Wrapper(String); + + impl Deref for Wrapper { + type Target = str; + fn deref(&self) -> &Self::Target { + // forwarding is ok + let res = Deref::deref(&self.0); + // we let `deref_mut` pass as well + let _ = DerefMut::deref_mut(&mut String::new()); + res + } + } + + impl DerefMut for Wrapper { + fn deref_mut(&mut self) -> &mut Self::Target { + // forwarding is ok + let res = DerefMut::deref_mut(&mut self.0); + // we let `deref` pass as well + let _ = Deref::deref(&String::new()); + res + } + } + + struct A(String); + struct AA(String); + struct AB(String); + + impl Deref for A { + type Target = str; + + fn deref(&self) -> &Self::Target { + // in a top-level `Deref` impl, ok + let _ = self.0.deref(); + // in a top-level `Deref` impl, acceptable + let _ = String::new().deref_mut(); + + #[allow(non_local_definitions)] + impl Deref for AA { + type Target = str; + fn deref(&self) -> &Self::Target { + // in a nested `Deref` impl, acceptable + let _ = String::new().deref_mut(); + // in a nested `Deref` impl, ok + self.0.deref() + } + } + + // still in a top-level `Deref` impl, ok + let _ = self.0.deref(); + // still in a top-level `Deref` impl, acceptable + let _ = String::new().deref_mut(); + + #[allow(non_local_definitions)] + impl DerefMut for AA { + fn deref_mut(&mut self) -> &mut Self::Target { + // in a top-level `DerefMut` impl, acceptable + let _ = self.0.deref(); + // in a top-level `DerefMut` impl, ok + self.0.deref_mut() + } + } + + // still in a top-level `Deref` impl, acceptable + let _ = String::new().deref_mut(); + // still in a top-level `Deref` impl, ok + self.0.deref() + } + } + + impl DerefMut for A { + fn deref_mut(&mut self) -> &mut Self::Target { + // in a top-level `DerefMut` impl, acceptable + let _ = self.0.deref(); + // in a top-level `DerefMut` impl, ok + let _ = self.0.deref_mut(); + + #[allow(non_local_definitions)] + impl Deref for AB { + type Target = str; + fn deref(&self) -> &Self::Target { + // in a nested `Deref` impl, acceptable + let _ = String::new().deref_mut(); + // in a nested `Deref` impl, ok + Deref::deref(&self.0) + } + } + + // still in a top-level `DerefMut` impl, acceptable + let _ = self.0.deref(); + // still in a top-level `DerefMut` impl, ok + let _ = self.0.deref_mut(); + + #[allow(non_local_definitions)] + impl DerefMut for AB { + fn deref_mut(&mut self) -> &mut Self::Target { + // in a nested `DerefMut` impl, acceptable + self.0.deref(); + // in a nested `DerefMut` impl, ok + self.0.deref_mut() + } + } + + // still in a top-level `DerefMut` impl, acceptable + let _ = self.0.deref(); + // still in a top-level `DerefMut` impl, ok + self.0.deref_mut() + } + } +} diff --git a/src/tools/clippy/tests/ui/explicit_deref_methods.rs b/src/tools/clippy/tests/ui/explicit_deref_methods.rs index b689649d49dd7..f6309cd404b85 100644 --- a/src/tools/clippy/tests/ui/explicit_deref_methods.rs +++ b/src/tools/clippy/tests/ui/explicit_deref_methods.rs @@ -156,3 +156,116 @@ fn main() { let _ = &DerefMut::deref_mut(&mut x); //~ explicit_deref_methods let _ = &DerefMut::deref_mut((&mut &mut x).deref_mut()); //~ explicit_deref_methods } + +mod issue_15392 { + use std::ops::{Deref, DerefMut}; + + struct Wrapper(String); + + impl Deref for Wrapper { + type Target = str; + fn deref(&self) -> &Self::Target { + // forwarding is ok + let res = Deref::deref(&self.0); + // we let `deref_mut` pass as well + let _ = DerefMut::deref_mut(&mut String::new()); + res + } + } + + impl DerefMut for Wrapper { + fn deref_mut(&mut self) -> &mut Self::Target { + // forwarding is ok + let res = DerefMut::deref_mut(&mut self.0); + // we let `deref` pass as well + let _ = Deref::deref(&String::new()); + res + } + } + + struct A(String); + struct AA(String); + struct AB(String); + + impl Deref for A { + type Target = str; + + fn deref(&self) -> &Self::Target { + // in a top-level `Deref` impl, ok + let _ = self.0.deref(); + // in a top-level `Deref` impl, acceptable + let _ = String::new().deref_mut(); + + #[allow(non_local_definitions)] + impl Deref for AA { + type Target = str; + fn deref(&self) -> &Self::Target { + // in a nested `Deref` impl, acceptable + let _ = String::new().deref_mut(); + // in a nested `Deref` impl, ok + self.0.deref() + } + } + + // still in a top-level `Deref` impl, ok + let _ = self.0.deref(); + // still in a top-level `Deref` impl, acceptable + let _ = String::new().deref_mut(); + + #[allow(non_local_definitions)] + impl DerefMut for AA { + fn deref_mut(&mut self) -> &mut Self::Target { + // in a top-level `DerefMut` impl, acceptable + let _ = self.0.deref(); + // in a top-level `DerefMut` impl, ok + self.0.deref_mut() + } + } + + // still in a top-level `Deref` impl, acceptable + let _ = String::new().deref_mut(); + // still in a top-level `Deref` impl, ok + self.0.deref() + } + } + + impl DerefMut for A { + fn deref_mut(&mut self) -> &mut Self::Target { + // in a top-level `DerefMut` impl, acceptable + let _ = self.0.deref(); + // in a top-level `DerefMut` impl, ok + let _ = self.0.deref_mut(); + + #[allow(non_local_definitions)] + impl Deref for AB { + type Target = str; + fn deref(&self) -> &Self::Target { + // in a nested `Deref` impl, acceptable + let _ = String::new().deref_mut(); + // in a nested `Deref` impl, ok + Deref::deref(&self.0) + } + } + + // still in a top-level `DerefMut` impl, acceptable + let _ = self.0.deref(); + // still in a top-level `DerefMut` impl, ok + let _ = self.0.deref_mut(); + + #[allow(non_local_definitions)] + impl DerefMut for AB { + fn deref_mut(&mut self) -> &mut Self::Target { + // in a nested `DerefMut` impl, acceptable + self.0.deref(); + // in a nested `DerefMut` impl, ok + self.0.deref_mut() + } + } + + // still in a top-level `DerefMut` impl, acceptable + let _ = self.0.deref(); + // still in a top-level `DerefMut` impl, ok + self.0.deref_mut() + } + } +} diff --git a/src/tools/clippy/tests/ui/implicit_hasher.fixed b/src/tools/clippy/tests/ui/implicit_hasher.fixed index bea5b9afc43ac..882a545963b4a 100644 --- a/src/tools/clippy/tests/ui/implicit_hasher.fixed +++ b/src/tools/clippy/tests/ui/implicit_hasher.fixed @@ -109,3 +109,27 @@ pub async fn election_vote(_data: HashMap { + $num * 10 + }; + } + + impl Foo for HashMap { + //~^ implicit_hasher + fn make() -> (Self, Self) { + (HashMap::default(), HashMap::with_capacity_and_hasher(times_ten!(5), Default::default())) + } + } + + impl Foo for HashSet { + //~^ implicit_hasher + fn make() -> (Self, Self) { + (HashSet::default(), HashSet::with_capacity_and_hasher(times_ten!(5), Default::default())) + } + } +} diff --git a/src/tools/clippy/tests/ui/implicit_hasher.rs b/src/tools/clippy/tests/ui/implicit_hasher.rs index afdf4da61650b..186f9e9978e57 100644 --- a/src/tools/clippy/tests/ui/implicit_hasher.rs +++ b/src/tools/clippy/tests/ui/implicit_hasher.rs @@ -109,3 +109,27 @@ pub async fn election_vote(_data: HashMap) {} //~^ implicit_hasher fn main() {} + +mod issue16128 { + use super::*; + + macro_rules! times_ten { + ($num:expr) => { + $num * 10 + }; + } + + impl Foo for HashMap { + //~^ implicit_hasher + fn make() -> (Self, Self) { + (HashMap::new(), HashMap::with_capacity(times_ten!(5))) + } + } + + impl Foo for HashSet { + //~^ implicit_hasher + fn make() -> (Self, Self) { + (HashSet::new(), HashSet::with_capacity(times_ten!(5))) + } + } +} diff --git a/src/tools/clippy/tests/ui/implicit_hasher.stderr b/src/tools/clippy/tests/ui/implicit_hasher.stderr index 6735998ed6541..326115c8e9a34 100644 --- a/src/tools/clippy/tests/ui/implicit_hasher.stderr +++ b/src/tools/clippy/tests/ui/implicit_hasher.stderr @@ -122,5 +122,33 @@ help: add a type parameter for `BuildHasher` LL | pub async fn election_vote(_data: HashMap) {} | +++++++++++++++++++++++++++++ +++ -error: aborting due to 9 previous errors +error: impl for `HashMap` should be generalized over different hashers + --> tests/ui/implicit_hasher.rs:122:40 + | +LL | impl Foo for HashMap { + | ^^^^^^^^^^^^^ + | +help: add a type parameter for `BuildHasher` + | +LL ~ impl Foo for HashMap { +LL | +LL | fn make() -> (Self, Self) { +LL ~ (HashMap::default(), HashMap::with_capacity_and_hasher(times_ten!(5), Default::default())) + | + +error: impl for `HashSet` should be generalized over different hashers + --> tests/ui/implicit_hasher.rs:129:37 + | +LL | impl Foo for HashSet { + | ^^^^^^^^^^ + | +help: add a type parameter for `BuildHasher` + | +LL ~ impl Foo for HashSet { +LL | +LL | fn make() -> (Self, Self) { +LL ~ (HashSet::default(), HashSet::with_capacity_and_hasher(times_ten!(5), Default::default())) + | + +error: aborting due to 11 previous errors diff --git a/src/tools/clippy/tests/ui/missing_doc.rs b/src/tools/clippy/tests/ui/missing_doc.rs deleted file mode 100644 index 705de959cb7da..0000000000000 --- a/src/tools/clippy/tests/ui/missing_doc.rs +++ /dev/null @@ -1,148 +0,0 @@ -//@needs-asm-support -//@aux-build: proc_macros.rs -//@aux-build: proc_macro_attr.rs - -#![warn(clippy::missing_docs_in_private_items)] -// When denying at the crate level, be sure to not get random warnings from the -// injected intrinsics by the compiler. -#![allow(dead_code)] -//! Some garbage docs for the crate here -#![doc = "More garbage"] - -#[macro_use] -extern crate proc_macro_attr; -extern crate proc_macros; - -use proc_macros::with_span; -use std::arch::global_asm; - -type Typedef = String; -//~^ missing_docs_in_private_items -pub type PubTypedef = String; - -mod module_no_dox {} -//~^ missing_docs_in_private_items -pub mod pub_module_no_dox {} - -/// dox -pub fn foo() {} -pub fn foo2() {} -fn foo3() {} -//~^ missing_docs_in_private_items -#[allow(clippy::missing_docs_in_private_items)] -pub fn foo4() {} - -// It sure is nice if doc(hidden) implies allow(missing_docs), and that it -// applies recursively -#[doc(hidden)] -mod a { - pub fn baz() {} - pub mod b { - pub fn baz() {} - } -} - -enum Baz { - //~^ missing_docs_in_private_items - BazA { a: isize, b: isize }, - //~^ missing_docs_in_private_items - //~| missing_docs_in_private_items - //~| missing_docs_in_private_items - BarB, - //~^ missing_docs_in_private_items -} - -pub enum PubBaz { - PubBazA { a: isize }, -} - -/// dox -pub enum PubBaz2 { - /// dox - PubBaz2A { - /// dox - a: isize, - }, -} - -#[allow(clippy::missing_docs_in_private_items)] -pub enum PubBaz3 { - PubBaz3A { b: isize }, -} - -#[doc(hidden)] -pub fn baz() {} - -const FOO: u32 = 0; -//~^ missing_docs_in_private_items -/// dox -pub const FOO1: u32 = 0; -#[allow(clippy::missing_docs_in_private_items)] -pub const FOO2: u32 = 0; -#[doc(hidden)] -pub const FOO3: u32 = 0; -pub const FOO4: u32 = 0; - -static BAR: u32 = 0; -//~^ missing_docs_in_private_items -/// dox -pub static BAR1: u32 = 0; -#[allow(clippy::missing_docs_in_private_items)] -pub static BAR2: u32 = 0; -#[doc(hidden)] -pub static BAR3: u32 = 0; -pub static BAR4: u32 = 0; - -mod internal_impl { - //~^ missing_docs_in_private_items - /// dox - pub fn documented() {} - pub fn undocumented1() {} - pub fn undocumented2() {} - fn undocumented3() {} - //~^ missing_docs_in_private_items - /// dox - pub mod globbed { - /// dox - pub fn also_documented() {} - pub fn also_undocumented1() {} - fn also_undocumented2() {} - //~^ missing_docs_in_private_items - } -} -/// dox -pub mod public_interface { - pub use crate::internal_impl::globbed::*; - pub use crate::internal_impl::{documented as foo, documented, undocumented1 as bar, undocumented2}; -} - -fn main() {} - -// Ensure global asm doesn't require documentation. -global_asm! { "" } - -// Don't lint proc macro output with an unexpected span. -with_span!(span pub struct FooPm { pub field: u32}); -with_span!(span pub struct FooPm2;); -with_span!(span pub enum FooPm3 { A, B(u32), C { field: u32 }}); -with_span!(span pub fn foo_pm() {}); -with_span!(span pub static FOO_PM: u32 = 0;); -with_span!(span pub const FOO2_PM: u32 = 0;); - -// Don't lint unnamed constants -const _: () = (); - -fn issue13298() { - //~^ missing_docs_in_private_items - // Rustdoc doesn't generate documentation for items within other items like fns or consts - const MSG: &str = "Hello, world!"; -} - -// issue #12197 -// Undocumented field originated inside of spanned proc-macro attribute -/// Some dox for struct. -#[rewrite_struct] -pub struct Test { - /// Dox - a: u8, -} diff --git a/src/tools/clippy/tests/ui/missing_doc.stderr b/src/tools/clippy/tests/ui/missing_doc.stderr deleted file mode 100644 index 63e440b82d147..0000000000000 --- a/src/tools/clippy/tests/ui/missing_doc.stderr +++ /dev/null @@ -1,102 +0,0 @@ -error: missing documentation for a type alias - --> tests/ui/missing_doc.rs:19:1 - | -LL | type Typedef = String; - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::missing_docs_in_private_items)]` - -error: missing documentation for a module - --> tests/ui/missing_doc.rs:23:1 - | -LL | mod module_no_dox {} - | ^^^^^^^^^^^^^^^^^^^^ - -error: missing documentation for a function - --> tests/ui/missing_doc.rs:30:1 - | -LL | fn foo3() {} - | ^^^^^^^^^^^^ - -error: missing documentation for an enum - --> tests/ui/missing_doc.rs:45:1 - | -LL | / enum Baz { -LL | | -LL | | BazA { a: isize, b: isize }, -... | -LL | | } - | |_^ - -error: missing documentation for a variant - --> tests/ui/missing_doc.rs:47:5 - | -LL | BazA { a: isize, b: isize }, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: missing documentation for a struct field - --> tests/ui/missing_doc.rs:47:12 - | -LL | BazA { a: isize, b: isize }, - | ^^^^^^^^ - -error: missing documentation for a struct field - --> tests/ui/missing_doc.rs:47:22 - | -LL | BazA { a: isize, b: isize }, - | ^^^^^^^^ - -error: missing documentation for a variant - --> tests/ui/missing_doc.rs:51:5 - | -LL | BarB, - | ^^^^ - -error: missing documentation for a constant - --> tests/ui/missing_doc.rs:76:1 - | -LL | const FOO: u32 = 0; - | ^^^^^^^^^^^^^^^^^^^ - -error: missing documentation for a static - --> tests/ui/missing_doc.rs:86:1 - | -LL | static BAR: u32 = 0; - | ^^^^^^^^^^^^^^^^^^^^ - -error: missing documentation for a module - --> tests/ui/missing_doc.rs:96:1 - | -LL | / mod internal_impl { -LL | | -LL | | /// dox -LL | | pub fn documented() {} -... | -LL | | } - | |_^ - -error: missing documentation for a function - --> tests/ui/missing_doc.rs:102:5 - | -LL | fn undocumented3() {} - | ^^^^^^^^^^^^^^^^^^^^^ - -error: missing documentation for a function - --> tests/ui/missing_doc.rs:109:9 - | -LL | fn also_undocumented2() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: missing documentation for a function - --> tests/ui/missing_doc.rs:135:1 - | -LL | / fn issue13298() { -LL | | -LL | | // Rustdoc doesn't generate documentation for items within other items like fns or consts -LL | | const MSG: &str = "Hello, world!"; -LL | | } - | |_^ - -error: aborting due to 14 previous errors - diff --git a/src/tools/clippy/tests/ui/missing_doc_crate.rs b/src/tools/clippy/tests/ui/missing_doc_crate.rs deleted file mode 100644 index e6e783a2bb405..0000000000000 --- a/src/tools/clippy/tests/ui/missing_doc_crate.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ check-pass - -#![warn(clippy::missing_docs_in_private_items)] -#![allow(clippy::doc_include_without_cfg)] -#![doc = include_str!("../../README.md")] - -fn main() {} diff --git a/src/tools/clippy/tests/ui/missing_doc_crate_missing.rs b/src/tools/clippy/tests/ui/missing_doc_crate_missing.rs deleted file mode 100644 index f55d8b67cb847..0000000000000 --- a/src/tools/clippy/tests/ui/missing_doc_crate_missing.rs +++ /dev/null @@ -1,4 +0,0 @@ -#![warn(clippy::missing_docs_in_private_items)] -//~^ missing_docs_in_private_items - -fn main() {} diff --git a/src/tools/clippy/tests/ui/missing_doc_crate_missing.stderr b/src/tools/clippy/tests/ui/missing_doc_crate_missing.stderr deleted file mode 100644 index d6a4342c5031e..0000000000000 --- a/src/tools/clippy/tests/ui/missing_doc_crate_missing.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error: missing documentation for the crate - --> tests/ui/missing_doc_crate_missing.rs:1:1 - | -LL | / #![warn(clippy::missing_docs_in_private_items)] -... | -LL | | fn main() {} - | |____________^ - | - = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::missing_docs_in_private_items)]` - -error: aborting due to 1 previous error - diff --git a/src/tools/clippy/tests/ui/missing_doc_impl.rs b/src/tools/clippy/tests/ui/missing_doc_impl.rs deleted file mode 100644 index 034ce31dfe768..0000000000000 --- a/src/tools/clippy/tests/ui/missing_doc_impl.rs +++ /dev/null @@ -1,114 +0,0 @@ -//@aux-build: proc_macros.rs - -#![warn(clippy::missing_docs_in_private_items)] -#![allow(dead_code)] -#![feature(associated_type_defaults)] - -//! Some garbage docs for the crate here -#![doc = "More garbage"] - -extern crate proc_macros; -use proc_macros::with_span; - -struct Foo { - //~^ missing_docs_in_private_items - a: isize, - //~^ missing_docs_in_private_items - b: isize, - //~^ missing_docs_in_private_items -} - -pub struct PubFoo { - pub a: isize, - b: isize, - //~^ missing_docs_in_private_items -} - -#[allow(clippy::missing_docs_in_private_items)] -pub struct PubFoo2 { - pub a: isize, - pub c: isize, -} - -/// dox -pub trait A { - /// dox - fn foo(&self); - /// dox - fn foo_with_impl(&self) {} -} - -#[allow(clippy::missing_docs_in_private_items)] -trait B { - fn foo(&self); - fn foo_with_impl(&self) {} -} - -pub trait C { - fn foo(&self); - fn foo_with_impl(&self) {} -} - -#[allow(clippy::missing_docs_in_private_items)] -pub trait D { - fn dummy(&self) {} -} - -/// dox -pub trait E: Sized { - type AssociatedType; - type AssociatedTypeDef = Self; - - /// dox - type DocumentedType; - /// dox - type DocumentedTypeDef = Self; - /// dox - fn dummy(&self) {} -} - -impl Foo { - pub fn new() -> Self { - //~^ missing_docs_in_private_items - Foo { a: 0, b: 0 } - } - fn bar() {} - //~^ missing_docs_in_private_items -} - -impl PubFoo { - pub fn foo() {} - /// dox - pub fn foo1() {} - #[must_use = "yep"] - fn foo2() -> u32 { - //~^ missing_docs_in_private_items - 1 - } - #[allow(clippy::missing_docs_in_private_items)] - pub fn foo3() {} -} - -#[allow(clippy::missing_docs_in_private_items)] -trait F { - fn a(); - fn b(&self); -} - -// should need to redefine documentation for implementations of traits -impl F for Foo { - fn a() {} - fn b(&self) {} -} - -fn main() {} - -// don't lint proc macro output -with_span!(span - pub struct FooPm; - impl FooPm { - pub fn foo() {} - pub const fn bar() {} - pub const X: u32 = 0; - } -); diff --git a/src/tools/clippy/tests/ui/missing_doc_impl.stderr b/src/tools/clippy/tests/ui/missing_doc_impl.stderr deleted file mode 100644 index 999ff06f593e9..0000000000000 --- a/src/tools/clippy/tests/ui/missing_doc_impl.stderr +++ /dev/null @@ -1,57 +0,0 @@ -error: missing documentation for a struct - --> tests/ui/missing_doc_impl.rs:13:1 - | -LL | / struct Foo { -LL | | -LL | | a: isize, -... | -LL | | } - | |_^ - | - = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::missing_docs_in_private_items)]` - -error: missing documentation for a struct field - --> tests/ui/missing_doc_impl.rs:15:5 - | -LL | a: isize, - | ^^^^^^^^ - -error: missing documentation for a struct field - --> tests/ui/missing_doc_impl.rs:17:5 - | -LL | b: isize, - | ^^^^^^^^ - -error: missing documentation for a struct field - --> tests/ui/missing_doc_impl.rs:23:5 - | -LL | b: isize, - | ^^^^^^^^ - -error: missing documentation for an associated function - --> tests/ui/missing_doc_impl.rs:71:5 - | -LL | / pub fn new() -> Self { -LL | | -LL | | Foo { a: 0, b: 0 } -LL | | } - | |_____^ - -error: missing documentation for an associated function - --> tests/ui/missing_doc_impl.rs:75:5 - | -LL | fn bar() {} - | ^^^^^^^^^^^ - -error: missing documentation for an associated function - --> tests/ui/missing_doc_impl.rs:84:5 - | -LL | / fn foo2() -> u32 { -LL | | -LL | | 1 -LL | | } - | |_____^ - -error: aborting due to 7 previous errors - diff --git a/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs index 132673d5164ab..c1512ba3e2696 100644 --- a/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs +++ b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs @@ -105,6 +105,14 @@ fn correct3() { } } +fn with_adjustment(f: &unsafe fn()) { + unsafe { + //~^ multiple_unsafe_ops_per_block + f(); + f(); + } +} + fn issue10064() { unsafe fn read_char_bad(ptr: *const u8) -> char { unsafe { char::from_u32_unchecked(*ptr.cast::()) } @@ -209,4 +217,99 @@ async fn issue13879() { } } +fn issue16076() { + #[derive(Clone, Copy)] + union U { + i: u32, + f: f32, + } + + let u = U { i: 0 }; + + // Taking a raw pointer to a place is safe since Rust 1.92 + unsafe { + _ = &raw const u.i; + _ = &raw const u.i; + } + + // Taking a reference to a union field is not safe + unsafe { + //~^ multiple_unsafe_ops_per_block + _ = &u.i; + _ = &u.i; + } + + // Check that we still check and lint the prefix of the raw pointer to a field access + #[expect(clippy::deref_addrof)] + unsafe { + //~^ multiple_unsafe_ops_per_block + _ = &raw const (*&raw const u).i; + _ = &raw const (*&raw const u).i; + } + + union V { + u: U, + } + + // Taking a raw pointer to a union field of an union field (etc.) is safe + let v = V { u }; + unsafe { + _ = &raw const v.u.i; + _ = &raw const v.u.i; + } + + // Check that unions in structs work properly as well + struct T { + u: U, + } + let t = T { u }; + unsafe { + _ = &raw const t.u.i; + _ = &raw const t.u.i; + } + + // As well as structs in unions + #[derive(Clone, Copy)] + struct X { + i: i32, + } + union Z { + x: X, + } + let z = Z { x: X { i: 0 } }; + unsafe { + _ = &raw const z.x.i; + _ = &raw const z.x.i; + } + + // If a field needs to be adjusted then it is accessed + struct S { + i: i32, + } + union W<'a> { + s: &'a S, + } + let s = S { i: 0 }; + let w = W { s: &s }; + unsafe { + //~^ multiple_unsafe_ops_per_block + _ = &raw const w.s.i; + _ = &raw const w.s.i; + } +} + +fn check_closures() { + unsafe fn apply(f: impl Fn()) { + todo!() + } + unsafe fn f(_x: i32) { + todo!() + } + + unsafe { + //~^ multiple_unsafe_ops_per_block + apply(|| f(0)); + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.stderr b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.stderr index 922a464c6b6ef..63f7742b734b1 100644 --- a/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.stderr +++ b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.stderr @@ -113,24 +113,45 @@ LL | asm!("nop"); | ^^^^^^^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:110:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:109:5 + | +LL | / unsafe { +LL | | +LL | | f(); +LL | | f(); +LL | | } + | |_____^ + | +note: unsafe function call occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:111:9 + | +LL | f(); + | ^^^ +note: unsafe function call occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:112:9 + | +LL | f(); + | ^^^ + +error: this `unsafe` block contains 2 unsafe operations, expected only one + --> tests/ui/multiple_unsafe_ops_per_block.rs:118:9 | LL | unsafe { char::from_u32_unchecked(*ptr.cast::()) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:110:18 + --> tests/ui/multiple_unsafe_ops_per_block.rs:118:18 | LL | unsafe { char::from_u32_unchecked(*ptr.cast::()) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: raw pointer dereference occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:110:43 + --> tests/ui/multiple_unsafe_ops_per_block.rs:118:43 | LL | unsafe { char::from_u32_unchecked(*ptr.cast::()) } | ^^^^^^^^^^^^^^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:131:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:139:9 | LL | / unsafe { LL | | @@ -140,18 +161,18 @@ LL | | } | |_________^ | note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:133:13 + --> tests/ui/multiple_unsafe_ops_per_block.rs:141:13 | LL | x(); | ^^^ note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:134:13 + --> tests/ui/multiple_unsafe_ops_per_block.rs:142:13 | LL | x(); | ^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:143:13 + --> tests/ui/multiple_unsafe_ops_per_block.rs:151:13 | LL | / unsafe { LL | | @@ -161,18 +182,18 @@ LL | | } | |_____________^ | note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:145:17 + --> tests/ui/multiple_unsafe_ops_per_block.rs:153:17 | LL | T::X(); | ^^^^^^ note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:146:17 + --> tests/ui/multiple_unsafe_ops_per_block.rs:154:17 | LL | T::X(); | ^^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:154:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:162:9 | LL | / unsafe { LL | | @@ -182,18 +203,18 @@ LL | | } | |_________^ | note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:156:13 + --> tests/ui/multiple_unsafe_ops_per_block.rs:164:13 | LL | x.0(); | ^^^^^ note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:157:13 + --> tests/ui/multiple_unsafe_ops_per_block.rs:165:13 | LL | x.0(); | ^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:184:5 + --> tests/ui/multiple_unsafe_ops_per_block.rs:192:5 | LL | / unsafe { LL | | @@ -204,18 +225,18 @@ LL | | } | |_____^ | note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:186:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:194:9 | LL | not_very_safe(); | ^^^^^^^^^^^^^^^ note: modification of a mutable static occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:187:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:195:9 | LL | STATIC += 1; | ^^^^^^^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:199:5 + --> tests/ui/multiple_unsafe_ops_per_block.rs:207:5 | LL | / unsafe { LL | | @@ -225,18 +246,18 @@ LL | | } | |_____^ | note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:201:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:209:9 | LL | not_very_safe(); | ^^^^^^^^^^^^^^^ note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:202:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:210:9 | LL | foo_unchecked().await; | ^^^^^^^^^^^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:206:5 + --> tests/ui/multiple_unsafe_ops_per_block.rs:214:5 | LL | / unsafe { LL | | @@ -245,15 +266,98 @@ LL | | } | |_____^ | note: unsafe method call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:208:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:216:9 | LL | Some(foo_unchecked()).unwrap_unchecked().await; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:208:14 + --> tests/ui/multiple_unsafe_ops_per_block.rs:216:14 | LL | Some(foo_unchecked()).unwrap_unchecked().await; | ^^^^^^^^^^^^^^^ -error: aborting due to 11 previous errors +error: this `unsafe` block contains 2 unsafe operations, expected only one + --> tests/ui/multiple_unsafe_ops_per_block.rs:236:5 + | +LL | / unsafe { +LL | | +LL | | _ = &u.i; +LL | | _ = &u.i; +LL | | } + | |_____^ + | +note: union field access occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:238:14 + | +LL | _ = &u.i; + | ^^^ +note: union field access occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:239:14 + | +LL | _ = &u.i; + | ^^^ + +error: this `unsafe` block contains 2 unsafe operations, expected only one + --> tests/ui/multiple_unsafe_ops_per_block.rs:244:5 + | +LL | / unsafe { +LL | | +LL | | _ = &raw const (*&raw const u).i; +LL | | _ = &raw const (*&raw const u).i; +LL | | } + | |_____^ + | +note: raw pointer dereference occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:246:24 + | +LL | _ = &raw const (*&raw const u).i; + | ^^^^^^^^^^^^^^^ +note: raw pointer dereference occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:247:24 + | +LL | _ = &raw const (*&raw const u).i; + | ^^^^^^^^^^^^^^^ + +error: this `unsafe` block contains 2 unsafe operations, expected only one + --> tests/ui/multiple_unsafe_ops_per_block.rs:294:5 + | +LL | / unsafe { +LL | | +LL | | _ = &raw const w.s.i; +LL | | _ = &raw const w.s.i; +LL | | } + | |_____^ + | +note: union field access occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:296:24 + | +LL | _ = &raw const w.s.i; + | ^^^ +note: union field access occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:297:24 + | +LL | _ = &raw const w.s.i; + | ^^^ + +error: this `unsafe` block contains 2 unsafe operations, expected only one + --> tests/ui/multiple_unsafe_ops_per_block.rs:309:5 + | +LL | / unsafe { +LL | | +LL | | apply(|| f(0)); +LL | | } + | |_____^ + | +note: unsafe function call occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:311:9 + | +LL | apply(|| f(0)); + | ^^^^^^^^^^^^^^ +note: unsafe function call occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:311:18 + | +LL | apply(|| f(0)); + | ^^^^ + +error: aborting due to 16 previous errors diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed index a54a4ce13d53f..08903ef7fddac 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed @@ -166,3 +166,32 @@ fn issue13902() { //~^ redundant_pattern_matching } } + +fn issue16045() { + fn f() -> Result<(), ()> { + let x = Ok::<_, ()>(Some(123)); + if x?.is_some() { + //~^ redundant_pattern_matching + } + + Ok(()) + } + + async fn g() { + struct F { + x: Option, + } + + impl Future for F { + type Output = Option; + + fn poll(self: std::pin::Pin<&mut Self>, _: &mut std::task::Context<'_>) -> std::task::Poll { + std::task::Poll::Ready(self.x) + } + } + let x = F { x: Some(123) }; + if x.await.is_some() { + //~^ redundant_pattern_matching + } + } +} diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs index 7252fce8cce6d..95eff3f9ebf90 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs @@ -202,3 +202,32 @@ fn issue13902() { //~^ redundant_pattern_matching } } + +fn issue16045() { + fn f() -> Result<(), ()> { + let x = Ok::<_, ()>(Some(123)); + if let Some(_) = x? { + //~^ redundant_pattern_matching + } + + Ok(()) + } + + async fn g() { + struct F { + x: Option, + } + + impl Future for F { + type Output = Option; + + fn poll(self: std::pin::Pin<&mut Self>, _: &mut std::task::Context<'_>) -> std::task::Poll { + std::task::Poll::Ready(self.x) + } + } + let x = F { x: Some(123) }; + if let Some(_) = x.await { + //~^ redundant_pattern_matching + } + } +} diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr index e5a6598898aa1..6fd0c5a6f8595 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr @@ -224,5 +224,17 @@ error: redundant pattern matching, consider using `is_none()` LL | let _ = matches!(*p, None); | ^^^^^^^^^^^^^^^^^^ help: try: `(*p).is_none()` -error: aborting due to 31 previous errors +error: redundant pattern matching, consider using `is_some()` + --> tests/ui/redundant_pattern_matching_option.rs:209:16 + | +LL | if let Some(_) = x? { + | -------^^^^^^^----- help: try: `if x?.is_some()` + +error: redundant pattern matching, consider using `is_some()` + --> tests/ui/redundant_pattern_matching_option.rs:229:16 + | +LL | if let Some(_) = x.await { + | -------^^^^^^^---------- help: try: `if x.await.is_some()` + +error: aborting due to 33 previous errors diff --git a/src/tools/clippy/tests/ui/sliced_string_as_bytes.fixed b/src/tools/clippy/tests/ui/sliced_string_as_bytes.fixed index 16c0daff78fdc..b5576188b83f6 100644 --- a/src/tools/clippy/tests/ui/sliced_string_as_bytes.fixed +++ b/src/tools/clippy/tests/ui/sliced_string_as_bytes.fixed @@ -32,6 +32,12 @@ fn main() { let bytes = &"consectetur adipiscing".as_bytes()[..=5]; //~^ sliced_string_as_bytes + // this lint is a perf lint meant to catch utf-8 alignment checks. + // while the slicing here *is* redundant, it's more like a needless borrow, and shouldn't affect + // perf + let bytes = s[..].as_bytes(); + let bytes = string[..].as_bytes(); + let f = Foo; let bytes = f[0..4].as_bytes(); } diff --git a/src/tools/clippy/tests/ui/sliced_string_as_bytes.rs b/src/tools/clippy/tests/ui/sliced_string_as_bytes.rs index 67985ae5b9842..58b8d92902942 100644 --- a/src/tools/clippy/tests/ui/sliced_string_as_bytes.rs +++ b/src/tools/clippy/tests/ui/sliced_string_as_bytes.rs @@ -32,6 +32,12 @@ fn main() { let bytes = "consectetur adipiscing"[..=5].as_bytes(); //~^ sliced_string_as_bytes + // this lint is a perf lint meant to catch utf-8 alignment checks. + // while the slicing here *is* redundant, it's more like a needless borrow, and shouldn't affect + // perf + let bytes = s[..].as_bytes(); + let bytes = string[..].as_bytes(); + let f = Foo; let bytes = f[0..4].as_bytes(); } diff --git a/src/tools/clippy/tests/ui/transmute.rs b/src/tools/clippy/tests/ui/transmute.rs index e7099104f942d..afb79deac20f8 100644 --- a/src/tools/clippy/tests/ui/transmute.rs +++ b/src/tools/clippy/tests/ui/transmute.rs @@ -128,4 +128,17 @@ fn bytes_to_str(mb: &mut [u8]) { //~^ transmute_bytes_to_str } +fn issue16104() { + let b = vec![1_u8, 2_u8]; + macro_rules! take_ref { + ($x:expr) => { + $x.as_slice() + }; + } + unsafe { + let _: &str = std::mem::transmute(take_ref!(b)); + //~^ transmute_bytes_to_str + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/transmute.stderr b/src/tools/clippy/tests/ui/transmute.stderr index 9478db09481a8..6f9a0b717fc90 100644 --- a/src/tools/clippy/tests/ui/transmute.stderr +++ b/src/tools/clippy/tests/ui/transmute.stderr @@ -106,5 +106,11 @@ error: transmute from a `&[u8]` to a `&str` LL | const _: &str = unsafe { std::mem::transmute(B) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_unchecked(B)` -error: aborting due to 16 previous errors +error: transmute from a `&[u8]` to a `&str` + --> tests/ui/transmute.rs:139:23 + | +LL | let _: &str = std::mem::transmute(take_ref!(b)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(take_ref!(b)).unwrap()` + +error: aborting due to 17 previous errors diff --git a/src/tools/clippy/tests/ui/transmute_ref_to_ref.rs b/src/tools/clippy/tests/ui/transmute_ref_to_ref.rs index 8bdf07b4a428b..ed8fb80832918 100644 --- a/src/tools/clippy/tests/ui/transmute_ref_to_ref.rs +++ b/src/tools/clippy/tests/ui/transmute_ref_to_ref.rs @@ -18,3 +18,23 @@ fn main() { //~^ transmute_ptr_to_ptr } } + +fn issue16104(make_ptr: fn() -> *const u32) { + macro_rules! call { + ($x:expr) => { + $x() + }; + } + macro_rules! take_ref { + ($x:expr) => { + &$x + }; + } + + unsafe { + let _: *const f32 = std::mem::transmute(call!(make_ptr)); + //~^ transmute_ptr_to_ptr + let _: &f32 = std::mem::transmute(take_ref!(1u32)); + //~^ transmute_ptr_to_ptr + } +} diff --git a/src/tools/clippy/tests/ui/transmute_ref_to_ref.stderr b/src/tools/clippy/tests/ui/transmute_ref_to_ref.stderr index e8d659f9c5d8d..1b845ef859d88 100644 --- a/src/tools/clippy/tests/ui/transmute_ref_to_ref.stderr +++ b/src/tools/clippy/tests/ui/transmute_ref_to_ref.stderr @@ -22,5 +22,23 @@ error: transmute from a reference to a reference LL | let alt_slice: &[u32] = unsafe { std::mem::transmute(bytes) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(bytes as *const [u8] as *const [u32])` -error: aborting due to 3 previous errors +error: transmute from a pointer to a pointer + --> tests/ui/transmute_ref_to_ref.rs:35:29 + | +LL | let _: *const f32 = std::mem::transmute(call!(make_ptr)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `pointer::cast` instead + | +LL - let _: *const f32 = std::mem::transmute(call!(make_ptr)); +LL + let _: *const f32 = call!(make_ptr).cast::(); + | + +error: transmute from a reference to a reference + --> tests/ui/transmute_ref_to_ref.rs:37:23 + | +LL | let _: &f32 = std::mem::transmute(take_ref!(1u32)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(take_ref!(1u32) as *const u32 as *const f32)` + +error: aborting due to 5 previous errors diff --git a/src/tools/clippy/tests/ui/unchecked_time_subtraction.stderr b/src/tools/clippy/tests/ui/unchecked_time_subtraction.stderr index 7a39712269cf7..c129497447fc0 100644 --- a/src/tools/clippy/tests/ui/unchecked_time_subtraction.stderr +++ b/src/tools/clippy/tests/ui/unchecked_time_subtraction.stderr @@ -1,4 +1,4 @@ -error: unchecked subtraction of a 'Duration' from an 'Instant' +error: unchecked subtraction of a `Duration` --> tests/ui/unchecked_time_subtraction.rs:9:13 | LL | let _ = _first - second; @@ -7,43 +7,43 @@ LL | let _ = _first - second; = note: `-D clippy::unchecked-time-subtraction` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::unchecked_time_subtraction)]` -error: unchecked subtraction of a 'Duration' from an 'Instant' +error: unchecked subtraction of a `Duration` --> tests/ui/unchecked_time_subtraction.rs:12:13 | LL | let _ = Instant::now() - Duration::from_secs(5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Instant::now().checked_sub(Duration::from_secs(5)).unwrap()` -error: unchecked subtraction of a 'Duration' from an 'Instant' +error: unchecked subtraction of a `Duration` --> tests/ui/unchecked_time_subtraction.rs:15:13 | LL | let _ = _first - Duration::from_secs(5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `_first.checked_sub(Duration::from_secs(5)).unwrap()` -error: unchecked subtraction of a 'Duration' from an 'Instant' +error: unchecked subtraction of a `Duration` --> tests/ui/unchecked_time_subtraction.rs:18:13 | LL | let _ = Instant::now() - second; | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Instant::now().checked_sub(second).unwrap()` -error: unchecked subtraction between 'Duration' values +error: unchecked subtraction of a `Duration` --> tests/ui/unchecked_time_subtraction.rs:25:13 | LL | let _ = dur1 - dur2; | ^^^^^^^^^^^ help: try: `dur1.checked_sub(dur2).unwrap()` -error: unchecked subtraction between 'Duration' values +error: unchecked subtraction of a `Duration` --> tests/ui/unchecked_time_subtraction.rs:28:13 | LL | let _ = Duration::from_secs(10) - Duration::from_secs(5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Duration::from_secs(10).checked_sub(Duration::from_secs(5)).unwrap()` -error: unchecked subtraction between 'Duration' values +error: unchecked subtraction of a `Duration` --> tests/ui/unchecked_time_subtraction.rs:31:13 | LL | let _ = second - dur1; | ^^^^^^^^^^^^^ help: try: `second.checked_sub(dur1).unwrap()` -error: unchecked subtraction between 'Duration' values +error: unchecked subtraction of a `Duration` --> tests/ui/unchecked_time_subtraction.rs:35:13 | LL | let _ = 2 * dur1 - dur2; diff --git a/src/tools/clippy/tests/ui/unchecked_time_subtraction_unfixable.stderr b/src/tools/clippy/tests/ui/unchecked_time_subtraction_unfixable.stderr index c25c112b06ce0..017e5b1c7c11e 100644 --- a/src/tools/clippy/tests/ui/unchecked_time_subtraction_unfixable.stderr +++ b/src/tools/clippy/tests/ui/unchecked_time_subtraction_unfixable.stderr @@ -1,4 +1,4 @@ -error: unchecked subtraction between 'Duration' values +error: unchecked subtraction of a `Duration` --> tests/ui/unchecked_time_subtraction_unfixable.rs:12:13 | LL | let _ = dur1 - dur2 - dur3; @@ -7,19 +7,19 @@ LL | let _ = dur1 - dur2 - dur3; = note: `-D clippy::unchecked-time-subtraction` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::unchecked_time_subtraction)]` -error: unchecked subtraction between 'Duration' values +error: unchecked subtraction of a `Duration` --> tests/ui/unchecked_time_subtraction_unfixable.rs:12:13 | LL | let _ = dur1 - dur2 - dur3; | ^^^^^^^^^^^ help: try: `dur1.checked_sub(dur2).unwrap()` -error: unchecked subtraction of a 'Duration' from an 'Instant' +error: unchecked subtraction of a `Duration` --> tests/ui/unchecked_time_subtraction_unfixable.rs:19:13 | LL | let _ = instant1 - dur2 - dur3; | ^^^^^^^^^^^^^^^^^^^^^^ -error: unchecked subtraction of a 'Duration' from an 'Instant' +error: unchecked subtraction of a `Duration` --> tests/ui/unchecked_time_subtraction_unfixable.rs:19:13 | LL | let _ = instant1 - dur2 - dur3; diff --git a/src/tools/clippy/tests/ui/useless_asref.fixed b/src/tools/clippy/tests/ui/useless_asref.fixed index 3c3ea5a736d43..54a7c0a8c0802 100644 --- a/src/tools/clippy/tests/ui/useless_asref.fixed +++ b/src/tools/clippy/tests/ui/useless_asref.fixed @@ -258,6 +258,41 @@ fn issue_14828() { ().as_ref(); } +fn issue16098(exts: Vec<&str>) { + use std::borrow::Cow; + + let v: Vec> = exts.iter().map(|s| Cow::Borrowed(*s)).collect(); + //~^ useless_asref + + trait Identity { + fn id(self) -> Self + where + Self: Sized, + { + self + } + } + impl Identity for &str {} + + let v: Vec> = exts.iter().map(|s| Cow::Borrowed(s.id())).collect(); + //~^ useless_asref + + let v: Vec> = exts + .iter() + .map(|s| Cow::Borrowed(*std::convert::identity(s))) + //~^ useless_asref + .collect(); + + struct Wrapper<'a>(&'a str); + let exts_field: Vec = exts.iter().map(|s| Wrapper(s)).collect(); + let v: Vec> = exts_field.iter().map(|w| Cow::Borrowed(w.0)).collect(); + //~^ useless_asref + + let exts_index: Vec<&[&str]> = exts.iter().map(|s| std::slice::from_ref(s)).collect(); + let v: Vec> = exts_index.iter().map(|arr| Cow::Borrowed(arr[0])).collect(); + //~^ useless_asref +} + fn main() { not_ok(); ok(); diff --git a/src/tools/clippy/tests/ui/useless_asref.rs b/src/tools/clippy/tests/ui/useless_asref.rs index c173dd677152d..1b9ce1d462335 100644 --- a/src/tools/clippy/tests/ui/useless_asref.rs +++ b/src/tools/clippy/tests/ui/useless_asref.rs @@ -258,6 +258,41 @@ fn issue_14828() { ().as_ref(); } +fn issue16098(exts: Vec<&str>) { + use std::borrow::Cow; + + let v: Vec> = exts.iter().map(|s| Cow::Borrowed(s.as_ref())).collect(); + //~^ useless_asref + + trait Identity { + fn id(self) -> Self + where + Self: Sized, + { + self + } + } + impl Identity for &str {} + + let v: Vec> = exts.iter().map(|s| Cow::Borrowed(s.id().as_ref())).collect(); + //~^ useless_asref + + let v: Vec> = exts + .iter() + .map(|s| Cow::Borrowed(std::convert::identity(s).as_ref())) + //~^ useless_asref + .collect(); + + struct Wrapper<'a>(&'a str); + let exts_field: Vec = exts.iter().map(|s| Wrapper(s)).collect(); + let v: Vec> = exts_field.iter().map(|w| Cow::Borrowed(w.0.as_ref())).collect(); + //~^ useless_asref + + let exts_index: Vec<&[&str]> = exts.iter().map(|s| std::slice::from_ref(s)).collect(); + let v: Vec> = exts_index.iter().map(|arr| Cow::Borrowed(arr[0].as_ref())).collect(); + //~^ useless_asref +} + fn main() { not_ok(); ok(); diff --git a/src/tools/clippy/tests/ui/useless_asref.stderr b/src/tools/clippy/tests/ui/useless_asref.stderr index 8255f5d9d2abe..861472b4419ed 100644 --- a/src/tools/clippy/tests/ui/useless_asref.stderr +++ b/src/tools/clippy/tests/ui/useless_asref.stderr @@ -112,5 +112,35 @@ error: this call to `as_ref.map(...)` does nothing LL | Some(1).as_ref().map(|&x| x.clone()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(1).clone()` -error: aborting due to 18 previous errors +error: this call to `as_ref` does nothing + --> tests/ui/useless_asref.rs:264:66 + | +LL | let v: Vec> = exts.iter().map(|s| Cow::Borrowed(s.as_ref())).collect(); + | ^^^^^^^^^^ help: try: `*s` + +error: this call to `as_ref` does nothing + --> tests/ui/useless_asref.rs:277:66 + | +LL | let v: Vec> = exts.iter().map(|s| Cow::Borrowed(s.id().as_ref())).collect(); + | ^^^^^^^^^^^^^^^ help: try: `s.id()` + +error: this call to `as_ref` does nothing + --> tests/ui/useless_asref.rs:282:32 + | +LL | .map(|s| Cow::Borrowed(std::convert::identity(s).as_ref())) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `*std::convert::identity(s)` + +error: this call to `as_ref` does nothing + --> tests/ui/useless_asref.rs:288:72 + | +LL | let v: Vec> = exts_field.iter().map(|w| Cow::Borrowed(w.0.as_ref())).collect(); + | ^^^^^^^^^^^^ help: try: `w.0` + +error: this call to `as_ref` does nothing + --> tests/ui/useless_asref.rs:292:74 + | +LL | let v: Vec> = exts_index.iter().map(|arr| Cow::Borrowed(arr[0].as_ref())).collect(); + | ^^^^^^^^^^^^^^^ help: try: `arr[0]` + +error: aborting due to 23 previous errors diff --git a/src/tools/clippy/tests/ui/vec.fixed b/src/tools/clippy/tests/ui/useless_vec.fixed similarity index 90% rename from src/tools/clippy/tests/ui/vec.fixed rename to src/tools/clippy/tests/ui/useless_vec.fixed index 55742459c92cf..3cea4862611d8 100644 --- a/src/tools/clippy/tests/ui/vec.fixed +++ b/src/tools/clippy/tests/ui/useless_vec.fixed @@ -1,5 +1,4 @@ #![warn(clippy::useless_vec)] -#![allow(clippy::nonstandard_macro_braces, clippy::uninlined_format_args, unused)] use std::rc::Rc; @@ -39,17 +38,14 @@ fn main() { on_mut_slice(&mut [1, 2]); //~^ useless_vec - on_slice(&[1, 2]); - //~^ useless_vec - on_slice(&[1, 2]); - on_mut_slice(&mut [1, 2]); - //~^ useless_vec #[rustfmt::skip] - on_slice(&[1, 2]); - //~^ useless_vec - on_slice(&[1, 2]); - on_mut_slice(&mut [1, 2]); - //~^ useless_vec + #[allow(clippy::nonstandard_macro_braces)] // not an `expect` as it will only lint _before_ the fix + { + on_slice(&[1, 2]); + //~^ useless_vec + on_mut_slice(&mut [1, 2]); + //~^ useless_vec + }; on_slice(&[1; 2]); //~^ useless_vec @@ -75,22 +71,24 @@ fn main() { on_vec(&vec![1; 201]); // Ok, size of `vec` higher than `too_large_for_stack` on_mut_vec(&mut vec![1; 201]); // Ok, size of `vec` higher than `too_large_for_stack` - // Ok + // Ok, size of `vec` higher than `too_large_for_stack` for a in vec![1; 201] { - println!("{:?}", a); + println!("{a:?}"); } // https://github.com/rust-lang/rust-clippy/issues/2262#issuecomment-783979246 let _x: i32 = [1, 2, 3].iter().sum(); //~^ useless_vec - // Do lint - let mut x = [1, 2, 3]; - //~^ useless_vec - x.fill(123); - dbg!(x[0]); - dbg!(x.len()); - dbg!(x.iter().sum::()); + // Do lint, only used as slice + { + let mut x = [1, 2, 3]; + //~^ useless_vec + x.fill(123); + dbg!(x[0]); + dbg!(x.len()); + dbg!(x.iter().sum::()); + } let _x: &[i32] = &[1, 2, 3]; //~^ useless_vec diff --git a/src/tools/clippy/tests/ui/useless_vec.rs b/src/tools/clippy/tests/ui/useless_vec.rs index 880809f81d7ae..2b5d71ae7fa40 100644 --- a/src/tools/clippy/tests/ui/useless_vec.rs +++ b/src/tools/clippy/tests/ui/useless_vec.rs @@ -1,15 +1,251 @@ -//@no-rustfix: no suggestions - #![warn(clippy::useless_vec)] -// Regression test for . -fn foo() { - // There should be no suggestion in this case. - let _some_variable = vec![ +use std::rc::Rc; + +struct StructWithVec { + _x: Vec, +} + +fn on_slice(_: &[u8]) {} + +fn on_mut_slice(_: &mut [u8]) {} + +#[allow(clippy::ptr_arg)] +fn on_vec(_: &Vec) {} + +fn on_mut_vec(_: &mut Vec) {} + +struct Line { + length: usize, +} + +impl Line { + fn length(&self) -> usize { + self.length + } +} + +fn main() { + on_slice(&vec![]); + //~^ useless_vec + on_slice(&[]); + on_mut_slice(&mut vec![]); + //~^ useless_vec + + on_slice(&vec![1, 2]); + //~^ useless_vec + on_slice(&[1, 2]); + on_mut_slice(&mut vec![1, 2]); + //~^ useless_vec + + #[rustfmt::skip] + #[allow(clippy::nonstandard_macro_braces)] // not an `expect` as it will only lint _before_ the fix + { + on_slice(&vec!(1, 2)); //~^ useless_vec - 1, 2, // i'm here to stay - 3, 4, // but this one going away ;-; - ]; // that is life anyways + on_mut_slice(&mut vec!(1, 2)); + //~^ useless_vec + }; + + on_slice(&vec![1; 2]); + //~^ useless_vec + on_slice(&[1; 2]); + on_mut_slice(&mut vec![1; 2]); + //~^ useless_vec + + on_vec(&vec![]); + on_vec(&vec![1, 2]); + on_vec(&vec![1; 2]); + on_mut_vec(&mut vec![]); + on_mut_vec(&mut vec![1, 2]); + on_mut_vec(&mut vec![1; 2]); + + // Now with non-constant expressions + let line = Line { length: 2 }; + + on_slice(&vec![2; line.length]); + on_slice(&vec![2; line.length()]); + on_mut_slice(&mut vec![2; line.length]); + on_mut_slice(&mut vec![2; line.length()]); + + on_vec(&vec![1; 201]); // Ok, size of `vec` higher than `too_large_for_stack` + on_mut_vec(&mut vec![1; 201]); // Ok, size of `vec` higher than `too_large_for_stack` + + // Ok, size of `vec` higher than `too_large_for_stack` + for a in vec![1; 201] { + println!("{a:?}"); + } + + // https://github.com/rust-lang/rust-clippy/issues/2262#issuecomment-783979246 + let _x: i32 = vec![1, 2, 3].iter().sum(); + //~^ useless_vec + + // Do lint, only used as slice + { + let mut x = vec![1, 2, 3]; + //~^ useless_vec + x.fill(123); + dbg!(x[0]); + dbg!(x.len()); + dbg!(x.iter().sum::()); + } + + let _x: &[i32] = &vec![1, 2, 3]; + //~^ useless_vec + + for _ in vec![1, 2, 3] {} + //~^ useless_vec + + // Don't lint + let x = vec![1, 2, 3]; + let _v: Vec = x; + + let x = vec![1, 2, 3]; + let _s = StructWithVec { _x: x }; + + // Explicit type annotation would make the change to [1, 2, 3] + // a compile error. + let _x: Vec = vec![1, 2, 3]; + + // Calling a Vec method through a mutable reference + let mut x = vec![1, 2, 3]; + let re = &mut x; + re.push(4); + + // Comparing arrays whose length is not equal is a compile error + let x = vec![1, 2, 3]; + let y = vec![1, 2, 3, 4]; + dbg!(x == y); + + // Non-copy types + let _x = vec![String::new(); 10]; + #[allow(clippy::rc_clone_in_vec_init)] + let _x = vec![Rc::new(1); 10]; + + // Too large + let _x = vec![1; 201]; +} + +fn issue11075() { + macro_rules! repro { + ($e:expr) => { + stringify!($e) + }; + } + #[allow(clippy::never_loop)] + for _string in vec![repro!(true), repro!(null)] { + //~^ useless_vec + unimplemented!(); + } + + macro_rules! in_macro { + ($e:expr, $vec:expr, $vec2:expr) => {{ + vec![1; 2].fill(3); + vec![1, 2].fill(3); + for _ in vec![1, 2] {} + for _ in vec![1; 2] {} + for _ in vec![$e, $e] {} + for _ in vec![$e; 2] {} + for _ in $vec {} + for _ in $vec2 {} + }}; + } + + in_macro!(1, vec![1, 2], vec![1; 2]); + //~^ useless_vec + //~| useless_vec + + macro_rules! from_macro { + () => { + vec![1, 2, 3] + }; + } + macro_rules! from_macro_repeat { + () => { + vec![1; 3] + }; + } + + for _ in from_macro!() {} + for _ in from_macro_repeat!() {} +} + +#[clippy::msrv = "1.53"] +fn above() { + for a in vec![1, 2, 3] { + //~^ useless_vec + let _: usize = a; + } + + for a in vec![String::new(), String::new()] { + //~^ useless_vec + let _: String = a; + } +} + +#[clippy::msrv = "1.52"] +fn below() { + for a in vec![1, 2, 3] { + let _: usize = a; + } + + for a in vec![String::new(), String::new()] { + let _: String = a; + } +} + +fn func_needing_vec(_bar: usize, _baz: Vec) {} +fn func_not_needing_vec(_bar: usize, _baz: usize) {} + +fn issue11861() { + macro_rules! this_macro_needs_vec { + ($x:expr) => {{ + func_needing_vec($x.iter().sum(), $x); + for _ in $x {} + }}; + } + macro_rules! this_macro_doesnt_need_vec { + ($x:expr) => {{ func_not_needing_vec($x.iter().sum(), $x.iter().sum()) }}; + } + + // Do not lint the next line + this_macro_needs_vec!(vec![1]); + this_macro_doesnt_need_vec!(vec![1]); + //~^ useless_vec + + macro_rules! m { + ($x:expr) => { + fn f2() { + let _x: Vec = $x; + } + fn f() { + let _x = $x; + $x.starts_with(&[]); + } + }; + } + + // should not lint + m!(vec![1]); } -fn main() {} +fn issue_11958() { + fn f(_s: &[String]) {} + + // should not lint, `String` is not `Copy` + f(&vec!["test".to_owned(); 2]); +} + +fn issue_12101() { + for a in &(vec![1, 2]) {} + //~^ useless_vec +} + +fn issue_14531() { + // The lint used to suggest using an array rather than a reference to a slice. + + fn requires_ref_slice(v: &[()]) {} + let v = &vec![]; + //~^ useless_vec + requires_ref_slice(v); +} diff --git a/src/tools/clippy/tests/ui/useless_vec.stderr b/src/tools/clippy/tests/ui/useless_vec.stderr index e47364fb06d3b..65120d8b338fc 100644 --- a/src/tools/clippy/tests/ui/useless_vec.stderr +++ b/src/tools/clippy/tests/ui/useless_vec.stderr @@ -1,21 +1,125 @@ error: useless use of `vec!` - --> tests/ui/useless_vec.rs:8:26 + --> tests/ui/useless_vec.rs:29:14 | -LL | let _some_variable = vec![ - | __________________________^ -LL | | -LL | | 1, 2, // i'm here to stay -LL | | 3, 4, // but this one going away ;-; -LL | | ]; // that is life anyways - | |_____^ +LL | on_slice(&vec![]); + | ^^^^^^^ help: you can use a slice directly: `&[]` | = note: `-D clippy::useless-vec` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::useless_vec)]` -help: you can use an array directly + +error: useless use of `vec!` + --> tests/ui/useless_vec.rs:32:18 + | +LL | on_mut_slice(&mut vec![]); + | ^^^^^^^^^^^ help: you can use a slice directly: `&mut []` + +error: useless use of `vec!` + --> tests/ui/useless_vec.rs:35:14 + | +LL | on_slice(&vec![1, 2]); + | ^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]` + +error: useless use of `vec!` + --> tests/ui/useless_vec.rs:38:18 + | +LL | on_mut_slice(&mut vec![1, 2]); + | ^^^^^^^^^^^^^^^ help: you can use a slice directly: `&mut [1, 2]` + +error: useless use of `vec!` + --> tests/ui/useless_vec.rs:44:18 + | +LL | on_slice(&vec!(1, 2)); + | ^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]` + +error: useless use of `vec!` + --> tests/ui/useless_vec.rs:46:22 | -LL ~ let _some_variable = [1, 2, // i'm here to stay -LL ~ 3, 4]; // that is life anyways +LL | on_mut_slice(&mut vec!(1, 2)); + | ^^^^^^^^^^^^^^^ help: you can use a slice directly: `&mut [1, 2]` + +error: useless use of `vec!` + --> tests/ui/useless_vec.rs:50:14 + | +LL | on_slice(&vec![1; 2]); + | ^^^^^^^^^^^ help: you can use a slice directly: `&[1; 2]` + +error: useless use of `vec!` + --> tests/ui/useless_vec.rs:53:18 + | +LL | on_mut_slice(&mut vec![1; 2]); + | ^^^^^^^^^^^^^^^ help: you can use a slice directly: `&mut [1; 2]` + +error: useless use of `vec!` + --> tests/ui/useless_vec.rs:80:19 + | +LL | let _x: i32 = vec![1, 2, 3].iter().sum(); + | ^^^^^^^^^^^^^ help: you can use an array directly: `[1, 2, 3]` + +error: useless use of `vec!` + --> tests/ui/useless_vec.rs:85:21 + | +LL | let mut x = vec![1, 2, 3]; + | ^^^^^^^^^^^^^ help: you can use an array directly: `[1, 2, 3]` + +error: useless use of `vec!` + --> tests/ui/useless_vec.rs:93:22 + | +LL | let _x: &[i32] = &vec![1, 2, 3]; + | ^^^^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2, 3]` + +error: useless use of `vec!` + --> tests/ui/useless_vec.rs:96:14 + | +LL | for _ in vec![1, 2, 3] {} + | ^^^^^^^^^^^^^ help: you can use an array directly: `[1, 2, 3]` + +error: useless use of `vec!` + --> tests/ui/useless_vec.rs:136:20 + | +LL | for _string in vec![repro!(true), repro!(null)] { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can use an array directly: `[repro!(true), repro!(null)]` + +error: useless use of `vec!` + --> tests/ui/useless_vec.rs:154:18 + | +LL | in_macro!(1, vec![1, 2], vec![1; 2]); + | ^^^^^^^^^^ help: you can use an array directly: `[1, 2]` + +error: useless use of `vec!` + --> tests/ui/useless_vec.rs:154:30 + | +LL | in_macro!(1, vec![1, 2], vec![1; 2]); + | ^^^^^^^^^^ help: you can use an array directly: `[1; 2]` + +error: useless use of `vec!` + --> tests/ui/useless_vec.rs:175:14 + | +LL | for a in vec![1, 2, 3] { + | ^^^^^^^^^^^^^ help: you can use an array directly: `[1, 2, 3]` + +error: useless use of `vec!` + --> tests/ui/useless_vec.rs:180:14 + | +LL | for a in vec![String::new(), String::new()] { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can use an array directly: `[String::new(), String::new()]` + +error: useless use of `vec!` + --> tests/ui/useless_vec.rs:213:33 + | +LL | this_macro_doesnt_need_vec!(vec![1]); + | ^^^^^^^ help: you can use an array directly: `[1]` + +error: useless use of `vec!` + --> tests/ui/useless_vec.rs:240:14 + | +LL | for a in &(vec![1, 2]) {} + | ^^^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]` + +error: useless use of `vec!` + --> tests/ui/useless_vec.rs:248:13 | +LL | let v = &vec![]; + | ^^^^^^^ help: you can use a slice directly: `&[]` -error: aborting due to 1 previous error +error: aborting due to 20 previous errors diff --git a/src/tools/clippy/tests/ui/useless_vec_unfixable.rs b/src/tools/clippy/tests/ui/useless_vec_unfixable.rs new file mode 100644 index 0000000000000..7f45f4df5ee6e --- /dev/null +++ b/src/tools/clippy/tests/ui/useless_vec_unfixable.rs @@ -0,0 +1,14 @@ +//@no-rustfix: no suggestions +#![warn(clippy::useless_vec)] + +// Regression test for . +fn foo() { + // There should be no suggestion in this case. + let _some_variable = vec![ + //~^ useless_vec + 1, 2, // i'm here to stay + 3, 4, // but this one going away ;-; + ]; // that is life anyways +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/useless_vec_unfixable.stderr b/src/tools/clippy/tests/ui/useless_vec_unfixable.stderr new file mode 100644 index 0000000000000..980194ac71910 --- /dev/null +++ b/src/tools/clippy/tests/ui/useless_vec_unfixable.stderr @@ -0,0 +1,21 @@ +error: useless use of `vec!` + --> tests/ui/useless_vec_unfixable.rs:7:26 + | +LL | let _some_variable = vec![ + | __________________________^ +LL | | +LL | | 1, 2, // i'm here to stay +LL | | 3, 4, // but this one going away ;-; +LL | | ]; // that is life anyways + | |_____^ + | + = note: `-D clippy::useless-vec` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::useless_vec)]` +help: you can use an array directly + | +LL ~ let _some_variable = [1, 2, // i'm here to stay +LL ~ 3, 4]; // that is life anyways + | + +error: aborting due to 1 previous error + diff --git a/src/tools/clippy/tests/ui/vec.rs b/src/tools/clippy/tests/ui/vec.rs deleted file mode 100644 index fbf7131323c3b..0000000000000 --- a/src/tools/clippy/tests/ui/vec.rs +++ /dev/null @@ -1,253 +0,0 @@ -#![warn(clippy::useless_vec)] -#![allow(clippy::nonstandard_macro_braces, clippy::uninlined_format_args, unused)] - -use std::rc::Rc; - -struct StructWithVec { - _x: Vec, -} - -fn on_slice(_: &[u8]) {} - -fn on_mut_slice(_: &mut [u8]) {} - -#[allow(clippy::ptr_arg)] -fn on_vec(_: &Vec) {} - -fn on_mut_vec(_: &mut Vec) {} - -struct Line { - length: usize, -} - -impl Line { - fn length(&self) -> usize { - self.length - } -} - -fn main() { - on_slice(&vec![]); - //~^ useless_vec - on_slice(&[]); - on_mut_slice(&mut vec![]); - //~^ useless_vec - - on_slice(&vec![1, 2]); - //~^ useless_vec - on_slice(&[1, 2]); - on_mut_slice(&mut vec![1, 2]); - //~^ useless_vec - - on_slice(&vec![1, 2]); - //~^ useless_vec - on_slice(&[1, 2]); - on_mut_slice(&mut vec![1, 2]); - //~^ useless_vec - #[rustfmt::skip] - on_slice(&vec!(1, 2)); - //~^ useless_vec - on_slice(&[1, 2]); - on_mut_slice(&mut vec![1, 2]); - //~^ useless_vec - - on_slice(&vec![1; 2]); - //~^ useless_vec - on_slice(&[1; 2]); - on_mut_slice(&mut vec![1; 2]); - //~^ useless_vec - - on_vec(&vec![]); - on_vec(&vec![1, 2]); - on_vec(&vec![1; 2]); - on_mut_vec(&mut vec![]); - on_mut_vec(&mut vec![1, 2]); - on_mut_vec(&mut vec![1; 2]); - - // Now with non-constant expressions - let line = Line { length: 2 }; - - on_slice(&vec![2; line.length]); - on_slice(&vec![2; line.length()]); - on_mut_slice(&mut vec![2; line.length]); - on_mut_slice(&mut vec![2; line.length()]); - - on_vec(&vec![1; 201]); // Ok, size of `vec` higher than `too_large_for_stack` - on_mut_vec(&mut vec![1; 201]); // Ok, size of `vec` higher than `too_large_for_stack` - - // Ok - for a in vec![1; 201] { - println!("{:?}", a); - } - - // https://github.com/rust-lang/rust-clippy/issues/2262#issuecomment-783979246 - let _x: i32 = vec![1, 2, 3].iter().sum(); - //~^ useless_vec - - // Do lint - let mut x = vec![1, 2, 3]; - //~^ useless_vec - x.fill(123); - dbg!(x[0]); - dbg!(x.len()); - dbg!(x.iter().sum::()); - - let _x: &[i32] = &vec![1, 2, 3]; - //~^ useless_vec - - for _ in vec![1, 2, 3] {} - //~^ useless_vec - - // Don't lint - let x = vec![1, 2, 3]; - let _v: Vec = x; - - let x = vec![1, 2, 3]; - let _s = StructWithVec { _x: x }; - - // Explicit type annotation would make the change to [1, 2, 3] - // a compile error. - let _x: Vec = vec![1, 2, 3]; - - // Calling a Vec method through a mutable reference - let mut x = vec![1, 2, 3]; - let re = &mut x; - re.push(4); - - // Comparing arrays whose length is not equal is a compile error - let x = vec![1, 2, 3]; - let y = vec![1, 2, 3, 4]; - dbg!(x == y); - - // Non-copy types - let _x = vec![String::new(); 10]; - #[allow(clippy::rc_clone_in_vec_init)] - let _x = vec![Rc::new(1); 10]; - - // Too large - let _x = vec![1; 201]; -} - -fn issue11075() { - macro_rules! repro { - ($e:expr) => { - stringify!($e) - }; - } - #[allow(clippy::never_loop)] - for _string in vec![repro!(true), repro!(null)] { - //~^ useless_vec - unimplemented!(); - } - - macro_rules! in_macro { - ($e:expr, $vec:expr, $vec2:expr) => {{ - vec![1; 2].fill(3); - vec![1, 2].fill(3); - for _ in vec![1, 2] {} - for _ in vec![1; 2] {} - for _ in vec![$e, $e] {} - for _ in vec![$e; 2] {} - for _ in $vec {} - for _ in $vec2 {} - }}; - } - - in_macro!(1, vec![1, 2], vec![1; 2]); - //~^ useless_vec - //~| useless_vec - - macro_rules! from_macro { - () => { - vec![1, 2, 3] - }; - } - macro_rules! from_macro_repeat { - () => { - vec![1; 3] - }; - } - - for _ in from_macro!() {} - for _ in from_macro_repeat!() {} -} - -#[clippy::msrv = "1.53"] -fn above() { - for a in vec![1, 2, 3] { - //~^ useless_vec - let _: usize = a; - } - - for a in vec![String::new(), String::new()] { - //~^ useless_vec - let _: String = a; - } -} - -#[clippy::msrv = "1.52"] -fn below() { - for a in vec![1, 2, 3] { - let _: usize = a; - } - - for a in vec![String::new(), String::new()] { - let _: String = a; - } -} - -fn func_needing_vec(_bar: usize, _baz: Vec) {} -fn func_not_needing_vec(_bar: usize, _baz: usize) {} - -fn issue11861() { - macro_rules! this_macro_needs_vec { - ($x:expr) => {{ - func_needing_vec($x.iter().sum(), $x); - for _ in $x {} - }}; - } - macro_rules! this_macro_doesnt_need_vec { - ($x:expr) => {{ func_not_needing_vec($x.iter().sum(), $x.iter().sum()) }}; - } - - // Do not lint the next line - this_macro_needs_vec!(vec![1]); - this_macro_doesnt_need_vec!(vec![1]); - //~^ useless_vec - - macro_rules! m { - ($x:expr) => { - fn f2() { - let _x: Vec = $x; - } - fn f() { - let _x = $x; - $x.starts_with(&[]); - } - }; - } - - // should not lint - m!(vec![1]); -} - -fn issue_11958() { - fn f(_s: &[String]) {} - - // should not lint, `String` is not `Copy` - f(&vec!["test".to_owned(); 2]); -} - -fn issue_12101() { - for a in &(vec![1, 2]) {} - //~^ useless_vec -} - -fn issue_14531() { - // The lint used to suggest using an array rather than a reference to a slice. - - fn requires_ref_slice(v: &[()]) {} - let v = &vec![]; - //~^ useless_vec - requires_ref_slice(v); -} diff --git a/src/tools/clippy/tests/ui/vec.stderr b/src/tools/clippy/tests/ui/vec.stderr deleted file mode 100644 index d16c8a8944a24..0000000000000 --- a/src/tools/clippy/tests/ui/vec.stderr +++ /dev/null @@ -1,137 +0,0 @@ -error: useless use of `vec!` - --> tests/ui/vec.rs:30:14 - | -LL | on_slice(&vec![]); - | ^^^^^^^ help: you can use a slice directly: `&[]` - | - = note: `-D clippy::useless-vec` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::useless_vec)]` - -error: useless use of `vec!` - --> tests/ui/vec.rs:33:18 - | -LL | on_mut_slice(&mut vec![]); - | ^^^^^^^^^^^ help: you can use a slice directly: `&mut []` - -error: useless use of `vec!` - --> tests/ui/vec.rs:36:14 - | -LL | on_slice(&vec![1, 2]); - | ^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]` - -error: useless use of `vec!` - --> tests/ui/vec.rs:39:18 - | -LL | on_mut_slice(&mut vec![1, 2]); - | ^^^^^^^^^^^^^^^ help: you can use a slice directly: `&mut [1, 2]` - -error: useless use of `vec!` - --> tests/ui/vec.rs:42:14 - | -LL | on_slice(&vec![1, 2]); - | ^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]` - -error: useless use of `vec!` - --> tests/ui/vec.rs:45:18 - | -LL | on_mut_slice(&mut vec![1, 2]); - | ^^^^^^^^^^^^^^^ help: you can use a slice directly: `&mut [1, 2]` - -error: useless use of `vec!` - --> tests/ui/vec.rs:48:14 - | -LL | on_slice(&vec!(1, 2)); - | ^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]` - -error: useless use of `vec!` - --> tests/ui/vec.rs:51:18 - | -LL | on_mut_slice(&mut vec![1, 2]); - | ^^^^^^^^^^^^^^^ help: you can use a slice directly: `&mut [1, 2]` - -error: useless use of `vec!` - --> tests/ui/vec.rs:54:14 - | -LL | on_slice(&vec![1; 2]); - | ^^^^^^^^^^^ help: you can use a slice directly: `&[1; 2]` - -error: useless use of `vec!` - --> tests/ui/vec.rs:57:18 - | -LL | on_mut_slice(&mut vec![1; 2]); - | ^^^^^^^^^^^^^^^ help: you can use a slice directly: `&mut [1; 2]` - -error: useless use of `vec!` - --> tests/ui/vec.rs:84:19 - | -LL | let _x: i32 = vec![1, 2, 3].iter().sum(); - | ^^^^^^^^^^^^^ help: you can use an array directly: `[1, 2, 3]` - -error: useless use of `vec!` - --> tests/ui/vec.rs:88:17 - | -LL | let mut x = vec![1, 2, 3]; - | ^^^^^^^^^^^^^ help: you can use an array directly: `[1, 2, 3]` - -error: useless use of `vec!` - --> tests/ui/vec.rs:95:22 - | -LL | let _x: &[i32] = &vec![1, 2, 3]; - | ^^^^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2, 3]` - -error: useless use of `vec!` - --> tests/ui/vec.rs:98:14 - | -LL | for _ in vec![1, 2, 3] {} - | ^^^^^^^^^^^^^ help: you can use an array directly: `[1, 2, 3]` - -error: useless use of `vec!` - --> tests/ui/vec.rs:138:20 - | -LL | for _string in vec![repro!(true), repro!(null)] { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can use an array directly: `[repro!(true), repro!(null)]` - -error: useless use of `vec!` - --> tests/ui/vec.rs:156:18 - | -LL | in_macro!(1, vec![1, 2], vec![1; 2]); - | ^^^^^^^^^^ help: you can use an array directly: `[1, 2]` - -error: useless use of `vec!` - --> tests/ui/vec.rs:156:30 - | -LL | in_macro!(1, vec![1, 2], vec![1; 2]); - | ^^^^^^^^^^ help: you can use an array directly: `[1; 2]` - -error: useless use of `vec!` - --> tests/ui/vec.rs:177:14 - | -LL | for a in vec![1, 2, 3] { - | ^^^^^^^^^^^^^ help: you can use an array directly: `[1, 2, 3]` - -error: useless use of `vec!` - --> tests/ui/vec.rs:182:14 - | -LL | for a in vec![String::new(), String::new()] { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can use an array directly: `[String::new(), String::new()]` - -error: useless use of `vec!` - --> tests/ui/vec.rs:215:33 - | -LL | this_macro_doesnt_need_vec!(vec![1]); - | ^^^^^^^ help: you can use an array directly: `[1]` - -error: useless use of `vec!` - --> tests/ui/vec.rs:242:14 - | -LL | for a in &(vec![1, 2]) {} - | ^^^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]` - -error: useless use of `vec!` - --> tests/ui/vec.rs:250:13 - | -LL | let v = &vec![]; - | ^^^^^^^ help: you can use a slice directly: `&[]` - -error: aborting due to 22 previous errors - diff --git a/src/tools/clippy/triagebot.toml b/src/tools/clippy/triagebot.toml index db951b95ef50a..3bf62b6b3bbaf 100644 --- a/src/tools/clippy/triagebot.toml +++ b/src/tools/clippy/triagebot.toml @@ -63,7 +63,8 @@ contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIB users_on_vacation = [ "matthiaskrgr", "Manishearth", - "blyxyas", + "Alexendoo", + "y21", ] [assign.owners] diff --git a/src/tools/clippy/util/gh-pages/index_template.html b/src/tools/clippy/util/gh-pages/index_template.html index e443baff08086..91a5c12631958 100644 --- a/src/tools/clippy/util/gh-pages/index_template.html +++ b/src/tools/clippy/util/gh-pages/index_template.html @@ -57,119 +57,115 @@

Clippy Lints Total number: {{+ count {# #}