diff --git a/clippy_lints/src/assertions_on_result_states.rs b/clippy_lints/src/assertions_on_result_states.rs index 08253b0c4995..bd28abde4b47 100644 --- a/clippy_lints/src/assertions_on_result_states.rs +++ b/clippy_lints/src/assertions_on_result_states.rs @@ -1,10 +1,9 @@ -use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::diagnostics::{applicability_for_ctxt, span_lint_and_then}; use clippy_utils::macros::{PanicExpn, find_assert_args, root_macro_call_first_node}; -use clippy_utils::source::snippet_with_context; +use clippy_utils::source::SpanExt; use clippy_utils::ty::{has_debug_impl, is_copy, is_type_diagnostic_item}; use clippy_utils::usage::local_used_after_expr; use clippy_utils::{path_res, sym}; -use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::{Expr, ExprKind, Node}; use rustc_lint::{LateContext, LateLintPass}; @@ -76,10 +75,11 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates { }, _ => return, }; + let ctxt = condition.span.ctxt(); + let Some(recv) = recv.span.get_source_text_at_ctxt(cx, ctxt) else { + return; + }; span_lint_and_then(cx, ASSERTIONS_ON_RESULT_STATES, macro_call.span, message, |diag| { - let mut app = Applicability::MachineApplicable; - let recv = snippet_with_context(cx, recv.span, condition.span.ctxt(), "..", &mut app).0; - // `assert!` doesn't return anything, but `Result::unwrap(_err)` does, so we might need to add a // semicolon to the suggestion to avoid leaking the type let sugg = match cx.tcx.parent_hir_node(e.hir_id) { @@ -90,7 +90,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates { // this is the last-resort option, because it's rather verbose _ => format!("{{ {recv}.{replacement}(); }}"), }; - diag.span_suggestion(macro_call.span, "replace with", sugg, app); + diag.span_suggestion(macro_call.span, "replace with", sugg, applicability_for_ctxt(ctxt)); }); } } diff --git a/clippy_lints/src/attrs/non_minimal_cfg.rs b/clippy_lints/src/attrs/non_minimal_cfg.rs index 7eff5eccfa13..a76bdcfdfb3e 100644 --- a/clippy_lints/src/attrs/non_minimal_cfg.rs +++ b/clippy_lints/src/attrs/non_minimal_cfg.rs @@ -1,6 +1,6 @@ use super::{Attribute, NON_MINIMAL_CFG}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_ast::{MetaItemInner, MetaItemKind}; use rustc_errors::Applicability; use rustc_lint::EarlyContext; diff --git a/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs b/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs index 6ee3290fa761..a647f976908a 100644 --- a/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs +++ b/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs @@ -1,6 +1,6 @@ use super::{Attribute, UNNECESSARY_CLIPPY_CFG}; use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use itertools::Itertools; use rustc_ast::AttrStyle; use rustc_errors::Applicability; diff --git a/clippy_lints/src/attrs/useless_attribute.rs b/clippy_lints/src/attrs/useless_attribute.rs index 1cebc18edc90..fc780472e03c 100644 --- a/clippy_lints/src/attrs/useless_attribute.rs +++ b/clippy_lints/src/attrs/useless_attribute.rs @@ -1,7 +1,7 @@ use super::USELESS_ATTRIBUTE; use super::utils::{is_lint_level, is_word, namespace_and_lint}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{SpanRangeExt, first_line_of_span}; +use clippy_utils::source::{SpanExt, first_line_of_span}; use clippy_utils::sym; use rustc_ast::{Attribute, Item, ItemKind}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/bool_to_int_with_if.rs b/clippy_lints/src/bool_to_int_with_if.rs index 129e77478406..866b0055d0ab 100644 --- a/clippy_lints/src/bool_to_int_with_if.rs +++ b/clippy_lints/src/bool_to_int_with_if.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::HasSession; use clippy_utils::sugg::Sugg; use clippy_utils::{higher, is_else_clause, is_in_const_context, span_contains_comment}; use rustc_ast::LitKind; @@ -59,7 +58,7 @@ impl<'tcx> LateLintPass<'tcx> for BoolToIntWithIf { && !is_in_const_context(cx) { let ty = cx.typeck_results().expr_ty(then); - let mut applicability = if span_contains_comment(cx.sess().source_map(), expr.span) { + let mut applicability = if span_contains_comment(cx, expr.span) { Applicability::MaybeIncorrect } else { Applicability::MachineApplicable diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 64aeb27df693..edb9a83336cf 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -2,7 +2,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::higher::has_let_expr; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use clippy_utils::{eq_expr_value, sym}; diff --git a/clippy_lints/src/borrow_deref_ref.rs b/clippy_lints/src/borrow_deref_ref.rs index 70c9c45a60c8..350324099d0d 100644 --- a/clippy_lints/src/borrow_deref_ref.rs +++ b/clippy_lints/src/borrow_deref_ref.rs @@ -1,6 +1,6 @@ use crate::reference::DEREF_ADDROF; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::ty::implements_trait; use clippy_utils::{get_parent_expr, is_expr_temporary_value, is_from_proc_macro, is_lint_allowed, is_mutable}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/casts/as_ptr_cast_mut.rs b/clippy_lints/src/casts/as_ptr_cast_mut.rs index 15ecba20a0bc..74388808a130 100644 --- a/clippy_lints/src/casts/as_ptr_cast_mut.rs +++ b/clippy_lints/src/casts/as_ptr_cast_mut.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; diff --git a/clippy_lints/src/casts/borrow_as_ptr.rs b/clippy_lints/src/casts/borrow_as_ptr.rs index eb75d5576f5c..5e22e072ff04 100644 --- a/clippy_lints/src/casts/borrow_as_ptr.rs +++ b/clippy_lints/src/casts/borrow_as_ptr.rs @@ -1,6 +1,6 @@ -use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::diagnostics::{applicability_for_ctxt, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::msrvs::Msrv; -use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; +use clippy_utils::source::SpanExt; use clippy_utils::sugg::has_enclosing_paren; use clippy_utils::{get_parent_expr, is_expr_temporary_value, is_from_proc_macro, is_lint_allowed, msrvs, std_or_core}; use rustc_errors::Applicability; @@ -21,18 +21,21 @@ pub(super) fn check<'tcx>( if let TyKind::Ptr(target) = cast_to.kind && !matches!(target.ty.kind, TyKind::TraitObject(..)) && let ExprKind::AddrOf(BorrowKind::Ref, mutability, e) = cast_expr.kind + && let ctxt = expr.span.ctxt() + && cast_expr.span.ctxt() == ctxt && !is_lint_allowed(cx, BORROW_AS_PTR, expr.hir_id) // Fix #9884 && !is_expr_temporary_value(cx, e) && !is_from_proc_macro(cx, expr) + && let Some(snip) = e.span.get_source_text_at_ctxt(cx, ctxt) { - let mut app = Applicability::MachineApplicable; - let snip = snippet_with_context(cx, e.span, cast_expr.span.ctxt(), "..", &mut app).0; - let (suggestion, span) = if msrv.meets(cx, msrvs::RAW_REF_OP) { // Make sure that the span to be replaced doesn't include parentheses, that could break the // suggestion. - let span = if has_enclosing_paren(snippet_with_applicability(cx, expr.span, "", &mut app)) { + let Some(src) = expr.span.get_source_text(cx) else { + return false; + }; + let span = if has_enclosing_paren(&*src) { expr.span .with_lo(expr.span.lo() + BytePos(1)) .with_hi(expr.span.hi() - BytePos(1)) @@ -51,7 +54,15 @@ pub(super) fn check<'tcx>( (format!("{std_or_core}::ptr::{macro_name}!({snip})"), expr.span) }; - span_lint_and_sugg(cx, BORROW_AS_PTR, span, "borrow as raw pointer", "try", suggestion, app); + span_lint_and_sugg( + cx, + BORROW_AS_PTR, + span, + "borrow as raw pointer", + "try", + suggestion, + applicability_for_ctxt(ctxt), + ); return true; } false diff --git a/clippy_lints/src/casts/cast_lossless.rs b/clippy_lints/src/casts/cast_lossless.rs index c924fba6b5c8..bcfb59028201 100644 --- a/clippy_lints/src/casts/cast_lossless.rs +++ b/clippy_lints/src/casts/cast_lossless.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_in_const_context; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_isize_or_usize; use rustc_errors::Applicability; diff --git a/clippy_lints/src/casts/manual_dangling_ptr.rs b/clippy_lints/src/casts/manual_dangling_ptr.rs index 92910cf8adf5..c066ba9bd6ed 100644 --- a/clippy_lints/src/casts/manual_dangling_ptr.rs +++ b/clippy_lints/src/casts/manual_dangling_ptr.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::{expr_or_init, is_path_diagnostic_item, std_or_core, sym}; use rustc_ast::LitKind; use rustc_errors::Applicability; diff --git a/clippy_lints/src/casts/unnecessary_cast.rs b/clippy_lints/src/casts/unnecessary_cast.rs index c88a0539d70e..d410b3820ed1 100644 --- a/clippy_lints/src/casts/unnecessary_cast.rs +++ b/clippy_lints/src/casts/unnecessary_cast.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::numeric_literal::NumericLiteral; -use clippy_utils::source::{SpanRangeExt, snippet_opt}; +use clippy_utils::source::{SpanExt, snippet_opt}; use clippy_utils::visitors::{Visitable, for_each_expr_without_closures}; use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, is_ty_alias, path_to_local}; use rustc_ast::{LitFloatType, LitIntType, LitKind}; @@ -167,7 +167,7 @@ pub(super) fn check<'tcx>( sym::assert_ne_macro, sym::debug_assert_ne_macro, ]; - matches!(expr.span.ctxt().outer_expn_data().macro_def_id, Some(def_id) if + matches!(expr.span.ctxt().outer_expn_data().macro_def_id, Some(def_id) if cx.tcx.get_diagnostic_name(def_id).is_some_and(|sym| ALLOWED_MACROS.contains(&sym))) } diff --git a/clippy_lints/src/casts/zero_ptr.rs b/clippy_lints/src/casts/zero_ptr.rs index f4738e7b0d51..d33d08230d1a 100644 --- a/clippy_lints/src/casts/zero_ptr.rs +++ b/clippy_lints/src/casts/zero_ptr.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::{is_in_const_context, is_integer_literal, std_or_core}; use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability, Ty, TyKind}; diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index 7646aa48b772..5d3635681b2e 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -1,6 +1,6 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::source::{IntoSpan, SpanRangeExt}; +use clippy_utils::source::SpanExt; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{LimitStack, get_async_fn_body, is_async_fn, sym}; @@ -110,14 +110,15 @@ impl CognitiveComplexity { FnKind::ItemFn(ident, _, _) | FnKind::Method(ident, _) => ident.span, FnKind::Closure => { let header_span = body_span.with_hi(decl.output.span().lo()); - if let Some(range) = header_span.map_range(cx, |_, src, range| { - let mut idxs = src.get(range.clone())?.match_indices('|'); - Some(range.start + idxs.next()?.0..range.start + idxs.next()?.0 + 1) - }) { - range.with_ctxt(header_span.ctxt()) - } else { + let Some(s) = header_span.map_range(cx, |range| { + range.edit_range(|src, range| { + let mut idxs = src.get(range.clone())?.match_indices('|'); + Some(range.start + idxs.next()?.0..range.start + idxs.next()?.0 + 1) + }) + }) else { return; - } + }; + s }, }; diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs index ad610fbd8d2c..a7dcac66c613 100644 --- a/clippy_lints/src/collapsible_if.rs +++ b/clippy_lints/src/collapsible_if.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::{IntoSpan as _, SpanRangeExt, snippet, snippet_block_with_applicability}; +use clippy_utils::source::{SourceFileRange, SpanExt, snippet, snippet_block_with_applicability}; use clippy_utils::{span_contains_non_whitespace, tokenize_with_text}; use rustc_ast::BinOpKind; use rustc_errors::Applicability; @@ -113,15 +113,15 @@ impl CollapsibleIf { span_extract_keyword(cx.tcx.sess.source_map(), up_to_else, "else") && let Some(else_if_keyword_span) = span_extract_keyword(cx.tcx.sess.source_map(), else_before_if, "if") + && let Some(else_keyword_span) = + else_keyword_span.map_range(cx, SourceFileRange::add_leading_whitespace) + && let Some(else_open_bracket) = else_block + .span + .map_range(cx, |range| range.set_to_prefix('{')?.add_leading_whitespace()) + && let Some(else_closing_bracket) = else_block + .span + .map_range(cx, |range| range.set_to_suffix('}')?.add_leading_whitespace()) { - let else_keyword_span = else_keyword_span.with_leading_whitespace(cx).into_span(); - let else_open_bracket = else_block.span.split_at(1).0.with_leading_whitespace(cx).into_span(); - let else_closing_bracket = { - let end = else_block.span.shrink_to_hi(); - end.with_lo(end.lo() - BytePos(1)) - .with_leading_whitespace(cx) - .into_span() - }; let sugg = vec![ // Remove the outer else block `else` (else_keyword_span, String::new()), @@ -171,6 +171,12 @@ impl CollapsibleIf { && self.eligible_condition(cx, check_inner) && expr.span.eq_ctxt(inner.span) && !block_starts_with_significant_tokens(cx, then, inner, self.lint_commented_code) + && let Some(then_open_bracket) = then + .span + .map_range(cx, |range| range.set_to_prefix('{')?.add_leading_whitespace()) + && let Some(then_closing_bracket) = then + .span + .map_range(cx, |range| range.set_to_suffix('}')?.add_leading_whitespace()) { span_lint_and_then( cx, @@ -178,13 +184,6 @@ impl CollapsibleIf { expr.span, "this `if` statement can be collapsed", |diag| { - let then_open_bracket = then.span.split_at(1).0.with_leading_whitespace(cx).into_span(); - let then_closing_bracket = { - let end = then.span.shrink_to_hi(); - end.with_lo(end.lo() - BytePos(1)) - .with_leading_whitespace(cx) - .into_span() - }; let (paren_start, inner_if_span, paren_end) = peel_parens(cx.tcx.sess.source_map(), inner.span); let inner_if = inner_if_span.split_at(2).0; let mut sugg = vec![ diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index 4fdb497950f8..95e432ae0565 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint, span_lint_and_note, span_lint_and_then}; use clippy_utils::higher::has_let_expr; -use clippy_utils::source::{IntoSpan, SpanRangeExt, first_line_of_span, indent_of, reindent_multiline, snippet}; +use clippy_utils::source::{SpanExt, first_line_of_span, indent_of, reindent_multiline, snippet}; use clippy_utils::ty::{InteriorMut, needs_ordered_drop}; use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{ @@ -239,21 +239,23 @@ fn lint_branches_sharing_code<'tcx>( let suggestion = reindent_multiline(&suggestion, true, cond_indent); (replace_span, suggestion) }); - let end_suggestion = res.end_span(last_block, sm).map(|span| { + let end_suggestion = res.end_span(last_block, sm).and_then(|span| { let moved_snipped = reindent_multiline(&snippet(cx, span, "_"), true, None); let indent = indent_of(cx, expr.span.shrink_to_hi()); let suggestion = "}\n".to_string() + &moved_snipped; let suggestion = reindent_multiline(&suggestion, true, indent); - let span = span.with_hi(last_block.span.hi()); // Improve formatting if the inner block has indentation (i.e. normal Rust formatting) - let span = span - .map_range(cx, |_, src, range| { - (range.start > 4 && src.get(range.start - 4..range.start)? == " ") - .then_some(range.start - 4..range.end) + let span = span.map_range(cx, |range| { + range.set_end_if_after(last_block.span.hi())?.edit_range(|src, range| { + if src.get(..range.start)?.ends_with(" ") { + Some(range.start - 4..range.end) + } else { + Some(range) + } }) - .map_or(span, |range| range.with_ctxt(span.ctxt())); - (span, suggestion.clone()) + })?; + Some((span, suggestion)) }); let (span, msg, end_span) = match (&start_suggestion, &end_suggestion) { diff --git a/clippy_lints/src/default_constructed_unit_structs.rs b/clippy_lints/src/default_constructed_unit_structs.rs index f8a9037fc804..195c8c2d5989 100644 --- a/clippy_lints/src/default_constructed_unit_structs.rs +++ b/clippy_lints/src/default_constructed_unit_structs.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_ty_alias; -use clippy_utils::source::SpanRangeExt as _; +use clippy_utils::source::SpanExt as _; use hir::ExprKind; use hir::def::Res; use rustc_errors::Applicability; @@ -75,7 +75,7 @@ impl LateLintPass<'_> for DefaultConstructedUnitStructs { && !base.is_suggestable_infer_ty() { let mut removals = vec![(expr.span.with_lo(qpath.qself_span().hi()), String::new())]; - if expr.span.with_source_text(cx, |s| s.starts_with('<')) == Some(true) { + if expr.span.check_source_text(cx, |s| s.starts_with('<')) { // Remove `<`, '>` has already been removed by the existing removal expression. removals.push((expr.span.with_hi(qpath.qself_span().lo()), String::new())); } diff --git a/clippy_lints/src/default_instead_of_iter_empty.rs b/clippy_lints/src/default_instead_of_iter_empty.rs index 056e39c02af9..dc1125776c47 100644 --- a/clippy_lints/src/default_instead_of_iter_empty.rs +++ b/clippy_lints/src/default_instead_of_iter_empty.rs @@ -1,7 +1,6 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_context; +use clippy_utils::diagnostics::{applicability_for_ctxt, span_lint_and_sugg}; +use clippy_utils::source::SpanExt; use clippy_utils::{last_path_segment, std_or_core}; -use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, GenericArg, QPath, TyKind, def}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -41,10 +40,11 @@ impl<'tcx> LateLintPass<'tcx> for DefaultIterEmpty { && let ctxt = expr.span.ctxt() && ty.span.ctxt() == ctxt { - let mut applicability = Applicability::MachineApplicable; let Some(path) = std_or_core(cx) else { return }; let path = format!("{path}::iter::empty"); - let sugg = make_sugg(cx, ty_path, ctxt, &mut applicability, &path); + let Some(sugg) = make_sugg(cx, ty_path, ctxt, &path) else { + return; + }; span_lint_and_sugg( cx, DEFAULT_INSTEAD_OF_ITER_EMPTY, @@ -52,30 +52,24 @@ impl<'tcx> LateLintPass<'tcx> for DefaultIterEmpty { format!("`{path}()` is the more idiomatic way"), "try", sugg, - applicability, + applicability_for_ctxt(ctxt), ); } } } -fn make_sugg( - cx: &LateContext<'_>, - ty_path: &QPath<'_>, - ctxt: SyntaxContext, - applicability: &mut Applicability, - path: &str, -) -> String { +fn make_sugg(cx: &LateContext<'_>, ty_path: &QPath<'_>, ctxt: SyntaxContext, path: &str) -> Option { if let Some(last) = last_path_segment(ty_path).args && let Some(iter_ty) = last.args.iter().find_map(|arg| match arg { GenericArg::Type(ty) => Some(ty), _ => None, }) { - format!( + Some(format!( "{path}::<{}>()", - snippet_with_context(cx, iter_ty.span, ctxt, "..", applicability).0 - ) + iter_ty.span.get_source_text_at_ctxt(cx, ctxt)?, + )) } else { - format!("{path}()") + Some(format!("{path}()")) } } diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 9337816c80d9..f22c7015f7ba 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; -use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; +use clippy_utils::source::{SpanExt, snippet_with_context}; use clippy_utils::sugg::has_enclosing_paren; use clippy_utils::ty::{adjust_derefs_manually_drop, implements_trait, is_manually_drop, peel_and_count_ty_refs}; use clippy_utils::{ @@ -19,7 +19,7 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMut use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypeckResults}; use rustc_session::impl_lint_pass; use rustc_span::symbol::sym; -use rustc_span::{Span, Symbol}; +use rustc_span::{Span, Symbol, SyntaxContext}; use std::borrow::Cow; declare_clippy_lint! { @@ -222,8 +222,6 @@ struct RefPat { always_deref: bool, /// The spans of all the ref bindings for this local. spans: Vec, - /// The applicability of this suggestion. - app: Applicability, /// All the replacements which need to be made. replacements: Vec<(Span, String)>, /// The [`HirId`] that the lint should be emitted at. @@ -603,37 +601,29 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { if let Some(opt_prev_pat) = self.ref_locals.get_mut(&id) { // This binding id has been seen before. Add this pattern to the list of changes. if let Some(prev_pat) = opt_prev_pat { - if pat.span.from_expansion() { + if !pat.span.from_expansion() + && let Some(src) = name.span.get_source_text_at_ctxt(cx, SyntaxContext::root()) + { + prev_pat.spans.push(pat.span); + prev_pat.replacements.push((pat.span, src.to_owned())); + } else { // Doesn't match the context of the previous pattern. Can't lint here. *opt_prev_pat = None; - } else { - prev_pat.spans.push(pat.span); - prev_pat.replacements.push(( - pat.span, - snippet_with_context(cx, name.span, pat.span.ctxt(), "..", &mut prev_pat.app) - .0 - .into(), - )); } } - return; - } - - if !pat.span.from_expansion() + } else if !pat.span.from_expansion() && let ty::Ref(_, tam, _) = *cx.typeck_results().pat_ty(pat).kind() // only lint immutable refs, because borrowed `&mut T` cannot be moved out && let ty::Ref(_, _, Mutability::Not) = *tam.kind() + && let Some(src) = name.span.get_source_text_at_ctxt(cx, SyntaxContext::root()) { - let mut app = Applicability::MachineApplicable; - let snip = snippet_with_context(cx, name.span, pat.span.ctxt(), "..", &mut app).0; self.current_body = self.current_body.or(cx.enclosing_body); self.ref_locals.insert( id, Some(RefPat { always_deref: true, spans: vec![pat.span], - app, - replacements: vec![(pat.span, snip.into())], + replacements: vec![(pat.span, src.to_owned())], hir_id: pat.hir_id, }), ); @@ -645,7 +635,6 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { if Some(body.id()) == self.current_body { for pat in self.ref_locals.drain(..).filter_map(|(_, x)| x) { let replacements = pat.replacements; - let app = pat.app; let lint = if pat.always_deref { NEEDLESS_BORROW } else { @@ -658,7 +647,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { pat.spans, "this pattern creates a reference to a reference", |diag| { - diag.multipart_suggestion("try", replacements, app); + diag.multipart_suggestion("try", replacements, Applicability::MachineApplicable); }, ); } @@ -1155,27 +1144,27 @@ impl<'tcx> Dereferencing<'tcx> { span, kind: ExprKind::Unary(UnOp::Deref, _), .. - }) if !span.from_expansion() => { + }) if !span.from_expansion() + && let Some(src) = e.span.get_source_text_at_ctxt(cx, SyntaxContext::root()) => + { // Remove explicit deref. - let snip = snippet_with_context(cx, e.span, span.ctxt(), "..", &mut pat.app).0; - pat.replacements.push((span, snip.into())); + pat.replacements.push((span, src.to_owned())); }, - Some(parent) if !parent.span.from_expansion() => { + Some(parent) + if !parent.span.from_expansion() + && cx.precedence(parent) != ExprPrecedence::Unambiguous + && let Some(src) = e.span.get_source_text_at_ctxt(cx, SyntaxContext::root()) => + { // Double reference might be needed at this point. - if cx.precedence(parent) == ExprPrecedence::Unambiguous { - // Parentheses would be needed here, don't lint. - *outer_pat = None; - } else { - pat.always_deref = false; - let snip = snippet_with_context(cx, e.span, parent.span.ctxt(), "..", &mut pat.app).0; - pat.replacements.push((e.span, format!("&{snip}"))); - } + pat.always_deref = false; + pat.replacements.push((e.span, format!("&{src}"))); }, - _ if !e.span.from_expansion() => { + _ if !e.span.from_expansion() + && let Some(src) = e.span.get_source_text_at_ctxt(cx, SyntaxContext::root()) => + { // Double reference might be needed at this point. pat.always_deref = false; - let snip = snippet_with_applicability(cx, e.span, "..", &mut pat.app); - pat.replacements.push((e.span, format!("&{snip}"))); + pat.replacements.push((e.span, format!("&{src}"))); }, // Edge case for macros. The span of the identifier will usually match the context of the // binding, but not if the identifier was created in a macro. e.g. `concat_idents` and proc diff --git a/clippy_lints/src/empty_line_after.rs b/clippy_lints/src/empty_line_after.rs index 76e67b1154be..c83570b336fb 100644 --- a/clippy_lints/src/empty_line_after.rs +++ b/clippy_lints/src/empty_line_after.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{SpanRangeExt, snippet_indent}; +use clippy_utils::source::{SpanExt, snippet_indent}; use clippy_utils::tokenize_with_text; use itertools::Itertools; use rustc_ast::token::CommentKind; diff --git a/clippy_lints/src/equatable_if_let.rs b/clippy_lints/src/equatable_if_let.rs index c3fc09343dbf..3d038c26c08d 100644 --- a/clippy_lints/src/equatable_if_let.rs +++ b/clippy_lints/src/equatable_if_let.rs @@ -1,7 +1,6 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_context; +use clippy_utils::diagnostics::{applicability_for_ctxt, span_lint_and_sugg}; +use clippy_utils::source::SpanExt; use clippy_utils::ty::implements_trait; -use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::Ty; @@ -104,21 +103,18 @@ 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) - && !expr.span.in_external_macro(cx.sess().source_map()) + && let ctxt = expr.span.ctxt() + && !ctxt.in_external_macro(cx.sess().source_map()) + && let Some(pat_src) = let_expr.span.get_source_text_at_ctxt(cx, ctxt) + && let Some(init_src) = let_expr.init.span.get_source_text_at_ctxt(cx, ctxt) { 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(), + PatKind::Struct(..) => format!("({pat_src})"), + _ => pat_src.to_owned(), }; span_lint_and_sugg( cx, @@ -126,11 +122,8 @@ impl<'tcx> LateLintPass<'tcx> for PatternEquality { 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, + format!("{init_src} == {pat_str}"), + applicability_for_ctxt(ctxt), ); } else { span_lint_and_sugg( @@ -139,12 +132,8 @@ impl<'tcx> LateLintPass<'tcx> for PatternEquality { 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, + format!("matches!({init_src}, {pat_src})"), + applicability_for_ctxt(ctxt), ); } } diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 94e66769eb26..35681a907ea6 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::{FormatArgsStorage, find_format_arg_expr, root_macro_call_first_node}; -use clippy_utils::source::{SpanRangeExt, snippet_with_context}; +use clippy_utils::source::{SpanExt, snippet_with_context}; use clippy_utils::sugg::Sugg; use rustc_ast::{FormatArgsPiece, FormatOptions, FormatTrait}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index 3359aa603239..76820f709916 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -9,7 +9,7 @@ use clippy_utils::macros::{ root_macro_call_first_node, }; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::{SpanRangeExt, snippet}; +use clippy_utils::source::{SpanExt, snippet}; use clippy_utils::ty::{implements_trait, is_type_lang_item}; use clippy_utils::{is_diag_trait_item, is_from_proc_macro, is_in_test, trait_ref_of_method}; use itertools::Itertools; diff --git a/clippy_lints/src/four_forward_slashes.rs b/clippy_lints/src/four_forward_slashes.rs index a7b0edeb7991..6854d2adfc3b 100644 --- a/clippy_lints/src/four_forward_slashes.rs +++ b/clippy_lints/src/four_forward_slashes.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::SpanRangeExt as _; +use clippy_utils::source::SpanExt as _; use itertools::Itertools; use rustc_errors::Applicability; use rustc_hir::Item; diff --git a/clippy_lints/src/from_over_into.rs b/clippy_lints/src/from_over_into.rs index e3bb5ee10db7..3b1a74610c09 100644 --- a/clippy_lints/src/from_over_into.rs +++ b/clippy_lints/src/from_over_into.rs @@ -5,7 +5,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::span_is_local; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::path_def_id; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_errors::Applicability; use rustc_hir::intravisit::{Visitor, walk_path}; use rustc_hir::{ diff --git a/clippy_lints/src/functions/too_many_lines.rs b/clippy_lints/src/functions/too_many_lines.rs index 33eede8e65ac..da3ad2287c31 100644 --- a/clippy_lints/src/functions/too_many_lines.rs +++ b/clippy_lints/src/functions/too_many_lines.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::FnKind; diff --git a/clippy_lints/src/if_not_else.rs b/clippy_lints/src/if_not_else.rs index e8afa69b537e..bc20f095d403 100644 --- a/clippy_lints/src/if_not_else.rs +++ b/clippy_lints/src/if_not_else.rs @@ -1,7 +1,7 @@ use clippy_utils::consts::is_zero_integer_const; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; use clippy_utils::is_else_clause; -use clippy_utils::source::{HasSession, indent_of, reindent_multiline, snippet}; +use clippy_utils::source::{indent_of, reindent_multiline, snippet}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; @@ -91,30 +91,30 @@ impl LateLintPass<'_> for IfNotElse { } } -fn make_sugg<'a>( - sess: &impl HasSession, - cond_kind: &'a ExprKind<'a>, +fn make_sugg( + cx: &LateContext<'_>, + cond_kind: &ExprKind<'_>, cond_inner: Span, els_span: Span, - default: &'a str, + default: &str, indent_relative_to: Option, ) -> String { - let cond_inner_snip = snippet(sess, cond_inner, default); - let els_snip = snippet(sess, els_span, default); - let indent = indent_relative_to.and_then(|s| indent_of(sess, s)); + let cond_inner_snip = snippet(cx, cond_inner, default); + let els_snip = snippet(cx, els_span, default); + let indent = indent_relative_to.and_then(|s| indent_of(cx, s)); let suggestion = match cond_kind { ExprKind::Unary(UnOp::Not, cond_rest) => { format!( "if {} {} else {}", - snippet(sess, cond_rest.span, default), + snippet(cx, cond_rest.span, default), els_snip, cond_inner_snip ) }, ExprKind::Binary(_, lhs, rhs) => { - let lhs_snip = snippet(sess, lhs.span, default); - let rhs_snip = snippet(sess, rhs.span, default); + let lhs_snip = snippet(cx, lhs.span, default); + let rhs_snip = snippet(cx, rhs.span, default); format!("if {lhs_snip} == {rhs_snip} {els_snip} else {cond_inner_snip}") }, diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs index b50d91f10146..1519871fa692 100644 --- a/clippy_lints/src/if_then_some_else_none.rs +++ b/clippy_lints/src/if_then_some_else_none.rs @@ -1,14 +1,13 @@ use clippy_config::Conf; -use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::diagnostics::{applicability_for_ctxt, span_lint_and_then}; use clippy_utils::eager_or_lazy::switch_to_eager_eval; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::{snippet_with_applicability, snippet_with_context, walk_span_to_context}; +use clippy_utils::source::{SpanExt, snippet_with_applicability, walk_span_to_context}; use clippy_utils::sugg::Sugg; use clippy_utils::{ contains_return, expr_adjustment_requires_coercion, higher, is_else_clause, is_in_const_context, is_res_lang_ctor, path_res, peel_blocks, sym, }; -use rustc_errors::Applicability; use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -97,11 +96,13 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { return; } - let mut app = Applicability::MachineApplicable; + let mut app = applicability_for_ctxt(ctxt); let cond_snip = Sugg::hir_with_context(cx, cond, ctxt, "[condition]", &mut app) .maybe_paren() .to_string(); - let arg_snip = snippet_with_context(cx, then_arg.span, ctxt, "[body]", &mut app).0; + let Some(arg_snip) = then_arg.span.get_source_text_at_ctxt(cx, ctxt) else { + return; + }; let method_body = if let Some(first_stmt) = then_block.stmts.first() && let Some(first_stmt_span) = walk_span_to_context(first_stmt.span, ctxt) { @@ -110,9 +111,9 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { let closure = if method_name == sym::then { "|| " } else { "" }; format!("{closure} {{ {} {arg_snip} }}", block_snippet.trim_end()) } else if method_name == sym::then { - (std::borrow::Cow::Borrowed("|| ") + arg_snip).into_owned() + format!("|| {arg_snip}") } else { - arg_snip.into_owned() + arg_snip.to_owned() }; diag.span_suggestion( diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs index b3c90f364e83..448a174632ee 100644 --- a/clippy_lints/src/implicit_hasher.rs +++ b/clippy_lints/src/implicit_hasher.rs @@ -12,7 +12,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::{SpanExt, snippet}; use clippy_utils::sym; use clippy_utils::ty::is_type_diagnostic_item; @@ -117,17 +117,13 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher { if !item.span.eq_ctxt(target.span()) { return; } - - let generics_suggestion_span = impl_.generics.span.substitute_dummy({ - let range = (item.span.lo()..target.span().lo()).map_range(cx, |_, src, range| { - Some(src.get(range.clone())?.find("impl")? + 4..range.end) - }); - if let Some(range) = range { - range.with_ctxt(item.span.ctxt()) - } else { - return; - } - }); + let Some(generics_span) = item.span.map_range(cx, |file| { + file.set_end_if_within(target.span().lo())? + .edit_range(|src, range| Some(src.get(range.clone())?.find("impl")? + 4..range.end)) + }) else { + return; + }; + let generics_suggestion_span = impl_.generics.span.substitute_dummy(generics_span); let mut ctr_vis = ImplicitHasherConstructorVisitor::new(cx, target); for item in impl_.items.iter().map(|&item| cx.tcx.hir_impl_item(item)) { @@ -164,19 +160,17 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher { if generics.span.from_expansion() { continue; } - let generics_suggestion_span = generics.span.substitute_dummy({ - let range = - (item.span.lo()..body.params[0].pat.span.lo()).map_range(cx, |_, src, range| { + let Some(generics_span) = item.span.map_range(cx, |file| { + file.set_end_if_within(body.params[0].pat.span.lo())? + .edit_range(|src, range| { let (pre, post) = src.get(range.clone())?.split_once("fn")?; let pos = post.find('(')? + pre.len() + 2; Some(pos..pos) - }); - if let Some(range) = range { - range.with_ctxt(item.span.ctxt()) - } else { - return; - } - }); + }) + }) else { + return; + }; + let generics_suggestion_span = generics.span.substitute_dummy(generics_span); let mut ctr_vis = ImplicitHasherConstructorVisitor::new(cx, target); ctr_vis.visit_body(body); diff --git a/clippy_lints/src/implicit_saturating_add.rs b/clippy_lints/src/implicit_saturating_add.rs index 0fdbf6797381..66493d597eb2 100644 --- a/clippy_lints/src/implicit_saturating_add.rs +++ b/clippy_lints/src/implicit_saturating_add.rs @@ -1,10 +1,9 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::{applicability_for_ctxt, span_lint_and_sugg}; use clippy_utils::get_parent_expr; -use clippy_utils::source::snippet_with_context; +use clippy_utils::source::SpanExt; use rustc_ast::ast::{LitIntType, LitKind}; use rustc_data_structures::packed::Pu128; -use rustc_errors::Applicability; use rustc_hir::{AssignOpKind, BinOpKind, Block, Expr, ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{IntTy, Ty, UintTy}; @@ -71,9 +70,8 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingAdd { && let ExprKind::Lit(lit) = value.kind && let LitKind::Int(Pu128(1), LitIntType::Unsuffixed) = lit.node && block.expr.is_none() + && let Some(code) = target.span.get_source_text_at_ctxt(cx, ctxt) { - let mut app = Applicability::MachineApplicable; - let code = snippet_with_context(cx, target.span, ctxt, "_", &mut app).0; let sugg = if let Some(parent) = get_parent_expr(cx, expr) && let ExprKind::If(_cond, _then, Some(else_)) = parent.kind && else_.hir_id == expr.hir_id @@ -89,7 +87,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingAdd { "manual saturating add detected", "use instead", sugg, - app, + applicability_for_ctxt(ctxt), ); } } diff --git a/clippy_lints/src/ineffective_open_options.rs b/clippy_lints/src/ineffective_open_options.rs index a159f6157183..55b3e7ee1bb3 100644 --- a/clippy_lints/src/ineffective_open_options.rs +++ b/clippy_lints/src/ineffective_open_options.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{peel_blocks, peel_hir_expr_while, sym}; use rustc_ast::LitKind; @@ -64,15 +64,15 @@ impl<'tcx> LateLintPass<'tcx> for IneffectiveOpenOptions { match name.ident.name { sym::append => append = true, sym::write - if let Some(range) = call_span.map_range(cx, |_, text, range| { - if text.get(..range.start)?.ends_with('.') { - Some(range.start - 1..range.end) - } else { - None - } + if let Some(call_span) = call_span.map_range(cx, |range| { + range.add_leading_whitespace()?.edit_range(|text, range| { + text.get(..range.start)? + .ends_with('.') + .then_some(range.start.wrapping_sub(1)..range.end) + }) }) => { - write = Some(call_span.with_lo(range.start)); + write = Some(call_span); }, _ => {}, } diff --git a/clippy_lints/src/init_numbered_fields.rs b/clippy_lints/src/init_numbered_fields.rs index 7a14bbfb9e8b..646ed94189a9 100644 --- a/clippy_lints/src/init_numbered_fields.rs +++ b/clippy_lints/src/init_numbered_fields.rs @@ -1,12 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; +use clippy_utils::source::{SpanExt, snippet_with_applicability}; +use itertools::Itertools; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Expr, ExprKind, StructTailExpr}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::SyntaxContext; -use std::borrow::Cow; declare_clippy_lint! { /// ### What it does @@ -54,13 +54,15 @@ impl<'tcx> LateLintPass<'tcx> for NumberedFields { // This is the only syntax macros can use that works for all struct types. && !e.span.from_expansion() && let mut has_side_effects = false - && let Ok(mut expr_spans) = fields + && let Some(mut expr_spans) = fields .iter() .map(|f| { has_side_effects |= f.expr.can_have_side_effects(); - f.ident.as_str().parse::().map(|x| (x, f.expr.span)) + let name = f.ident.as_str().parse::().ok()?; + let snip = f.expr.span.get_source_text_at_ctxt(cx, SyntaxContext::root())?; + Some((name, snip)) }) - .collect::, _>>() + .collect::>>() // We can only reorder the expressions if there are no side effects. && (!has_side_effects || expr_spans.is_sorted_by_key(|&(idx, _)| idx)) { @@ -83,11 +85,8 @@ impl<'tcx> LateLintPass<'tcx> for NumberedFields { snippet_with_applicability(cx, path.span(), "..", &mut app), expr_spans .into_iter() - .map( - |(_, span)| snippet_with_context(cx, span, SyntaxContext::root(), "..", &mut app).0 - ) - .intersperse(Cow::Borrowed(", ")) - .collect::() + .format_with(", ", |(_, src), fmt| fmt(&src)) + .to_owned() ), app, ); diff --git a/clippy_lints/src/instant_subtraction.rs b/clippy_lints/src/instant_subtraction.rs index 13117f60abd5..7827ecd771d4 100644 --- a/clippy_lints/src/instant_subtraction.rs +++ b/clippy_lints/src/instant_subtraction.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::{applicability_for_ctxt, span_lint_and_sugg}; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::snippet_with_context; +use clippy_utils::source::SpanExt; use clippy_utils::sugg::Sugg; use clippy_utils::{is_path_diagnostic_item, ty}; use rustc_errors::Applicability; @@ -133,19 +133,18 @@ fn print_unchecked_duration_subtraction_sugg( right_expr: &Expr<'_>, expr: &Expr<'_>, ) { - let mut applicability = Applicability::MachineApplicable; - let ctxt = expr.span.ctxt(); - let left_expr = snippet_with_context(cx, left_expr.span, ctxt, "", &mut applicability).0; - let right_expr = snippet_with_context(cx, right_expr.span, ctxt, "", &mut applicability).0; - - span_lint_and_sugg( - cx, - UNCHECKED_DURATION_SUBTRACTION, - expr.span, - "unchecked subtraction of a 'Duration' from an 'Instant'", - "try", - format!("{left_expr}.checked_sub({right_expr}).unwrap()"), - applicability, - ); + if let Some(left_expr) = left_expr.span.get_source_text_at_ctxt(cx, ctxt) + && let Some(right_expr) = right_expr.span.get_source_text_at_ctxt(cx, ctxt) + { + span_lint_and_sugg( + cx, + UNCHECKED_DURATION_SUBTRACTION, + expr.span, + "unchecked subtraction of a 'Duration' from an 'Instant'", + "try", + format!("{left_expr}.checked_sub({right_expr}).unwrap()"), + applicability_for_ctxt(ctxt), + ); + } } diff --git a/clippy_lints/src/int_plus_one.rs b/clippy_lints/src/int_plus_one.rs index 67ce57de254d..24d9ccb27788 100644 --- a/clippy_lints/src/int_plus_one.rs +++ b/clippy_lints/src/int_plus_one.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_ast::ast::{BinOpKind, Expr, ExprKind, LitKind}; use rustc_ast::token; use rustc_errors::Applicability; diff --git a/clippy_lints/src/invalid_upcast_comparisons.rs b/clippy_lints/src/invalid_upcast_comparisons.rs index 1666e8e5ae32..f391c6261687 100644 --- a/clippy_lints/src/invalid_upcast_comparisons.rs +++ b/clippy_lints/src/invalid_upcast_comparisons.rs @@ -1,4 +1,4 @@ -use rustc_errors::Applicability; +use clippy_utils::source::SpanExt; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf; @@ -10,7 +10,6 @@ use clippy_utils::comparisons; use clippy_utils::comparisons::Rel; use clippy_utils::consts::{ConstEvalCtxt, FullInt}; use clippy_utils::diagnostics::span_lint; -use clippy_utils::source::snippet_with_context; declare_clippy_lint! { /// ### What it does @@ -69,15 +68,10 @@ fn numeric_cast_precast_bounds(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option< } fn err_upcast_comparison(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, always: bool) { - if let ExprKind::Cast(cast_val, _) = expr.kind { - let mut applicability = Applicability::MachineApplicable; - let (cast_val_snip, _) = snippet_with_context( - cx, - cast_val.span, - expr.span.ctxt(), - "the expression", - &mut applicability, - ); + if let ExprKind::Cast(cast_val, _) = expr.kind + && let ctxt = expr.span.ctxt() + && let Some(cast_val_snip) = cast_val.span.get_source_text_at_ctxt(cx, ctxt) + { span_lint( cx, INVALID_UPCAST_COMPARISONS, diff --git a/clippy_lints/src/items_after_test_module.rs b/clippy_lints/src/items_after_test_module.rs index dd63de288b87..3ab4be144251 100644 --- a/clippy_lints/src/items_after_test_module.rs +++ b/clippy_lints/src/items_after_test_module.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::{fulfill_or_allowed, is_cfg_test, is_from_proc_macro}; use rustc_errors::{Applicability, SuggestionStyle}; use rustc_hir::{HirId, Item, ItemKind, Mod}; diff --git a/clippy_lints/src/large_stack_frames.rs b/clippy_lints/src/large_stack_frames.rs index 5ed948c02bbc..922f81a92785 100644 --- a/clippy_lints/src/large_stack_frames.rs +++ b/clippy_lints/src/large_stack_frames.rs @@ -3,7 +3,7 @@ use std::{fmt, ops}; use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::fn_has_unsatisfiable_preds; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl}; diff --git a/clippy_lints/src/legacy_numeric_constants.rs b/clippy_lints/src/legacy_numeric_constants.rs index 42c636505c01..efebfb512957 100644 --- a/clippy_lints/src/legacy_numeric_constants.rs +++ b/clippy_lints/src/legacy_numeric_constants.rs @@ -2,7 +2,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_from_proc_macro; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use hir::def_id::DefId; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 28a0fbc05115..b438e743aac6 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -1,5 +1,5 @@ -use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::{SpanRangeExt, snippet_with_context}; +use clippy_utils::diagnostics::{applicability_for_ctxt, span_lint, span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::source::SpanExt; use clippy_utils::sugg::{Sugg, has_enclosing_paren}; use clippy_utils::ty::implements_trait; use clippy_utils::{ @@ -546,19 +546,19 @@ fn check_len( return; } - if method_name == sym::len && has_is_empty(cx, receiver) { - let mut applicability = Applicability::MachineApplicable; + if method_name == sym::len + && has_is_empty(cx, receiver) + && let ctxt = span.ctxt() + && let Some(src) = receiver.span.get_source_text_at_ctxt(cx, ctxt) + { span_lint_and_sugg( cx, LEN_ZERO, span, format!("length comparison to {}", if compare_to == 0 { "zero" } else { "one" }), format!("using `{op}is_empty` is clearer and more explicit"), - format!( - "{op}{}.is_empty()", - snippet_with_context(cx, receiver.span, span.ctxt(), "_", &mut applicability).0, - ), - applicability, + format!("{op}{src}.is_empty()"), + applicability_for_ctxt(ctxt), ); } } diff --git a/clippy_lints/src/let_with_type_underscore.rs b/clippy_lints/src/let_with_type_underscore.rs index 24a4c321bdab..6782fce376ee 100644 --- a/clippy_lints/src/let_with_type_underscore.rs +++ b/clippy_lints/src/let_with_type_underscore.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_from_proc_macro; -use clippy_utils::source::{IntoSpan, SpanRangeExt}; +use clippy_utils::source::SpanExt; use rustc_ast::{Local, TyKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; @@ -34,12 +34,13 @@ impl EarlyLintPass for UnderscoreTyped { && let sm = cx.sess().source_map() && !local.span.in_external_macro(sm) && !is_from_proc_macro(cx, &**ty) + && let Some(span_to_remove) = + ty.span.map_range(sm, |src| { + src.add_leading_whitespace()? + .add_leading_match(':')? + .add_leading_whitespace() + }) { - let span_to_remove = sm - .span_extend_to_prev_char_before(ty.span, ':', true) - .with_leading_whitespace(cx) - .into_span(); - span_lint_and_then( cx, LET_WITH_TYPE_UNDERSCORE, diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index 7cbfa2d097ae..b7ed91f241f7 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::numeric_literal::{NumericLiteral, Radix}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_ast::ast::{Expr, ExprKind, LitKind}; use rustc_ast::token; use rustc_errors::Applicability; diff --git a/clippy_lints/src/loops/explicit_into_iter_loop.rs b/clippy_lints/src/loops/explicit_into_iter_loop.rs index 4aa1c2e211d3..68c2664a03b9 100644 --- a/clippy_lints/src/loops/explicit_into_iter_loop.rs +++ b/clippy_lints/src/loops/explicit_into_iter_loop.rs @@ -1,8 +1,7 @@ use super::EXPLICIT_INTO_ITER_LOOP; -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::{applicability_for_ctxt, span_lint_and_sugg}; use clippy_utils::is_trait_method; -use clippy_utils::source::snippet_with_context; -use rustc_errors::Applicability; +use clippy_utils::source::SpanExt; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; @@ -75,8 +74,10 @@ pub(super) fn check(cx: &LateContext<'_>, self_arg: &Expr<'_>, call_expr: &Expr< _ => return, }; - let mut applicability = Applicability::MachineApplicable; - let object = snippet_with_context(cx, self_arg.span, call_expr.span.ctxt(), "_", &mut applicability).0; + let ctxt = call_expr.span.ctxt(); + let Some(object) = self_arg.span.get_source_text_at_ctxt(cx, ctxt) else { + return; + }; span_lint_and_sugg( cx, EXPLICIT_INTO_ITER_LOOP, @@ -85,6 +86,6 @@ pub(super) fn check(cx: &LateContext<'_>, self_arg: &Expr<'_>, call_expr: &Expr< iteration methods", "to write this more concisely, try", format!("{}{object}", adjust.display()), - applicability, + applicability_for_ctxt(ctxt), ); } diff --git a/clippy_lints/src/loops/explicit_iter_loop.rs b/clippy_lints/src/loops/explicit_iter_loop.rs index 010652e1cb90..1788c1b441a8 100644 --- a/clippy_lints/src/loops/explicit_iter_loop.rs +++ b/clippy_lints/src/loops/explicit_iter_loop.rs @@ -1,13 +1,12 @@ use super::EXPLICIT_ITER_LOOP; -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::{applicability_for_ctxt, span_lint_and_sugg}; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::snippet_with_context; +use clippy_utils::source::SpanExt; use clippy_utils::sym; use clippy_utils::ty::{ implements_trait, implements_trait_with_env, is_copy, is_type_lang_item, make_normalized_projection, make_normalized_projection_with_regions, normalize_with_regions, }; -use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability}; use rustc_lint::LateContext; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; @@ -35,8 +34,10 @@ pub(super) fn check( } } - let mut applicability = Applicability::MachineApplicable; - let object = snippet_with_context(cx, self_arg.span, call_expr.span.ctxt(), "_", &mut applicability).0; + let ctxt = call_expr.span.ctxt(); + let Some(object) = self_arg.span.get_source_text_at_ctxt(cx, ctxt) else { + return; + }; span_lint_and_sugg( cx, EXPLICIT_ITER_LOOP, @@ -45,7 +46,7 @@ pub(super) fn check( iteration methods", "to write this more concisely, try", format!("{}{object}", adjust.display()), - applicability, + applicability_for_ctxt(ctxt), ); } diff --git a/clippy_lints/src/loops/manual_flatten.rs b/clippy_lints/src/loops/manual_flatten.rs index ddb8bb536c04..b74eaa505c2e 100644 --- a/clippy_lints/src/loops/manual_flatten.rs +++ b/clippy_lints/src/loops/manual_flatten.rs @@ -2,7 +2,7 @@ use super::MANUAL_FLATTEN; use super::utils::make_iterator_snippet; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::{HasSession, indent_of, reindent_multiline, snippet_with_applicability}; +use clippy_utils::source::{indent_of, reindent_multiline, snippet_with_applicability}; use clippy_utils::visitors::is_local_used; use clippy_utils::{higher, is_refutable, path_to_local_id, peel_blocks_with_stmt, span_contains_comment}; use rustc_errors::Applicability; @@ -49,7 +49,7 @@ pub(super) fn check<'tcx>( format!("unnecessary `if let` since only the `{if_let_type}` variant of the iterator element is used"); // Prepare the help message - let mut applicability = if span_contains_comment(cx.sess().source_map(), body.span) { + let mut applicability = if span_contains_comment(cx.tcx.sess.source_map(), body.span) { Applicability::MaybeIncorrect } else { Applicability::MachineApplicable diff --git a/clippy_lints/src/loops/manual_slice_fill.rs b/clippy_lints/src/loops/manual_slice_fill.rs index 15c656cc7bc7..ba7271f4a3bf 100644 --- a/clippy_lints/src/loops/manual_slice_fill.rs +++ b/clippy_lints/src/loops/manual_slice_fill.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::eager_or_lazy::switch_to_eager_eval; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::{HasSession, snippet_with_applicability}; +use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{implements_trait, is_slice_like}; use clippy_utils::visitors::is_local_used; use clippy_utils::{higher, peel_blocks_with_stmt, span_contains_comment}; @@ -93,7 +93,7 @@ fn sugg<'tcx>( slice_span: rustc_span::Span, assignval_span: rustc_span::Span, ) { - let mut app = if span_contains_comment(cx.sess().source_map(), body.span) { + let mut app = if span_contains_comment(cx, body.span) { Applicability::MaybeIncorrect // Comments may be informational. } else { Applicability::MachineApplicable diff --git a/clippy_lints/src/loops/same_item_push.rs b/clippy_lints/src/loops/same_item_push.rs index e792edbe23e0..8027ced0df4e 100644 --- a/clippy_lints/src/loops/same_item_push.rs +++ b/clippy_lints/src/loops/same_item_push.rs @@ -22,7 +22,7 @@ pub(super) fn check<'tcx>( msrv: Msrv, ) { fn emit_lint(cx: &LateContext<'_>, vec: &Expr<'_>, pushed_item: &Expr<'_>, ctxt: SyntaxContext, msrv: Msrv) { - let mut app = Applicability::Unspecified; + let mut app: Applicability = Applicability::Unspecified; let vec_str = snippet_with_context(cx, vec.span, ctxt, "", &mut app).0; let item_str = snippet_with_context(cx, pushed_item.span, ctxt, "", &mut app).0; diff --git a/clippy_lints/src/manual_abs_diff.rs b/clippy_lints/src/manual_abs_diff.rs index 5814b6815a1e..d59d5e7b8830 100644 --- a/clippy_lints/src/manual_abs_diff.rs +++ b/clippy_lints/src/manual_abs_diff.rs @@ -2,7 +2,6 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::If; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::HasSession as _; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_type_diagnostic_item, peel_and_count_ty_refs}; use clippy_utils::{eq_expr_value, peel_blocks, span_contains_comment}; @@ -76,10 +75,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualAbsDiff { (a, b) = (b, a); } let applicability = { - let source_map = cx.sess().source_map(); - if span_contains_comment(source_map, if_expr.then.span) - || span_contains_comment(source_map, r#else.span) - { + if span_contains_comment(cx, if_expr.then.span) || span_contains_comment(cx, r#else.span) { Applicability::MaybeIncorrect } else { Applicability::MachineApplicable diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index ba1ad599e116..6683f9c54f45 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{SpanRangeExt, position_before_rarrow, snippet_block}; +use clippy_utils::source::{SpanExt, position_before_rarrow, snippet_block}; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ diff --git a/clippy_lints/src/manual_bits.rs b/clippy_lints/src/manual_bits.rs index 40fe88532729..2f1f16275297 100644 --- a/clippy_lints/src/manual_bits.rs +++ b/clippy_lints/src/manual_bits.rs @@ -1,11 +1,10 @@ use clippy_config::Conf; -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::{applicability_for_ctxt, span_lint_and_sugg}; use clippy_utils::get_parent_expr; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::snippet_with_context; +use clippy_utils::source::SpanExt; use rustc_ast::ast::LitKind; use rustc_data_structures::packed::Pu128; -use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, GenericArg, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; @@ -59,19 +58,16 @@ impl<'tcx> LateLintPass<'tcx> for ManualBits { && let ExprKind::Lit(lit) = &other_expr.kind && let LitKind::Int(Pu128(8), _) = lit.node && self.msrv.meets(cx, msrvs::INTEGER_BITS) + && let Some(ty_snip) = real_ty_span.get_source_text_at_ctxt(cx, ctxt) { - let mut app = Applicability::MachineApplicable; - let ty_snip = snippet_with_context(cx, real_ty_span, ctxt, "..", &mut app).0; - let sugg = create_sugg(cx, expr, format!("{ty_snip}::BITS")); - span_lint_and_sugg( cx, MANUAL_BITS, expr.span, "usage of `size_of::()` to obtain the size of `T` in bits", "consider using", - sugg, - app, + create_sugg(cx, expr, format!("{ty_snip}::BITS")), + applicability_for_ctxt(ctxt), ); } } diff --git a/clippy_lints/src/manual_div_ceil.rs b/clippy_lints/src/manual_div_ceil.rs index ed0cce754b95..57613a8927d9 100644 --- a/clippy_lints/src/manual_div_ceil.rs +++ b/clippy_lints/src/manual_div_ceil.rs @@ -1,12 +1,11 @@ use clippy_config::Conf; -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::{applicability_for_ctxt, span_lint_and_sugg}; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::snippet_with_context; +use clippy_utils::source::SpanExt; use clippy_utils::sugg::{Sugg, has_enclosing_paren}; use clippy_utils::{SpanlessEq, sym}; use rustc_ast::{BinOpKind, LitIntType, LitKind, UnOp}; use rustc_data_structures::packed::Pu128; -use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self}; @@ -55,8 +54,6 @@ impl_lint_pass!(ManualDivCeil => [MANUAL_DIV_CEIL]); impl<'tcx> LateLintPass<'tcx> for ManualDivCeil { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) { - let mut applicability = Applicability::MachineApplicable; - if let ExprKind::Binary(div_op, div_lhs, div_rhs) = expr.kind && div_op.node == BinOpKind::Div && check_int_ty_and_feature(cx, div_lhs) @@ -71,7 +68,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualDivCeil { && check_literal(sub_rhs) && check_eq_expr(cx, sub_lhs, div_rhs) { - build_suggestion(cx, expr, inner_lhs, div_rhs, &mut applicability); + build_suggestion(cx, expr, inner_lhs, div_rhs); return; } @@ -82,7 +79,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualDivCeil { && check_literal(sub_rhs) && check_eq_expr(cx, sub_lhs, div_rhs) { - build_suggestion(cx, expr, inner_rhs, div_rhs, &mut applicability); + build_suggestion(cx, expr, inner_rhs, div_rhs); return; } @@ -93,17 +90,17 @@ impl<'tcx> LateLintPass<'tcx> for ManualDivCeil { && check_literal(inner_rhs) && check_eq_expr(cx, add_rhs, div_rhs) { - build_suggestion(cx, expr, add_lhs, div_rhs, &mut applicability); + build_suggestion(cx, expr, add_lhs, div_rhs); } // (x + (Y - 1)) / Y if inner_op.node == BinOpKind::Add && differ_by_one(inner_rhs, div_rhs) { - build_suggestion(cx, expr, inner_lhs, div_rhs, &mut applicability); + build_suggestion(cx, expr, inner_lhs, div_rhs); } // ((Y - 1) + x) / Y if inner_op.node == BinOpKind::Add && differ_by_one(inner_lhs, div_rhs) { - build_suggestion(cx, expr, inner_rhs, div_rhs, &mut applicability); + build_suggestion(cx, expr, inner_rhs, div_rhs); } // (x - (-Y - 1)) / Y @@ -111,7 +108,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualDivCeil { && let ExprKind::Unary(UnOp::Neg, abs_div_rhs) = div_rhs.kind && differ_by_one(abs_div_rhs, inner_rhs) { - build_suggestion(cx, expr, inner_lhs, div_rhs, &mut applicability); + build_suggestion(cx, expr, inner_lhs, div_rhs); } } } @@ -157,14 +154,11 @@ fn check_eq_expr(cx: &LateContext<'_>, lhs: &Expr<'_>, rhs: &Expr<'_>) -> bool { SpanlessEq::new(cx).eq_expr(lhs, rhs) } -fn build_suggestion( - cx: &LateContext<'_>, - expr: &Expr<'_>, - lhs: &Expr<'_>, - rhs: &Expr<'_>, - applicability: &mut Applicability, -) { - let dividend_sugg = Sugg::hir_with_applicability(cx, lhs, "..", applicability).maybe_paren(); +fn build_suggestion(cx: &LateContext<'_>, expr: &Expr<'_>, lhs: &Expr<'_>, rhs: &Expr<'_>) { + let ctxt = expr.span.ctxt(); + let mut applicability = applicability_for_ctxt(ctxt); + + let dividend_sugg = Sugg::hir_with_applicability(cx, lhs, "..", &mut applicability).maybe_paren(); let type_suffix = if cx.typeck_results().expr_ty(lhs).is_numeric() && matches!( lhs.kind, @@ -199,17 +193,17 @@ fn build_suggestion( } else { format!("{dividend_sugg_str}{type_suffix}") }; - let divisor_snippet = snippet_with_context(cx, rhs.span, expr.span.ctxt(), "..", applicability); - - let sugg = format!("{suggestion_before_div_ceil}.div_ceil({})", divisor_snippet.0); + let Some(divisor_snippet) = rhs.span.get_source_text_at_ctxt(cx, ctxt) else { + return; + }; span_lint_and_sugg( cx, MANUAL_DIV_CEIL, expr.span, "manually reimplementing `div_ceil`", "consider using `.div_ceil()`", - sugg, - *applicability, + format!("{suggestion_before_div_ceil}.div_ceil({divisor_snippet})"), + applicability, ); } diff --git a/clippy_lints/src/manual_float_methods.rs b/clippy_lints/src/manual_float_methods.rs index bd2785fea270..a9dfe98f1eb4 100644 --- a/clippy_lints/src/manual_float_methods.rs +++ b/clippy_lints/src/manual_float_methods.rs @@ -2,7 +2,7 @@ use clippy_config::Conf; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::{is_from_proc_macro, path_to_local}; use rustc_errors::Applicability; use rustc_hir::def::DefKind; diff --git a/clippy_lints/src/manual_hash_one.rs b/clippy_lints/src/manual_hash_one.rs index b3ee45cc0209..cdb1f3b1f665 100644 --- a/clippy_lints/src/manual_hash_one.rs +++ b/clippy_lints/src/manual_hash_one.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::visitors::{is_local_used, local_used_once}; use clippy_utils::{is_trait_method, path_to_local_id, sym}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/manual_range_patterns.rs b/clippy_lints/src/manual_range_patterns.rs index bf4f2bff3195..13afac9b3edc 100644 --- a/clippy_lints/src/manual_range_patterns.rs +++ b/clippy_lints/src/manual_range_patterns.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_ast::LitKind; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; diff --git a/clippy_lints/src/manual_rem_euclid.rs b/clippy_lints/src/manual_rem_euclid.rs index 41e07e26bff0..fed9e673da2a 100644 --- a/clippy_lints/src/manual_rem_euclid.rs +++ b/clippy_lints/src/manual_rem_euclid.rs @@ -1,10 +1,9 @@ use clippy_config::Conf; use clippy_utils::consts::{ConstEvalCtxt, FullInt}; -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::{applicability_for_ctxt, span_lint_and_sugg}; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::snippet_with_context; +use clippy_utils::source::SpanExt; use clippy_utils::{is_in_const_context, path_to_local}; -use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, Node, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::impl_lint_pass; @@ -84,8 +83,9 @@ impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid { _ => return, } - let mut app = Applicability::MachineApplicable; - let rem_of = snippet_with_context(cx, rem2_lhs.span, ctxt, "_", &mut app).0; + let Some(rem_of) = rem2_lhs.span.get_source_text_at_ctxt(cx, ctxt) else { + return; + }; span_lint_and_sugg( cx, MANUAL_REM_EUCLID, @@ -93,7 +93,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid { "manual `rem_euclid` implementation", "consider using", format!("{rem_of}.rem_euclid({const1})"), - app, + applicability_for_ctxt(ctxt), ); } } diff --git a/clippy_lints/src/manual_slice_size_calculation.rs b/clippy_lints/src/manual_slice_size_calculation.rs index de12fa29d02c..23012ff968b0 100644 --- a/clippy_lints/src/manual_slice_size_calculation.rs +++ b/clippy_lints/src/manual_slice_size_calculation.rs @@ -1,10 +1,9 @@ use clippy_config::Conf; -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::{applicability_for_ctxt, span_lint_and_sugg}; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::snippet_with_context; +use clippy_utils::source::SpanExt; use clippy_utils::ty::peel_and_count_ty_refs; use clippy_utils::{expr_or_init, is_in_const_context, std_or_core}; -use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; @@ -58,15 +57,14 @@ impl<'tcx> LateLintPass<'tcx> for ManualSliceSizeCalculation { && !expr.span.from_expansion() && let Some((receiver, refs_count)) = simplify(cx, left, right) && (!is_in_const_context(cx) || self.msrv.meets(cx, msrvs::CONST_SIZE_OF_VAL)) + && let ctxt = expr.span.ctxt() + && let Some(val_name) = receiver.span.get_source_text_at_ctxt(cx, ctxt) { - let ctxt = expr.span.ctxt(); - let mut app = Applicability::MachineApplicable; let deref = if refs_count > 0 { "*".repeat(refs_count - 1) } else { "&".into() }; - let val_name = snippet_with_context(cx, receiver.span, ctxt, "slice", &mut app).0; let Some(sugg) = std_or_core(cx) else { return }; span_lint_and_sugg( @@ -76,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualSliceSizeCalculation { "manual slice size calculation", "try", format!("{sugg}::mem::size_of_val({deref}{val_name})"), - app, + applicability_for_ctxt(ctxt), ); } } diff --git a/clippy_lints/src/match_result_ok.rs b/clippy_lints/src/match_result_ok.rs index e0cb5d14d3c9..a5c081747574 100644 --- a/clippy_lints/src/match_result_ok.rs +++ b/clippy_lints/src/match_result_ok.rs @@ -1,8 +1,7 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_context; +use clippy_utils::diagnostics::{applicability_for_ctxt, span_lint_and_sugg}; +use clippy_utils::source::SpanExt; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{higher, is_res_lang_ctor, sym}; -use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -62,10 +61,9 @@ impl<'tcx> LateLintPass<'tcx> for MatchResultOk { && let ctxt = expr.span.ctxt() && let_expr.span.ctxt() == ctxt && let_pat.span.ctxt() == ctxt + && let Some(some_expr_string) = ok_pat.span.get_source_text_at_ctxt(cx, ctxt) + && let Some(trimmed_ok) = recv.span.get_source_text_at_ctxt(cx, ctxt) { - let mut applicability = Applicability::MachineApplicable; - let some_expr_string = snippet_with_context(cx, ok_pat.span, ctxt, "", &mut applicability).0; - let trimmed_ok = snippet_with_context(cx, recv.span, ctxt, "", &mut applicability).0; let sugg = format!( "{ifwhile} let Ok({some_expr_string}) = {}", trimmed_ok.trim().trim_end_matches('.'), @@ -77,7 +75,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchResultOk { "matching on `Some` with `ok()` is redundant", format!("consider matching on `Ok({some_expr_string})` and removing the call to `ok` instead"), sugg, - applicability, + applicability_for_ctxt(ctxt), ); } } diff --git a/clippy_lints/src/matches/manual_unwrap_or.rs b/clippy_lints/src/matches/manual_unwrap_or.rs index 8c3f52542d91..7338c2795a4c 100644 --- a/clippy_lints/src/matches/manual_unwrap_or.rs +++ b/clippy_lints/src/matches/manual_unwrap_or.rs @@ -1,5 +1,5 @@ use clippy_utils::consts::ConstEvalCtxt; -use clippy_utils::source::{SpanRangeExt as _, indent_of, reindent_multiline}; +use clippy_utils::source::{SpanExt as _, indent_of, reindent_multiline}; use rustc_ast::{BindingMode, ByRef}; use rustc_errors::Applicability; use rustc_hir::def::Res; diff --git a/clippy_lints/src/matches/match_same_arms.rs b/clippy_lints/src/matches/match_same_arms.rs index ae277da089fd..3c73acef73fb 100644 --- a/clippy_lints/src/matches/match_same_arms.rs +++ b/clippy_lints/src/matches/match_same_arms.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::{SpanlessEq, SpanlessHash, fulfill_or_allowed, is_lint_allowed, path_to_local, search_same}; use core::cmp::Ordering; use core::{iter, slice}; diff --git a/clippy_lints/src/matches/match_wild_enum.rs b/clippy_lints/src/matches/match_wild_enum.rs index 70a03ff93762..6105d63a48d2 100644 --- a/clippy_lints/src/matches/match_wild_enum.rs +++ b/clippy_lints/src/matches/match_wild_enum.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{is_refutable, peel_hir_pat_refs, recurse_or_patterns}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs index 83939d325794..cbb4fec43982 100644 --- a/clippy_lints/src/matches/single_match.rs +++ b/clippy_lints/src/matches/single_match.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{ - SpanRangeExt, expr_block, snippet, snippet_block_with_context, snippet_with_applicability, snippet_with_context, + SpanExt, expr_block, snippet, snippet_block_with_context, snippet_with_applicability, snippet_with_context, }; use clippy_utils::ty::{implements_trait, peel_and_count_ty_refs}; use clippy_utils::{is_lint_allowed, is_unit_expr, peel_blocks, peel_hir_pat_refs, peel_n_hir_expr_refs}; @@ -23,7 +23,7 @@ use super::{MATCH_BOOL, SINGLE_MATCH, SINGLE_MATCH_ELSE}; /// match arms. fn empty_arm_has_comment(cx: &LateContext<'_>, span: Span) -> bool { if let Some(ff) = span.get_source_range(cx) - && let Some(text) = ff.as_str() + && let Some(text) = ff.current_text() { text.as_bytes().windows(2).any(|w| w == b"//" || w == b"/*") } else { diff --git a/clippy_lints/src/methods/bind_instead_of_map.rs b/clippy_lints/src/methods/bind_instead_of_map.rs index f8520c23ea50..805c37fca3b6 100644 --- a/clippy_lints/src/methods/bind_instead_of_map.rs +++ b/clippy_lints/src/methods/bind_instead_of_map.rs @@ -1,7 +1,7 @@ use super::{BIND_INSTEAD_OF_MAP, contains_return}; -use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::diagnostics::{applicability_for_ctxt, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::peel_blocks; -use clippy_utils::source::{snippet, snippet_with_context}; +use clippy_utils::source::{SpanExt, snippet}; use clippy_utils::visitors::find_all_ret_expressions; use rustc_errors::Applicability; use rustc_hir as hir; @@ -95,17 +95,24 @@ impl BindInsteadOfMap { && self.is_variant(cx, path.res) && !contains_return(inner_expr) && let Some(msg) = self.lint_msg(cx) + && let ctxt = closure_expr.span.ctxt() + && let Some(some_inner_snip) = inner_expr.span.get_source_text_at_ctxt(cx, ctxt) { - let mut app = Applicability::MachineApplicable; - let some_inner_snip = snippet_with_context(cx, inner_expr.span, closure_expr.span.ctxt(), "_", &mut app).0; - let closure_args_snip = snippet(cx, closure_args_span, ".."); let option_snip = snippet(cx, recv.span, ".."); let note = format!( "{option_snip}.{}({closure_args_snip} {some_inner_snip})", self.good_method_name ); - span_lint_and_sugg(cx, BIND_INSTEAD_OF_MAP, expr.span, msg, "try", note, app); + span_lint_and_sugg( + cx, + BIND_INSTEAD_OF_MAP, + expr.span, + msg, + "try", + note, + applicability_for_ctxt(ctxt), + ); true } else { false diff --git a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs index 6f9702f6c6c3..9b7aeda31bfb 100644 --- a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs +++ b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::{SpanRangeExt, indent_of, reindent_multiline}; +use clippy_utils::source::{SpanExt, indent_of, reindent_multiline}; use clippy_utils::sym; use clippy_utils::ty::is_type_lang_item; use rustc_ast::ast::LitKind; diff --git a/clippy_lints/src/methods/clone_on_copy.rs b/clippy_lints/src/methods/clone_on_copy.rs index 0a456d1057ad..2cb526512ee1 100644 --- a/clippy_lints/src/methods/clone_on_copy.rs +++ b/clippy_lints/src/methods/clone_on_copy.rs @@ -1,7 +1,6 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_context; +use clippy_utils::diagnostics::{applicability_for_ctxt, span_lint_and_sugg}; +use clippy_utils::source::SpanExt; use clippy_utils::ty::is_copy; -use rustc_errors::Applicability; use rustc_hir::{BindingMode, ByRef, Expr, ExprKind, MatchSource, Node, PatKind, QPath}; use rustc_lint::LateContext; use rustc_middle::ty::adjustment::Adjust; @@ -75,15 +74,17 @@ pub(super) fn check( _ => false, }; - let mut app = Applicability::MachineApplicable; - let snip = snippet_with_context(cx, arg.span, expr.span.ctxt(), "_", &mut app).0; + let ctxt = expr.span.ctxt(); + let Some(snip) = arg.span.get_source_text_at_ctxt(cx, ctxt) else { + return; + }; let deref_count = arg_adjustments .iter() .take_while(|adj| matches!(adj.kind, Adjust::Deref(_))) .count(); let (help, sugg) = if deref_count == 0 { - ("try removing the `clone` call", snip.into()) + ("try removing the `clone` call", snip.to_owned()) } else if parent_is_suffix_expr { ("try dereferencing it", format!("({}{snip})", "*".repeat(deref_count))) } else { @@ -99,7 +100,7 @@ pub(super) fn check( )), help, sugg, - app, + applicability_for_ctxt(ctxt), ); } } diff --git a/clippy_lints/src/methods/clone_on_ref_ptr.rs b/clippy_lints/src/methods/clone_on_ref_ptr.rs index 65583c6a9811..c57845de6afd 100644 --- a/clippy_lints/src/methods/clone_on_ref_ptr.rs +++ b/clippy_lints/src/methods/clone_on_ref_ptr.rs @@ -1,6 +1,5 @@ -use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet_with_context; -use rustc_errors::Applicability; +use clippy_utils::diagnostics::{applicability_for_ctxt, span_lint_and_then}; +use clippy_utils::source::SpanExt; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty; @@ -22,14 +21,16 @@ pub(super) fn check( if let ty::Adt(adt, subst) = obj_ty.kind() && let Some(name) = cx.tcx.get_diagnostic_name(adt.did()) - { - let caller_type = match name { + && let caller_type = match name { sym::Rc => "std::rc::Rc", sym::Arc => "std::sync::Arc", sym::RcWeak => "std::rc::Weak", sym::ArcWeak => "std::sync::Weak", _ => return, - }; + } + && let ctxt = expr.span.ctxt() + && let Some(snippet) = receiver.span.get_source_text_at_ctxt(cx, ctxt) + { span_lint_and_then( cx, CLONE_ON_REF_PTR, @@ -37,13 +38,11 @@ pub(super) fn check( "using `.clone()` on a ref-counted pointer", |diag| { // Sometimes unnecessary ::<_> after Rc/Arc/Weak - let mut app = Applicability::Unspecified; - let snippet = snippet_with_context(cx, receiver.span, expr.span.ctxt(), "..", &mut app).0; diag.span_suggestion( expr.span, "try", format!("{caller_type}::<{}>::clone(&{snippet})", subst.type_at(0)), - app, + applicability_for_ctxt(ctxt), ); }, ); diff --git a/clippy_lints/src/methods/filter_map_bool_then.rs b/clippy_lints/src/methods/filter_map_bool_then.rs index 94944bd9445b..046d0f073044 100644 --- a/clippy_lints/src/methods/filter_map_bool_then.rs +++ b/clippy_lints/src/methods/filter_map_bool_then.rs @@ -1,13 +1,12 @@ use super::FILTER_MAP_BOOL_THEN; -use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{SpanRangeExt, snippet_with_context}; +use clippy_utils::diagnostics::{applicability_for_ctxt, span_lint_and_then}; +use clippy_utils::source::SpanExt; use clippy_utils::ty::is_copy; use clippy_utils::{ CaptureKind, can_move_expr_to_closure, contains_return, is_from_proc_macro, is_trait_method, peel_blocks, }; use rustc_ast::Mutability; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, HirId, Param, Pat}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty::Binder; @@ -45,11 +44,10 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: & .filter(|adj| matches!(adj.kind, Adjust::Deref(_))) .count() && let Some(param_snippet) = param.span.get_source_text(cx) + && let ctxt = expr.span.ctxt() + && let Some(filter) = recv.span.get_source_text_at_ctxt(cx, ctxt) + && let Some(map) = then_body.span.get_source_text_at_ctxt(cx, ctxt) { - let mut applicability = Applicability::MachineApplicable; - let (filter, _) = snippet_with_context(cx, recv.span, expr.span.ctxt(), "..", &mut applicability); - let (map, _) = snippet_with_context(cx, then_body.span, expr.span.ctxt(), "..", &mut applicability); - span_lint_and_then( cx, FILTER_MAP_BOOL_THEN, @@ -64,7 +62,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: & "filter(|&{param_snippet}| {derefs}{filter}).map(|{param_snippet}| {map})", derefs = "*".repeat(needed_derefs) ), - applicability, + applicability_for_ctxt(ctxt), ); } else { diag.help("consider using `filter` then `map` instead"); diff --git a/clippy_lints/src/methods/implicit_clone.rs b/clippy_lints/src/methods/implicit_clone.rs index 0ba84919395c..620a58980571 100644 --- a/clippy_lints/src/methods/implicit_clone.rs +++ b/clippy_lints/src/methods/implicit_clone.rs @@ -1,8 +1,7 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_context; +use clippy_utils::diagnostics::{applicability_for_ctxt, span_lint_and_sugg}; +use clippy_utils::source::SpanExt; use clippy_utils::ty::{implements_trait, peel_and_count_ty_refs}; use clippy_utils::{is_diag_item_method, is_diag_trait_item, sym}; -use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::Symbol; @@ -20,9 +19,9 @@ pub fn check(cx: &LateContext<'_>, method_name: Symbol, expr: &hir::Expr<'_>, re && return_type == input_type && let Some(clone_trait) = cx.tcx.lang_items().clone_trait() && implements_trait(cx, return_type, clone_trait, &[]) + && let ctxt = expr.span.ctxt() + && let Some(recv_snip) = recv.span.get_source_text_at_ctxt(cx, ctxt) { - let mut app = Applicability::MachineApplicable; - let recv_snip = snippet_with_context(cx, recv.span, expr.span.ctxt(), "..", &mut app).0; span_lint_and_sugg( cx, IMPLICIT_CLONE, @@ -34,7 +33,7 @@ pub fn check(cx: &LateContext<'_>, method_name: Symbol, expr: &hir::Expr<'_>, re } else { format!("{recv_snip}.clone()") }, - app, + applicability_for_ctxt(ctxt), ); } } diff --git a/clippy_lints/src/methods/manual_inspect.rs b/clippy_lints/src/methods/manual_inspect.rs index bc96815944d5..763b6016924f 100644 --- a/clippy_lints/src/methods/manual_inspect.rs +++ b/clippy_lints/src/methods/manual_inspect.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::{IntoSpan, SpanRangeExt}; +use clippy_utils::source::{SourceFileRange, SpanExt}; use clippy_utils::ty::get_field_by_name; use clippy_utils::visitors::{for_each_expr, for_each_expr_without_closures}; use clippy_utils::{ExprUseNode, expr_use_ctxt, is_diag_item_method, is_diag_trait_item, path_to_local_id, sym}; @@ -89,7 +89,7 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: }) .is_none(); - if ret_count != 0 { + if !can_lint || ret_count != 0 { // A return expression that didn't return the original value was found. return; } @@ -98,18 +98,25 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: let mut addr_of_edits = Vec::with_capacity(delayed.len()); for x in delayed { match x { - UseKind::Return(s) => edits.push((s.with_leading_whitespace(cx).with_ctxt(s.ctxt()), String::new())), + UseKind::Return(s) => { + if let Some(s) = s.map_range(cx, SourceFileRange::add_leading_whitespace) { + edits.push((s, String::new())); + } else { + return; + } + }, UseKind::Borrowed(s) => { - let range = s.map_range(cx, |_, src, range| { - let src = src.get(range.clone())?; - let trimmed = src.trim_start_matches([' ', '\t', '\n', '\r', '(']); - trimmed.starts_with('&').then(|| { - let pos = range.start + src.len() - trimmed.len(); - pos..pos + 1 + if let Some(s) = s.map_range(cx, |range| { + range.edit_range(|src, range| { + let src = src.get(range.clone())?; + let trimmed = src.trim_start_matches([' ', '\t', '\n', '\r', '(']); + trimmed.starts_with('&').then(|| { + let pos = range.start + src.len() - trimmed.len(); + pos..pos + 1 + }) }) - }); - if let Some(range) = range { - addr_of_edits.push((range.with_ctxt(s.ctxt()), String::new())); + }) { + addr_of_edits.push((s, String::new())); } else { requires_copy = true; requires_deref = true; @@ -156,10 +163,10 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: } } - if can_lint - && (!requires_copy || cx.type_is_copy_modulo_regions(arg_ty)) + if (!requires_copy || cx.type_is_copy_modulo_regions(arg_ty)) // This case could be handled, but a fair bit of care would need to be taken. && (!requires_deref || arg_ty.is_freeze(cx.tcx, cx.typing_env())) + && let Some(final_expr_span) = final_expr.span.map_range(cx, SourceFileRange::add_leading_whitespace) { if requires_deref { edits.push((param.span.shrink_to_lo(), "&".into())); @@ -172,13 +179,7 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: _ => return, }; edits.push((name_span, edit.to_string())); - edits.push(( - final_expr - .span - .with_leading_whitespace(cx) - .with_ctxt(final_expr.span.ctxt()), - String::new(), - )); + edits.push((final_expr_span, String::new())); let app = if edits.iter().any(|(s, _)| s.from_expansion()) { Applicability::MaybeIncorrect } else { diff --git a/clippy_lints/src/methods/manual_ok_or.rs b/clippy_lints/src/methods/manual_ok_or.rs index 077957fa44dc..15827e545400 100644 --- a/clippy_lints/src/methods/manual_ok_or.rs +++ b/clippy_lints/src/methods/manual_ok_or.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{SpanRangeExt, indent_of, reindent_multiline}; +use clippy_utils::source::{SpanExt, indent_of, reindent_multiline}; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{is_res_lang_ctor, path_res, path_to_local_id}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/manual_repeat_n.rs b/clippy_lints/src/methods/manual_repeat_n.rs index 83b57cca17bf..552cc91e7ea3 100644 --- a/clippy_lints/src/methods/manual_repeat_n.rs +++ b/clippy_lints/src/methods/manual_repeat_n.rs @@ -1,8 +1,7 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::{applicability_for_ctxt, span_lint_and_sugg}; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::{snippet, snippet_with_context}; +use clippy_utils::source::SpanExt; use clippy_utils::{expr_use_ctxt, fn_def_id, is_trait_method, std_or_core}; -use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_span::sym; @@ -24,20 +23,18 @@ pub(super) fn check<'tcx>( && !expr_use_ctxt(cx, expr).is_ty_unified && let Some(std_or_core) = std_or_core(cx) && msrv.meets(cx, msrvs::REPEAT_N) + && let ctxt = expr.span.ctxt() + && let Some(repeat_src) = repeat_arg.span.get_source_text_at_ctxt(cx, ctxt) + && let Some(take_src) = take_arg.span.get_source_text_at_ctxt(cx, ctxt) { - let mut app = Applicability::MachineApplicable; span_lint_and_sugg( cx, MANUAL_REPEAT_N, expr.span, "this `repeat().take()` can be written more concisely", "consider using `repeat_n()` instead", - format!( - "{std_or_core}::iter::repeat_n({}, {})", - snippet_with_context(cx, repeat_arg.span, expr.span.ctxt(), "..", &mut app).0, - snippet(cx, take_arg.span, "..") - ), - app, + format!("{std_or_core}::iter::repeat_n({}, {})", repeat_src, take_src), + applicability_for_ctxt(ctxt), ); } } diff --git a/clippy_lints/src/methods/manual_str_repeat.rs b/clippy_lints/src/methods/manual_str_repeat.rs index a811dd1cee18..8641ca9c4a76 100644 --- a/clippy_lints/src/methods/manual_str_repeat.rs +++ b/clippy_lints/src/methods/manual_str_repeat.rs @@ -1,10 +1,9 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::{applicability_for_ctxt, span_lint_and_sugg}; use clippy_utils::is_path_diagnostic_item; -use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; +use clippy_utils::source::{SpanExt, snippet_with_applicability}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use rustc_ast::LitKind; -use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem}; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; @@ -64,10 +63,9 @@ pub(super) fn check( && let ctxt = collect_expr.span.ctxt() && ctxt == take_expr.span.ctxt() && ctxt == take_self_arg.span.ctxt() + && let Some(count_snip) = take_arg.span.get_source_text_at_ctxt(cx, ctxt) { - let mut app = Applicability::MachineApplicable; - let count_snip = snippet_with_context(cx, take_arg.span, ctxt, "..", &mut app).0; - + let mut app = applicability_for_ctxt(ctxt); let val_str = match repeat_kind { RepeatKind::Char(_) if repeat_arg.span.ctxt() != ctxt => return, RepeatKind::Char('\'') => r#""'""#.into(), diff --git a/clippy_lints/src/methods/manual_try_fold.rs b/clippy_lints/src/methods/manual_try_fold.rs index 23dba47f60f4..7c4fef39f8d3 100644 --- a/clippy_lints/src/methods/manual_try_fold.rs +++ b/clippy_lints/src/methods/manual_try_fold.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::ty::implements_trait; use clippy_utils::{is_from_proc_macro, is_trait_method}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/map_all_any_identity.rs b/clippy_lints/src/methods/map_all_any_identity.rs index ac11baa2d54c..ef0e559a9ff7 100644 --- a/clippy_lints/src/methods/map_all_any_identity.rs +++ b/clippy_lints/src/methods/map_all_any_identity.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::{is_expr_identity_function, is_trait_method}; use rustc_errors::Applicability; use rustc_hir::Expr; diff --git a/clippy_lints/src/methods/needless_character_iteration.rs b/clippy_lints/src/methods/needless_character_iteration.rs index 71c1576cd57d..d968e1f3f100 100644 --- a/clippy_lints/src/methods/needless_character_iteration.rs +++ b/clippy_lints/src/methods/needless_character_iteration.rs @@ -7,7 +7,7 @@ use rustc_span::Span; use super::NEEDLESS_CHARACTER_ITERATION; use super::utils::get_last_chain_binding_hir_id; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::{is_path_diagnostic_item, path_to_local_id, peel_blocks, sym}; fn peels_expr_ref<'a, 'tcx>(mut expr: &'a Expr<'tcx>) -> &'a Expr<'tcx> { diff --git a/clippy_lints/src/methods/needless_option_as_deref.rs b/clippy_lints/src/methods/needless_option_as_deref.rs index d77d044340dc..7ceff05e69e6 100644 --- a/clippy_lints/src/methods/needless_option_as_deref.rs +++ b/clippy_lints/src/methods/needless_option_as_deref.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::usage::local_used_after_expr; use clippy_utils::{path_res, sym}; diff --git a/clippy_lints/src/methods/stable_sort_primitive.rs b/clippy_lints/src/methods/stable_sort_primitive.rs index 17d1a6abde0a..ddb4d51159a9 100644 --- a/clippy_lints/src/methods/stable_sort_primitive.rs +++ b/clippy_lints/src/methods/stable_sort_primitive.rs @@ -1,7 +1,6 @@ -use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::diagnostics::{applicability_for_ctxt, span_lint_and_then}; use clippy_utils::is_slice_of_primitives; -use clippy_utils::source::snippet_with_context; -use rustc_errors::Applicability; +use clippy_utils::source::SpanExt; use rustc_hir::Expr; use rustc_lint::LateContext; @@ -12,6 +11,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, recv: &'tcx && let Some(impl_id) = cx.tcx.impl_of_assoc(method_id) && cx.tcx.type_of(impl_id).instantiate_identity().is_slice() && let Some(slice_type) = is_slice_of_primitives(cx, recv) + && let ctxt = e.span.ctxt() + && let Some(recv_snip) = recv.span.get_source_text_at_ctxt(cx, ctxt) { span_lint_and_then( cx, @@ -19,9 +20,12 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, recv: &'tcx e.span, format!("used `sort` on primitive type `{slice_type}`"), |diag| { - let mut app = Applicability::MachineApplicable; - let recv_snip = snippet_with_context(cx, recv.span, e.span.ctxt(), "..", &mut app).0; - diag.span_suggestion(e.span, "try", format!("{recv_snip}.sort_unstable()"), app); + diag.span_suggestion( + e.span, + "try", + format!("{recv_snip}.sort_unstable()"), + applicability_for_ctxt(ctxt), + ); diag.note( "an unstable sort typically performs faster without any observable difference for this data type", ); diff --git a/clippy_lints/src/methods/str_split.rs b/clippy_lints/src/methods/str_split.rs index 479064a0671e..ea26711f8ad1 100644 --- a/clippy_lints/src/methods/str_split.rs +++ b/clippy_lints/src/methods/str_split.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_context; +use clippy_utils::source::SpanExt; use clippy_utils::sym; use clippy_utils::visitors::is_const_evaluatable; use rustc_ast::ast::LitKind; @@ -21,6 +21,7 @@ pub(super) fn check<'a>(cx: &LateContext<'a>, expr: &'_ Expr<'_>, split_recv: &' && let ExprKind::Lit(split_lit) = split_arg.kind && (matches!(split_lit.node, LitKind::Char('\n')) || matches!(split_lit.node, LitKind::Str(sym::LF | sym::CRLF, _))) + && let Some(src) = trim_recv.span.get_source_text_at_ctxt(cx, expr.span.ctxt()) { let mut app = Applicability::MaybeIncorrect; span_lint_and_sugg( @@ -29,11 +30,8 @@ pub(super) fn check<'a>(cx: &LateContext<'a>, expr: &'_ Expr<'_>, split_recv: &' expr.span, "using `str.trim().split()` with hard-coded newlines", "use `str.lines()` instead", - format!( - "{}.lines()", - snippet_with_context(cx, trim_recv.span, expr.span.ctxt(), "..", &mut app).0 - ), - app, + format!("{}.lines()", src), + Applicability::MaybeIncorrect, ); } } diff --git a/clippy_lints/src/methods/string_lit_chars_any.rs b/clippy_lints/src/methods/string_lit_chars_any.rs index f0f9d30d3000..0de3460dcb40 100644 --- a/clippy_lints/src/methods/string_lit_chars_any.rs +++ b/clippy_lints/src/methods/string_lit_chars_any.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::{is_from_proc_macro, is_trait_method, path_to_local}; use itertools::Itertools; use rustc_ast::LitKind; diff --git a/clippy_lints/src/methods/suspicious_to_owned.rs b/clippy_lints/src/methods/suspicious_to_owned.rs index ffc237e3c24c..c4319521be1c 100644 --- a/clippy_lints/src/methods/suspicious_to_owned.rs +++ b/clippy_lints/src/methods/suspicious_to_owned.rs @@ -1,8 +1,7 @@ -use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::diagnostics::{applicability_for_ctxt, span_lint_and_then}; use clippy_utils::is_diag_trait_item; -use clippy_utils::source::snippet_with_context; +use clippy_utils::source::SpanExt; use clippy_utils::ty::is_type_diagnostic_item; -use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty::print::with_forced_trimmed_paths; @@ -15,9 +14,9 @@ pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) - && is_diag_trait_item(cx, method_def_id, sym::ToOwned) && let input_type = cx.typeck_results().expr_ty(expr) && is_type_diagnostic_item(cx, input_type, sym::Cow) + && let ctxt = expr.span.ctxt() + && let Some(recv_snip) = recv.span.get_source_text_at_ctxt(cx, ctxt) { - let mut app = Applicability::MaybeIncorrect; - let recv_snip = snippet_with_context(cx, recv.span, expr.span.ctxt(), "..", &mut app).0; span_lint_and_then( cx, SUSPICIOUS_TO_OWNED, @@ -26,6 +25,7 @@ pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) - "this `to_owned` call clones the {input_type} itself and does not cause the {input_type} contents to become owned" )), |diag| { + let app = applicability_for_ctxt(ctxt); diag.span_suggestion( expr.span, "depending on intent, either make the Cow an Owned variant", diff --git a/clippy_lints/src/methods/unnecessary_first_then_check.rs b/clippy_lints/src/methods/unnecessary_first_then_check.rs index d322909bef35..9c5768dfb6f5 100644 --- a/clippy_lints/src/methods/unnecessary_first_then_check.rs +++ b/clippy_lints/src/methods/unnecessary_first_then_check.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; diff --git a/clippy_lints/src/methods/unnecessary_get_then_check.rs b/clippy_lints/src/methods/unnecessary_get_then_check.rs index 39fce2c40c91..fa5a944ee5c8 100644 --- a/clippy_lints/src/methods/unnecessary_get_then_check.rs +++ b/clippy_lints/src/methods/unnecessary_get_then_check.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/clippy_lints/src/methods/unnecessary_iter_cloned.rs index 20cf35363d13..1f169919779a 100644 --- a/clippy_lints/src/methods/unnecessary_iter_cloned.rs +++ b/clippy_lints/src/methods/unnecessary_iter_cloned.rs @@ -1,7 +1,7 @@ use super::utils::clone_or_copy_needed; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::ForLoop; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::ty::{get_iterator_item_ty, implements_trait}; use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{can_mut_borrow_both, fn_def_id, get_parent_expr, path_to_local}; diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 640931a82899..08e78b0fde24 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -2,7 +2,7 @@ use super::implicit_clone::is_clone_like; use super::unnecessary_iter_cloned::{self, is_into_iter}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::{SpanRangeExt, snippet}; +use clippy_utils::source::{SpanExt, snippet}; use clippy_utils::ty::{ get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, is_type_lang_item, peel_and_count_ty_refs, }; diff --git a/clippy_lints/src/methods/unused_enumerate_index.rs b/clippy_lints/src/methods/unused_enumerate_index.rs index af4ade3cc0f7..90a3cebd61fb 100644 --- a/clippy_lints/src/methods/unused_enumerate_index.rs +++ b/clippy_lints/src/methods/unused_enumerate_index.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; -use clippy_utils::source::{SpanRangeExt, snippet}; +use clippy_utils::source::{SpanExt, snippet}; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{expr_or_init, is_trait_method, pat_is_wild}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/misc_early/unneeded_field_pattern.rs b/clippy_lints/src/misc_early/unneeded_field_pattern.rs index 33ab94e00a5c..b2ee3f0c24f1 100644 --- a/clippy_lints/src/misc_early/unneeded_field_pattern.rs +++ b/clippy_lints/src/misc_early/unneeded_field_pattern.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use itertools::Itertools; use rustc_ast::ast::{Pat, PatKind}; use rustc_lint::EarlyContext; diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index 7772051eb5c6..92282dc4f544 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/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_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,113 +57,45 @@ 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 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 - } - } - - 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; - } - - // `#[doc(hidden)]` disables missing_docs check. - if self.doc_hidden() { - return; - } - - if sp.from_expansion() { - 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()) { - return; - } - } else if def_id != CRATE_DEF_ID && cx.effective_visibilities.is_exported(def_id) { - 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; + fn is_missing_docs(&self, cx: &LateContext<'_>, def_id: LocalDefId, hir_id: HirId) -> bool { + if cx.tcx.sess.opts.test { + return false; } - 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)); - - if !has_doc { - span_lint( - cx, - MISSING_DOCS_IN_PRIVATE_ITEMS, - sp, - format!("missing documentation for {article} {desc}"), - ); + 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 => {}, } - } - /// 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) + !cx.tcx.hir_attrs(hir_id).iter().any(is_doc_attr) } } @@ -176,112 +103,192 @@ 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); + self.attr_depth += 1; + if self.doc_hidden_depth == 0 && is_doc_hidden(attrs) { + self.doc_hidden_depth = self.attr_depth; + } } 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"); + 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; + } } - fn check_crate_post(&mut self, _: &LateContext<'tcx>) { - self.prev_span = None; - } + 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; + } - 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); - } + 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; + }, + 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; }, - hir::ItemKind::Const(ident, ..) => { - if ident.name == kw::Underscore { - note_prev_span_then_ret!(self.prev_span, it.span); + ItemKind::ExternCrate(..) + | ItemKind::ForeignMod { .. } + | ItemKind::GlobalAsm { .. } + | ItemKind::Use(..) => 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 }, - 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), - } - let (article, desc) = cx.tcx.article_and_description(it.owner_id.to_def_id()); + 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, + }; - 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); + if !item.span.from_expansion() + && self.is_missing_docs(cx, item.owner_id.def_id, item.hir_id()) + && !is_from_proc_macro(cx, item) + { + span_lint( + cx, + MISSING_DOCS_IN_PRIVATE_ITEMS, + span, + "missing documentation for item", + ); + } + if matches!(item.kind, ItemKind::Mod(..)) { + self.module_depth += 1; } - 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()); + 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 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_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) + { + span_lint( + cx, + MISSING_DOCS_IN_PRIVATE_ITEMS, + item.ident.span, + "missing documentation for trait item", + ); } - 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. - if let Some(cid) = cx.tcx.associated_item(impl_item.owner_id).impl_container(cx.tcx) { - if cx.tcx.impl_trait_ref(cid).is_some() { - note_prev_span_then_ret!(self.prev_span, impl_item.span); - } - } else { - note_prev_span_then_ret!(self.prev_span, impl_item.span); + 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) + { + span_lint( + cx, + MISSING_DOCS_IN_PRIVATE_ITEMS, + item.ident.span, + "missing documentation for impl item", + ); } + } - 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(&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()); } - 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_body_post(&mut self, _: &LateContext<'tcx>, body: &Body<'tcx>) { + if self.in_body == Some(body.id()) { + self.in_body = None; + } + } + + 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 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 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/clippy_lints/src/missing_enforced_import_rename.rs b/clippy_lints/src/missing_enforced_import_rename.rs index eeea6dfd5f4b..c1c6ff13c6c5 100644 --- a/clippy_lints/src/missing_enforced_import_rename.rs +++ b/clippy_lints/src/missing_enforced_import_rename.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::paths::{PathNS, lookup_path_str}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::def_id::DefIdMap; diff --git a/clippy_lints/src/multiple_bound_locations.rs b/clippy_lints/src/multiple_bound_locations.rs index 741f38f97560..0b610d1bd372 100644 --- a/clippy_lints/src/multiple_bound_locations.rs +++ b/clippy_lints/src/multiple_bound_locations.rs @@ -6,7 +6,7 @@ use rustc_session::declare_lint_pass; use rustc_span::Span; use clippy_utils::diagnostics::span_lint; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; declare_clippy_lint! { /// ### What it does @@ -57,7 +57,8 @@ impl EarlyLintPass for MultipleBoundLocations { && let Some(Some(bound_span)) = pred .bounded_ty .span - .with_source_text(cx, |src| generic_params_with_bounds.get(src)) + .get_source_text(cx) + .map(|src| generic_params_with_bounds.get(&*src)) { emit_lint(cx, *bound_span, pred.bounded_ty.span); } diff --git a/clippy_lints/src/needless_borrows_for_generic_args.rs b/clippy_lints/src/needless_borrows_for_generic_args.rs index c7c4976aeb7b..53bf00f2ff47 100644 --- a/clippy_lints/src/needless_borrows_for_generic_args.rs +++ b/clippy_lints/src/needless_borrows_for_generic_args.rs @@ -1,11 +1,10 @@ use clippy_config::Conf; -use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::diagnostics::{applicability_for_ctxt, span_lint_and_then}; use clippy_utils::mir::{PossibleBorrowerMap, enclosing_mir, expr_local, local_assignments, used_exactly_once}; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::snippet_with_context; +use clippy_utils::source::SpanExt; use clippy_utils::ty::{implements_trait, is_copy}; use clippy_utils::{DefinedTy, ExprUseNode, expr_use_ctxt, peel_n_hir_expr_refs}; -use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{Body, Expr, ExprKind, Mutability, Path, QPath}; @@ -117,6 +116,11 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowsForGenericArgs<'tcx> { self.msrv, ) && count != 0 + && let ctxt = expr.span.ctxt() + && let Some(snip) = peel_n_hir_expr_refs(expr, count) + .0 + .span + .get_source_text_at_ctxt(cx, ctxt) { span_lint_and_then( cx, @@ -124,10 +128,12 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowsForGenericArgs<'tcx> { expr.span, "the borrowed expression implements the required traits", |diag| { - let mut app = Applicability::MachineApplicable; - let snip_span = peel_n_hir_expr_refs(expr, count).0.span; - let snip = snippet_with_context(cx, snip_span, expr.span.ctxt(), "..", &mut app).0; - diag.span_suggestion(expr.span, "change this to", snip.into_owned(), app); + diag.span_suggestion( + expr.span, + "change this to", + snip.to_owned(), + applicability_for_ctxt(ctxt), + ); }, ); } diff --git a/clippy_lints/src/needless_else.rs b/clippy_lints/src/needless_else.rs index f8bb72a16db2..d457e0757923 100644 --- a/clippy_lints/src/needless_else.rs +++ b/clippy_lints/src/needless_else.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{IntoSpan, SpanRangeExt}; +use clippy_utils::source::SpanExt; use rustc_ast::ast::{Expr, ExprKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; @@ -38,19 +38,34 @@ impl EarlyLintPass for NeedlessElse { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { if let ExprKind::If(_, then_block, Some(else_clause)) = &expr.kind && let ExprKind::Block(block, _) = &else_clause.kind + && !then_block.span.from_expansion() && !expr.span.from_expansion() && !else_clause.span.from_expansion() && block.stmts.is_empty() - && let range = (then_block.span.hi()..expr.span.hi()).trim_start(cx) - && range.clone().check_source_text(cx, |src| { - // Ignore else blocks that contain comments or #[cfg]s - !src.contains(['/', '#']) + // Only take the span of `else { .. }` if no comments/cfgs/macros exist. + && let Some(lint_sp) = else_clause.span.map_range(cx, |range| { + range.set_start_if_before(then_block.span.hi())?.edit_range(|text, range| { + let text = text.get(range.clone())?; + let trimmed = text.trim_start(); + if trimmed + .strip_prefix("else")? + .trim_start() + .strip_prefix('{')? + .strip_suffix('}')? + .chars() + .all(char::is_whitespace) + { + Some(range.start + (text.len() - trimmed.len())..range.end) + } else { + None + } + }) }) { span_lint_and_sugg( cx, NEEDLESS_ELSE, - range.with_ctxt(expr.span.ctxt()), + lint_sp, "this `else` branch is empty", "you can remove it", String::new(), diff --git a/clippy_lints/src/needless_if.rs b/clippy_lints/src/needless_if.rs index c90019f6ee16..417b5e1dac71 100644 --- a/clippy_lints/src/needless_if.rs +++ b/clippy_lints/src/needless_if.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::higher::If; use clippy_utils::is_from_proc_macro; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_errors::Applicability; use rustc_hir::{ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; diff --git a/clippy_lints/src/needless_late_init.rs b/clippy_lints/src/needless_late_init.rs index a914267cf500..3c20f6861814 100644 --- a/clippy_lints/src/needless_late_init.rs +++ b/clippy_lints/src/needless_late_init.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::path_to_local; -use clippy_utils::source::{SourceText, SpanRangeExt, snippet}; +use clippy_utils::source::{SourceText, SpanExt, snippet}; use clippy_utils::ty::needs_ordered_drop; use clippy_utils::visitors::{for_each_expr, for_each_expr_without_closures, is_local_used}; use core::ops::ControlFlow; diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 32ded96c1236..f8e951bbbb5a 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ptr::get_spans; -use clippy_utils::source::{SpanRangeExt, snippet}; +use clippy_utils::source::{SpanExt, snippet}; use clippy_utils::ty::{ implements_trait, implements_trait_with_env_from_iter, is_copy, is_type_diagnostic_item, is_type_lang_item, }; diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index 0d6666eed455..d6adb8d7e932 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::ty::{expr_type_is_certain, has_drop}; use clippy_utils::{ in_automatically_derived, is_inside_always_const_context, is_lint_allowed, path_to_local, peel_blocks, diff --git a/clippy_lints/src/non_octal_unix_permissions.rs b/clippy_lints/src/non_octal_unix_permissions.rs index cb934466bd89..72ebe13562be 100644 --- a/clippy_lints/src/non_octal_unix_permissions.rs +++ b/clippy_lints/src/non_octal_unix_permissions.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{SpanRangeExt, snippet_with_applicability}; +use clippy_utils::source::{SpanExt, snippet_with_applicability}; use clippy_utils::sym; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; diff --git a/clippy_lints/src/nonstandard_macro_braces.rs b/clippy_lints/src/nonstandard_macro_braces.rs index 83f7d9319697..825bb2151107 100644 --- a/clippy_lints/src/nonstandard_macro_braces.rs +++ b/clippy_lints/src/nonstandard_macro_braces.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_config::types::MacroMatcher; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{SourceText, SpanRangeExt}; +use clippy_utils::source::{SourceText, SpanExt}; use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/octal_escapes.rs b/clippy_lints/src/octal_escapes.rs index 6e7ee727965d..2ac9e010c69c 100644 --- a/clippy_lints/src/octal_escapes.rs +++ b/clippy_lints/src/octal_escapes.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_ast::token::LitKind; use rustc_ast::{Expr, ExprKind}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/operators/assign_op_pattern.rs b/clippy_lints/src/operators/assign_op_pattern.rs index 2d303e40bd1c..d2b08bee8c94 100644 --- a/clippy_lints/src/operators/assign_op_pattern.rs +++ b/clippy_lints/src/operators/assign_op_pattern.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::Msrv; use clippy_utils::qualify_min_const_fn::is_stable_const_fn; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::ty::implements_trait; use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{binop_traits, eq_expr_value, is_in_const_context, trait_ref_of_method}; diff --git a/clippy_lints/src/operators/misrefactored_assign_op.rs b/clippy_lints/src/operators/misrefactored_assign_op.rs index 8daedd1c9014..06f7cfec05ce 100644 --- a/clippy_lints/src/operators/misrefactored_assign_op.rs +++ b/clippy_lints/src/operators/misrefactored_assign_op.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::{eq_expr_value, sugg}; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/operators/needless_bitwise_bool.rs b/clippy_lints/src/operators/needless_bitwise_bool.rs index 9d8e833ef6d7..8f41ade58313 100644 --- a/clippy_lints/src/operators/needless_bitwise_bool.rs +++ b/clippy_lints/src/operators/needless_bitwise_bool.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; diff --git a/clippy_lints/src/pathbuf_init_then_push.rs b/clippy_lints/src/pathbuf_init_then_push.rs index 4ce6827cac9b..4c0c07cb68b3 100644 --- a/clippy_lints/src/pathbuf_init_then_push.rs +++ b/clippy_lints/src/pathbuf_init_then_push.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{SpanRangeExt, snippet}; +use clippy_utils::source::{SpanExt, snippet}; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{path_to_local_id, sym}; use rustc_ast::{LitKind, StrStyle}; diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 9eed46460a61..23895db606d5 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then, span_lint_hir_and_then}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::sugg::Sugg; use clippy_utils::visitors::contains_unsafe_block; use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, path_def_id, path_to_local, std_or_core, sym}; diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 03d00ba849f3..e6b2a504f08e 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -2,7 +2,7 @@ use clippy_config::Conf; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::{SpanRangeExt, snippet, snippet_with_applicability}; +use clippy_utils::source::{SpanExt, snippet, snippet_with_applicability}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::implements_trait; use clippy_utils::{ @@ -17,7 +17,7 @@ use rustc_lint::{LateContext, LateLintPass, Lint}; use rustc_middle::ty::{self, ClauseKind, GenericArgKind, PredicatePolarity, Ty}; use rustc_session::impl_lint_pass; use rustc_span::source_map::Spanned; -use rustc_span::{Span, sym}; +use rustc_span::{Span, SyntaxContext, sym}; use std::cmp::Ordering; declare_clippy_lint! { @@ -187,8 +187,11 @@ impl<'tcx> LateLintPass<'tcx> for Ranges { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if let ExprKind::Binary(ref op, l, r) = expr.kind && self.msrv.meets(cx, msrvs::RANGE_CONTAINS) + && let ctxt = expr.span.ctxt() + && l.span.ctxt() == ctxt + && r.span.ctxt() == ctxt { - check_possible_range_contains(cx, op.node, l, r, expr, expr.span); + check_possible_range_contains(cx, op.node, l, r, expr.span, expr.span.ctxt()); } check_exclusive_range_plus_one(cx, expr); @@ -202,8 +205,8 @@ fn check_possible_range_contains( op: BinOpKind, left: &Expr<'_>, right: &Expr<'_>, - expr: &Expr<'_>, span: Span, + ctxt: SyntaxContext, ) { if is_in_const_context(cx) { return; @@ -289,13 +292,22 @@ fn check_possible_range_contains( // the same operator precedence if let ExprKind::Binary(ref lhs_op, _left, new_lhs) = left.kind && op == lhs_op.node - && let new_span = Span::new(new_lhs.span.lo(), right.span.hi(), expr.span.ctxt(), expr.span.parent()) - && new_span.check_source_text(cx, |src| { - // Do not continue if we have mismatched number of parens, otherwise the suggestion is wrong - src.matches('(').count() == src.matches(')').count() + && let new_lhs_data = new_lhs.span.data() + && new_lhs_data.ctxt == ctxt + && let Some(new_data) = new_lhs_data.map_range(cx, |file| { + file.set_end_if_after(right.span.hi())?; + let src = file.current_text()?; + (src.matches('(').count() == src.matches(')').count()).then_some(file) }) { - check_possible_range_contains(cx, op, new_lhs, right, expr, new_span); + check_possible_range_contains( + cx, + op, + new_lhs, + right, + Span::new(new_data.lo, new_data.hi, new_data.ctxt, new_data.parent), + ctxt, + ); } } @@ -522,7 +534,10 @@ fn check_range_switch<'tcx>( .to_string() }); let end = Sugg::hir_with_applicability(cx, y, "", &mut app).maybe_paren(); - match span.with_source_text(cx, |src| src.starts_with('(') && src.ends_with(')')) { + match span + .get_source_text(cx) + .map(|src| src.starts_with('(') && src.ends_with(')')) + { Some(true) => { diag.span_suggestion(span, "use", format!("({start}{operator}{end})"), app); }, diff --git a/clippy_lints/src/raw_strings.rs b/clippy_lints/src/raw_strings.rs index 943e662479e9..b29810a5c013 100644 --- a/clippy_lints/src/raw_strings.rs +++ b/clippy_lints/src/raw_strings.rs @@ -1,6 +1,6 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{SpanRangeExt, snippet_opt}; +use clippy_utils::source::{SpanExt, snippet_opt}; use rustc_ast::ast::{Expr, ExprKind}; use rustc_ast::token::LitKind; use rustc_errors::Applicability; diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index de6766cbe94a..e479c2059f85 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then}; use clippy_utils::fn_has_unsatisfiable_preds; use clippy_utils::mir::{LocalUsage, PossibleBorrowerMap, visit_local_usage}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::ty::{has_drop, is_copy, is_type_lang_item, peel_and_count_ty_refs}; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; diff --git a/clippy_lints/src/redundant_pub_crate.rs b/clippy_lints/src/redundant_pub_crate.rs index 0c1c664f1117..047e5780f3d7 100644 --- a/clippy_lints/src/redundant_pub_crate.rs +++ b/clippy_lints/src/redundant_pub_crate.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::HasSession; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Item, ItemKind, UseKind}; @@ -49,7 +48,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate { && !cx.effective_visibilities.is_exported(item.owner_id.def_id) && self.is_exported.last() == Some(&false) && !is_ignorable_export(item) - && !item.span.in_external_macro(cx.sess().source_map()) + && !item.span.in_external_macro(cx.tcx.sess.source_map()) { let span = item .kind diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index 89d945161f62..3f1d871e7856 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -3,7 +3,7 @@ use std::fmt::Display; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::paths::PathLookup; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::{path_def_id, paths}; use rustc_ast::ast::{LitKind, StrStyle}; use rustc_hir::def_id::DefIdMap; diff --git a/clippy_lints/src/returns/let_and_return.rs b/clippy_lints/src/returns/let_and_return.rs index e2002fb36e5a..fb498629f324 100644 --- a/clippy_lints/src/returns/let_and_return.rs +++ b/clippy_lints/src/returns/let_and_return.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::sugg::has_enclosing_paren; use clippy_utils::visitors::for_each_expr; use clippy_utils::{binary_expr_needs_parentheses, fn_def_id, path_to_local_id, span_contains_cfg}; diff --git a/clippy_lints/src/semicolon_block.rs b/clippy_lints/src/semicolon_block.rs index 371d62a06849..d7d77097a490 100644 --- a/clippy_lints/src/semicolon_block.rs +++ b/clippy_lints/src/semicolon_block.rs @@ -1,6 +1,6 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_errors::Applicability; use rustc_hir::{Block, Expr, ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; diff --git a/clippy_lints/src/semicolon_if_nothing_returned.rs b/clippy_lints/src/semicolon_if_nothing_returned.rs index 63237c655ef1..daa782b03035 100644 --- a/clippy_lints/src/semicolon_if_nothing_returned.rs +++ b/clippy_lints/src/semicolon_if_nothing_returned.rs @@ -1,6 +1,5 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_context; -use rustc_errors::Applicability; +use clippy_utils::diagnostics::{applicability_for_ctxt, span_lint_and_sugg}; +use clippy_utils::source::SpanExt; use rustc_hir::{Block, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::declare_lint_pass; @@ -42,8 +41,8 @@ impl<'tcx> LateLintPass<'tcx> for SemicolonIfNothingReturned { && !from_attr_macro(expr.span) && let t_expr = cx.typeck_results().expr_ty(expr) && t_expr.is_unit() - && let mut app = Applicability::MachineApplicable - && let snippet = snippet_with_context(cx, expr.span, block.span.ctxt(), "}", &mut app).0 + && let ctxt = block.span.ctxt() + && let Some(snippet) = expr.span.get_source_text_at_ctxt(cx, ctxt) && !snippet.ends_with('}') && !snippet.ends_with(';') && cx.sess().source_map().is_multiline(block.span) @@ -59,7 +58,7 @@ impl<'tcx> LateLintPass<'tcx> for SemicolonIfNothingReturned { "consider adding a `;` to the last statement for consistent formatting", "add a `;` here", format!("{snippet};"), - app, + applicability_for_ctxt(ctxt), ); } } diff --git a/clippy_lints/src/single_range_in_vec_init.rs b/clippy_lints/src/single_range_in_vec_init.rs index dda2f8cc1d00..84bc3a554878 100644 --- a/clippy_lints/src/single_range_in_vec_init.rs +++ b/clippy_lints/src/single_range_in_vec_init.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::VecArgs; use clippy_utils::macros::root_macro_call_first_node; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::ty::implements_trait; use clippy_utils::{is_no_std_crate, sym}; use rustc_ast::{LitIntType, LitKind, UintTy}; diff --git a/clippy_lints/src/strlen_on_c_strings.rs b/clippy_lints/src/strlen_on_c_strings.rs index 33856c750d7e..eb216900ceba 100644 --- a/clippy_lints/src/strlen_on_c_strings.rs +++ b/clippy_lints/src/strlen_on_c_strings.rs @@ -1,9 +1,8 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_context; +use clippy_utils::diagnostics::{applicability_for_ctxt, span_lint_and_sugg}; +use clippy_utils::source::SpanExt; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use clippy_utils::visitors::is_expr_unsafe; use clippy_utils::{match_libc_symbol, sym}; -use rustc_errors::Applicability; use rustc_hir::{Block, BlockCheckMode, Expr, ExprKind, LangItem, Node, UnsafeSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -47,8 +46,17 @@ impl<'tcx> LateLintPass<'tcx> for StrlenOnCStrings { && let ExprKind::MethodCall(path, self_arg, [], _) = recv.kind && !recv.span.from_expansion() && path.ident.name == sym::as_ptr + && let ty = cx.typeck_results().expr_ty(self_arg).peel_refs() + && let method_name = if is_type_diagnostic_item(cx, ty, sym::cstring_type) { + "as_bytes" + } else if is_type_lang_item(cx, ty, LangItem::CStr) { + "to_bytes" + } else { + return; + } + && let ctxt = expr.span.ctxt() + && let Some(val_name) = self_arg.span.get_source_text_at_ctxt(cx, ctxt) { - let ctxt = expr.span.ctxt(); let span = match cx.tcx.parent_hir_node(expr.hir_id) { Node::Block(&Block { rules: BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided), @@ -57,18 +65,6 @@ impl<'tcx> LateLintPass<'tcx> for StrlenOnCStrings { }) if span.ctxt() == ctxt && !is_expr_unsafe(cx, self_arg) => span, _ => expr.span, }; - - let ty = cx.typeck_results().expr_ty(self_arg).peel_refs(); - let mut app = Applicability::MachineApplicable; - let val_name = snippet_with_context(cx, self_arg.span, ctxt, "..", &mut app).0; - let method_name = if is_type_diagnostic_item(cx, ty, sym::cstring_type) { - "as_bytes" - } else if is_type_lang_item(cx, ty, LangItem::CStr) { - "to_bytes" - } else { - return; - }; - span_lint_and_sugg( cx, STRLEN_ON_C_STRINGS, @@ -76,7 +72,7 @@ impl<'tcx> LateLintPass<'tcx> for StrlenOnCStrings { "using `libc::strlen` on a `CString` or `CStr` value", "try", format!("{val_name}.{method_name}().len()"), - app, + applicability_for_ctxt(ctxt), ); } } diff --git a/clippy_lints/src/swap_ptr_to_ref.rs b/clippy_lints/src/swap_ptr_to_ref.rs index ff196355a2e3..43cd634c0842 100644 --- a/clippy_lints/src/swap_ptr_to_ref.rs +++ b/clippy_lints/src/swap_ptr_to_ref.rs @@ -1,7 +1,6 @@ -use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::diagnostics::{applicability_for_ctxt, span_lint_and_then}; use clippy_utils::path_def_id; -use clippy_utils::source::snippet_with_context; -use rustc_errors::Applicability; +use clippy_utils::source::SpanExt; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -54,15 +53,15 @@ impl LateLintPass<'_> for SwapPtrToRef { e.span, "call to `core::mem::swap` with a parameter derived from a raw pointer", |diag| { - if !((from_ptr1 && arg1_span.is_none()) || (from_ptr2 && arg2_span.is_none())) { - let mut app = Applicability::MachineApplicable; - let snip1 = snippet_with_context(cx, arg1_span.unwrap_or(arg1.span), ctxt, "..", &mut app).0; - let snip2 = snippet_with_context(cx, arg2_span.unwrap_or(arg2.span), ctxt, "..", &mut app).0; + if !((from_ptr1 && arg1_span.is_none()) || (from_ptr2 && arg2_span.is_none())) + && let Some(snip1) = arg1_span.unwrap_or(arg1.span).get_source_text_at_ctxt(cx, ctxt) + && let Some(snip2) = arg2_span.unwrap_or(arg2.span).get_source_text_at_ctxt(cx, ctxt) + { diag.span_suggestion( e.span, "use ptr::swap", format!("core::ptr::swap({snip1}, {snip2})"), - app, + applicability_for_ctxt(ctxt), ); } }, diff --git a/clippy_lints/src/toplevel_ref_arg.rs b/clippy_lints/src/toplevel_ref_arg.rs index 074b79263d37..7b4363a5f9de 100644 --- a/clippy_lints/src/toplevel_ref_arg.rs +++ b/clippy_lints/src/toplevel_ref_arg.rs @@ -1,8 +1,7 @@ -use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then}; -use clippy_utils::source::{snippet, snippet_with_context}; +use clippy_utils::diagnostics::{applicability_for_ctxt, span_lint_hir, span_lint_hir_and_then}; +use clippy_utils::source::{SpanExt, snippet}; use clippy_utils::sugg::Sugg; use clippy_utils::{is_lint_allowed, iter_input_pats}; -use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{BindingMode, Body, ByRef, FnDecl, Mutability, PatKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -87,14 +86,16 @@ impl<'tcx> LateLintPass<'tcx> for ToplevelRefArg { && !stmt.span.in_external_macro(cx.tcx.sess.source_map()) { let ctxt = local.span.ctxt(); - let mut app = Applicability::MachineApplicable; + let mut app = applicability_for_ctxt(ctxt); let sugg_init = Sugg::hir_with_context(cx, init, ctxt, "..", &mut app); let (mutopt, initref) = match mutabl { Mutability::Mut => ("mut ", sugg_init.mut_addr()), Mutability::Not => ("", sugg_init.addr()), }; let tyopt = if let Some(ty) = local.ty { - let ty_snip = snippet_with_context(cx, ty.span, ctxt, "_", &mut app).0; + let Some(ty_snip) = ty.span.get_source_text_at_ctxt(cx, ctxt) else { + return; + }; format!(": &{mutopt}{ty_snip}") } else { String::new() diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index 9182a55081f4..6f866a64ceaa 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::{SpanRangeExt, snippet, snippet_with_applicability}; +use clippy_utils::source::{SpanExt, snippet, snippet_with_applicability}; use clippy_utils::{SpanlessEq, SpanlessHash, is_from_proc_macro}; use core::hash::{Hash, Hasher}; use itertools::Itertools; diff --git a/clippy_lints/src/transmute/missing_transmute_annotations.rs b/clippy_lints/src/transmute/missing_transmute_annotations.rs index 543f3c45e146..692fe5559943 100644 --- a/clippy_lints/src/transmute/missing_transmute_annotations.rs +++ b/clippy_lints/src/transmute/missing_transmute_annotations.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{HasSession, SpanRangeExt as _}; +use clippy_utils::source::SpanExt; use rustc_errors::Applicability; use rustc_hir::{Expr, GenericArg, HirId, LetStmt, Node, Path, TyKind}; use rustc_lint::LateContext; @@ -111,10 +111,8 @@ fn ty_cannot_be_named(ty: Ty<'_>) -> bool { ) } -fn maybe_name_by_expr<'a>(sess: &impl HasSession, span: Span, default: &'a str) -> Cow<'a, str> { - span.with_source_text(sess, |name| { - (name.len() + 9 < default.len()).then_some(format!("`{name}`'s type").into()) - }) - .flatten() - .unwrap_or(default.into()) +fn maybe_name_by_expr<'a>(cx: &LateContext<'_>, span: Span, default: &'a str) -> Cow<'a, str> { + span.get_source_text(cx) + .filter(|name| name.len() + 9 < default.len()) + .map_or(default.into(), |name| format!("`{name}`'s type").into()) } diff --git a/clippy_lints/src/unit_types/let_unit_value.rs b/clippy_lints/src/unit_types/let_unit_value.rs index d5b6c1758549..c0792434f089 100644 --- a/clippy_lints/src/unit_types/let_unit_value.rs +++ b/clippy_lints/src/unit_types/let_unit_value.rs @@ -1,6 +1,6 @@ -use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::diagnostics::{applicability_for_ctxt, span_lint_and_then}; use clippy_utils::macros::{FormatArgsStorage, find_format_arg_expr, is_format_macro, root_macro_call_first_node}; -use clippy_utils::source::{indent_of, reindent_multiline, snippet_with_context}; +use clippy_utils::source::{SpanExt, indent_of, reindent_multiline}; use clippy_utils::visitors::{for_each_local_assignment, for_each_value_source}; use core::ops::ControlFlow; use rustc_ast::{FormatArgs, FormatArgumentKind}; @@ -24,7 +24,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, format_args: &FormatArgsStorag if let Some(init) = local.init && !local.pat.span.from_expansion() - && !local.span.in_external_macro(cx.sess().source_map()) + && let ctxt = local.span.ctxt() + && !ctxt.in_external_macro(cx.sess().source_map()) && !local.span.is_from_async_await() && cx.typeck_results().pat_ty(local.pat).is_unit() { @@ -62,11 +63,9 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, format_args: &FormatArgsStorag }, ); } - } else { - if let ExprKind::Match(_, _, MatchSource::AwaitDesugar) = init.kind { - return; - } - + } else if !matches!(init.kind, ExprKind::Match(_, _, MatchSource::AwaitDesugar)) + && let Some(src) = init.span.get_source_text_at_ctxt(cx, ctxt) + { span_lint_and_then( cx, LET_UNIT_VALUE, @@ -74,10 +73,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, format_args: &FormatArgsStorag "this let-binding has unit value", |diag| { let mut suggestions = Vec::new(); - - // Suggest omitting the `let` binding - let mut app = Applicability::MachineApplicable; - let snip = snippet_with_context(cx, init.span, local.span.ctxt(), "()", &mut app).0; + let app = applicability_for_ctxt(ctxt); // If this is a binding pattern, we need to add suggestions to remove any usages // of the variable @@ -100,24 +96,20 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, format_args: &FormatArgsStorag if has_in_format_capture { suggestions.push(( init.span, - format!("();\n{}", reindent_multiline(&snip, false, indent_of(cx, local.span))), + format!("();\n{}", reindent_multiline(&src, false, indent_of(cx, local.span))), )); - diag.multipart_suggestion( - "replace variable usages with `()`", - suggestions, - Applicability::MachineApplicable, - ); + diag.multipart_suggestion("replace variable usages with `()`", suggestions, app); return; } } - suggestions.push((local.span, format!("{snip};"))); + suggestions.push((local.span, format!("{src};"))); let message = if suggestions.len() == 1 { "omit the `let` binding" } else { "omit the `let` binding and replace variable usages with `()`" }; - diag.multipart_suggestion(message, suggestions, Applicability::MachineApplicable); + diag.multipart_suggestion(message, suggestions, app); }, ); } diff --git a/clippy_lints/src/unit_types/unit_arg.rs b/clippy_lints/src/unit_types/unit_arg.rs index ae6d8a1c1aa3..c9d1ffe778ae 100644 --- a/clippy_lints/src/unit_types/unit_arg.rs +++ b/clippy_lints/src/unit_types/unit_arg.rs @@ -1,7 +1,7 @@ use std::iter; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{SpanRangeExt, indent_of, reindent_multiline}; +use clippy_utils::source::{SpanExt, indent_of, reindent_multiline}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::expr_type_is_certain; use clippy_utils::{is_expr_default, is_from_proc_macro}; diff --git a/clippy_lints/src/unused_result_ok.rs b/clippy_lints/src/unused_result_ok.rs index f5ed10fb7609..5ce7e06eedf9 100644 --- a/clippy_lints/src/unused_result_ok.rs +++ b/clippy_lints/src/unused_result_ok.rs @@ -1,8 +1,7 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_context; +use clippy_utils::diagnostics::{applicability_for_ctxt, span_lint_and_sugg}; +use clippy_utils::source::SpanExt; use clippy_utils::sym; use clippy_utils::ty::is_type_diagnostic_item; -use rustc_errors::Applicability; use rustc_hir::{ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::declare_lint_pass; @@ -39,19 +38,17 @@ impl LateLintPass<'_> for UnusedResultOk { && ok_path.ident.name == sym::ok && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result) && !stmt.span.in_external_macro(cx.sess().source_map()) + && let ctxt = expr.span.ctxt() + && let Some(snippet) = recv.span.get_source_text_at_ctxt(cx, ctxt) { - let ctxt = expr.span.ctxt(); - let mut applicability = Applicability::MaybeIncorrect; - let snippet = snippet_with_context(cx, recv.span, ctxt, "", &mut applicability).0; - let sugg = format!("let _ = {snippet}"); span_lint_and_sugg( cx, UNUSED_RESULT_OK, expr.span, "ignoring a result with `.ok()` is misleading", "consider using `let _ =` and removing the call to `.ok()` instead", - sugg, - applicability, + format!("let _ = {snippet}"), + applicability_for_ctxt(ctxt), ); } } diff --git a/clippy_lints/src/unused_unit.rs b/clippy_lints/src/unused_unit.rs index d503bd3379b0..c55a5979c72d 100644 --- a/clippy_lints/src/unused_unit.rs +++ b/clippy_lints/src/unused_unit.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{SpanRangeExt, position_before_rarrow}; +use clippy_utils::source::SpanExt; use clippy_utils::{is_never_expr, is_unit_expr}; use rustc_ast::{Block, StmtKind}; use rustc_errors::Applicability; @@ -12,7 +12,7 @@ use rustc_hir::{ use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::edition::Edition; -use rustc_span::{BytePos, Pos as _, Span, sym}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does @@ -78,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedUnit { return; } - lint_unneeded_unit_return(cx, hir_ty.span, span); + lint_unneeded_unit_return(cx, hir_ty.span); } } @@ -112,7 +112,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedUnit { && args.span_ext.hi() != hir_ty.span.hi() && is_unit_ty(hir_ty) { - lint_unneeded_unit_return(cx, hir_ty.span, poly.span); + lint_unneeded_unit_return(cx, hir_ty.span); } } } @@ -158,24 +158,20 @@ fn get_def(span: Span) -> Option { } } -fn lint_unneeded_unit_return(cx: &LateContext<'_>, ty_span: Span, span: Span) { - let (ret_span, appl) = - if let Some(Some(rpos)) = span.with_hi(ty_span.hi()).with_source_text(cx, position_before_rarrow) { - ( - ty_span.with_lo(span.lo() + BytePos::from_usize(rpos)), - Applicability::MachineApplicable, - ) - } else { - (ty_span, Applicability::MaybeIncorrect) - }; - - span_lint_and_sugg( - cx, - UNUSED_UNIT, - ret_span, - "unneeded unit return type", - "remove the `-> ()`", - String::new(), - appl, - ); +fn lint_unneeded_unit_return(cx: &LateContext<'_>, ty_span: Span) { + if let Some(sp) = ty_span.map_range(cx, |src| { + src.add_leading_whitespace()? + .add_leading_match("->")? + .add_leading_whitespace() + }) { + span_lint_and_sugg( + cx, + UNUSED_UNIT, + sp, + "unneeded unit return type", + "remove the `-> ()`", + String::new(), + Applicability::MachineApplicable, + ); + } } diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index 5274fdbd1dc2..924ff95c0257 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -1,5 +1,5 @@ -use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::{snippet, snippet_with_context}; +use clippy_utils::diagnostics::{applicability_for_ctxt, span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::source::{SpanExt, snippet}; use clippy_utils::sugg::{DiagExt as _, Sugg}; use clippy_utils::ty::{get_type_diagnostic_name, is_copy, is_type_diagnostic_item, same_type_modulo_regions}; use clippy_utils::{ @@ -207,17 +207,18 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { if is_trait_method(cx, e, sym::Into) && name.ident.name == sym::into { let a = cx.typeck_results().expr_ty(e); let b = cx.typeck_results().expr_ty(recv); - if same_type_modulo_regions(a, b) { - let mut app = Applicability::MachineApplicable; - let sugg = snippet_with_context(cx, recv.span, e.span.ctxt(), "", &mut app).0; + if same_type_modulo_regions(a, b) + && let ctxt = e.span.ctxt() + && let Some(sugg) = recv.span.get_source_text_at_ctxt(cx, ctxt) + { span_lint_and_sugg( cx, USELESS_CONVERSION, e.span, format!("useless conversion to the same type: `{b}`"), "consider removing `.into()`", - sugg.into_owned(), - app, + sugg.to_owned(), + applicability_for_ctxt(ctxt), ); } } diff --git a/clippy_lints/src/utils/format_args_collector.rs b/clippy_lints/src/utils/format_args_collector.rs index 6629a67f78bd..8f5014d1e3ad 100644 --- a/clippy_lints/src/utils/format_args_collector.rs +++ b/clippy_lints/src/utils/format_args_collector.rs @@ -1,5 +1,5 @@ use clippy_utils::macros::FormatArgsStorage; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use itertools::Itertools; use rustc_ast::{Crate, Expr, ExprKind, FormatArgs}; use rustc_data_structures::fx::FxHashMap; diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index 52b30ddce12b..34af63b3ecec 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -7,7 +7,7 @@ use clippy_config::Conf; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; 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, is_trait_method, span_contains_comment, sym}; diff --git a/clippy_lints/src/visibility.rs b/clippy_lints/src/visibility.rs index d17b3df99216..1a3d616121cb 100644 --- a/clippy_lints/src/visibility.rs +++ b/clippy_lints/src/visibility.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_ast::ast::{Item, VisibilityKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index c55c5ec2f51a..2a9c4f84a702 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::macros::{FormatArgsStorage, MacroCall, format_arg_removal_span, root_macro_call_first_node}; -use clippy_utils::source::{SpanRangeExt, expand_past_previous_comma}; +use clippy_utils::source::{SpanExt, expand_past_previous_comma}; use clippy_utils::{is_in_test, sym}; use rustc_ast::token::LitKind; use rustc_ast::{ diff --git a/clippy_utils/src/attrs.rs b/clippy_utils/src/attrs.rs index 2d42e76dcbc9..a46aedd81705 100644 --- a/clippy_utils/src/attrs.rs +++ b/clippy_utils/src/attrs.rs @@ -1,4 +1,4 @@ -use crate::source::SpanRangeExt; +use crate::source::SpanExt; use crate::{sym, tokenize_with_text}; use rustc_ast::attr; use rustc_ast::attr::AttributeExt; diff --git a/clippy_utils/src/check_proc_macro.rs b/clippy_utils/src/check_proc_macro.rs index 47f9d0591e92..2f95608ef4a8 100644 --- a/clippy_utils/src/check_proc_macro.rs +++ b/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/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index ecd88daa6b39..138320f2e758 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -4,7 +4,7 @@ //! executable MIR bodies, so we have to do this instead. #![allow(clippy::float_cmp)] -use crate::source::{SpanRangeExt, walk_span_to_context}; +use crate::source::{SpanExt, walk_span_to_context}; use crate::{clip, is_direct_expn_of, sext, unsext}; use rustc_abi::Size; @@ -707,11 +707,10 @@ impl<'tcx> ConstEvalCtxt<'tcx> { if let Some(expr_span) = walk_span_to_context(expr.span, span.ctxt) && let expr_lo = expr_span.lo() && expr_lo >= span.lo - && let Some(src) = (span.lo..expr_lo).get_source_range(&self.tcx) - && let Some(src) = src.as_str() + && let Some(src) = (span.lo..expr_lo).get_source_text(self.tcx) { use rustc_lexer::TokenKind::{BlockComment, LineComment, OpenBrace, Semi, Whitespace}; - if !tokenize(src, FrontmatterAllowed::No) + if !tokenize(&src, FrontmatterAllowed::No) .map(|t| t.kind) .filter(|t| !matches!(t, Whitespace | LineComment { .. } | BlockComment { .. } | Semi)) .eq([OpenBrace]) diff --git a/clippy_utils/src/diagnostics.rs b/clippy_utils/src/diagnostics.rs index 8a19039a7fe7..684d60d1bef0 100644 --- a/clippy_utils/src/diagnostics.rs +++ b/clippy_utils/src/diagnostics.rs @@ -13,7 +13,7 @@ use rustc_errors::{Applicability, Diag, DiagMessage, MultiSpan, SubdiagMessage}; use rustc_errors::{EmissionGuarantee, SubstitutionPart, Suggestions}; use rustc_hir::HirId; use rustc_lint::{LateContext, Lint, LintContext}; -use rustc_span::Span; +use rustc_span::{Span, SyntaxContext}; use std::env; fn docs_link(diag: &mut Diag<'_, ()>, lint: &'static Lint) { @@ -71,6 +71,26 @@ fn validate_diag(diag: &Diag<'_, impl EmissionGuarantee>) { } } +/// `MachineApplicable` if this is the root context, `MaybeIncorrect` otherwise. +#[inline] +pub fn applicability_for_ctxt(ctxt: SyntaxContext) -> Applicability { + if ctxt.is_root() { + Applicability::MaybeIncorrect + } else { + Applicability::MachineApplicable + } +} + +/// `MachineApplicable` if the span is from the root context, `MaybeIncorrect` otherwise. +#[inline] +pub fn applicability_for_span(sp: Span) -> Applicability { + if sp.from_expansion() { + Applicability::MaybeIncorrect + } else { + Applicability::MachineApplicable + } +} + /// Emit a basic lint message with a `msg` and a `span`. /// /// This is the most primitive of our lint emission methods and can diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index b79e15cd7170..dca31228fdfb 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -1,6 +1,6 @@ use crate::consts::ConstEvalCtxt; use crate::macros::macro_backtrace; -use crate::source::{SpanRange, SpanRangeExt, walk_span_to_context}; +use crate::source::{SpanExt, SpanLike, walk_span_to_context}; use crate::tokenize_with_text; use rustc_ast::ast; use rustc_ast::ast::InlineAsmTemplatePiece; @@ -1370,15 +1370,15 @@ pub fn hash_expr(cx: &LateContext<'_>, e: &Expr<'_>) -> u64 { fn eq_span_tokens( cx: &LateContext<'_>, - left: impl SpanRange, - right: impl SpanRange, + left: impl SpanLike, + right: impl SpanLike, pred: impl Fn(TokenKind) -> bool, ) -> bool { fn f(cx: &LateContext<'_>, left: Range, right: Range, pred: impl Fn(TokenKind) -> bool) -> bool { if let Some(lsrc) = left.get_source_range(cx) - && let Some(lsrc) = lsrc.as_str() + && let Some(lsrc) = lsrc.current_text() && let Some(rsrc) = right.get_source_range(cx) - && let Some(rsrc) = rsrc.as_str() + && let Some(rsrc) = rsrc.current_text() { let pred = |&(token, ..): &(TokenKind, _, _)| pred(token); let map = |(_, source, _)| source; diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 5223cd872a68..8ca5c6385c42 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -2,6 +2,7 @@ #![feature(if_let_guard)] #![feature(macro_metavar_expr)] #![feature(never_type)] +#![feature(pattern)] #![feature(rustc_private)] #![feature(assert_matches)] #![feature(unwrap_infallible)] @@ -123,12 +124,13 @@ use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::SourceMap; use rustc_span::symbol::{Ident, Symbol, kw}; use rustc_span::{InnerSpan, Span}; -use source::{SpanRangeExt, walk_span_to_context}; +use source::{SpanExt, walk_span_to_context}; use visitors::{Visitable, for_each_unconsumed_temporary}; use crate::ast_utils::unordered_over; use crate::consts::{ConstEvalCtxt, Constant, mir_to_const}; use crate::higher::Range; +use crate::source::HasSourceMap; 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; @@ -2855,8 +2857,8 @@ pub fn tokenize_with_text(s: &str) -> impl Iterator bool { - let Ok(snippet) = sm.span_to_snippet(span) else { +pub fn span_contains_comment<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> bool { + let Ok(snippet) = sm.source_map().span_to_snippet(span) else { return false; }; return tokenize(&snippet, FrontmatterAllowed::No).any(|token| { @@ -2871,7 +2873,7 @@ pub fn span_contains_comment(sm: &SourceMap, span: Span) -> bool { /// token, including comments unless `skip_comments` is set. /// This is useful to determine if there are any actual code tokens in the span that are omitted in /// the late pass, such as platform-specific code. -pub fn span_contains_non_whitespace(cx: &impl source::HasSession, span: Span, skip_comments: bool) -> bool { +pub fn span_contains_non_whitespace<'sm>(cx: impl HasSourceMap<'sm>, span: Span, skip_comments: bool) -> bool { matches!(span.get_source_text(cx), Some(snippet) if tokenize_with_text(&snippet).any(|(token, _, _)| match token { TokenKind::Whitespace => false, @@ -2880,6 +2882,7 @@ pub fn span_contains_non_whitespace(cx: &impl source::HasSession, span: Span, sk } )) } + /// Returns all the comments a given span contains /// /// Comments are returned wrapped with their relevant delimiters diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index 638d32903123..3b6220437eac 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -2,8 +2,7 @@ #![allow(clippy::module_name_repetitions)] -use std::sync::Arc; - +use core::str::pattern::{Pattern, ReverseSearcher}; use rustc_ast::{LitKind, StrStyle}; use rustc_errors::Applicability; use rustc_hir::{BlockCheckMode, Expr, ExprKind, UnsafeSource}; @@ -16,187 +15,330 @@ use rustc_span::{ BytePos, DUMMY_SP, FileNameDisplayPreference, Pos, RelativeBytePos, SourceFile, SourceFileAndLine, Span, SpanData, SyntaxContext, hygiene, }; -use std::borrow::Cow; +use std::borrow::{Borrow, Cow}; use std::fmt; use std::ops::{Deref, Index, Range}; +use std::sync::Arc; -pub trait HasSession { - fn sess(&self) -> &Session; +pub trait HasSourceMap<'sm>: Copy { + #[must_use] + fn source_map(self) -> &'sm SourceMap; } -impl HasSession for Session { - fn sess(&self) -> &Session { +impl<'sm> HasSourceMap<'sm> for &'sm SourceMap { + #[inline] + fn source_map(self) -> &'sm SourceMap { self } } -impl HasSession for TyCtxt<'_> { - fn sess(&self) -> &Session { - self.sess +impl<'sm> HasSourceMap<'sm> for &'sm Session { + #[inline] + fn source_map(self) -> &'sm SourceMap { + self.source_map() } } -impl HasSession for EarlyContext<'_> { - fn sess(&self) -> &Session { - ::rustc_lint::LintContext::sess(self) +impl<'sm> HasSourceMap<'sm> for TyCtxt<'sm> { + #[inline] + fn source_map(self) -> &'sm SourceMap { + self.sess.source_map() } } -impl HasSession for LateContext<'_> { - fn sess(&self) -> &Session { - self.tcx.sess() +impl<'sm> HasSourceMap<'sm> for &'sm EarlyContext<'_> { + #[inline] + fn source_map(self) -> &'sm SourceMap { + ::rustc_lint::LintContext::sess(self).source_map() + } +} +impl<'sm> HasSourceMap<'sm> for &LateContext<'sm> { + #[inline] + fn source_map(self) -> &'sm SourceMap { + self.tcx.sess.source_map() } } -/// Conversion of a value into the range portion of a `Span`. -pub trait SpanRange: Sized { +/// A type which can be treated as a span for the purpose of retrieving the source text. +pub trait SpanLike: Sized { + #[must_use] fn into_range(self) -> Range; + #[must_use] + fn into_span_data(self) -> SpanData; + #[must_use] + fn from_span_data(data: SpanData) -> Self; + + /// Walks this span up the macro call chain to the target context. Returns `None` if the target + /// context cannot be found. + /// + /// Given the following code: + /// + /// ```rust,ignore + /// macro_rules! m1 { ($e:expr) => { f1($e) }; } + /// macro_rules! m2 { ($e:expr) => { f2(m1!($e)) }; } + /// f3(m2!(0)) + /// // expands to `f3(f2(f1(0)))` + /// ``` + /// + /// Since both early and late lint passes see the expanded code, both will see their respective + /// trees as `f3(f2(f1(0)))`. This function can be used to get e.g. the span of function + /// argument as the caller actually typed rather than the span of the argument after a macro is + /// expanded. + /// + /// The following table lists of the results of various possible argument combinations: + /// + /// |span |context|result span| + /// |-------|-------|-----------| + /// |`f3(_)`|`f3(_)`|`f3(_)` | + /// |`f2(_)`|`f3(_)`|`m2!(0)` | + /// |`f1(_)`|`f3(_)`|`m2!(0)` | + /// |`f1(_)`|`f2(_)`|`m1!($e)` | + /// |`0` |`f3(_)`|`0` | + /// |`0` |`f2(_)`|None | + /// |`0` |`f1(_)`|None | + #[must_use] + fn walk_to_ctxt(self, ctxt: SyntaxContext) -> Option>; } -impl SpanRange for Span { +impl SpanLike for Span { + #[inline] fn into_range(self) -> Range { let data = self.data(); data.lo..data.hi } + #[inline] + fn into_span_data(self) -> SpanData { + self.data() + } + #[inline] + fn from_span_data(data: SpanData) -> Self { + Span::new(data.lo, data.hi, data.ctxt, data.parent) + } + #[inline] + fn walk_to_ctxt(self, ctxt: SyntaxContext) -> Option> { + let other = hygiene::walk_chain(self, ctxt).data(); + (other.ctxt == ctxt).then_some(other.lo..other.hi) + } } -impl SpanRange for SpanData { +impl SpanLike for SpanData { + #[inline] fn into_range(self) -> Range { self.lo..self.hi } -} -impl SpanRange for Range { - fn into_range(self) -> Range { + #[inline] + fn into_span_data(self) -> SpanData { self } -} - -/// Conversion of a value into a `Span` -pub trait IntoSpan: Sized { - fn into_span(self) -> Span; - fn with_ctxt(self, ctxt: SyntaxContext) -> Span; -} -impl IntoSpan for Span { - fn into_span(self) -> Span { - self + #[inline] + fn from_span_data(data: SpanData) -> Self { + data } - fn with_ctxt(self, ctxt: SyntaxContext) -> Span { - self.with_ctxt(ctxt) + #[inline] + fn walk_to_ctxt(self, ctxt: SyntaxContext) -> Option> { + self.span().walk_to_ctxt(ctxt) } } -impl IntoSpan for SpanData { - fn into_span(self) -> Span { - self.span() +impl SpanLike for Range { + #[inline] + fn into_range(self) -> Range { + self } - fn with_ctxt(self, ctxt: SyntaxContext) -> Span { - Span::new(self.lo, self.hi, ctxt, self.parent) + #[inline] + fn into_span_data(self) -> SpanData { + SpanData { + lo: self.start, + hi: self.end, + ctxt: SyntaxContext::root(), + parent: None, + } } -} -impl IntoSpan for Range { - fn into_span(self) -> Span { - Span::with_root_ctxt(self.start, self.end) + #[inline] + fn from_span_data(data: SpanData) -> Self { + data.lo..data.hi } - fn with_ctxt(self, ctxt: SyntaxContext) -> Span { - Span::new(self.start, self.end, ctxt, None) + #[inline] + fn walk_to_ctxt(self, ctxt: SyntaxContext) -> Option> { + ctxt.is_root().then_some(self) } } -pub trait SpanRangeExt: SpanRange { - /// Attempts to get a handle to the source text. Returns `None` if either the span is malformed, - /// or the source text is not accessible. - fn get_source_text(self, cx: &impl HasSession) -> Option { - get_source_range(cx.sess().source_map(), self.into_range()).and_then(SourceText::new) +/// Helper functions to interact with the source text of a span. +pub trait SpanExt: SpanLike { + /// Attempts to get a handle to the source file and the text range within that file. Returns + /// `None` if the source text is not available. + /// + /// With debug assertions this will assert that the range: + /// * Does not start after it's end. + /// * Does not exceed the bounds of a single source file. + /// * Lies on a UTF-8 boundary. + #[inline] + #[must_use] + #[cfg_attr(debug_assertions, track_caller)] + fn get_source_range<'sm>(self, sm: impl HasSourceMap<'sm>) -> Option> { + SourceFileRange::new(sm.source_map(), self.into_range()) } - /// Gets the source file, and range in the file, of the given span. Returns `None` if the span - /// extends through multiple files, or is malformed. - fn get_source_range(self, cx: &impl HasSession) -> Option { - get_source_range(cx.sess().source_map(), self.into_range()) + /// Attempts to get a handle to the source text. Returns `None` if the source text could not be + /// accessed for any reason. + /// + /// With debug assertions this will assert that the range: + /// * Does not start after it's end. + /// * Does not exceed the bounds of a single source file. + /// * Lies on a UTF-8 boundary. + #[inline] + #[must_use] + #[cfg_attr(debug_assertions, track_caller)] + fn get_source_text<'sm>(self, sm: impl HasSourceMap<'sm>) -> Option { + SourceFileRange::new(sm.source_map(), self.into_range()).and_then(SourceFileRange::into_text) } - /// Calls the given function with the source text referenced and returns the value. Returns - /// `None` if the source text cannot be retrieved. - fn with_source_text(self, cx: &impl HasSession, f: impl for<'a> FnOnce(&'a str) -> T) -> Option { - with_source_text(cx.sess().source_map(), self.into_range(), f) + /// Attempts to get a handle to the source after walking to the given `SyntaxContext`. Returns + /// `None` if the source text could not be accessed for any reason or this span is not at or a + /// child of the target context. + /// + /// With debug assertions this will assert that the range: + /// * Does not start after it's end. + /// * Does not exceed the bounds of a single source file. + /// * Lies on a UTF-8 boundary. + #[inline] + #[must_use] + #[cfg_attr(debug_assertions, track_caller)] + fn get_source_text_at_ctxt<'sm>(self, sm: impl HasSourceMap<'sm>, ctxt: SyntaxContext) -> Option { + self.walk_to_ctxt(ctxt) + .and_then(|r| SourceFileRange::new(sm.source_map(), r)) + .and_then(SourceFileRange::into_text) } /// Checks if the referenced source text satisfies the given predicate. Returns `false` if the - /// source text cannot be retrieved. - fn check_source_text(self, cx: &impl HasSession, pred: impl for<'a> FnOnce(&'a str) -> bool) -> bool { - self.with_source_text(cx, pred).unwrap_or(false) - } - - /// Calls the given function with the both the text of the source file and the referenced range, - /// and returns the value. Returns `None` if the source text cannot be retrieved. - fn with_source_text_and_range( - self, - cx: &impl HasSession, - f: impl for<'a> FnOnce(&'a str, Range) -> T, - ) -> Option { - with_source_text_and_range(cx.sess().source_map(), self.into_range(), f) + /// source text could not be accessed for any reason. + /// + /// With debug assertions this will assert that the range: + /// * Does not start after it's end. + /// * Does not exceed the bounds of a single source file. + /// * Lies on a UTF-8 boundary. + #[inline] + #[must_use] + #[cfg_attr(debug_assertions, track_caller)] + fn check_source_text<'sm>(self, sm: impl HasSourceMap<'sm>, pred: impl FnOnce(&str) -> bool) -> bool { + SourceFileRange::new(sm.source_map(), self.into_range()).is_some_and(|x| x.current_text().is_some_and(pred)) } - /// Calls the given function with the both the text of the source file and the referenced range, - /// and creates a new span with the returned range. Returns `None` if the source text cannot be - /// retrieved, or no result is returned. + /// Maps the range of the current span. Returns `None` if either the given function returns + /// `None`, or the source text could not be accessed for any reason. /// - /// The new range must reside within the same source file. - fn map_range( + /// With debug assertions this will assert that both the initial and mapped ranges: + /// * Do not start after their respective ends. + /// * Do not exceed the bounds of a single source file. + /// * Lie on a UTF-8 boundary. + #[inline] + #[must_use] + #[cfg_attr(debug_assertions, track_caller)] + fn map_range<'sm>( self, - cx: &impl HasSession, - f: impl for<'a> FnOnce(&'a SourceFile, &'a str, Range) -> Option>, - ) -> Option> { - map_range(cx.sess().source_map(), self.into_range(), f) + sm: impl HasSourceMap<'sm>, + f: impl for<'a> FnOnce(&'a mut SourceFileRange<'sm>) -> Option<&'a mut SourceFileRange<'sm>>, + ) -> Option { + let data = self.into_span_data(); + if let Some(mut range) = SourceFileRange::new(sm.source_map(), data.lo..data.hi) + && let Some(range) = f(&mut range) + // Make sure the span is valid. Always passes with debug assertions as + // `SourceFileRange` panics whenever a bad range is set. + && range.as_text().is_some() + { + let range = range.source_range(); + Some(Self::from_span_data(SpanData { + lo: range.start, + hi: range.end, + ..data + })) + } else { + None + } } +} +impl SpanExt for T {} - #[allow(rustdoc::invalid_rust_codeblocks, reason = "The codeblock is intentionally broken")] - /// Extends the range to include all preceding whitespace characters. - /// - /// The range will not be expanded if it would cross a line boundary, the line the range would - /// be extended to ends with a line comment and the text after the range contains a - /// non-whitespace character on the same line. e.g. - /// - /// ```ignore - /// ( // Some comment - /// foo) - /// ``` - /// - /// When the range points to `foo`, suggesting to remove the range after it's been extended will - /// cause the `)` to be placed inside the line comment as `( // Some comment)`. - fn with_leading_whitespace(self, cx: &impl HasSession) -> Range { - with_leading_whitespace(cx.sess().source_map(), self.into_range()) - } +mod source_text { + use core::slice::SliceIndex; + use rustc_span::SourceFile; + use rustc_span::source_map::SourceMap; + use std::sync::Arc; - /// Trims the leading whitespace from the range. - fn trim_start(self, cx: &impl HasSession) -> Range { - trim_start(cx.sess().source_map(), self.into_range()) + /// Handle to a substring of text in a source file. + #[derive(Clone)] + pub struct SourceText { + file: Arc, + // This is a pointer into the text owned by the source file. If the source is external + // then the `FreezeLock` on the text must be frozen. + text: *const str, } -} -impl SpanRangeExt for T {} + impl SourceText { + /// Gets the text of the given file. Returns `None` if the file's text could not be loaded. + #[must_use] + pub fn new(sm: &SourceMap, file: Arc) -> Option { + if !sm.ensure_source_file_source_present(&file) { + return None; + } + let text: *const str = if let Some(text) = &file.src { + &raw const ***text + } else if let Some(src) = file.external_src.get() + // `get` or `freeze` must be used to access the lock. + // Since `ensure_source_file_source_present` calls `freeze` when loading the source + // we use `get` to avoid the extra load. + && let Some(text) = src.get_source() + { + text + } else { + return None; + }; + Some(Self { file, text }) + } -/// Handle to a range of text in a source file. -pub struct SourceText(SourceFileRange); -impl SourceText { - /// Takes ownership of the source file handle if the source text is accessible. - pub fn new(text: SourceFileRange) -> Option { - if text.as_str().is_some() { - Some(Self(text)) - } else { - None + /// Gets the source text. + #[inline] + #[must_use] + pub fn as_str(&self) -> &str { + // SAFETY: `text` is owned by `sf` and comes from either an `Option>`, or a + // frozen `FeezeLock` (which ultimately contains an `Arc`). Neither + // of these can change so long as we own `sf`. + unsafe { &*self.text } } - } - /// Gets the source text. - pub fn as_str(&self) -> &str { - self.0.as_str().unwrap() - } + /// Applies an indexing operation to the contained string. Returns `None` if the index is + /// not valid. + #[inline] + #[must_use] + pub fn with_index(mut self, idx: impl SliceIndex) -> Option { + self.text = self.as_str().get(idx)?; + Some(self) + } + /// Gets the source file containing the text. + #[inline] + #[must_use] + pub fn file(&self) -> &Arc { + &self.file + } + } +} +pub use self::source_text::SourceText; +impl SourceText { /// Converts this into an owned string. + #[inline] pub fn to_owned(&self) -> String { self.as_str().to_owned() } } impl Deref for SourceText { type Target = str; + #[inline] fn deref(&self) -> &Self::Target { self.as_str() } } +impl Borrow for SourceText { + #[inline] + fn borrow(&self) -> &str { + self.as_str() + } +} impl AsRef for SourceText { + #[inline] fn as_ref(&self) -> &str { self.as_str() } @@ -206,81 +348,526 @@ where str: Index, { type Output = >::Output; + #[inline] fn index(&self, idx: T) -> &Self::Output { &self.as_str()[idx] } } impl fmt::Display for SourceText { + #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.as_str().fmt(f) } } impl fmt::Debug for SourceText { + #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.as_str().fmt(f) } } -fn get_source_range(sm: &SourceMap, sp: Range) -> Option { - let start = sm.lookup_byte_offset(sp.start); - let end = sm.lookup_byte_offset(sp.end); - if !Arc::ptr_eq(&start.sf, &end.sf) || start.pos > end.pos { - return None; - } - sm.ensure_source_file_source_present(&start.sf); - let range = start.pos.to_usize()..end.pos.to_usize(); - Some(SourceFileRange { sf: start.sf, range }) -} +#[cfg(not(debug_assertions))] +fn dbg_check_range(_: &SourceFileRange<'_>, _: Range) {} + +#[cfg(debug_assertions)] +#[track_caller] +fn dbg_check_range(current: &SourceFileRange<'_>, new: Range) { + use core::fmt::Write; -fn with_source_text(sm: &SourceMap, sp: Range, f: impl for<'a> FnOnce(&'a str) -> T) -> Option { - if let Some(src) = get_source_range(sm, sp) - && let Some(src) = src.as_str() + if new.start > new.end + || new.end > current.file().source_len + || current + .file_text() + .get(new.start.to_usize()..new.end.to_usize()) + .is_none() { - Some(f(src)) - } else { - None + let mut msg = String::with_capacity(512); + + let file = current.file(); + let new_start = BytePos(new.start.0.wrapping_add(file.start_pos.0)); + let new_end = BytePos(new.end.0.wrapping_add(file.start_pos.0)); + + let _ = write!( + msg, + "error setting the requested range `{:?}: ", + // signed numbers will better show most errors. + new.start.0.cast_signed()..new.end.0.cast_signed(), + ); + if new_start > new_end { + msg.push_str("the start and end overlap"); + } else if new_start < file.start_pos || file.start_pos.0 + file.source_len.0 < new_end.0 { + let _ = write!( + msg, + "the bounds are outside the current file (len: {})", + file.source_len.to_u32(), + ); + } else { + msg.push_str("the ends are not on UTF-8 boundaries"); + } + + let start = BytePos::from_u32(current.range.start.to_u32()) + file.start_pos; + let end = BytePos::from_u32(current.range.end.to_u32()) + file.start_pos; + let (start_line, start_col, _) = file.lookup_file_pos_with_col_display(start); + let (end_line, end_col, _) = file.lookup_file_pos_with_col_display(end); + let _ = write!( + msg, + "\n current: {}:{}:{}: {}:{}", + file.name.display(FileNameDisplayPreference::Local), + start_line, + start_col.to_u32(), + end_line, + end_col.to_u32(), + ); + + let files = current.sm.files(); + let mut print_loc = |label: &str, pos: BytePos| { + if files + .last() + .is_some_and(|f| pos <= f.start_pos + BytePos::from_u32(f.source_len.to_u32())) + { + let file = current.sm.lookup_source_file(pos); + let file_name = file.name.display(FileNameDisplayPreference::Local); + let rel_pos = RelativeBytePos::from_u32((pos - file.start_pos).to_u32()); + if let Some(text) = SourceText::new(current.sm, file.clone()) + && text.get(rel_pos.to_usize()..).is_some() + { + let (line, col, _) = file.lookup_file_pos_with_col_display(pos); + let _ = write!(msg, "\n {label}: {file_name}:{line}:{}", col.to_u32()); + } else { + let line = file.lookup_line(rel_pos).unwrap_or(0); + let offset = rel_pos - file.lines()[line]; + let _ = write!(msg, "\n {label}: {file_name}:{} + {}", line + 1, offset.to_u32()); + } + } else { + let _ = write!(msg, "\n {label}: not a file"); + } + }; + if new.start != current.range.start { + print_loc("new start", new_start); + } + if new.end != current.range.end { + print_loc("new end", new_end); + } + + std::panic::panic_any(msg); } } -fn with_source_text_and_range( - sm: &SourceMap, - sp: Range, - f: impl for<'a> FnOnce(&'a str, Range) -> T, -) -> Option { - if let Some(src) = get_source_range(sm, sp) - && let Some(text) = &src.sf.src +/// Handle to a source file's text and a range within that file. +/// +/// With debug assertions the range is checked to be a valid substring of the source text. Without +/// assertions `None` will be returned from various functions when accessing the substring of the +/// source text fails. +#[derive(Clone)] +pub struct SourceFileRange<'sm> { + file: SourceText, + range: Range, + #[cfg(debug_assertions)] + sm: &'sm SourceMap, + #[cfg(not(debug_assertions))] + sm: core::marker::PhantomData<&'sm SourceMap>, +} +impl<'sm> SourceFileRange<'sm> { + /// Attempts to get a handle to the source file and the text range within that file. Returns + /// `None` if the source text is not available. + /// + /// With debug assertions this will assert that the range: + /// * Does not start after it's end. + /// * Does not cross multiple files. + /// * Does not exceed the bounds of the source map. + /// * Lies on a UTF-8 boundary. + #[must_use] + #[cfg_attr(debug_assertions, track_caller)] + pub fn new(sm: &'sm SourceMap, range: Range) -> Option { + let start = sm.lookup_byte_offset(range.start); + let end = RelativeBytePos::from_u32(range.end.to_u32() - start.sf.start_pos.to_u32()); + let mut res = Self { + file: SourceText::new(sm, start.sf)?, + range: RelativeBytePos::from_u32(0)..RelativeBytePos::from_u32(0), + #[cfg(debug_assertions)] + sm, + #[cfg(not(debug_assertions))] + sm: core::marker::PhantomData, + }; + res.set_range(RelativeBytePos::from_u32(start.pos.to_u32())..end); + Some(res) + } + + /// Gets a reference to the containing source file. + #[inline] + #[must_use] + pub fn file(&self) -> &SourceFile { + self.file.file() + } + + /// Checks if this range is part of the same file as another range. + #[inline] + #[must_use] + pub fn is_same_file_as(&self, other: &Self) -> bool { + Arc::ptr_eq(self.file.file(), other.file.file()) + } + + /// Gets the whole source text of the file. + #[inline] + #[must_use] + pub fn file_text(&self) -> &str { + self.file.as_str() + } + + /// Gets the source text contained within the current range. Returns `None` if the current range + /// is not valid. + #[inline] + #[must_use] + pub fn current_text(&self) -> Option<&str> { + // The range will have already been validated if debug assertions are enabled. + self.file_text() + .get(self.range.start.to_usize()..self.range.end.to_usize()) + } + + /// Gets the current range in the file. + #[inline] + #[must_use] + pub fn range(&self) -> Range { + self.range.clone() + } + + /// Gets the current range as a range in the source map. + #[inline] + #[must_use] + pub fn source_range(&self) -> Range { + BytePos(self.range.start.0 + self.file().start_pos.0)..BytePos(self.range.end.0 + self.file().start_pos.0) + } + + /// Converts this into handle which acts as a `&str`. Returns `None` if the current range is + /// ill-formed. + #[inline] + #[must_use] + pub fn into_text(self) -> Option { + self.file + .with_index(self.range.start.to_usize()..self.range.end.to_usize()) + } + + /// Converts this into handle which acts as a `&str`. Returns `None` if the current range is + /// ill-formed. + #[inline] + #[must_use] + pub fn as_text(&self) -> Option { + self.file + .clone() + .with_index(self.range.start.to_usize()..self.range.end.to_usize()) + } + + /// Sets the current range in the file. + /// + /// With debug assertions this will assert that the range: + /// * Does not start after it's end. + /// * Does not exceed the bounds of the file. + /// * Lies on a UTF-8 boundary. + #[inline] + #[cfg_attr(debug_assertions, track_caller)] + pub fn set_range(&mut self, range: Range) -> &mut Self { + dbg_check_range(self, range.clone()); + self.range = range; + self + } + + /// Sets the current range to the range between the current range and the given range. + /// Does nothing and returns `None` if the ranges overlap. + /// + /// With debug assertions enabled this will assert that the given range: + /// * Is within the same file as the current range. + /// * Lies on a UTF-8 boundary. + #[inline] + #[must_use] + #[cfg_attr(debug_assertions, track_caller)] + pub fn set_range_between_other(&mut self, other: impl SpanLike) -> Option<&mut Self> { + fn f<'a, 'sm>( + self_: &'a mut SourceFileRange<'sm>, + other: Range, + ) -> Option<&'a mut SourceFileRange<'sm>> { + let file = self_.file(); + let other = other.into_range(); + let other: Range = RelativeBytePos(other.start.0.wrapping_sub(file.start_pos.0)) + ..RelativeBytePos(other.end.0.wrapping_sub(file.start_pos.0)); + dbg_check_range(self_, other.clone()); + if self_.range.end.0.cast_signed() < other.start.0.cast_signed() { + self_.range.start = self_.range.end; + self_.range.end = other.start; + Some(self_) + } else if self_.range.start.0.cast_signed() > other.end.0.cast_signed() { + self_.range.end = self_.range.start; + self_.range.start = other.end; + Some(self_) + } else { + None + } + } + f(self, other.into_range()) + } + + /// Sets the start of this range to the given source map position if it's at or before + /// the current range. + /// + /// With debug assertions enabled this will assert that the position: + /// * Is within the same file. + /// * Lies on a UTF-8 boundary. + #[inline] + #[must_use] + #[cfg_attr(debug_assertions, track_caller)] + pub fn set_start_if_before(&mut self, pos: BytePos) -> Option<&mut Self> { + let rel_pos = RelativeBytePos(pos.0.wrapping_sub(self.file().start_pos.0)); + dbg_check_range(self, RelativeBytePos(0)..rel_pos); + + // Signed comparison will catch some cross file positions. + if rel_pos.0.cast_signed() <= self.range.start.0.cast_signed() { + self.range.start = rel_pos; + Some(self) + } else { + None + } + } + + /// Sets the start of this range to the given source map position if it's within the + /// current range. + /// + /// With debug assertions enabled this will assert that the position: + /// * Is within the same file. + /// * Lies on a UTF-8 boundary. + #[inline] + #[must_use] + #[cfg_attr(debug_assertions, track_caller)] + pub fn set_start_if_within(&mut self, pos: BytePos) -> Option<&mut Self> { + let rel_pos = RelativeBytePos(pos.0.wrapping_sub(self.file().start_pos.0)); + dbg_check_range(self, RelativeBytePos(0)..rel_pos); + if self.range.start <= rel_pos && rel_pos <= self.range.end { + self.range.start = rel_pos; + Some(self) + } else { + None + } + } + + /// Sets the end of this range to the given source map position if it's at or after + /// the current range. + /// + /// With debug assertions enabled this will assert that the position: + /// * Is within the same file. + /// * Lies on a UTF-8 boundary. + #[inline] + #[must_use] + #[cfg_attr(debug_assertions, track_caller)] + pub fn set_end_if_after(&mut self, pos: BytePos) -> Option<&mut Self> { + let rel_pos = RelativeBytePos(pos.0.wrapping_sub(self.file().start_pos.0)); + dbg_check_range(self, RelativeBytePos(0)..rel_pos); + + // Signed comparison will catch some cross file positions. + if self.range.end.0.cast_signed() <= rel_pos.0.cast_signed() { + self.range.end = rel_pos; + Some(self) + } else { + None + } + } + + /// Sets the end of this range to the given source map position if it's within the + /// current range. + /// + /// With debug assertions enabled this will assert that the position: + /// * Is within the same file. + /// * Lies on a UTF-8 boundary. + #[inline] + #[must_use] + #[cfg_attr(debug_assertions, track_caller)] + pub fn set_end_if_within(&mut self, pos: BytePos) -> Option<&mut Self> { + let rel_pos = RelativeBytePos(pos.0.wrapping_sub(self.file().start_pos.0)); + dbg_check_range(self, RelativeBytePos(0)..rel_pos); + if self.range.start <= rel_pos && rel_pos <= self.range.end { + self.range.end = rel_pos; + Some(self) + } else { + None + } + } + + /// Maps the current range using the given function. Return `None` if the function returns + /// `None`, or the current range is ill-formed. + /// + /// The range passed to the closure has only been validated when debug assertions are enabled. + /// Always use `str::get` instead of the index operator when using the range. + /// + /// With debug assertions this will assert that the mapped range: + /// * Does not start after it's end. + /// * Is within the same file. + /// * Lies on a UTF-8 boundary. + #[inline] + #[must_use] + #[cfg_attr(debug_assertions, track_caller)] + pub fn edit_range(&mut self, f: impl FnOnce(&str, Range) -> Option>) -> Option<&mut Self> { + let range = f(self.file_text(), self.range.start.to_usize()..self.range.end.to_usize()); + let range = range?; + self.set_range(RelativeBytePos::from_usize(range.start)..RelativeBytePos::from_usize(range.end)); + Some(self) + } + + /// Trims the whitespace from the start of the range. Returns `None` if the current range is + /// ill-formed. + #[must_use] + pub fn remove_leading_whitespace(&mut self) -> Option<&mut Self> { + self.edit_range(|src, range| { + let src = src.get(range.clone())?; + Some(range.start + (src.len() - src.trim_start().len())..range.end) + }) + } + + /// Extends the range to include all preceding whitespace characters. + /// + /// The range will not be expanded if it would cross a line boundary, the line the range would + /// be extended to ends with a line comment and the text after the range contains a + /// non-whitespace character on the same line. e.g. + /// + /// ```ignore + /// ( // Some comment + /// foo) + /// ``` + /// + /// When the range points to `foo`, suggesting to remove the range after it's been extended will + /// cause the `)` to be placed inside the line comment as `( // Some comment)`. + #[must_use] + pub fn add_leading_whitespace(&mut self) -> Option<&mut Self> { + let text_before = self.file_text().get(..self.range.start.to_usize())?.trim_end(); + let range = self.range.clone(); + let file = self.file(); + let lines = self.file().lines(); + + // First check if extending backwards crosses lines into a comment line. + let post_search_line = lines.partition_point(|&pos| pos.to_usize() <= text_before.len()); + if let Some(&search_line_end) = lines.get(post_search_line) + // Did we extend pass a line boundary? + && search_line_end <= range.start + && let search_start = lines.get(post_search_line - 1).map_or(0, |&x| x.to_usize()) + && ends_with_line_comment_or_broken(&text_before[search_start..]) + // Next check if there's anything after the current range on the same line. + && let next_line = lines.partition_point(|&pos| pos < range.end) + && let next_start = lines.get(next_line).map_or(file.source_len, |&x| x) + && tokenize(self.file_text().get(range.end.to_usize()..next_start.to_usize())?, FrontmatterAllowed::No) + .any(|t| !matches!(t.kind, TokenKind::Whitespace)) + { + // Do nothing; removing whitespace would move code into a comment. + } else { + self.set_range(RelativeBytePos::from_usize(text_before.len())..range.end); + } + Some(self) + } + + /// Extends the range to include all trailing whitespace. + #[must_use] + pub fn add_trailing_whitespace(&mut self) -> Option<&mut Self> { + self.edit_range(|src, range: Range| { + let tail = src.get(range.end..)?; + Some(range.start..src.len() - tail.trim_start().len()) + }) + } + + /// Extends the range to include the given pattern if it immediately precedes the current + /// range. Returns `None` if the pattern isn't matched or the range is ill-formed. + #[must_use] + pub fn add_leading_match

(&mut self, pat: P) -> Option<&mut Self> + where + P: Pattern, + for<'a> P::Searcher<'a>: ReverseSearcher<'a>, { - Some(f(text, src.range)) - } else { - None + self.edit_range(|src, range| { + let head = src.get(..range.start)?; + head.strip_suffix(pat).map(|s| s.len()..range.end) + }) } -} -#[expect(clippy::cast_possible_truncation)] -fn map_range( - sm: &SourceMap, - sp: Range, - f: impl for<'a> FnOnce(&'a SourceFile, &'a str, Range) -> Option>, -) -> Option> { - if let Some(src) = get_source_range(sm, sp.clone()) - && let Some(text) = &src.sf.src - && let Some(range) = f(&src.sf, text, src.range.clone()) + /// Extends the range to include the given pattern if it immediately precedes the current + /// range. Returns `None` if the pattern isn't matched or the range is ill-formed. + #[must_use] + pub fn add_trailing_match(&mut self, pat: impl Pattern) -> Option<&mut Self> { + self.edit_range(|src, range| { + let tail = src.get(range.end..)?; + tail.strip_prefix(pat) + .map(|trimmed| range.start..src.len() - trimmed.len()) + }) + } + + /// Sets the range to that of the given prefix. Returns `None` if there is no matching prefix + /// or the range is ill-formed. + #[must_use] + pub fn set_to_prefix(&mut self, pat: impl Pattern) -> Option<&mut Self> { + self.edit_range(|src, range| { + let src = src.get(range.clone())?; + Some(range.start..range.end - src.strip_prefix(pat)?.len()) + }) + } + + /// Sets the range to that of the given suffix. Returns `None` if there is no matching suffix + /// or the range is ill-formed. + #[must_use] + pub fn set_to_suffix

(&mut self, pat: P) -> Option<&mut Self> + where + P: Pattern, + for<'a> P::Searcher<'a>: ReverseSearcher<'a>, { - debug_assert!( - range.start <= text.len() && range.end <= text.len(), - "Range `{range:?}` is outside the source file (file `{}`, length `{}`)", - src.sf.name.display(FileNameDisplayPreference::Local), - text.len(), - ); - debug_assert!(range.start <= range.end, "Range `{range:?}` has overlapping bounds"); - let dstart = (range.start as u32).wrapping_sub(src.range.start as u32); - let dend = (range.end as u32).wrapping_sub(src.range.start as u32); - Some(BytePos(sp.start.0.wrapping_add(dstart))..BytePos(sp.start.0.wrapping_add(dend))) - } else { - None + self.edit_range(|src, range| { + let src = src.get(range.clone())?; + Some(range.start + src.strip_suffix(pat)?.len()..range.end) + }) + } + + /// Gets the indent of the line this range starts on. + #[must_use] + pub fn get_line_indent(&self) -> &str { + let file = self.file.file(); + if let Some(line) = file.lookup_line(self.range.start) + && let Some(start) = file.lines().get(line) + { + let end = file.lines().get(line + 1).map_or(file.source_len, |&x| x); + let line = &self.file_text()[start.to_usize()..end.to_usize()]; + &line[..line.len() - line.trim_start().len()] + } else { + "" + } + } +} +impl fmt::Debug for SourceFileRange<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let file = self.file.file(); + if self.as_text().is_some() { + let start = BytePos::from_u32(self.range.start.to_u32()) + file.start_pos; + let end = BytePos::from_u32(self.range.end.to_u32()) + file.start_pos; + let (start_line, start_col, _) = file.lookup_file_pos_with_col_display(start); + let (end_line, end_col, _) = file.lookup_file_pos_with_col_display(end); + write!( + f, + "{}:{}:{}: {}:{}", + file.name.display(FileNameDisplayPreference::Local), + start_line, + start_col.to_u32(), + end_line, + end_col.to_u32(), + ) + } else { + let start_line = file.lookup_line(self.range.start).unwrap_or(0); + let start_offset = self.range.start - file.lines()[start_line]; + let end_line = file.lookup_line(self.range.end).unwrap_or(0); + let end_offset = self.range.end - file.lines()[end_line]; + write!( + f, + "{}:{} + {}: {} + {}", + file.name.display(FileNameDisplayPreference::Local), + start_line, + start_offset.0, + end_line, + end_offset.0, + ) + } } } +/// Checks if the last token of the string is either a line comment or an incomplete token. fn ends_with_line_comment_or_broken(text: &str) -> bool { let Some(last) = tokenize(text, FrontmatterAllowed::No).last() else { return false; @@ -304,65 +891,16 @@ fn ends_with_line_comment_or_broken(text: &str) -> bool { } } -fn with_leading_whitespace_inner(lines: &[RelativeBytePos], src: &str, range: Range) -> Option { - debug_assert!(lines.is_empty() || lines[0].to_u32() == 0); - - let start = src.get(..range.start)?.trim_end(); - let next_line = lines.partition_point(|&pos| pos.to_usize() <= start.len()); - if let Some(line_end) = lines.get(next_line) - && line_end.to_usize() <= range.start - && let prev_start = lines.get(next_line - 1).map_or(0, |&x| x.to_usize()) - && ends_with_line_comment_or_broken(&start[prev_start..]) - && let next_line = lines.partition_point(|&pos| pos.to_usize() < range.end) - && let next_start = lines.get(next_line).map_or(src.len(), |&x| x.to_usize()) - && tokenize(src.get(range.end..next_start)?, FrontmatterAllowed::No) - .any(|t| !matches!(t.kind, TokenKind::Whitespace)) - { - Some(range.start) - } else { - Some(start.len()) - } -} - -fn with_leading_whitespace(sm: &SourceMap, sp: Range) -> Range { - map_range(sm, sp.clone(), |sf, src, range| { - Some(with_leading_whitespace_inner(sf.lines(), src, range.clone())?..range.end) - }) - .unwrap_or(sp) -} - -fn trim_start(sm: &SourceMap, sp: Range) -> Range { - map_range(sm, sp.clone(), |_, src, range| { - let src = src.get(range.clone())?; - Some(range.start + (src.len() - src.trim_start().len())..range.end) - }) - .unwrap_or(sp) -} - -pub struct SourceFileRange { - pub sf: Arc, - pub range: Range, -} -impl SourceFileRange { - /// Attempts to get the text from the source file. This can fail if the source text isn't - /// loaded. - pub fn as_str(&self) -> Option<&str> { - (self.sf.src.as_ref().map(|src| src.as_str())) - .or_else(|| self.sf.external_src.get()?.get_source()) - .and_then(|x| x.get(self.range.clone())) - } -} - /// Like `snippet_block`, but add braces if the expr is not an `ExprKind::Block` with no label. -pub fn expr_block( - sess: &impl HasSession, +pub fn expr_block<'sm>( + sm: impl HasSourceMap<'sm>, expr: &Expr<'_>, outer: SyntaxContext, default: &str, indent_relative_to: Option, app: &mut Applicability, ) -> String { - let (code, from_macro) = snippet_block_with_context(sess, expr.span, outer, default, indent_relative_to, app); + let (code, from_macro) = snippet_block_with_context(sm, expr.span, outer, default, indent_relative_to, app); if !from_macro && let ExprKind::Block(block, None) = expr.kind && block.rules != BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) @@ -387,13 +925,13 @@ pub fn expr_block( /// let x = (); /// // ^^^^^^^^^^ /// ``` -pub fn first_line_of_span(sess: &impl HasSession, span: Span) -> Span { - first_char_in_first_line(sess, span).map_or(span, |first_char_pos| span.with_lo(first_char_pos)) +pub fn first_line_of_span<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> Span { + first_char_in_first_line(sm, span).map_or(span, |first_char_pos| span.with_lo(first_char_pos)) } -fn first_char_in_first_line(sess: &impl HasSession, span: Span) -> Option { - let line_span = line_span(sess, span); - snippet_opt(sess, line_span).and_then(|snip| { +fn first_char_in_first_line<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> Option { + let line_span = line_span(sm, span); + snippet_opt(sm, line_span).and_then(|snip| { snip.find(|c: char| !c.is_whitespace()) .map(|pos| line_span.lo() + BytePos::from_usize(pos)) }) @@ -408,9 +946,9 @@ fn first_char_in_first_line(sess: &impl HasSession, span: Span) -> Option Span { +fn line_span<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> Span { let span = original_sp(span, DUMMY_SP); - let SourceFileAndLine { sf, line } = sess.sess().source_map().lookup_line(span.lo()).unwrap(); + let SourceFileAndLine { sf, line } = sm.source_map().lookup_line(span.lo()).unwrap(); let line_start = sf.lines()[line]; let line_start = sf.absolute_position(line_start); span.with_lo(line_start) @@ -424,13 +962,13 @@ fn line_span(sess: &impl HasSession, span: Span) -> Span { /// let x = (); /// // ^^ -- will return 4 /// ``` -pub fn indent_of(sess: &impl HasSession, span: Span) -> Option { - snippet_opt(sess, line_span(sess, span)).and_then(|snip| snip.find(|c: char| !c.is_whitespace())) +pub fn indent_of<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> Option { + snippet_opt(sm, line_span(sm, span)).and_then(|snip| snip.find(|c: char| !c.is_whitespace())) } /// Gets a snippet of the indentation of the line of a span -pub fn snippet_indent(sess: &impl HasSession, span: Span) -> Option { - snippet_opt(sess, line_span(sess, span)).map(|mut s| { +pub fn snippet_indent<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> Option { + snippet_opt(sm, line_span(sm, span)).map(|mut s| { let len = s.len() - s.trim_start().len(); s.truncate(len); s @@ -442,8 +980,8 @@ pub fn snippet_indent(sess: &impl HasSession, span: Span) -> Option { // sources that the user has no control over. // For some reason these attributes don't have any expansion info on them, so // we have to check it this way until there is a better way. -pub fn is_present_in_source(sess: &impl HasSession, span: Span) -> bool { - if let Some(snippet) = snippet_opt(sess, span) +pub fn is_present_in_source<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> bool { + if let Some(snippet) = snippet_opt(sm, span) && snippet.is_empty() { return false; @@ -533,8 +1071,8 @@ fn reindent_multiline_inner(s: &str, ignore_first: bool, indent: Option, /// snippet(cx, span1, "..") // -> "value" /// snippet(cx, span2, "..") // -> "Vec::new()" /// ``` -pub fn snippet<'a>(sess: &impl HasSession, span: Span, default: &'a str) -> Cow<'a, str> { - snippet_opt(sess, span).map_or_else(|| Cow::Borrowed(default), From::from) +pub fn snippet<'a, 'sm>(sm: impl HasSourceMap<'sm>, span: Span, default: &'a str) -> Cow<'a, str> { + snippet_opt(sm, span).map_or_else(|| Cow::Borrowed(default), From::from) } /// Same as [`snippet`], but it adapts the applicability level by following rules: @@ -543,17 +1081,17 @@ pub fn snippet<'a>(sess: &impl HasSession, span: Span, default: &'a str) -> Cow< /// - If the span is inside a macro, change the applicability level to `MaybeIncorrect`. /// - If the default value is used and the applicability level is `MachineApplicable`, change it to /// `HasPlaceholders` -pub fn snippet_with_applicability<'a>( - sess: &impl HasSession, +pub fn snippet_with_applicability<'a, 'sm>( + sm: impl HasSourceMap<'sm>, span: Span, default: &'a str, applicability: &mut Applicability, ) -> Cow<'a, str> { - snippet_with_applicability_sess(sess.sess(), span, default, applicability) + snippet_with_applicability_sm(sm.source_map(), span, default, applicability) } -fn snippet_with_applicability_sess<'a>( - sess: &Session, +fn snippet_with_applicability_sm<'a>( + sm: &SourceMap, span: Span, default: &'a str, applicability: &mut Applicability, @@ -561,7 +1099,7 @@ fn snippet_with_applicability_sess<'a>( if *applicability != Applicability::Unspecified && span.from_expansion() { *applicability = Applicability::MaybeIncorrect; } - snippet_opt(sess, span).map_or_else( + snippet_opt(sm, span).map_or_else( || { if *applicability == Applicability::MachineApplicable { *applicability = Applicability::HasPlaceholders; @@ -573,8 +1111,8 @@ fn snippet_with_applicability_sess<'a>( } /// Converts a span to a code snippet. Returns `None` if not available. -pub fn snippet_opt(sess: &impl HasSession, span: Span) -> Option { - sess.sess().source_map().span_to_snippet(span).ok() +pub fn snippet_opt<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> Option { + sm.source_map().span_to_snippet(span).ok() } /// Converts a span (from a block) to a code snippet if available, otherwise use default. @@ -611,36 +1149,41 @@ pub fn snippet_opt(sess: &impl HasSession, span: Span) -> Option { /// } // aligned with `if` /// ``` /// Note that the first line of the snippet always has 0 indentation. -pub fn snippet_block(sess: &impl HasSession, span: Span, default: &str, indent_relative_to: Option) -> String { - let snip = snippet(sess, span, default); - let indent = indent_relative_to.and_then(|s| indent_of(sess, s)); +pub fn snippet_block<'sm>( + sm: impl HasSourceMap<'sm>, + span: Span, + default: &str, + indent_relative_to: Option, +) -> String { + let snip = snippet(sm, span, default); + let indent = indent_relative_to.and_then(|s| indent_of(sm, s)); reindent_multiline(&snip, true, indent) } /// Same as `snippet_block`, but adapts the applicability level by the rules of /// `snippet_with_applicability`. -pub fn snippet_block_with_applicability( - sess: &impl HasSession, +pub fn snippet_block_with_applicability<'sm>( + sm: impl HasSourceMap<'sm>, span: Span, default: &str, indent_relative_to: Option, applicability: &mut Applicability, ) -> String { - let snip = snippet_with_applicability(sess, span, default, applicability); - let indent = indent_relative_to.and_then(|s| indent_of(sess, s)); + let snip = snippet_with_applicability(sm, span, default, applicability); + let indent = indent_relative_to.and_then(|s| indent_of(sm, s)); reindent_multiline(&snip, true, indent) } -pub fn snippet_block_with_context( - sess: &impl HasSession, +pub fn snippet_block_with_context<'sm>( + sm: impl HasSourceMap<'sm>, span: Span, outer: SyntaxContext, default: &str, indent_relative_to: Option, app: &mut Applicability, ) -> (String, bool) { - let (snip, from_macro) = snippet_with_context(sess, span, outer, default, app); - let indent = indent_relative_to.and_then(|s| indent_of(sess, s)); + let (snip, from_macro) = snippet_with_context(sm, span, outer, default, app); + let indent = indent_relative_to.and_then(|s| indent_of(sm, s)); (reindent_multiline(&snip, true, indent), from_macro) } @@ -654,18 +1197,18 @@ pub fn snippet_block_with_context( /// correctly get a snippet of `vec![]`. /// /// This will also return whether or not the snippet is a macro call. -pub fn snippet_with_context<'a>( - sess: &impl HasSession, +pub fn snippet_with_context<'a, 'sm>( + sm: impl HasSourceMap<'sm>, span: Span, outer: SyntaxContext, default: &'a str, applicability: &mut Applicability, ) -> (Cow<'a, str>, bool) { - snippet_with_context_sess(sess.sess(), span, outer, default, applicability) + snippet_with_context_sm(sm.source_map(), span, outer, default, applicability) } -fn snippet_with_context_sess<'a>( - sess: &Session, +fn snippet_with_context_sm<'a>( + sm: &SourceMap, span: Span, outer: SyntaxContext, default: &'a str, @@ -684,7 +1227,7 @@ fn snippet_with_context_sess<'a>( ); ( - snippet_with_applicability_sess(sess, span, default, applicability), + snippet_with_applicability_sm(sm, span, default, applicability), is_macro_call, ) } @@ -747,15 +1290,15 @@ pub fn trim_span(sm: &SourceMap, span: Span) -> Span { /// writeln!(o, "") -> writeln!(o, "") /// ^^ ^^^^ /// ``` -pub fn expand_past_previous_comma(sess: &impl HasSession, span: Span) -> Span { - let extended = sess.sess().source_map().span_extend_to_prev_char(span, ',', true); +pub fn expand_past_previous_comma<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> Span { + let extended = sm.source_map().span_extend_to_prev_char(span, ',', true); extended.with_lo(extended.lo() - BytePos(1)) } /// Converts `expr` to a `char` literal if it's a `str` literal containing a single /// character (or a single byte with `ascii_only`) -pub fn str_literal_to_char_literal( - sess: &impl HasSession, +pub fn str_literal_to_char_literal<'sm>( + sm: impl HasSourceMap<'sm>, expr: &Expr<'_>, applicability: &mut Applicability, ascii_only: bool, @@ -770,7 +1313,7 @@ pub fn str_literal_to_char_literal( } && len == 1 { - let snip = snippet_with_applicability(sess, expr.span, string, applicability); + let snip = snippet_with_applicability(sm, expr.span, string, applicability); let ch = if let StrStyle::Raw(nhash) = style { let nhash = nhash as usize; // for raw string: r##"a"## diff --git a/tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.rs b/tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.rs deleted file mode 100644 index 155f680c7b13..000000000000 --- a/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/tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.stderr b/tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.stderr deleted file mode 100644 index 8f511883e900..000000000000 --- a/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/tests/ui-toml/missing_docs_allow_unused/clippy.toml b/tests/ui-toml/missing_docs_in_private_items/allow_unused/clippy.toml similarity index 100% rename from tests/ui-toml/missing_docs_allow_unused/clippy.toml rename to tests/ui-toml/missing_docs_in_private_items/allow_unused/clippy.toml diff --git a/tests/ui-toml/pub_crate_missing_docs/clippy.toml b/tests/ui-toml/missing_docs_in_private_items/crate_root/clippy.toml similarity index 100% rename from tests/ui-toml/pub_crate_missing_docs/clippy.toml rename to tests/ui-toml/missing_docs_in_private_items/crate_root/clippy.toml diff --git a/tests/ui-toml/missing_docs_in_private_items/default/clippy.toml b/tests/ui-toml/missing_docs_in_private_items/default/clippy.toml new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.allow_unused.stderr b/tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.allow_unused.stderr new file mode 100644 index 000000000000..7895e79b9245 --- /dev/null +++ b/tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.allow_unused.stderr @@ -0,0 +1,644 @@ +error: missing documentation for 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 field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:60:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for impl item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:77:8 + | +LL | fn f3() {} + | ^^ + +error: missing documentation for impl item + --> 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 item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:117:4 + | +LL | fn fn_crate() {} + | ^^^^^^^^ + +error: missing documentation for item + --> 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 item + --> 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 item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:120:6 + | +LL | type TyAliasCrate = u32; + | ^^^^^^^^^^^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:121:7 + | +LL | trait TraitAliasCrate = Iterator; + | ^^^^^^^^^^^^^^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:122:8 + | +LL | struct StructCrate; + | ^^^^^^^^^^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:124:8 + | +LL | struct StructFieldCrate { + | ^^^^^^^^^^^^^^^^ + +error: missing documentation for 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 field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:128:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for item + --> 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 item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:140:6 + | +LL | enum EnumCrate { + | ^^^^^^^^^ + +error: missing documentation for variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:141:5 + | +LL | V1, + | ^^ + +error: missing documentation for variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:142:5 + | +LL | V2(u32), + | ^^ + +error: missing documentation for variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:144:5 + | +LL | V3 { + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:145:9 + | +LL | f1: u32, + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:155:9 + | +LL | f1: u32, + | ^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:161:7 + | +LL | union UnionCrate { + | ^^^^^^^^^^ + +error: missing documentation for 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 field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:165:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for impl item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:176:12 + | +LL | pub fn f1() {} + | ^^ + +error: missing documentation for impl item + --> 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 impl item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:182:8 + | +LL | fn f3() {} + | ^^ + +error: missing documentation for impl item + --> 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 item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:190:7 + | +LL | trait TraitCrate { + | ^^^^^^^^^^ + +error: missing documentation for trait item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:191:8 + | +LL | fn f1(); + | ^^ + +error: missing documentation for trait item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:192:8 + | +LL | fn f2() {} + | ^^ + +error: missing documentation for trait item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:193:11 + | +LL | const C1: u32; + | ^^ + +error: missing documentation for trait item + --> 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 trait item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:195:10 + | +LL | type T1; + | ^^ + +error: missing documentation for item + --> 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 item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:220:7 + | +LL | macro mac_crate { + | ^^^^^^^^^ + +error: missing documentation for 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 field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:241:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:255:5 + | +LL | V1, + | ^^ + +error: missing documentation for variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:256:5 + | +LL | V2(u32), + | ^^ + +error: missing documentation for variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:258:5 + | +LL | V3 { + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:259:9 + | +LL | f1: u32, + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:269:9 + | +LL | f1: u32, + | ^^ + +error: missing documentation for 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 field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:279:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for impl item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:290:12 + | +LL | pub fn f1() {} + | ^^ + +error: missing documentation for impl item + --> 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 impl item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:296:8 + | +LL | fn f3() {} + | ^^ + +error: missing documentation for impl item + --> 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 trait item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:305:8 + | +LL | fn f1(); + | ^^ + +error: missing documentation for trait item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:306:8 + | +LL | fn f2() {} + | ^^ + +error: missing documentation for trait item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:307:11 + | +LL | const C1: u32; + | ^^ + +error: missing documentation for trait item + --> 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 trait item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:309:10 + | +LL | type T1; + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:541:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:567:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:588:8 + | +LL | fn f3() {} + | ^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:591:12 + | +LL | struct S3 { + | ^^ + +error: missing documentation for 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 field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:595:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:600:10 + | +LL | enum E3 { + | ^^ + +error: missing documentation for variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:602:9 + | +LL | V1 { + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:603:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:609:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for item + --> 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 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 field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:623:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:630:9 + | +LL | V1 { + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:631:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:637:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:647:5 + | +LL | mod mod_crate { + | ^^^^^^^^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:648:12 + | +LL | pub fn f1() {} + | ^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:651:16 + | +LL | pub struct S1 { + | ^^ + +error: missing documentation for 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 field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:655:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:660:14 + | +LL | pub enum E1 { + | ^^ + +error: missing documentation for variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:662:9 + | +LL | V1 { + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:663:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:669:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for item + --> 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 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 field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:683:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:690:9 + | +LL | V1 { + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:691:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:697:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:705:8 + | +LL | fn f3() {} + | ^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:708:12 + | +LL | struct S3 { + | ^^ + +error: missing documentation for 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 field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:712:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:717:10 + | +LL | enum E3 { + | ^^ + +error: missing documentation for variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:719:9 + | +LL | V1 { + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:720:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:726:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for item + --> 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 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 field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:740:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:747:9 + | +LL | V1 { + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:748:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:754:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1061:9 + | +LL | f2: u32, + | ^^ + +error: missing documentation for 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 item + --> 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 item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1072:18 + | +LL | pub enum E1 { + | ^^ + +error: missing documentation for variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1074:13 + | +LL | V2, + | ^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1077:20 + | +LL | pub struct S2; + | ^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1096:18 + | +LL | $(pub fn f2() {}) + | ^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1166:20 + | +LL | pub struct VisFromOutside; + | ^^^^^^^^^^^^^^ + +error: aborting due to 106 previous errors + diff --git a/tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.crate_root.stderr b/tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.crate_root.stderr new file mode 100644 index 000000000000..0534040d9d05 --- /dev/null +++ b/tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.crate_root.stderr @@ -0,0 +1,500 @@ +error: missing documentation for 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 field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:32:5 + | +LL | _f7: u32, + | ^^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:60:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:66:5 + | +LL | _f7: u32, + | ^^^ + +error: missing documentation for impl item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:77:8 + | +LL | fn f3() {} + | ^^ + +error: missing documentation for impl item + --> 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 item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:117:4 + | +LL | fn fn_crate() {} + | ^^^^^^^^ + +error: missing documentation for item + --> 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 item + --> 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 item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:120:6 + | +LL | type TyAliasCrate = u32; + | ^^^^^^^^^^^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:121:7 + | +LL | trait TraitAliasCrate = Iterator; + | ^^^^^^^^^^^^^^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:122:8 + | +LL | struct StructCrate; + | ^^^^^^^^^^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:124:8 + | +LL | struct StructFieldCrate { + | ^^^^^^^^^^^^^^^^ + +error: missing documentation for 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 field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:128:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for 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 field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:134:5 + | +LL | _f7: u32, + | ^^^ + +error: missing documentation for item + --> 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 item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:140:6 + | +LL | enum EnumCrate { + | ^^^^^^^^^ + +error: missing documentation for variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:141:5 + | +LL | V1, + | ^^ + +error: missing documentation for variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:142:5 + | +LL | V2(u32), + | ^^ + +error: missing documentation for variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:144:5 + | +LL | V3 { + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:145:9 + | +LL | f1: u32, + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:155:9 + | +LL | f1: u32, + | ^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:161:7 + | +LL | union UnionCrate { + | ^^^^^^^^^^ + +error: missing documentation for 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 field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:165:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for 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 field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:171:5 + | +LL | _f7: u32, + | ^^^ + +error: missing documentation for impl item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:176:12 + | +LL | pub fn f1() {} + | ^^ + +error: missing documentation for impl item + --> 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 impl item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:182:8 + | +LL | fn f3() {} + | ^^ + +error: missing documentation for impl item + --> 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 item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:190:7 + | +LL | trait TraitCrate { + | ^^^^^^^^^^ + +error: missing documentation for trait item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:191:8 + | +LL | fn f1(); + | ^^ + +error: missing documentation for trait item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:192:8 + | +LL | fn f2() {} + | ^^ + +error: missing documentation for trait item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:193:11 + | +LL | const C1: u32; + | ^^ + +error: missing documentation for trait item + --> 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 trait item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:195:10 + | +LL | type T1; + | ^^ + +error: missing documentation for item + --> 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 item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:220:7 + | +LL | macro mac_crate { + | ^^^^^^^^^ + +error: missing documentation for 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 field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:241:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for 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 field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:247:5 + | +LL | _f7: u32, + | ^^^ + +error: missing documentation for variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:255:5 + | +LL | V1, + | ^^ + +error: missing documentation for variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:256:5 + | +LL | V2(u32), + | ^^ + +error: missing documentation for variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:258:5 + | +LL | V3 { + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:259:9 + | +LL | f1: u32, + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:269:9 + | +LL | f1: u32, + | ^^ + +error: missing documentation for 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 field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:279:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for 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 field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:285:5 + | +LL | _f7: u32, + | ^^^ + +error: missing documentation for impl item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:290:12 + | +LL | pub fn f1() {} + | ^^ + +error: missing documentation for impl item + --> 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 impl item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:296:8 + | +LL | fn f3() {} + | ^^ + +error: missing documentation for impl item + --> 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 trait item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:305:8 + | +LL | fn f1(); + | ^^ + +error: missing documentation for trait item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:306:8 + | +LL | fn f2() {} + | ^^ + +error: missing documentation for trait item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:307:11 + | +LL | const C1: u32; + | ^^ + +error: missing documentation for trait item + --> 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 trait item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:309:10 + | +LL | type T1; + | ^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:647:5 + | +LL | mod mod_crate { + | ^^^^^^^^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:648:12 + | +LL | pub fn f1() {} + | ^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:651:16 + | +LL | pub struct S1 { + | ^^ + +error: missing documentation for 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 item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:660:14 + | +LL | pub enum E1 { + | ^^ + +error: missing documentation for variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:662:9 + | +LL | V1 { + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:663:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:669:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for item + --> 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 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 variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:690:9 + | +LL | V1 { + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:691:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:697:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for 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 item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1072:18 + | +LL | pub enum E1 { + | ^^ + +error: missing documentation for variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1074:13 + | +LL | V2, + | ^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1077:20 + | +LL | pub struct S2; + | ^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1096:18 + | +LL | $(pub fn f2() {}) + | ^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1166:20 + | +LL | pub struct VisFromOutside; + | ^^^^^^^^^^^^^^ + +error: aborting due to 82 previous errors + diff --git a/tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.default.stderr b/tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.default.stderr new file mode 100644 index 000000000000..8ce45727e2d4 --- /dev/null +++ b/tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.default.stderr @@ -0,0 +1,704 @@ +error: missing documentation for 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 field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:32:5 + | +LL | _f7: u32, + | ^^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:60:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:66:5 + | +LL | _f7: u32, + | ^^^ + +error: missing documentation for impl item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:77:8 + | +LL | fn f3() {} + | ^^ + +error: missing documentation for impl item + --> 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 item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:117:4 + | +LL | fn fn_crate() {} + | ^^^^^^^^ + +error: missing documentation for item + --> 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 item + --> 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 item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:120:6 + | +LL | type TyAliasCrate = u32; + | ^^^^^^^^^^^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:121:7 + | +LL | trait TraitAliasCrate = Iterator; + | ^^^^^^^^^^^^^^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:122:8 + | +LL | struct StructCrate; + | ^^^^^^^^^^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:124:8 + | +LL | struct StructFieldCrate { + | ^^^^^^^^^^^^^^^^ + +error: missing documentation for 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 field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:128:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for 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 field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:134:5 + | +LL | _f7: u32, + | ^^^ + +error: missing documentation for item + --> 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 item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:140:6 + | +LL | enum EnumCrate { + | ^^^^^^^^^ + +error: missing documentation for variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:141:5 + | +LL | V1, + | ^^ + +error: missing documentation for variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:142:5 + | +LL | V2(u32), + | ^^ + +error: missing documentation for variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:144:5 + | +LL | V3 { + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:145:9 + | +LL | f1: u32, + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:155:9 + | +LL | f1: u32, + | ^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:161:7 + | +LL | union UnionCrate { + | ^^^^^^^^^^ + +error: missing documentation for 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 field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:165:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for 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 field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:171:5 + | +LL | _f7: u32, + | ^^^ + +error: missing documentation for impl item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:176:12 + | +LL | pub fn f1() {} + | ^^ + +error: missing documentation for impl item + --> 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 impl item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:182:8 + | +LL | fn f3() {} + | ^^ + +error: missing documentation for impl item + --> 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 item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:190:7 + | +LL | trait TraitCrate { + | ^^^^^^^^^^ + +error: missing documentation for trait item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:191:8 + | +LL | fn f1(); + | ^^ + +error: missing documentation for trait item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:192:8 + | +LL | fn f2() {} + | ^^ + +error: missing documentation for trait item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:193:11 + | +LL | const C1: u32; + | ^^ + +error: missing documentation for trait item + --> 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 trait item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:195:10 + | +LL | type T1; + | ^^ + +error: missing documentation for item + --> 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 item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:220:7 + | +LL | macro mac_crate { + | ^^^^^^^^^ + +error: missing documentation for 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 field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:241:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for 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 field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:247:5 + | +LL | _f7: u32, + | ^^^ + +error: missing documentation for variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:255:5 + | +LL | V1, + | ^^ + +error: missing documentation for variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:256:5 + | +LL | V2(u32), + | ^^ + +error: missing documentation for variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:258:5 + | +LL | V3 { + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:259:9 + | +LL | f1: u32, + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:269:9 + | +LL | f1: u32, + | ^^ + +error: missing documentation for 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 field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:279:5 + | +LL | f3: u32, + | ^^ + +error: missing documentation for 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 field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:285:5 + | +LL | _f7: u32, + | ^^^ + +error: missing documentation for impl item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:290:12 + | +LL | pub fn f1() {} + | ^^ + +error: missing documentation for impl item + --> 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 impl item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:296:8 + | +LL | fn f3() {} + | ^^ + +error: missing documentation for impl item + --> 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 trait item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:305:8 + | +LL | fn f1(); + | ^^ + +error: missing documentation for trait item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:306:8 + | +LL | fn f2() {} + | ^^ + +error: missing documentation for trait item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:307:11 + | +LL | const C1: u32; + | ^^ + +error: missing documentation for trait item + --> 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 trait item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:309:10 + | +LL | type T1; + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:541:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:567:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:588:8 + | +LL | fn f3() {} + | ^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:591:12 + | +LL | struct S3 { + | ^^ + +error: missing documentation for 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 field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:595:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:600:10 + | +LL | enum E3 { + | ^^ + +error: missing documentation for variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:602:9 + | +LL | V1 { + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:603:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:609:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for item + --> 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 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 field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:623:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:630:9 + | +LL | V1 { + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:631:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:637:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:647:5 + | +LL | mod mod_crate { + | ^^^^^^^^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:648:12 + | +LL | pub fn f1() {} + | ^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:651:16 + | +LL | pub struct S1 { + | ^^ + +error: missing documentation for 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 field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:655:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:660:14 + | +LL | pub enum E1 { + | ^^ + +error: missing documentation for variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:662:9 + | +LL | V1 { + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:663:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:669:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for item + --> 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 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 field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:683:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:690:9 + | +LL | V1 { + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:691:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:697:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:705:8 + | +LL | fn f3() {} + | ^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:708:12 + | +LL | struct S3 { + | ^^ + +error: missing documentation for 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 field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:712:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:717:10 + | +LL | enum E3 { + | ^^ + +error: missing documentation for variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:719:9 + | +LL | V1 { + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:720:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:726:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for item + --> 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 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 field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:740:9 + | +LL | f3: u32, + | ^^ + +error: missing documentation for variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:747:9 + | +LL | V1 { + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:748:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:754:13 + | +LL | f1: u32, + | ^^ + +error: missing documentation for field + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1061:9 + | +LL | f2: u32, + | ^^ + +error: missing documentation for 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 item + --> 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 item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1072:18 + | +LL | pub enum E1 { + | ^^ + +error: missing documentation for variant + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1074:13 + | +LL | V2, + | ^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1077:20 + | +LL | pub struct S2; + | ^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1096:18 + | +LL | $(pub fn f2() {}) + | ^^ + +error: missing documentation for item + --> tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs:1166:20 + | +LL | pub struct VisFromOutside; + | ^^^^^^^^^^^^^^ + +error: aborting due to 116 previous errors + diff --git a/tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs b/tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs new file mode 100644 index 000000000000..73e8ecb8c3e0 --- /dev/null +++ b/tests/ui-toml/missing_docs_in_private_items/missing_docs_in_private_items.rs @@ -0,0 +1,1168 @@ +//@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() { + #[expect(clippy::module_inception)] + 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/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs b/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs deleted file mode 100644 index 6a1d2b51abc8..000000000000 --- a/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/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr b/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr deleted file mode 100644 index 0d70276de42d..000000000000 --- a/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/tests/ui/missing_doc.rs b/tests/ui/missing_doc.rs deleted file mode 100644 index 705de959cb7d..000000000000 --- a/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/tests/ui/missing_doc.stderr b/tests/ui/missing_doc.stderr deleted file mode 100644 index 63e440b82d14..000000000000 --- a/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/tests/ui/missing_doc_crate.rs b/tests/ui/missing_doc_crate.rs deleted file mode 100644 index e6e783a2bb40..000000000000 --- a/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/tests/ui/missing_doc_crate_missing.rs b/tests/ui/missing_doc_crate_missing.rs deleted file mode 100644 index f55d8b67cb84..000000000000 --- a/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/tests/ui/missing_doc_crate_missing.stderr b/tests/ui/missing_doc_crate_missing.stderr deleted file mode 100644 index d6a4342c5031..000000000000 --- a/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/tests/ui/missing_doc_impl.rs b/tests/ui/missing_doc_impl.rs deleted file mode 100644 index 034ce31dfe76..000000000000 --- a/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/tests/ui/missing_doc_impl.stderr b/tests/ui/missing_doc_impl.stderr deleted file mode 100644 index 999ff06f593e..000000000000 --- a/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 -