Skip to content

Commit 432a8d0

Browse files
committed
resolve merge-conflict from rust-lang:master
2 parents ace8ece + ee83760 commit 432a8d0

File tree

212 files changed

+1263
-367
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

212 files changed

+1263
-367
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5463,6 +5463,7 @@ Released 2018-09-13
54635463
[`ref_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_patterns
54645464
[`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro
54655465
[`repeat_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_once
5466+
[`repeat_vec_with_capacity`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_vec_with_capacity
54665467
[`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts
54675468
[`reserve_after_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#reserve_after_initialization
54685469
[`rest_pat_in_fully_bound_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#rest_pat_in_fully_bound_structs
@@ -5546,6 +5547,7 @@ Released 2018-09-13
55465547
[`tabs_in_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#tabs_in_doc_comments
55475548
[`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment
55485549
[`temporary_cstring_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_cstring_as_ptr
5550+
[`test_attr_in_doctest`]: https://rust-lang.github.io/rust-clippy/master/index.html#test_attr_in_doctest
55495551
[`tests_outside_test_module`]: https://rust-lang.github.io/rust-clippy/master/index.html#tests_outside_test_module
55505552
[`to_digit_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_digit_is_some
55515553
[`to_string_in_display`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_display

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ toml = "0.7.3"
3737
walkdir = "2.3"
3838
# This is used by the `collect-metadata` alias.
3939
filetime = "0.2"
40-
itertools = "0.10.1"
40+
itertools = "0.11"
4141

4242
# UI test dependencies
4343
clippy_utils = { path = "clippy_utils" }

clippy_dev/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ edition = "2021"
77
aho-corasick = "0.7"
88
clap = "4.1.4"
99
indoc = "1.0"
10-
itertools = "0.10.1"
10+
itertools = "0.11"
1111
opener = "0.5"
1212
shell-escape = "0.1"
1313
walkdir = "2.3"

clippy_lints/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ cargo_metadata = "0.15.3"
1414
clippy_config = { path = "../clippy_config" }
1515
clippy_utils = { path = "../clippy_utils" }
1616
declare_clippy_lint = { path = "../declare_clippy_lint" }
17-
itertools = "0.10.1"
17+
itertools = "0.11"
1818
quine-mc_cluskey = "0.2"
1919
regex-syntax = "0.7"
2020
serde = { version = "1.0", features = ["derive"] }

clippy_lints/src/booleans.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -424,8 +424,9 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> {
424424
improvements.push(suggestion);
425425
}
426426
}
427-
let nonminimal_bool_lint = |suggestions: Vec<_>| {
427+
let nonminimal_bool_lint = |mut suggestions: Vec<_>| {
428428
if self.cx.tcx.lint_level_at_node(NONMINIMAL_BOOL, e.hir_id).0 != Level::Allow {
429+
suggestions.sort();
429430
span_lint_hir_and_then(
430431
self.cx,
431432
NONMINIMAL_BOOL,

clippy_lints/src/declared_lints.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
140140
crate::doc::MISSING_SAFETY_DOC_INFO,
141141
crate::doc::NEEDLESS_DOCTEST_MAIN_INFO,
142142
crate::doc::SUSPICIOUS_DOC_COMMENTS_INFO,
143+
crate::doc::TEST_ATTR_IN_DOCTEST_INFO,
143144
crate::doc::UNNECESSARY_SAFETY_DOC_INFO,
144145
crate::double_parens::DOUBLE_PARENS_INFO,
145146
crate::drop_forget_ref::DROP_NON_DROP_INFO,
@@ -598,6 +599,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
598599
crate::reference::DEREF_ADDROF_INFO,
599600
crate::regex::INVALID_REGEX_INFO,
600601
crate::regex::TRIVIAL_REGEX_INFO,
602+
crate::repeat_vec_with_capacity::REPEAT_VEC_WITH_CAPACITY_INFO,
601603
crate::reserve_after_initialization::RESERVE_AFTER_INITIALIZATION_INFO,
602604
crate::return_self_not_must_use::RETURN_SELF_NOT_MUST_USE_INFO,
603605
crate::returns::LET_AND_RETURN_INFO,

clippy_lints/src/dereference.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -771,7 +771,7 @@ impl TyCoercionStability {
771771
DefinedTy::Mir(ty) => Self::for_mir_ty(
772772
cx.tcx,
773773
ty.param_env,
774-
cx.tcx.erase_late_bound_regions(ty.value),
774+
cx.tcx.instantiate_bound_regions_with_erased(ty.value),
775775
for_return,
776776
),
777777
}

clippy_lints/src/derive.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ fn check_hash_peq<'tcx>(
255255
"you are deriving `Hash` but have implemented `PartialEq` explicitly",
256256
|diag| {
257257
if let Some(local_def_id) = impl_id.as_local() {
258-
let hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_def_id);
258+
let hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id);
259259
diag.span_note(cx.tcx.hir().span(hir_id), "`PartialEq` implemented here");
260260
}
261261
},
@@ -299,7 +299,7 @@ fn check_ord_partial_ord<'tcx>(
299299

300300
span_lint_and_then(cx, DERIVE_ORD_XOR_PARTIAL_ORD, span, mess, |diag| {
301301
if let Some(local_def_id) = impl_id.as_local() {
302-
let hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_def_id);
302+
let hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id);
303303
diag.span_note(cx.tcx.hir().span(hir_id), "`PartialOrd` implemented here");
304304
}
305305
});
@@ -381,7 +381,7 @@ fn check_unsafe_derive_deserialize<'tcx>(
381381
&& match_def_path(cx, trait_def_id, &paths::SERDE_DESERIALIZE)
382382
&& let ty::Adt(def, _) = ty.kind()
383383
&& let Some(local_def_id) = def.did().as_local()
384-
&& let adt_hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_def_id)
384+
&& let adt_hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id)
385385
&& !is_lint_allowed(cx, UNSAFE_DERIVE_DESERIALIZE, adt_hir_id)
386386
&& cx
387387
.tcx

clippy_lints/src/doc/mod.rs

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,39 @@ declare_clippy_lint! {
199199
"presence of `fn main() {` in code examples"
200200
}
201201

202+
declare_clippy_lint! {
203+
/// ### What it does
204+
/// Checks for `#[test]` in doctests unless they are marked with
205+
/// either `ignore`, `no_run` or `compile_fail`.
206+
///
207+
/// ### Why is this bad?
208+
/// Code in examples marked as `#[test]` will somewhat
209+
/// surprisingly not be run by `cargo test`. If you really want
210+
/// to show how to test stuff in an example, mark it `no_run` to
211+
/// make the intent clear.
212+
///
213+
/// ### Examples
214+
/// ```no_run
215+
/// /// An example of a doctest with a `main()` function
216+
/// ///
217+
/// /// # Examples
218+
/// ///
219+
/// /// ```
220+
/// /// #[test]
221+
/// /// fn equality_works() {
222+
/// /// assert_eq!(1_u8, 1);
223+
/// /// }
224+
/// /// ```
225+
/// fn test_attr_in_doctest() {
226+
/// unimplemented!();
227+
/// }
228+
/// ```
229+
#[clippy::version = "1.40.0"]
230+
pub TEST_ATTR_IN_DOCTEST,
231+
suspicious,
232+
"presence of `#[test]` in code examples"
233+
}
234+
202235
declare_clippy_lint! {
203236
/// ### What it does
204237
/// Detects the syntax `['foo']` in documentation comments (notice quotes instead of backticks)
@@ -305,15 +338,14 @@ declare_clippy_lint! {
305338
"suspicious usage of (outer) doc comments"
306339
}
307340

308-
#[expect(clippy::module_name_repetitions)]
309341
#[derive(Clone)]
310-
pub struct DocMarkdown {
342+
pub struct Documentation {
311343
valid_idents: FxHashSet<String>,
312344
in_trait_impl: bool,
313345
check_private_items: bool,
314346
}
315347

316-
impl DocMarkdown {
348+
impl Documentation {
317349
pub fn new(valid_idents: &[String], check_private_items: bool) -> Self {
318350
Self {
319351
valid_idents: valid_idents.iter().cloned().collect(),
@@ -323,18 +355,19 @@ impl DocMarkdown {
323355
}
324356
}
325357

326-
impl_lint_pass!(DocMarkdown => [
358+
impl_lint_pass!(Documentation => [
327359
DOC_LINK_WITH_QUOTES,
328360
DOC_MARKDOWN,
329361
MISSING_SAFETY_DOC,
330362
MISSING_ERRORS_DOC,
331363
MISSING_PANICS_DOC,
332364
NEEDLESS_DOCTEST_MAIN,
365+
TEST_ATTR_IN_DOCTEST,
333366
UNNECESSARY_SAFETY_DOC,
334367
SUSPICIOUS_DOC_COMMENTS
335368
]);
336369

337-
impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
370+
impl<'tcx> LateLintPass<'tcx> for Documentation {
338371
fn check_crate(&mut self, cx: &LateContext<'tcx>) {
339372
let attrs = cx.tcx.hir().attrs(hir::CRATE_HIR_ID);
340373
check_attrs(cx, &self.valid_idents, attrs);
@@ -516,6 +549,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
516549
let mut in_heading = false;
517550
let mut is_rust = false;
518551
let mut no_test = false;
552+
let mut ignore = false;
519553
let mut edition = None;
520554
let mut ticks_unbalanced = false;
521555
let mut text_to_check: Vec<(CowStr<'_>, Range<usize>)> = Vec::new();
@@ -531,6 +565,8 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
531565
break;
532566
} else if item == "no_test" {
533567
no_test = true;
568+
} else if item == "no_run" || item == "compile_fail" {
569+
ignore = true;
534570
}
535571
if let Some(stripped) = item.strip_prefix("edition") {
536572
is_rust = true;
@@ -544,6 +580,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
544580
End(CodeBlock(_)) => {
545581
in_code = false;
546582
is_rust = false;
583+
ignore = false;
547584
},
548585
Start(Link(_, url, _)) => in_link = Some(url),
549586
End(Link(..)) => in_link = None,
@@ -597,7 +634,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
597634
if in_code {
598635
if is_rust && !no_test {
599636
let edition = edition.unwrap_or_else(|| cx.tcx.sess.edition());
600-
needless_doctest_main::check(cx, &text, edition, range.clone(), fragments);
637+
needless_doctest_main::check(cx, &text, edition, range.clone(), fragments, ignore);
601638
}
602639
} else {
603640
if in_link.is_some() {

clippy_lints/src/doc/needless_doctest_main.rs

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use std::ops::Range;
22
use std::{io, thread};
33

4-
use crate::doc::NEEDLESS_DOCTEST_MAIN;
4+
use crate::doc::{NEEDLESS_DOCTEST_MAIN, TEST_ATTR_IN_DOCTEST};
55
use clippy_utils::diagnostics::span_lint;
6-
use rustc_ast::{Async, Fn, FnRetTy, ItemKind};
6+
use rustc_ast::{Async, Fn, FnRetTy, Item, ItemKind};
77
use rustc_data_structures::sync::Lrc;
88
use rustc_errors::emitter::EmitterWriter;
99
use rustc_errors::Handler;
@@ -13,14 +13,33 @@ use rustc_parse::parser::ForceCollect;
1313
use rustc_session::parse::ParseSess;
1414
use rustc_span::edition::Edition;
1515
use rustc_span::source_map::{FilePathMapping, SourceMap};
16-
use rustc_span::{sym, FileName};
16+
use rustc_span::{sym, FileName, Pos};
1717

1818
use super::Fragments;
1919

20-
pub fn check(cx: &LateContext<'_>, text: &str, edition: Edition, range: Range<usize>, fragments: Fragments<'_>) {
21-
fn has_needless_main(code: String, edition: Edition) -> bool {
20+
fn get_test_spans(item: &Item, test_attr_spans: &mut Vec<Range<usize>>) {
21+
test_attr_spans.extend(
22+
item.attrs
23+
.iter()
24+
.find(|attr| attr.has_name(sym::test))
25+
.map(|attr| attr.span.lo().to_usize()..item.ident.span.hi().to_usize()),
26+
);
27+
}
28+
29+
pub fn check(
30+
cx: &LateContext<'_>,
31+
text: &str,
32+
edition: Edition,
33+
range: Range<usize>,
34+
fragments: Fragments<'_>,
35+
ignore: bool,
36+
) {
37+
// return whether the code contains a needless `fn main` plus a vector of byte position ranges
38+
// of all `#[test]` attributes in not ignored code examples
39+
fn check_code_sample(code: String, edition: Edition, ignore: bool) -> (bool, Vec<Range<usize>>) {
2240
rustc_driver::catch_fatal_errors(|| {
2341
rustc_span::create_session_globals_then(edition, || {
42+
let mut test_attr_spans = vec![];
2443
let filename = FileName::anon_source_code(&code);
2544

2645
let fallback_bundle =
@@ -35,17 +54,21 @@ pub fn check(cx: &LateContext<'_>, text: &str, edition: Edition, range: Range<us
3554
Ok(p) => p,
3655
Err(errs) => {
3756
drop(errs);
38-
return false;
57+
return (false, test_attr_spans);
3958
},
4059
};
4160

4261
let mut relevant_main_found = false;
62+
let mut eligible = true;
4363
loop {
4464
match parser.parse_item(ForceCollect::No) {
4565
Ok(Some(item)) => match &item.kind {
4666
ItemKind::Fn(box Fn {
4767
sig, body: Some(block), ..
4868
}) if item.ident.name == sym::main => {
69+
if !ignore {
70+
get_test_spans(&item, &mut test_attr_spans);
71+
}
4972
let is_async = matches!(sig.header.asyncness, Async::Yes { .. });
5073
let returns_nothing = match &sig.decl.output {
5174
FnRetTy::Default(..) => true,
@@ -58,27 +81,34 @@ pub fn check(cx: &LateContext<'_>, text: &str, edition: Edition, range: Range<us
5881
relevant_main_found = true;
5982
} else {
6083
// This main function should not be linted, we're done
61-
return false;
84+
eligible = false;
85+
}
86+
},
87+
// Another function was found; this case is ignored for needless_doctest_main
88+
ItemKind::Fn(box Fn { .. }) => {
89+
eligible = false;
90+
if !ignore {
91+
get_test_spans(&item, &mut test_attr_spans);
6292
}
6393
},
6494
// Tests with one of these items are ignored
6595
ItemKind::Static(..)
6696
| ItemKind::Const(..)
6797
| ItemKind::ExternCrate(..)
68-
| ItemKind::ForeignMod(..)
69-
// Another function was found; this case is ignored
70-
| ItemKind::Fn(..) => return false,
98+
| ItemKind::ForeignMod(..) => {
99+
eligible = false;
100+
},
71101
_ => {},
72102
},
73103
Ok(None) => break,
74104
Err(e) => {
75105
e.cancel();
76-
return false;
106+
return (false, test_attr_spans);
77107
},
78108
}
79109
}
80110

81-
relevant_main_found
111+
(relevant_main_found & eligible, test_attr_spans)
82112
})
83113
})
84114
.ok()
@@ -90,11 +120,16 @@ pub fn check(cx: &LateContext<'_>, text: &str, edition: Edition, range: Range<us
90120
// Because of the global session, we need to create a new session in a different thread with
91121
// the edition we need.
92122
let text = text.to_owned();
93-
if thread::spawn(move || has_needless_main(text, edition))
123+
let (has_main, test_attr_spans) = thread::spawn(move || check_code_sample(text, edition, ignore))
94124
.join()
95-
.expect("thread::spawn failed")
96-
&& let Some(span) = fragments.span(cx, range.start..range.end - trailing_whitespace)
97-
{
125+
.expect("thread::spawn failed");
126+
if has_main && let Some(span) = fragments.span(cx, range.start..range.end - trailing_whitespace) {
98127
span_lint(cx, NEEDLESS_DOCTEST_MAIN, span, "needless `fn main` in doctest");
99128
}
129+
for span in test_attr_spans {
130+
let span = (range.start + span.start)..(range.start + span.end);
131+
if let Some(span) = fragments.span(cx, span) {
132+
span_lint(cx, TEST_ATTR_IN_DOCTEST, span, "unit tests in doctest are not executed");
133+
}
134+
}
100135
}

clippy_lints/src/equatable_if_let.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,12 @@ fn unary_pattern(pat: &Pat<'_>) -> bool {
4646
pats.iter().all(unary_pattern)
4747
}
4848
match &pat.kind {
49-
PatKind::Slice(_, _, _) | PatKind::Range(_, _, _) | PatKind::Binding(..) | PatKind::Wild | PatKind::Or(_) => {
50-
false
51-
},
49+
PatKind::Slice(_, _, _)
50+
| PatKind::Range(_, _, _)
51+
| PatKind::Binding(..)
52+
| PatKind::Wild
53+
| PatKind::Never
54+
| PatKind::Or(_) => false,
5255
PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)),
5356
PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => etc.as_opt_usize().is_none() && array_rec(a),
5457
PatKind::Ref(x, _) | PatKind::Box(x) => unary_pattern(x),

clippy_lints/src/error_impl_error.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ impl<'tcx> LateLintPass<'tcx> for ErrorImplError {
5858
if let Some(trait_def_id) = imp.of_trait.and_then(|t| t.trait_def_id())
5959
&& error_def_id == trait_def_id
6060
&& let Some(def_id) = path_res(cx, imp.self_ty).opt_def_id().and_then(DefId::as_local)
61-
&& let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id)
61+
&& let hir_id = cx.tcx.local_def_id_to_hir_id(def_id)
6262
&& let Some(ident) = cx.tcx.opt_item_ident(def_id.to_def_id())
6363
&& ident.name == sym::Error
6464
&& is_visible_outside_module(cx, def_id) =>

clippy_lints/src/escape.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal {
7474
let parent_id = cx
7575
.tcx
7676
.hir()
77-
.get_parent_item(cx.tcx.hir().local_def_id_to_hir_id(fn_def_id))
77+
.get_parent_item(cx.tcx.local_def_id_to_hir_id(fn_def_id))
7878
.def_id;
7979
let parent_node = cx.tcx.hir().find_by_def_id(parent_id);
8080

clippy_lints/src/excessive_bools.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ impl<'tcx> LateLintPass<'tcx> for ExcessiveBools {
171171
span: Span,
172172
def_id: LocalDefId,
173173
) {
174-
let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
174+
let hir_id = cx.tcx.local_def_id_to_hir_id(def_id);
175175
if let Some(fn_header) = fn_kind.header()
176176
&& fn_header.abi == Abi::Rust
177177
&& get_parent_as_impl(cx.tcx, hir_id).map_or(true, |impl_item| impl_item.of_trait.is_none())

0 commit comments

Comments
 (0)