mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Merge commit 'a62c6af53676bb15a40488ce2d632de558f001de' into clippy-subtree-update
This commit is contained in:
+1
-1
@@ -42,7 +42,7 @@ walkdir = "2.3"
|
||||
filetime = "0.2.9"
|
||||
itertools = "0.12"
|
||||
pulldown-cmark = { version = "0.11", default-features = false, features = ["html"] }
|
||||
askama = { version = "0.15", default-features = false, features = ["alloc", "config", "derive"] }
|
||||
askama = { version = "0.15.4", default-features = false, features = ["alloc", "config", "derive"] }
|
||||
|
||||
[dev-dependencies.toml]
|
||||
version = "0.9.7"
|
||||
|
||||
@@ -79,7 +79,7 @@ to be run inside the `rust` directory):
|
||||
```bash
|
||||
git fetch upstream # assuming upstream is the rust-lang/rust remote
|
||||
git switch rustup
|
||||
git merge upstream/master --no-ff
|
||||
git merge upstream/main --no-ff
|
||||
```
|
||||
> Note: This is one of the few instances where a merge commit is allowed in
|
||||
> a PR.
|
||||
@@ -99,7 +99,7 @@ to be run inside the `rust` directory):
|
||||
|
||||
All the following commands have to be run inside the `rust` directory.
|
||||
|
||||
1. Make sure you have checked out the latest `master` of `rust-lang/rust`.
|
||||
1. Make sure you have checked out the latest `main` of `rust-lang/rust`.
|
||||
2. Sync the `rust-lang/rust-clippy` master to the rust-copy of Clippy:
|
||||
```bash
|
||||
git switch -c clippy-subtree-update
|
||||
|
||||
@@ -146,7 +146,7 @@ in this chapter:
|
||||
|
||||
- [Stages of compilation](https://rustc-dev-guide.rust-lang.org/compiler-src.html#the-main-stages-of-compilation)
|
||||
- [Diagnostic items](https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-items.html)
|
||||
- [Type checking](https://rustc-dev-guide.rust-lang.org/type-checking.html)
|
||||
- [Type checking](https://rustc-dev-guide.rust-lang.org/hir-typeck/summary.html)
|
||||
- [Ty module](https://rustc-dev-guide.rust-lang.org/ty.html)
|
||||
|
||||
[Adt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/ty_kind/enum.TyKind.html#variant.Adt
|
||||
@@ -154,7 +154,7 @@ in this chapter:
|
||||
[expr_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html#method.expr_ty
|
||||
[node_type]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html#method.node_type
|
||||
[is_char]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html#method.is_char
|
||||
[is_char_source]: https://doc.rust-lang.org/nightly/nightly-rustc/src/rustc_middle/ty/sty.rs.html#1831-1834
|
||||
[is_char_source]: https://github.com/rust-lang/rust/blob/d34f1f931489618efffc4007e6b6bdb9e10f6467/compiler/rustc_middle/src/ty/sty.rs#L1429-L1432
|
||||
[kind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html#method.kind
|
||||
[LateContext]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LateContext.html
|
||||
[LateLintPass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.LateLintPass.html
|
||||
@@ -163,5 +163,5 @@ in this chapter:
|
||||
[TyKind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/ty_kind/enum.TyKind.html
|
||||
[TypeckResults]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html
|
||||
[middle_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html
|
||||
[hir_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/struct.Ty.html
|
||||
[hir_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.Ty.html
|
||||
[lower_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_analysis/fn.lower_ty.html
|
||||
|
||||
@@ -246,7 +246,7 @@ A list of crate names to allow duplicates of
|
||||
|
||||
## `allowed-idents-below-min-chars`
|
||||
Allowed names below the minimum allowed characters. The value `".."` can be used as part of
|
||||
the list to indicate, that the configured values should be appended to the default
|
||||
the list to indicate that the configured values should be appended to the default
|
||||
configuration of Clippy. By default, any configuration will replace the default value.
|
||||
|
||||
**Default Value:** `["i", "j", "x", "y", "z", "w", "n"]`
|
||||
@@ -570,12 +570,12 @@ The list of disallowed types, written as fully qualified paths.
|
||||
|
||||
## `doc-valid-idents`
|
||||
The list of words this lint should not consider as identifiers needing ticks. The value
|
||||
`".."` can be used as part of the list to indicate, that the configured values should be appended to the
|
||||
`".."` can be used as part of the list to indicate that the configured values should be appended to the
|
||||
default configuration of Clippy. By default, any configuration will replace the default value. For example:
|
||||
* `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`.
|
||||
* `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list.
|
||||
|
||||
**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "MHz", "GHz", "THz", "AccessKit", "CoAP", "CoreFoundation", "CoreGraphics", "CoreText", "DevOps", "Direct2D", "Direct3D", "DirectWrite", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "InfiniBand", "RoCE", "ClojureScript", "CoffeeScript", "JavaScript", "PostScript", "PureScript", "TypeScript", "PowerPC", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenAL", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "OpenType", "WebGL", "WebGL2", "WebGPU", "WebRTC", "WebSocket", "WebTransport", "WebP", "OpenExr", "YCbCr", "sRGB", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "NetBSD", "OpenBSD", "NixOS", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]`
|
||||
**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "MHz", "GHz", "THz", "AccessKit", "CoAP", "CoreFoundation", "CoreGraphics", "CoreText", "DevOps", "Direct2D", "Direct3D", "DirectWrite", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "InfiniBand", "RoCE", "ClojureScript", "CoffeeScript", "JavaScript", "PostScript", "PureScript", "TypeScript", "PowerPC", "PowerShell", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenAL", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "OpenType", "WebGL", "WebGL2", "WebGPU", "WebRTC", "WebSocket", "WebTransport", "WebP", "OpenExr", "YCbCr", "sRGB", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "NetBSD", "OpenBSD", "NixOS", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]`
|
||||
|
||||
---
|
||||
**Affected lints:**
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
"IPv4", "IPv6",
|
||||
"InfiniBand", "RoCE",
|
||||
"ClojureScript", "CoffeeScript", "JavaScript", "PostScript", "PureScript", "TypeScript",
|
||||
"PowerPC", "WebAssembly",
|
||||
"PowerPC", "PowerShell", "WebAssembly",
|
||||
"NaN", "NaNs",
|
||||
"OAuth", "GraphQL",
|
||||
"OCaml",
|
||||
@@ -423,7 +423,7 @@ fn span_from_toml_range(file: &SourceFile, span: Range<usize>) -> Span {
|
||||
#[lints(multiple_crate_versions)]
|
||||
allowed_duplicate_crates: Vec<String> = Vec::new(),
|
||||
/// Allowed names below the minimum allowed characters. The value `".."` can be used as part of
|
||||
/// the list to indicate, that the configured values should be appended to the default
|
||||
/// the list to indicate that the configured values should be appended to the default
|
||||
/// configuration of Clippy. By default, any configuration will replace the default value.
|
||||
#[lints(min_ident_chars)]
|
||||
allowed_idents_below_min_chars: Vec<String> =
|
||||
@@ -620,7 +620,7 @@ fn span_from_toml_range(file: &SourceFile, span: Range<usize>) -> Span {
|
||||
#[lints(disallowed_types)]
|
||||
disallowed_types: Vec<DisallowedPath> = Vec::new(),
|
||||
/// The list of words this lint should not consider as identifiers needing ticks. The value
|
||||
/// `".."` can be used as part of the list to indicate, that the configured values should be appended to the
|
||||
/// `".."` can be used as part of the list to indicate that the configured values should be appended to the
|
||||
/// default configuration of Clippy. By default, any configuration will replace the default value. For example:
|
||||
/// * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`.
|
||||
/// * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list.
|
||||
|
||||
@@ -167,9 +167,9 @@ fn add_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> {
|
||||
let camel_name = to_camel_case(lint.name);
|
||||
|
||||
let new_lint = if enable_msrv {
|
||||
format!("Box::new(move |{ctor_arg}| Box::new({module_name}::{camel_name}::new(conf))),\n ",)
|
||||
format!("Box::new(move |{ctor_arg}| Box::new({module_name}::{camel_name}::new(conf))),\n ")
|
||||
} else {
|
||||
format!("Box::new(|{ctor_arg}| Box::new({module_name}::{camel_name})),\n ",)
|
||||
format!("Box::new(|{ctor_arg}| Box::new({module_name}::{camel_name})),\n ")
|
||||
};
|
||||
|
||||
lib_rs.insert_str(comment_start, &new_lint);
|
||||
|
||||
@@ -31,6 +31,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) {
|
||||
| sym::dead_code
|
||||
| sym::deprecated
|
||||
| sym::deprecated_in_future
|
||||
| sym::exported_private_dependencies
|
||||
| sym::hidden_glob_reexports
|
||||
| sym::unreachable_pub
|
||||
| sym::unused
|
||||
|
||||
@@ -100,7 +100,7 @@ fn check_table(cx: &LateContext<'_>, table: &DeTable<'_>, known_groups: &FxHashS
|
||||
"to have lints override the group set `{}` to a lower priority",
|
||||
group.as_ref()
|
||||
),
|
||||
format!("{{ level = {:?}, priority = {low_priority} }}", group_config.level,),
|
||||
format!("{{ level = {:?}, priority = {low_priority} }}", group_config.level),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
},
|
||||
|
||||
@@ -117,7 +117,7 @@ pub(super) fn check(
|
||||
return;
|
||||
}
|
||||
|
||||
format!("casting `{cast_from}` to `{cast_to}` may truncate the value{suffix}",)
|
||||
format!("casting `{cast_from}` to `{cast_to}` may truncate the value{suffix}")
|
||||
},
|
||||
|
||||
(ty::Adt(def, _), Some(to_nbits)) if def.is_enum() => {
|
||||
|
||||
@@ -15,6 +15,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, from: &Expr<'_>, to:
|
||||
let init_expr = expr_or_init(cx, from);
|
||||
if is_expr_const_aligned(cx, init_expr, ptr_ty.ty)
|
||||
&& let Some(std_or_core) = std_or_core(cx)
|
||||
&& let pointee_ty = cx.typeck_results().node_type(ptr_ty.ty.hir_id)
|
||||
&& pointee_ty.is_sized(cx.tcx, cx.typing_env())
|
||||
{
|
||||
let sugg_fn = match ptr_ty.mutbl {
|
||||
Mutability::Not => "ptr::dangling",
|
||||
|
||||
@@ -75,45 +75,47 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
"the `dbg!` macro is intended as a debugging tool",
|
||||
|diag| {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let (sugg_span, suggestion) =
|
||||
match is_async_move_desugar(expr).unwrap_or(expr).peel_drop_temps().kind {
|
||||
// dbg!()
|
||||
ExprKind::Block(..) => {
|
||||
// If the `dbg!` macro is a "free" statement and not contained within other expressions,
|
||||
// remove the whole statement.
|
||||
if let Node::Stmt(_) = cx.tcx.parent_hir_node(expr.hir_id)
|
||||
&& let Some(semi_span) =
|
||||
cx.sess().source_map().mac_call_stmt_semi_span(macro_call.span)
|
||||
{
|
||||
(macro_call.span.to(semi_span), String::new())
|
||||
} else {
|
||||
(macro_call.span, String::from("()"))
|
||||
}
|
||||
},
|
||||
ExprKind::Match(first, arms, _) => {
|
||||
let vals = collect_vals(first, arms);
|
||||
let suggestion = match vals.as_slice() {
|
||||
// dbg!(1) => 1
|
||||
&[val] => {
|
||||
snippet_with_applicability(cx, val.span.source_callsite(), "..", &mut applicability)
|
||||
.to_string()
|
||||
}
|
||||
// dbg!(2, 3) => (2, 3)
|
||||
&[first, .., last] => {
|
||||
let snippet = snippet_with_applicability(
|
||||
cx,
|
||||
first.span.source_callsite().to(last.span.source_callsite()),
|
||||
"..",
|
||||
&mut applicability,
|
||||
);
|
||||
format!("({snippet})")
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
(macro_call.span, suggestion)
|
||||
},
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let (sugg_span, suggestion) = match is_async_move_desugar(expr)
|
||||
.unwrap_or(expr)
|
||||
.peel_drop_temps()
|
||||
.kind
|
||||
{
|
||||
// dbg!()
|
||||
ExprKind::Block(..) => {
|
||||
// If the `dbg!` macro is a "free" statement and not contained within other expressions,
|
||||
// remove the whole statement.
|
||||
if let Node::Stmt(_) = cx.tcx.parent_hir_node(expr.hir_id)
|
||||
&& let Some(semi_span) = cx.sess().source_map().mac_call_stmt_semi_span(macro_call.span)
|
||||
{
|
||||
(macro_call.span.to(semi_span), String::new())
|
||||
} else {
|
||||
(macro_call.span, String::from("()"))
|
||||
}
|
||||
},
|
||||
ExprKind::Match(first, arms, _) => {
|
||||
let vals = collect_vals(first, arms);
|
||||
let suggestion = match *vals.as_slice() {
|
||||
// dbg!(1) => 1
|
||||
[val] => {
|
||||
snippet_with_applicability(cx, val.span.source_callsite(), "..", &mut applicability)
|
||||
.to_string()
|
||||
},
|
||||
// dbg!(2, 3) => (2, 3)
|
||||
[first, .., last] => {
|
||||
let snippet = snippet_with_applicability(
|
||||
cx,
|
||||
first.span.source_callsite().to(last.span.source_callsite()),
|
||||
"..",
|
||||
&mut applicability,
|
||||
);
|
||||
format!("({snippet})")
|
||||
},
|
||||
_ => unreachable!(),
|
||||
};
|
||||
(macro_call.span, suggestion)
|
||||
},
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
diag.span_suggestion(
|
||||
sugg_span,
|
||||
@@ -165,7 +167,7 @@ fn first_dbg_macro_in_expansion(cx: &LateContext<'_>, span: Span) -> Option<Macr
|
||||
}
|
||||
|
||||
/// Extracts all value expressions from the `match`-tree generated by `dbg!`.
|
||||
///
|
||||
///
|
||||
/// E.g. from
|
||||
/// ```rust, ignore
|
||||
/// match 1 {
|
||||
@@ -181,14 +183,20 @@ fn first_dbg_macro_in_expansion(cx: &LateContext<'_>, span: Span) -> Option<Macr
|
||||
fn collect_vals<'hir>(first: &'hir Expr<'hir>, mut arms: &'hir [Arm<'hir>]) -> Vec<&'hir Expr<'hir>> {
|
||||
let mut vals = vec![first];
|
||||
loop {
|
||||
let [arm] = arms else { unreachable!("dbg! macro expansion only has single-arm matches") };
|
||||
let [arm] = arms else {
|
||||
unreachable!("dbg! macro expansion only has single-arm matches")
|
||||
};
|
||||
|
||||
match is_async_move_desugar(arm.body).unwrap_or(arm.body).peel_drop_temps().kind {
|
||||
match is_async_move_desugar(arm.body)
|
||||
.unwrap_or(arm.body)
|
||||
.peel_drop_temps()
|
||||
.kind
|
||||
{
|
||||
ExprKind::Block(..) => return vals,
|
||||
ExprKind::Match(val, a, _) => {
|
||||
vals.push(val);
|
||||
arms = a;
|
||||
}
|
||||
},
|
||||
_ => unreachable!("dbg! macro expansion only results in block or match expressions"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,21 +53,26 @@ fn is_missing_punctuation(doc_string: &str) -> Vec<MissingPunctuation> {
|
||||
let mut no_report_depth = 0;
|
||||
let mut missing_punctuation = Vec::new();
|
||||
let mut current_paragraph = None;
|
||||
let mut current_event_is_missing_punctuation = false;
|
||||
|
||||
for (event, offset) in
|
||||
Parser::new_ext(doc_string, main_body_opts() - Options::ENABLE_SMART_PUNCTUATION).into_offset_iter()
|
||||
{
|
||||
let last_event_was_missing_punctuation = current_event_is_missing_punctuation;
|
||||
current_event_is_missing_punctuation = false;
|
||||
|
||||
match event {
|
||||
Event::Start(
|
||||
Tag::CodeBlock(..)
|
||||
| Tag::FootnoteDefinition(_)
|
||||
| Tag::Heading { .. }
|
||||
| Tag::HtmlBlock
|
||||
| Tag::List(..)
|
||||
| Tag::Table(_),
|
||||
) => {
|
||||
Event::Start(Tag::FootnoteDefinition(_) | Tag::Heading { .. } | Tag::HtmlBlock | Tag::Table(_)) => {
|
||||
no_report_depth += 1;
|
||||
},
|
||||
Event::Start(Tag::CodeBlock(..) | Tag::List(..)) => {
|
||||
no_report_depth += 1;
|
||||
if last_event_was_missing_punctuation {
|
||||
// Remove the error from the previous paragraph as it is followed by a code
|
||||
// block or a list.
|
||||
missing_punctuation.pop();
|
||||
}
|
||||
},
|
||||
Event::End(TagEnd::FootnoteDefinition) => {
|
||||
no_report_depth -= 1;
|
||||
},
|
||||
@@ -83,6 +88,7 @@ fn is_missing_punctuation(doc_string: &str) -> Vec<MissingPunctuation> {
|
||||
Event::End(TagEnd::Paragraph) => {
|
||||
if let Some(mp) = current_paragraph {
|
||||
missing_punctuation.push(mp);
|
||||
current_event_is_missing_punctuation = true;
|
||||
}
|
||||
},
|
||||
Event::Code(..) | Event::Start(Tag::Link { .. }) | Event::End(TagEnd::Link)
|
||||
|
||||
@@ -91,7 +91,7 @@ pub fn check(cx: &LateContext<'_>, doc: &str, range: Range<usize>, fragments: &F
|
||||
diag.span_suggestion_verbose(
|
||||
this_fragment.span.shrink_to_hi(),
|
||||
"add footnote definition",
|
||||
format!("\n\n{label}: <!-- description -->", label = &doc[start..end],),
|
||||
format!("\n\n{label}: <!-- description -->", label = &doc[start..end]),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
} else {
|
||||
|
||||
@@ -1016,6 +1016,7 @@ struct CodeTags {
|
||||
no_run: bool,
|
||||
ignore: bool,
|
||||
compile_fail: bool,
|
||||
test_harness: bool,
|
||||
|
||||
rust: bool,
|
||||
}
|
||||
@@ -1026,6 +1027,7 @@ fn default() -> Self {
|
||||
no_run: false,
|
||||
ignore: false,
|
||||
compile_fail: false,
|
||||
test_harness: false,
|
||||
|
||||
rust: true,
|
||||
}
|
||||
@@ -1059,7 +1061,11 @@ fn parse(lang: &str) -> Self {
|
||||
tags.compile_fail = true;
|
||||
seen_rust_tags = !seen_other_tags || seen_rust_tags;
|
||||
},
|
||||
"test_harness" | "standalone_crate" => {
|
||||
"test_harness" => {
|
||||
tags.test_harness = true;
|
||||
seen_rust_tags = !seen_other_tags || seen_rust_tags;
|
||||
},
|
||||
"standalone_crate" => {
|
||||
seen_rust_tags = !seen_other_tags || seen_rust_tags;
|
||||
},
|
||||
_ if item.starts_with("ignore-") => seen_rust_tags = true,
|
||||
@@ -1295,7 +1301,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
|
||||
if tags.rust && !tags.compile_fail && !tags.ignore {
|
||||
needless_doctest_main::check(cx, &text, range.start, fragments);
|
||||
|
||||
if !tags.no_run {
|
||||
if !tags.no_run && !tags.test_harness {
|
||||
test_attr_in_doctest::check(cx, &text, range.start, fragments);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind, QPath, RustcVersion};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_middle::ty::{self, TyCtxt, UintTy};
|
||||
use rustc_session::impl_lint_pass;
|
||||
use rustc_span::Symbol;
|
||||
|
||||
@@ -76,13 +76,14 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
|
||||
.typeck_results()
|
||||
.node_type(func_ty.hir_id)
|
||||
.is_diag_item(cx, sym::Duration)
|
||||
&& matches!(cx.typeck_results().expr_ty_adjusted(arg).kind(), ty::Uint(UintTy::U64))
|
||||
// We intentionally don't want to evaluate referenced constants, as we don't want to
|
||||
// recommend a literal value over using constants:
|
||||
//
|
||||
// let dur = Duration::from_secs(SIXTY);
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Duration::from_mins(1)`
|
||||
&& let Some(Constant::Int(value)) = ConstEvalCtxt::new(cx).eval_local(arg, expr.span.ctxt())
|
||||
&& let value = u64::try_from(value).expect("All Duration::from_<time-unit> constructors take a u64")
|
||||
&& let Ok(value) = u64::try_from(value) // Cannot fail
|
||||
// There is no need to promote e.g. 0 seconds to 0 hours
|
||||
&& value != 0
|
||||
&& let Some((promoted_constructor, promoted_value)) = self.promote(cx, func_name.ident.name, value)
|
||||
|
||||
@@ -337,7 +337,7 @@ fn check_missing_else(cx: &EarlyContext<'_>, first: &Expr, second: &Expr) {
|
||||
else_span,
|
||||
format!("this looks like {looks_like} but the `else` is missing"),
|
||||
None,
|
||||
format!("to remove this lint, add the missing `else` or add a new line before {next_thing}",),
|
||||
format!("to remove this lint, add the missing `else` or add a new line before {next_thing}"),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
use clippy_utils::source::snippet_indent;
|
||||
use clippy_utils::ty::is_must_use_ty;
|
||||
use clippy_utils::visitors::for_each_expr_without_closures;
|
||||
use clippy_utils::{return_ty, trait_ref_of_method};
|
||||
use clippy_utils::{is_entrypoint_fn, return_ty, trait_ref_of_method};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::find_attr;
|
||||
use rustc_span::Symbol;
|
||||
@@ -211,6 +211,7 @@ fn check_must_use_candidate<'tcx>(
|
||||
|| !cx.effective_visibilities.is_exported(item_id.def_id)
|
||||
|| is_must_use_ty(cx, return_ty(cx, item_id))
|
||||
|| item_span.from_expansion()
|
||||
|| is_entrypoint_fn(cx, item_id.def_id.to_def_id())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ fn suggestion(
|
||||
),
|
||||
(
|
||||
target.span(),
|
||||
format!("{}<{}, S>", target.type_name(), target.type_arguments(),),
|
||||
format!("{}<{}, S>", target.type_name(), target.type_arguments()),
|
||||
),
|
||||
];
|
||||
suggestions.extend(vis.suggestions);
|
||||
@@ -352,7 +352,7 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
|
||||
);
|
||||
self.suggestions.insert(
|
||||
e.span,
|
||||
format!("{container_name}::with_capacity_and_hasher({arg_snippet}, Default::default())",),
|
||||
format!("{container_name}::with_capacity_and_hasher({arg_snippet}, Default::default())"),
|
||||
);
|
||||
},
|
||||
_ => {},
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
/// Checks for usage of indexing or slicing that may panic at runtime.
|
||||
///
|
||||
/// This lint does not report on indexing or slicing operations
|
||||
/// that always panic, clippy's `out_of_bound_indexing` already
|
||||
/// that always panic, [out_of_bounds_indexing](#out_of_bounds_indexing) already
|
||||
/// handles those cases.
|
||||
///
|
||||
/// ### Why restrict this?
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
use clippy_utils::source::{snippet, snippet_with_context};
|
||||
use clippy_utils::visitors::{Descend, for_each_expr_without_closures};
|
||||
use clippy_utils::{contains_return, sym};
|
||||
use rustc_ast::BinOpKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{
|
||||
Block, Closure, Destination, Expr, ExprKind, HirId, InlineAsm, InlineAsmOperand, Node, Pat, Stmt, StmtKind,
|
||||
@@ -305,6 +306,9 @@ fn never_loop_expr<'tcx>(
|
||||
}
|
||||
},
|
||||
ExprKind::Call(e, es) => never_loop_expr_all(cx, once(e).chain(es.iter()), local_labels, main_loop_id),
|
||||
ExprKind::Binary(op, e1, _) if matches!(op.node, BinOpKind::And | BinOpKind::Or) => {
|
||||
never_loop_expr(cx, e1, local_labels, main_loop_id)
|
||||
},
|
||||
ExprKind::Binary(_, e1, e2)
|
||||
| ExprKind::Assign(e1, e2, _)
|
||||
| ExprKind::AssignOp(_, e1, e2)
|
||||
|
||||
@@ -301,7 +301,7 @@ fn replace_in_pattern(
|
||||
.collect::<Vec<_>>();
|
||||
let fields_string = fields.join(", ");
|
||||
|
||||
let dot_dot_str = if dot_dot.is_some() { " .." } else { "" };
|
||||
let dot_dot_str = if dot_dot.is_some() { ", .." } else { "" };
|
||||
let (sn_pth, _) = snippet_with_context(cx, path.span(), span.ctxt(), "", app);
|
||||
return format!("{sn_pth} {{ {fields_string}{dot_dot_str} }}");
|
||||
},
|
||||
|
||||
@@ -173,7 +173,7 @@ fn handle(
|
||||
expr.span,
|
||||
format!("this pattern reimplements `{ty_name}::unwrap_or`"),
|
||||
"replace with",
|
||||
format!("{suggestion}.unwrap_or({reindented_or_body})",),
|
||||
format!("{suggestion}.unwrap_or({reindented_or_body})"),
|
||||
app,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -187,7 +187,7 @@ pub(super) fn check_match<'tcx>(
|
||||
diag.span_suggestion_verbose(
|
||||
e.span,
|
||||
"use `matches!` directly",
|
||||
format!("{}matches!({snippet}, {pat_and_guard})", if b0 { "" } else { "!" },),
|
||||
format!("{}matches!({snippet}, {pat_and_guard})", if b0 { "" } else { "!" }),
|
||||
applicability,
|
||||
);
|
||||
},
|
||||
|
||||
@@ -34,7 +34,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E
|
||||
parent.span,
|
||||
format!("called `.bytes().nth().unwrap()` on a `{caller_type}`"),
|
||||
"try",
|
||||
format!("{receiver}.as_bytes()[{n}]",),
|
||||
format!("{receiver}.as_bytes()[{n}]"),
|
||||
applicability,
|
||||
);
|
||||
} else {
|
||||
|
||||
@@ -20,7 +20,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_span: Spa
|
||||
cx,
|
||||
INTO_ITER_ON_REF,
|
||||
method_span,
|
||||
format!("this `.into_iter()` call is equivalent to `.{method_name}()` and will not consume the `{kind}`",),
|
||||
format!("this `.into_iter()` call is equivalent to `.{method_name}()` and will not consume the `{kind}`"),
|
||||
"call directly",
|
||||
method_name.to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::res::MaybeDef;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::{get_parent_expr, sym};
|
||||
use clippy_utils::{SpanlessEq, get_parent_expr, sym};
|
||||
use rustc_ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
|
||||
@@ -228,3 +228,65 @@ pub(super) fn check_map(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn check_or<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
expr: &'tcx Expr<'tcx>,
|
||||
lhs: &'tcx Expr<'tcx>,
|
||||
rhs: &'tcx Expr<'tcx>,
|
||||
msrv: Msrv,
|
||||
) {
|
||||
let (some_recv, some_arg) = if let (
|
||||
ExprKind::MethodCall(none_path, none_recv, [], _),
|
||||
ExprKind::MethodCall(some_path, some_recv, [some_arg], _),
|
||||
)
|
||||
| (
|
||||
ExprKind::MethodCall(some_path, some_recv, [some_arg], _),
|
||||
ExprKind::MethodCall(none_path, none_recv, [], _),
|
||||
) = (lhs.kind, rhs.kind)
|
||||
&& none_path.ident.name == sym::is_none
|
||||
&& some_path.ident.name == sym::is_some_and
|
||||
&& cx
|
||||
.typeck_results()
|
||||
.expr_ty_adjusted(none_recv)
|
||||
.peel_refs()
|
||||
.is_diag_item(cx, sym::Option)
|
||||
&& cx
|
||||
.typeck_results()
|
||||
.expr_ty_adjusted(some_recv)
|
||||
.peel_refs()
|
||||
.is_diag_item(cx, sym::Option)
|
||||
&& SpanlessEq::new(cx).eq_expr(none_recv, some_recv)
|
||||
{
|
||||
(some_recv, some_arg)
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
|
||||
if !msrv.meets(cx, msrvs::IS_NONE_OR) {
|
||||
return;
|
||||
}
|
||||
|
||||
let Ok(map_func) = MapFunc::try_from(some_arg) else {
|
||||
return;
|
||||
};
|
||||
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
MANUAL_IS_VARIANT_AND,
|
||||
expr.span,
|
||||
"manual implementation of `Option::is_none_or`",
|
||||
|diag| {
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
let (recv_snip, _) = snippet_with_context(cx, some_recv.span, expr.span.ctxt(), "_", &mut app);
|
||||
let map_func_snip = map_func.sugg(cx, false, &mut app);
|
||||
|
||||
diag.span_suggestion(
|
||||
expr.span,
|
||||
"use",
|
||||
format!("{recv_snip}.is_none_or({map_func_snip})"),
|
||||
app,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ pub(super) fn check<'tcx>(
|
||||
fold_span,
|
||||
"usage of `Iterator::fold` on a type that implements `Try`",
|
||||
"use `try_fold` instead",
|
||||
format!("try_fold({init_snip}, {args_snip} ...)",),
|
||||
format!("try_fold({init_snip}, {args_snip} ...)"),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4965,6 +4965,16 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
io_other_error::check(cx, expr, func, args, self.msrv);
|
||||
swap_with_temporary::check(cx, expr, func, args);
|
||||
ip_constant::check(cx, expr, func, args);
|
||||
unwrap_expect_used::check_call(
|
||||
cx,
|
||||
expr,
|
||||
func,
|
||||
args,
|
||||
self.allow_unwrap_in_tests,
|
||||
self.allow_expect_in_tests,
|
||||
self.allow_unwrap_in_consts,
|
||||
self.allow_expect_in_consts,
|
||||
);
|
||||
},
|
||||
ExprKind::MethodCall(..) => {
|
||||
self.check_methods(cx, expr);
|
||||
@@ -4978,6 +4988,9 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
};
|
||||
lint_binary_expr_with_method_call(cx, &mut info);
|
||||
},
|
||||
ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Or => {
|
||||
manual_is_variant_and::check_or(cx, expr, lhs, rhs, self.msrv);
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
@@ -5538,7 +5551,7 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
unnecessary_sort_by::check(cx, expr, call_span, arg, true);
|
||||
},
|
||||
(sym::split, [arg]) => {
|
||||
str_split::check(cx, expr, recv, arg);
|
||||
str_split::check(cx, expr, recv, call_span, arg);
|
||||
},
|
||||
(sym::splitn | sym::rsplitn, [count_arg, pat_arg]) => {
|
||||
if let Some(Constant::Int(count)) = ConstEvalCtxt::new(cx).eval(count_arg) {
|
||||
|
||||
@@ -58,7 +58,10 @@ pub(super) fn check(
|
||||
.iter()
|
||||
.map(|x| &x.kind)
|
||||
.collect::<Box<[_]>>()
|
||||
&& let [ty::adjustment::Adjust::Deref(ty::adjustment::DerefAdjustKind::Builtin), ty::adjustment::Adjust::Borrow(_)] = *adj
|
||||
&& let [
|
||||
ty::adjustment::Adjust::Deref(ty::adjustment::DerefAdjustKind::Builtin),
|
||||
ty::adjustment::Adjust::Borrow(_),
|
||||
] = *adj
|
||||
&& let method_did = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id).unwrap()
|
||||
&& let Some(method_name) = cx.tcx.get_diagnostic_name(method_did)
|
||||
{
|
||||
|
||||
@@ -1,39 +1,48 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::sym;
|
||||
use clippy_utils::visitors::is_const_evaluatable;
|
||||
use rustc_ast::ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::Span;
|
||||
|
||||
use super::STR_SPLIT_AT_NEWLINE;
|
||||
|
||||
pub(super) fn check<'a>(cx: &LateContext<'a>, expr: &'_ Expr<'_>, split_recv: &'a Expr<'_>, split_arg: &'_ Expr<'_>) {
|
||||
pub(super) fn check<'a>(
|
||||
cx: &LateContext<'a>,
|
||||
expr: &'_ Expr<'_>,
|
||||
split_recv: &'a Expr<'_>,
|
||||
split_span: Span,
|
||||
split_arg: &'_ Expr<'_>,
|
||||
) {
|
||||
// We're looking for `A.trim().split(B)`, where the adjusted type of `A` is `&str` (e.g. an
|
||||
// expression returning `String`), and `B` is a `Pattern` that hard-codes a newline (either `"\n"`
|
||||
// or `"\r\n"`). There are a lot of ways to specify a pattern, and this lint only checks the most
|
||||
// basic ones: a `'\n'`, `"\n"`, and `"\r\n"`.
|
||||
if let ExprKind::MethodCall(trim_method_name, trim_recv, [], _) = split_recv.kind
|
||||
if let ExprKind::MethodCall(trim_method_name, trim_recv, [], trim_span) = split_recv.kind
|
||||
&& trim_method_name.ident.name == sym::trim
|
||||
&& cx.typeck_results().expr_ty_adjusted(trim_recv).peel_refs().is_str()
|
||||
&& !is_const_evaluatable(cx, trim_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, _)))
|
||||
&& matches!(
|
||||
split_lit.node,
|
||||
LitKind::Char('\n') | LitKind::Str(sym::LF | sym::CRLF, _)
|
||||
)
|
||||
{
|
||||
let mut app = Applicability::MaybeIncorrect;
|
||||
span_lint_and_sugg(
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
STR_SPLIT_AT_NEWLINE,
|
||||
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,
|
||||
|diag| {
|
||||
diag.span_suggestion_verbose(
|
||||
trim_span.to(split_span), // combine the call spans of the two methods
|
||||
"use `str.lines()` instead",
|
||||
"lines()",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'
|
||||
diag.span_suggestion(
|
||||
expr.span,
|
||||
"remove the call to `hash` or consider using",
|
||||
format!("0_u8.hash({})", snippet(cx, arg.span, ".."),),
|
||||
format!("0_u8.hash({})", snippet(cx, arg.span, "..")),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
diag.note("the implementation of `Hash` for `()` is a no-op");
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
use clippy_utils::ty::is_never_like;
|
||||
use clippy_utils::{is_in_test, is_inside_always_const_context, is_lint_allowed};
|
||||
use rustc_hir::Expr;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_lint::{LateContext, Lint};
|
||||
use rustc_middle::ty;
|
||||
use rustc_span::sym;
|
||||
@@ -87,3 +88,70 @@ pub(super) fn check(
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[expect(clippy::too_many_arguments, clippy::fn_params_excessive_bools)]
|
||||
pub(super) fn check_call(
|
||||
cx: &LateContext<'_>,
|
||||
expr: &Expr<'_>,
|
||||
func: &Expr<'_>,
|
||||
args: &[Expr<'_>],
|
||||
allow_unwrap_in_consts: bool,
|
||||
allow_unwrap_in_tests: bool,
|
||||
allow_expect_in_consts: bool,
|
||||
allow_expect_in_tests: bool,
|
||||
) {
|
||||
let Some(recv) = args.first() else {
|
||||
return;
|
||||
};
|
||||
let Some((DefKind::AssocFn, def_id)) = cx.typeck_results().type_dependent_def(func.hir_id) else {
|
||||
return;
|
||||
};
|
||||
|
||||
match cx.tcx.item_name(def_id) {
|
||||
sym::unwrap => {
|
||||
check(
|
||||
cx,
|
||||
expr,
|
||||
recv,
|
||||
false,
|
||||
allow_unwrap_in_consts,
|
||||
allow_unwrap_in_tests,
|
||||
Variant::Unwrap,
|
||||
);
|
||||
},
|
||||
sym::expect => {
|
||||
check(
|
||||
cx,
|
||||
expr,
|
||||
recv,
|
||||
false,
|
||||
allow_expect_in_consts,
|
||||
allow_expect_in_tests,
|
||||
Variant::Expect,
|
||||
);
|
||||
},
|
||||
clippy_utils::sym::unwrap_err => {
|
||||
check(
|
||||
cx,
|
||||
expr,
|
||||
recv,
|
||||
true,
|
||||
allow_unwrap_in_consts,
|
||||
allow_unwrap_in_tests,
|
||||
Variant::Unwrap,
|
||||
);
|
||||
},
|
||||
clippy_utils::sym::expect_err => {
|
||||
check(
|
||||
cx,
|
||||
expr,
|
||||
recv,
|
||||
true,
|
||||
allow_expect_in_consts,
|
||||
allow_expect_in_tests,
|
||||
Variant::Expect,
|
||||
);
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -364,15 +364,15 @@ fn report_indexes(cx: &LateContext<'_>, map: UnindexMap<u64, Vec<IndexEntry<'_>>
|
||||
// `v.len() < 5` and `v.len() <= 5` does nothing in terms of bounds checks.
|
||||
// The user probably meant `v.len() > 5`
|
||||
LengthComparison::LengthLessThanInt | LengthComparison::LengthLessThanOrEqualInt => {
|
||||
Some(format!("assert!({slice_str}.len() > {highest_index})",))
|
||||
Some(format!("assert!({slice_str}.len() > {highest_index})"))
|
||||
},
|
||||
// `5 < v.len()` == `v.len() > 5`
|
||||
LengthComparison::IntLessThanLength if asserted_len < highest_index => {
|
||||
Some(format!("assert!({slice_str}.len() > {highest_index})",))
|
||||
Some(format!("assert!({slice_str}.len() > {highest_index})"))
|
||||
},
|
||||
// `5 <= v.len() == `v.len() >= 5`
|
||||
LengthComparison::IntLessThanOrEqualLength if asserted_len <= highest_index => {
|
||||
Some(format!("assert!({slice_str}.len() > {highest_index})",))
|
||||
Some(format!("assert!({slice_str}.len() > {highest_index})"))
|
||||
},
|
||||
// `highest_index` here is rather a length, so we need to add 1 to it
|
||||
LengthComparison::LengthEqualInt if asserted_len < highest_index + 1 => match macro_call {
|
||||
|
||||
@@ -97,7 +97,7 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
|
||||
span_without_semi,
|
||||
"this import should be renamed",
|
||||
"try",
|
||||
format!("{import} as {name}",),
|
||||
format!("{import} as {name}"),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -10,10 +10,10 @@
|
||||
|
||||
use super::CMP_OWNED;
|
||||
|
||||
pub(super) fn check(cx: &LateContext<'_>, op: BinOpKind, lhs: &Expr<'_>, rhs: &Expr<'_>) {
|
||||
pub(super) fn check(cx: &LateContext<'_>, e: &Expr<'_>, op: BinOpKind, lhs: &Expr<'_>, rhs: &Expr<'_>) {
|
||||
if op.is_comparison() {
|
||||
check_op(cx, lhs, rhs, true);
|
||||
check_op(cx, rhs, lhs, false);
|
||||
check_op(cx, e, lhs, rhs, true);
|
||||
check_op(cx, e, rhs, lhs, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,11 @@ fn symmetric_partial_eq<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: Ty<'t
|
||||
})
|
||||
}
|
||||
|
||||
fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) {
|
||||
fn check_op(cx: &LateContext<'_>, outer: &Expr<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) {
|
||||
if !outer.span.eq_ctxt(expr.span) {
|
||||
return;
|
||||
}
|
||||
|
||||
let typeck = cx.typeck_results();
|
||||
let (arg, arg_span) = match expr.kind {
|
||||
ExprKind::MethodCall(_, arg, [], _)
|
||||
|
||||
@@ -1038,7 +1038,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
|
||||
float_equality_without_abs::check(cx, e, op.node, lhs, rhs);
|
||||
integer_division::check(cx, e, op.node, lhs, rhs);
|
||||
integer_division_remainder_used::check(cx, op.node, lhs, rhs, e.span);
|
||||
cmp_owned::check(cx, op.node, lhs, rhs);
|
||||
cmp_owned::check(cx, e, op.node, lhs, rhs);
|
||||
float_cmp::check(cx, e, op.node, lhs, rhs);
|
||||
modulo_one::check(cx, e, op.node, rhs);
|
||||
modulo_arithmetic::check(
|
||||
|
||||
@@ -32,7 +32,7 @@ pub(super) fn check<'tcx>(
|
||||
expr.span,
|
||||
"comparing with null is better expressed by the `.is_null()` method",
|
||||
"try",
|
||||
format!("{invert}{non_null_path_snippet}.is_null()",),
|
||||
format!("{invert}{non_null_path_snippet}.is_null()"),
|
||||
applicability,
|
||||
);
|
||||
true
|
||||
|
||||
@@ -474,7 +474,6 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr:
|
||||
if_else,
|
||||
..
|
||||
}) = higher::IfLet::hir(cx, expr)
|
||||
&& !is_else_clause(cx.tcx, expr)
|
||||
&& let PatKind::TupleStruct(ref path1, [field], ddpos) = let_pat.kind
|
||||
&& ddpos.as_opt_usize().is_none()
|
||||
&& let PatKind::Binding(BindingMode(by_ref, _), bind_id, ident, None) = field.kind
|
||||
@@ -509,10 +508,15 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr:
|
||||
ByRef::Yes(_, Mutability::Not) => ".as_ref()",
|
||||
ByRef::No => "",
|
||||
};
|
||||
let sugg = format!(
|
||||
|
||||
let mut sugg = format!(
|
||||
"{receiver_str}{method_call_str}?{}",
|
||||
if requires_semi { ";" } else { "" }
|
||||
);
|
||||
if is_else_clause(cx.tcx, expr) {
|
||||
sugg = format!("{{ {sugg} }}");
|
||||
}
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
QUESTION_MARK,
|
||||
|
||||
@@ -27,7 +27,7 @@ pub(super) fn check_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'_>)
|
||||
&& !initexpr.span.in_external_macro(cx.sess().source_map())
|
||||
&& !retexpr.span.in_external_macro(cx.sess().source_map())
|
||||
&& !local.span.from_expansion()
|
||||
&& !span_contains_non_whitespace(cx, stmt.span.between(retexpr.span), true)
|
||||
&& !span_contains_non_whitespace(cx, stmt.span.between(retexpr.span), false)
|
||||
{
|
||||
span_lint_hir_and_then(
|
||||
cx,
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
SpanlessEq, get_expr_use_or_unification_node, get_parent_expr, is_lint_allowed, method_calls, peel_blocks, sym,
|
||||
};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, LangItem, Node};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
@@ -410,6 +411,23 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
|
||||
diag.span_suggestion(expr.span, "try", format!("{snippet}.to_owned()"), applicability);
|
||||
},
|
||||
);
|
||||
} else if let ExprKind::Path(_) = expr.kind
|
||||
&& let Some(parent) = get_parent_expr(cx, expr)
|
||||
&& let ExprKind::Call(_, args) | ExprKind::MethodCall(_, _, args, _) = &parent.kind
|
||||
&& args.iter().any(|a| a.hir_id == expr.hir_id)
|
||||
&& let Res::Def(DefKind::AssocFn, def_id) = expr.res(cx)
|
||||
&& cx.tcx.is_diagnostic_item(sym::to_string_method, def_id)
|
||||
{
|
||||
// Detected `ToString::to_string` passed as an argument (generic: any call or method call)
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
STR_TO_STRING,
|
||||
expr.span,
|
||||
"`ToString::to_string` used as `&str` to `String` converter",
|
||||
"try",
|
||||
"ToOwned::to_owned".to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,9 +85,7 @@ impl LateLintPass<'_> for UncheckedTimeSubtraction {
|
||||
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
|
||||
let (lhs, rhs) = match expr.kind {
|
||||
ExprKind::Binary(op, lhs, rhs) if matches!(op.node, BinOpKind::Sub,) => (lhs, rhs),
|
||||
ExprKind::MethodCall(_, lhs, [rhs], _) if cx.ty_based_def(expr).is_diag_item(cx, sym::sub) => {
|
||||
(lhs, rhs)
|
||||
},
|
||||
ExprKind::MethodCall(_, lhs, [rhs], _) if cx.ty_based_def(expr).is_diag_item(cx, sym::sub) => (lhs, rhs),
|
||||
_ => return,
|
||||
};
|
||||
let typeck = cx.typeck_results();
|
||||
|
||||
@@ -109,7 +109,7 @@ fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
|
||||
diag.span_suggestion(
|
||||
stmt.span,
|
||||
"try",
|
||||
format!("let {name}{tyopt} = {initref};", name = snippet(cx, name.span, ".."),),
|
||||
format!("let {name}{tyopt} = {initref};", name = snippet(cx, name.span, "..")),
|
||||
app,
|
||||
);
|
||||
},
|
||||
|
||||
@@ -56,7 +56,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
expr.span,
|
||||
"constant division of `0.0` with `0.0` will always result in NaN",
|
||||
None,
|
||||
format!("consider using `{float_type}::NAN` if you would like a constant representing NaN",),
|
||||
format!("consider using `{float_type}::NAN` if you would like a constant representing NaN"),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,7 +168,7 @@ fn assign_expr_suggestion(
|
||||
let indent = snippet_indent(cx, outer_expr.span).unwrap_or_default();
|
||||
let var_name = snippet(cx, assign_expr_span.source_callsite(), "..");
|
||||
if needs_curly {
|
||||
format!("{{\n {indent}{inner_expr};\n {indent}{var_name} = {vec_str}[] as {return_type}\n{indent}}}",)
|
||||
format!("{{\n {indent}{inner_expr};\n {indent}{var_name} = {vec_str}[] as {return_type}\n{indent}}}")
|
||||
} else {
|
||||
format!("{inner_expr};\n{indent}{var_name} = {vec_str}[] as {return_type}")
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain:
|
||||
|
||||
<!-- begin autogenerated nightly -->
|
||||
```
|
||||
nightly-2026-01-22
|
||||
nightly-2026-02-11
|
||||
```
|
||||
<!-- end autogenerated nightly -->
|
||||
|
||||
|
||||
@@ -795,14 +795,14 @@ pub fn eq_const_item_rhs(l: &ConstItemRhsKind, r: &ConstItemRhsKind) -> bool {
|
||||
use ConstItemRhsKind::*;
|
||||
match (l, r) {
|
||||
(TypeConst { rhs: Some(l) }, TypeConst { rhs: Some(r) }) => eq_anon_const(l, r),
|
||||
(TypeConst { rhs: None }, TypeConst { rhs: None }) => true,
|
||||
(TypeConst { rhs: Some(..) }, TypeConst { rhs: None }) => false,
|
||||
(TypeConst { rhs: None }, TypeConst { rhs: Some(..) }) => false,
|
||||
(TypeConst { rhs: None }, TypeConst { rhs: None }) | (Body { rhs: None }, Body { rhs: None }) => true,
|
||||
(Body { rhs: Some(l) }, Body { rhs: Some(r) }) => eq_expr(l, r),
|
||||
(Body { rhs: None }, Body { rhs: None }) => true,
|
||||
(Body { rhs: None }, Body { rhs: Some(..) }) => false,
|
||||
(Body { rhs: Some(..) }, Body { rhs: None }) => false,
|
||||
(TypeConst {..}, Body { .. }) | ( Body { .. }, TypeConst { .. }) => false,
|
||||
(TypeConst { rhs: Some(..) }, TypeConst { rhs: None })
|
||||
| (TypeConst { rhs: None }, TypeConst { rhs: Some(..) })
|
||||
| (Body { rhs: None }, Body { rhs: Some(..) })
|
||||
| (Body { rhs: Some(..) }, Body { rhs: None })
|
||||
| (TypeConst { .. }, Body { .. })
|
||||
| (Body { .. }, TypeConst { .. }) => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,8 @@ pub enum Pat {
|
||||
Sym(Symbol),
|
||||
/// Any decimal or hexadecimal digit depending on the location.
|
||||
Num,
|
||||
/// An attribute.
|
||||
Attr(Symbol),
|
||||
}
|
||||
|
||||
/// Checks if the start and the end of the span's text matches the patterns. This will return false
|
||||
@@ -65,12 +67,20 @@ fn span_matches_pat(sess: &Session, span: Span, start_pat: Pat, end_pat: Pat) ->
|
||||
Pat::OwnedMultiStr(texts) => texts.iter().any(|s| start_str.starts_with(s)),
|
||||
Pat::Sym(sym) => start_str.starts_with(sym.as_str()),
|
||||
Pat::Num => start_str.as_bytes().first().is_some_and(u8::is_ascii_digit),
|
||||
Pat::Attr(sym) => {
|
||||
let start_str = start_str
|
||||
.strip_prefix("#[")
|
||||
.or_else(|| start_str.strip_prefix("#!["))
|
||||
.unwrap_or(start_str);
|
||||
start_str.trim_start().starts_with(sym.as_str())
|
||||
},
|
||||
} && match end_pat {
|
||||
Pat::Str(text) => end_str.ends_with(text),
|
||||
Pat::MultiStr(texts) => texts.iter().any(|s| end_str.ends_with(s)),
|
||||
Pat::OwnedMultiStr(texts) => texts.iter().any(|s| end_str.ends_with(s)),
|
||||
Pat::Sym(sym) => end_str.ends_with(sym.as_str()),
|
||||
Pat::Num => end_str.as_bytes().last().is_some_and(u8::is_ascii_hexdigit),
|
||||
Pat::Attr(_) => false,
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -350,18 +360,7 @@ fn attr_search_pat(attr: &Attribute) -> (Pat, Pat) {
|
||||
AttrKind::Normal(..) => {
|
||||
if let Some(name) = attr.name() {
|
||||
// NOTE: This will likely have false positives, like `allow = 1`
|
||||
let ident_string = name.to_string();
|
||||
if attr.style == AttrStyle::Outer {
|
||||
(
|
||||
Pat::OwnedMultiStr(vec!["#[".to_owned() + &ident_string, ident_string]),
|
||||
Pat::Str(""),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
Pat::OwnedMultiStr(vec!["#![".to_owned() + &ident_string, ident_string]),
|
||||
Pat::Str(""),
|
||||
)
|
||||
}
|
||||
(Pat::Attr(name), Pat::Str(""))
|
||||
} else {
|
||||
(Pat::Str("#"), Pat::Str("]"))
|
||||
}
|
||||
|
||||
@@ -147,6 +147,7 @@ macro_rules! generate {
|
||||
exp,
|
||||
expect_err,
|
||||
expn_data,
|
||||
exported_private_dependencies,
|
||||
extend,
|
||||
filter,
|
||||
filter_map,
|
||||
|
||||
@@ -31,9 +31,9 @@
|
||||
use rustc_trait_selection::traits::{Obligation, ObligationCause};
|
||||
#[cfg(bootstrap)]
|
||||
use std::assert_matches::debug_assert_matches;
|
||||
use std::collections::hash_map::Entry;
|
||||
#[cfg(not(bootstrap))]
|
||||
use std::debug_assert_matches;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::{iter, mem};
|
||||
|
||||
use crate::paths::{PathNS, lookup_path_str};
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[toolchain]
|
||||
# begin autogenerated nightly
|
||||
channel = "nightly-2026-01-22"
|
||||
channel = "nightly-2026-02-11"
|
||||
# end autogenerated nightly
|
||||
components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
|
||||
profile = "minimal"
|
||||
|
||||
@@ -91,7 +91,7 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.crate_name, self.major, self.minor, self.patch,
|
||||
)?;
|
||||
if let Some(ref commit_hash) = self.commit_hash {
|
||||
write!(f, ", commit_hash: \"{}\"", commit_hash.trim(),)?;
|
||||
write!(f, ", commit_hash: \"{}\"", commit_hash.trim())?;
|
||||
}
|
||||
if let Some(ref commit_date) = self.commit_date {
|
||||
write!(f, ", commit_date: \"{}\"", commit_date.trim())?;
|
||||
|
||||
+2
-2
@@ -192,7 +192,7 @@ fn display_help() -> ExitCode {
|
||||
|
||||
const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/new?template=ice.yml";
|
||||
|
||||
pub fn main() -> ExitCode {
|
||||
fn main() -> ExitCode {
|
||||
let early_dcx = EarlyDiagCtxt::new(ErrorOutputType::default());
|
||||
|
||||
rustc_driver::init_rustc_env_logger(&early_dcx);
|
||||
@@ -257,7 +257,7 @@ pub fn main() -> ExitCode {
|
||||
return match writeln!(&mut anstream::stdout().lock(), "{version_info}") {
|
||||
Ok(()) => ExitCode::SUCCESS,
|
||||
Err(_) => ExitCode::FAILURE,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument.
|
||||
|
||||
@@ -63,6 +63,11 @@ fn msrv_1_80() {
|
||||
let x = 1;
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[ expect ( dead_code ) ]
|
||||
//~^ allow_attributes
|
||||
struct Spaced;
|
||||
|
||||
#[deny(clippy::allow_attributes)]
|
||||
fn deny_allow_attributes() -> Option<u8> {
|
||||
let allow = None;
|
||||
|
||||
@@ -63,6 +63,11 @@ fn msrv_1_80() {
|
||||
let x = 1;
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[ allow ( dead_code ) ]
|
||||
//~^ allow_attributes
|
||||
struct Spaced;
|
||||
|
||||
#[deny(clippy::allow_attributes)]
|
||||
fn deny_allow_attributes() -> Option<u8> {
|
||||
let allow = None;
|
||||
|
||||
@@ -19,5 +19,11 @@ error: #[allow] attribute found
|
||||
LL | #[allow(unused)]
|
||||
| ^^^^^ help: replace it with: `expect`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error: #[allow] attribute found
|
||||
--> tests/ui/allow_attributes.rs:67:4
|
||||
|
|
||||
LL | #[ allow ( dead_code ) ]
|
||||
| ^^^^^ help: replace it with: `expect`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
||||
@@ -112,3 +112,35 @@ fn issue16322(item: String) {
|
||||
println!("Ja!");
|
||||
}
|
||||
}
|
||||
|
||||
fn issue16458() {
|
||||
macro_rules! partly_comes_from_macro {
|
||||
($i:ident: $ty:ty, $def:expr) => {
|
||||
let _ = {
|
||||
let res = <$ty>::default() == $def;
|
||||
let _i: $ty = $def;
|
||||
res
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
partly_comes_from_macro! {
|
||||
required_version: String, env!("HOME").to_string()
|
||||
}
|
||||
|
||||
macro_rules! all_comes_from_macro {
|
||||
($($i:ident: $ty:ty, $def:expr);+ $(;)*) => {
|
||||
$(
|
||||
let _ = {
|
||||
let res = <$ty>::default() == "$def";
|
||||
//~^ cmp_owned
|
||||
let _i: $ty = $def;
|
||||
res
|
||||
};
|
||||
)+
|
||||
};
|
||||
}
|
||||
all_comes_from_macro! {
|
||||
required_version: String, env!("HOME").to_string();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,3 +112,35 @@ fn issue16322(item: String) {
|
||||
println!("Ja!");
|
||||
}
|
||||
}
|
||||
|
||||
fn issue16458() {
|
||||
macro_rules! partly_comes_from_macro {
|
||||
($i:ident: $ty:ty, $def:expr) => {
|
||||
let _ = {
|
||||
let res = <$ty>::default() == $def;
|
||||
let _i: $ty = $def;
|
||||
res
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
partly_comes_from_macro! {
|
||||
required_version: String, env!("HOME").to_string()
|
||||
}
|
||||
|
||||
macro_rules! all_comes_from_macro {
|
||||
($($i:ident: $ty:ty, $def:expr);+ $(;)*) => {
|
||||
$(
|
||||
let _ = {
|
||||
let res = <$ty>::default() == "$def".to_string();
|
||||
//~^ cmp_owned
|
||||
let _i: $ty = $def;
|
||||
res
|
||||
};
|
||||
)+
|
||||
};
|
||||
}
|
||||
all_comes_from_macro! {
|
||||
required_version: String, env!("HOME").to_string();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,5 +55,18 @@ error: this creates an owned instance just for comparison
|
||||
LL | if item == t!(frohes_neu_Jahr).to_string() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t!(frohes_neu_Jahr)`
|
||||
|
||||
error: aborting due to 9 previous errors
|
||||
error: this creates an owned instance just for comparison
|
||||
--> tests/ui/cmp_owned/with_suggestion.rs:135:51
|
||||
|
|
||||
LL | let res = <$ty>::default() == "$def".to_string();
|
||||
| ^^^^^^^^^^^^^^^^^^ help: try: `"$def"`
|
||||
...
|
||||
LL | / all_comes_from_macro! {
|
||||
LL | | required_version: String, env!("HOME").to_string();
|
||||
LL | | }
|
||||
| |_____- in this macro invocation
|
||||
|
|
||||
= note: this error originates in the macro `all_comes_from_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to 10 previous errors
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ fn test_units() {
|
||||
/// IPv4 IPv6
|
||||
/// InfiniBand RoCE
|
||||
/// ClojureScript CoffeeScript JavaScript PostScript PureScript TypeScript
|
||||
/// PowerPC WebAssembly
|
||||
/// PowerPC PowerShell WebAssembly
|
||||
/// NaN NaNs
|
||||
/// OAuth GraphQL
|
||||
/// OCaml
|
||||
|
||||
@@ -75,7 +75,7 @@ fn test_units() {
|
||||
/// IPv4 IPv6
|
||||
/// InfiniBand RoCE
|
||||
/// ClojureScript CoffeeScript JavaScript PostScript PureScript TypeScript
|
||||
/// PowerPC WebAssembly
|
||||
/// PowerPC PowerShell WebAssembly
|
||||
/// NaN NaNs
|
||||
/// OAuth GraphQL
|
||||
/// OCaml
|
||||
|
||||
@@ -46,13 +46,6 @@ enum Exceptions {
|
||||
/// | -------------- | ----- |
|
||||
/// | Markdown table | A-ok |
|
||||
MarkdownTable,
|
||||
/// Here is a snippet.
|
||||
//~^ doc_paragraphs_missing_punctuation
|
||||
///
|
||||
/// ```
|
||||
/// // Code blocks are no issues.
|
||||
/// ```
|
||||
CodeBlock,
|
||||
}
|
||||
|
||||
// Check the lint can be expected on a whole enum at once.
|
||||
@@ -130,6 +123,24 @@ enum OrderedLists {
|
||||
Paren,
|
||||
}
|
||||
|
||||
/// Some elements do not have to be introduced by an independent clause.
|
||||
enum NotIndependentClause {
|
||||
/// Lists are allowed to be introduced by a clause that is not independent: this usually
|
||||
/// requires that
|
||||
///
|
||||
/// - items end with a comma or a semicolon, which is not enforced;
|
||||
/// - the last item end with a period, which is also not enforced.
|
||||
List,
|
||||
/// For instance, the function
|
||||
///
|
||||
/// ```
|
||||
/// fn answer() {}
|
||||
/// ```
|
||||
///
|
||||
/// returns the Answer to the Ultimate Question of Life, the Universe, and Everything.
|
||||
CodeBlock,
|
||||
}
|
||||
|
||||
/// Doc comments with trailing blank lines are supported.
|
||||
//~^ doc_paragraphs_missing_punctuation
|
||||
///
|
||||
|
||||
@@ -46,13 +46,6 @@ enum Exceptions {
|
||||
/// | -------------- | ----- |
|
||||
/// | Markdown table | A-ok |
|
||||
MarkdownTable,
|
||||
/// Here is a snippet
|
||||
//~^ doc_paragraphs_missing_punctuation
|
||||
///
|
||||
/// ```
|
||||
/// // Code blocks are no issues.
|
||||
/// ```
|
||||
CodeBlock,
|
||||
}
|
||||
|
||||
// Check the lint can be expected on a whole enum at once.
|
||||
@@ -130,6 +123,24 @@ enum OrderedLists {
|
||||
Paren,
|
||||
}
|
||||
|
||||
/// Some elements do not have to be introduced by an independent clause.
|
||||
enum NotIndependentClause {
|
||||
/// Lists are allowed to be introduced by a clause that is not independent: this usually
|
||||
/// requires that
|
||||
///
|
||||
/// - items end with a comma or a semicolon, which is not enforced;
|
||||
/// - the last item end with a period, which is also not enforced.
|
||||
List,
|
||||
/// For instance, the function
|
||||
///
|
||||
/// ```
|
||||
/// fn answer() {}
|
||||
/// ```
|
||||
///
|
||||
/// returns the Answer to the Ultimate Question of Life, the Universe, and Everything.
|
||||
CodeBlock,
|
||||
}
|
||||
|
||||
/// Doc comments with trailing blank lines are supported
|
||||
//~^ doc_paragraphs_missing_punctuation
|
||||
///
|
||||
|
||||
@@ -32,82 +32,76 @@ LL | /// <https://spec.commonmark.org/0.31.2/#autolinks>
|
||||
| ^ help: end the paragraph with some punctuation: `.`
|
||||
|
||||
error: doc paragraphs should end with a terminal punctuation mark
|
||||
--> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:49:26
|
||||
|
|
||||
LL | /// Here is a snippet
|
||||
| ^ help: end the paragraph with some punctuation: `.`
|
||||
|
||||
error: doc paragraphs should end with a terminal punctuation mark
|
||||
--> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:72:15
|
||||
--> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:65:15
|
||||
|
|
||||
LL | /// U+0001
|
||||
| ^ help: end the paragraph with some punctuation: `.`
|
||||
|
||||
error: doc paragraphs should end with a terminal punctuation mark
|
||||
--> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:79:29
|
||||
--> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:72:29
|
||||
|
|
||||
LL | //! inner attributes too
|
||||
| ^ help: end the paragraph with some punctuation: `.`
|
||||
|
||||
error: doc paragraphs should end with a terminal punctuation mark
|
||||
--> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:90:47
|
||||
--> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:83:47
|
||||
|
|
||||
LL | /// **But sometimes it is missing a period**
|
||||
| ^ help: end the paragraph with some punctuation: `.`
|
||||
|
||||
error: doc paragraphs should end with a terminal punctuation mark
|
||||
--> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:95:46
|
||||
--> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:88:46
|
||||
|
|
||||
LL | /// _But sometimes it is missing a period_
|
||||
| ^ help: end the paragraph with some punctuation: `.`
|
||||
|
||||
error: doc paragraphs should end with a terminal punctuation mark
|
||||
--> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:104:56
|
||||
--> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:97:56
|
||||
|
|
||||
LL | /// Doc comments can end with an [inline link](#anchor)
|
||||
| ^ help: end the paragraph with some punctuation: `.`
|
||||
|
||||
error: doc paragraphs should end with a terminal punctuation mark
|
||||
--> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:108:65
|
||||
--> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:101:65
|
||||
|
|
||||
LL | /// Some doc comments contain [link reference definitions][spec]
|
||||
| ^ help: end the paragraph with some punctuation: `.`
|
||||
|
||||
error: doc paragraphs should end with a terminal punctuation mark
|
||||
--> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:133:57
|
||||
--> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:144:57
|
||||
|
|
||||
LL | /// Doc comments with trailing blank lines are supported
|
||||
| ^ help: end the paragraph with some punctuation: `.`
|
||||
|
||||
error: doc paragraphs should end with a terminal punctuation mark
|
||||
--> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:139:48
|
||||
--> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:150:48
|
||||
|
|
||||
LL | /// This first paragraph is missing punctuation
|
||||
| ^ help: end the paragraph with some punctuation: `.`
|
||||
|
||||
error: doc paragraphs should end with a terminal punctuation mark
|
||||
--> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:143:34
|
||||
--> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:154:34
|
||||
|
|
||||
LL | /// And it has multiple sentences
|
||||
| ^ help: end the paragraph with some punctuation: `.`
|
||||
|
||||
error: doc paragraphs should end with a terminal punctuation mark
|
||||
--> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:146:37
|
||||
--> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:157:37
|
||||
|
|
||||
LL | /// Same for this third and last one
|
||||
| ^ help: end the paragraph with some punctuation: `.`
|
||||
|
||||
error: doc paragraphs should end with a terminal punctuation mark
|
||||
--> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:153:33
|
||||
--> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:164:33
|
||||
|
|
||||
LL | /// This ends with a code `span`
|
||||
| ^ help: end the paragraph with some punctuation: `.`
|
||||
|
||||
error: doc paragraphs should end with a terminal punctuation mark
|
||||
--> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:162:27
|
||||
--> tests/ui/doc/doc_paragraphs_missing_punctuation.rs:173:27
|
||||
|
|
||||
LL | * Block doc comments work
|
||||
| ^ help: end the paragraph with some punctuation: `.`
|
||||
|
||||
error: aborting due to 18 previous errors
|
||||
error: aborting due to 17 previous errors
|
||||
|
||||
|
||||
@@ -89,3 +89,8 @@ mod my_duration {
|
||||
let dur = Duration::from_secs(60);
|
||||
}
|
||||
}
|
||||
|
||||
fn issue16457() {
|
||||
// Methods taking something else than `u64` are not covered
|
||||
_ = Duration::from_nanos_u128(1 << 90);
|
||||
}
|
||||
|
||||
@@ -89,3 +89,8 @@ fn test() {
|
||||
let dur = Duration::from_secs(60);
|
||||
}
|
||||
}
|
||||
|
||||
fn issue16457() {
|
||||
// Methods taking something else than `u64` are not covered
|
||||
_ = Duration::from_nanos_u128(1 << 90);
|
||||
}
|
||||
|
||||
@@ -271,4 +271,12 @@ fn issue15987() -> i32 {
|
||||
r
|
||||
}
|
||||
|
||||
fn has_comment() -> Vec<usize> {
|
||||
let v = Vec::new();
|
||||
|
||||
// TODO: stuff
|
||||
|
||||
v
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
||||
@@ -271,4 +271,12 @@ fn issue15987() -> i32 {
|
||||
r
|
||||
}
|
||||
|
||||
fn has_comment() -> Vec<usize> {
|
||||
let v = Vec::new();
|
||||
|
||||
// TODO: stuff
|
||||
|
||||
v
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
||||
@@ -271,4 +271,12 @@ macro_rules! sample {
|
||||
r
|
||||
}
|
||||
|
||||
fn has_comment() -> Vec<usize> {
|
||||
let v = Vec::new();
|
||||
|
||||
// TODO: stuff
|
||||
|
||||
v
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#![feature(extern_types)]
|
||||
#![warn(clippy::manual_dangling_ptr)]
|
||||
use std::mem;
|
||||
|
||||
@@ -42,3 +43,14 @@ fn _msrv_1_84() {
|
||||
//~^ manual_dangling_ptr
|
||||
//~| manual_dangling_ptr
|
||||
}
|
||||
|
||||
fn issue16459() {
|
||||
unsafe extern "C" {
|
||||
type Extern;
|
||||
}
|
||||
let _ = unsafe { &mut *(1 as *mut Extern) };
|
||||
|
||||
struct Empty;
|
||||
let _ = unsafe { &mut *std::ptr::dangling_mut::<Empty>() };
|
||||
//~^ manual_dangling_ptr
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#![feature(extern_types)]
|
||||
#![warn(clippy::manual_dangling_ptr)]
|
||||
use std::mem;
|
||||
|
||||
@@ -42,3 +43,14 @@ fn _msrv_1_84() {
|
||||
//~^ manual_dangling_ptr
|
||||
//~| manual_dangling_ptr
|
||||
}
|
||||
|
||||
fn issue16459() {
|
||||
unsafe extern "C" {
|
||||
type Extern;
|
||||
}
|
||||
let _ = unsafe { &mut *(1 as *mut Extern) };
|
||||
|
||||
struct Empty;
|
||||
let _ = unsafe { &mut *(1 as *mut Empty) };
|
||||
//~^ manual_dangling_ptr
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
error: manual creation of a dangling pointer
|
||||
--> tests/ui/manual_dangling_ptr.rs:7:24
|
||||
--> tests/ui/manual_dangling_ptr.rs:8:24
|
||||
|
|
||||
LL | let _: *const u8 = 1 as *const _;
|
||||
| ^^^^^^^^^^^^^ help: use: `std::ptr::dangling()`
|
||||
@@ -8,58 +8,64 @@ LL | let _: *const u8 = 1 as *const _;
|
||||
= help: to override `-D warnings` add `#[allow(clippy::manual_dangling_ptr)]`
|
||||
|
||||
error: manual creation of a dangling pointer
|
||||
--> tests/ui/manual_dangling_ptr.rs:9:13
|
||||
--> tests/ui/manual_dangling_ptr.rs:10:13
|
||||
|
|
||||
LL | let _ = 2 as *const u32;
|
||||
| ^^^^^^^^^^^^^^^ help: use: `std::ptr::dangling::<u32>()`
|
||||
|
||||
error: manual creation of a dangling pointer
|
||||
--> tests/ui/manual_dangling_ptr.rs:11:13
|
||||
--> tests/ui/manual_dangling_ptr.rs:12:13
|
||||
|
|
||||
LL | let _ = 4 as *mut f32;
|
||||
| ^^^^^^^^^^^^^ help: use: `std::ptr::dangling_mut::<f32>()`
|
||||
|
||||
error: manual creation of a dangling pointer
|
||||
--> tests/ui/manual_dangling_ptr.rs:14:13
|
||||
--> tests/ui/manual_dangling_ptr.rs:15:13
|
||||
|
|
||||
LL | let _ = mem::align_of::<u8>() as *const u8;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `std::ptr::dangling::<u8>()`
|
||||
|
||||
error: manual creation of a dangling pointer
|
||||
--> tests/ui/manual_dangling_ptr.rs:16:13
|
||||
--> tests/ui/manual_dangling_ptr.rs:17:13
|
||||
|
|
||||
LL | let _ = mem::align_of::<u32>() as *const u32;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `std::ptr::dangling::<u32>()`
|
||||
|
||||
error: manual creation of a dangling pointer
|
||||
--> tests/ui/manual_dangling_ptr.rs:18:13
|
||||
--> tests/ui/manual_dangling_ptr.rs:19:13
|
||||
|
|
||||
LL | let _ = mem::align_of::<usize>() as *const usize;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `std::ptr::dangling::<usize>()`
|
||||
|
||||
error: manual creation of a dangling pointer
|
||||
--> tests/ui/manual_dangling_ptr.rs:21:9
|
||||
--> tests/ui/manual_dangling_ptr.rs:22:9
|
||||
|
|
||||
LL | foo(4 as *const _, 4 as *mut _);
|
||||
| ^^^^^^^^^^^^^ help: use: `std::ptr::dangling()`
|
||||
|
||||
error: manual creation of a dangling pointer
|
||||
--> tests/ui/manual_dangling_ptr.rs:21:24
|
||||
--> tests/ui/manual_dangling_ptr.rs:22:24
|
||||
|
|
||||
LL | foo(4 as *const _, 4 as *mut _);
|
||||
| ^^^^^^^^^^^ help: use: `std::ptr::dangling_mut()`
|
||||
|
||||
error: manual creation of a dangling pointer
|
||||
--> tests/ui/manual_dangling_ptr.rs:41:9
|
||||
--> tests/ui/manual_dangling_ptr.rs:42:9
|
||||
|
|
||||
LL | foo(4 as *const _, 4 as *mut _);
|
||||
| ^^^^^^^^^^^^^ help: use: `std::ptr::dangling()`
|
||||
|
||||
error: manual creation of a dangling pointer
|
||||
--> tests/ui/manual_dangling_ptr.rs:41:24
|
||||
--> tests/ui/manual_dangling_ptr.rs:42:24
|
||||
|
|
||||
LL | foo(4 as *const _, 4 as *mut _);
|
||||
| ^^^^^^^^^^^ help: use: `std::ptr::dangling_mut()`
|
||||
|
||||
error: aborting due to 10 previous errors
|
||||
error: manual creation of a dangling pointer
|
||||
--> tests/ui/manual_dangling_ptr.rs:54:28
|
||||
|
|
||||
LL | let _ = unsafe { &mut *(1 as *mut Empty) };
|
||||
| ^^^^^^^^^^^^^^^^^ help: use: `std::ptr::dangling_mut::<Empty>()`
|
||||
|
||||
error: aborting due to 11 previous errors
|
||||
|
||||
|
||||
@@ -226,3 +226,22 @@ mod with_func {
|
||||
assert_eq!(a1, a2);
|
||||
}
|
||||
}
|
||||
|
||||
fn issue16419() {
|
||||
let then_fn = |s: &str| s.len() > 3;
|
||||
let opt: Option<&str> = Some("test");
|
||||
let _ = opt.is_none_or(then_fn);
|
||||
//~^ manual_is_variant_and
|
||||
|
||||
let _ = opt.is_none_or(then_fn);
|
||||
//~^ manual_is_variant_and
|
||||
}
|
||||
|
||||
#[clippy::msrv = "1.75.0"]
|
||||
fn issue16419_msrv() {
|
||||
let then_fn = |s: &str| s.len() > 3;
|
||||
let opt: Option<&str> = Some("test");
|
||||
let _ = opt.is_none() || opt.is_some_and(then_fn);
|
||||
|
||||
let _ = opt.is_some_and(then_fn) || opt.is_none();
|
||||
}
|
||||
|
||||
@@ -235,3 +235,22 @@ fn check_result(b: Result<u8, ()>) {
|
||||
assert_eq!(a1, a2);
|
||||
}
|
||||
}
|
||||
|
||||
fn issue16419() {
|
||||
let then_fn = |s: &str| s.len() > 3;
|
||||
let opt: Option<&str> = Some("test");
|
||||
let _ = opt.is_none() || opt.is_some_and(then_fn);
|
||||
//~^ manual_is_variant_and
|
||||
|
||||
let _ = opt.is_some_and(then_fn) || opt.is_none();
|
||||
//~^ manual_is_variant_and
|
||||
}
|
||||
|
||||
#[clippy::msrv = "1.75.0"]
|
||||
fn issue16419_msrv() {
|
||||
let then_fn = |s: &str| s.len() > 3;
|
||||
let opt: Option<&str> = Some("test");
|
||||
let _ = opt.is_none() || opt.is_some_and(then_fn);
|
||||
|
||||
let _ = opt.is_some_and(then_fn) || opt.is_none();
|
||||
}
|
||||
|
||||
@@ -222,5 +222,17 @@ error: called `.map() != Ok()`
|
||||
LL | let a1 = b.map(iad) != Ok(false);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ help: use: `!b.is_ok_and(|x| !iad(x))`
|
||||
|
||||
error: aborting due to 31 previous errors
|
||||
error: manual implementation of `Option::is_none_or`
|
||||
--> tests/ui/manual_is_variant_and.rs:242:13
|
||||
|
|
||||
LL | let _ = opt.is_none() || opt.is_some_and(then_fn);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `opt.is_none_or(then_fn)`
|
||||
|
||||
error: manual implementation of `Option::is_none_or`
|
||||
--> tests/ui/manual_is_variant_and.rs:245:13
|
||||
|
|
||||
LL | let _ = opt.is_some_and(then_fn) || opt.is_none();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `opt.is_none_or(then_fn)`
|
||||
|
||||
error: aborting due to 33 previous errors
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#![allow(unused_braces, unused_variables, dead_code)]
|
||||
#![allow(unused_braces, unused_variables, dead_code, irrefutable_let_patterns)]
|
||||
#![allow(
|
||||
clippy::collapsible_else_if,
|
||||
clippy::let_unit_value,
|
||||
@@ -182,3 +182,16 @@ fn issue9939b() {
|
||||
let Some(Issue9939b { earthquake: erosion, hurricane: _x }) = issue else { unreachable!("can't happen") };
|
||||
assert!(erosion);
|
||||
}
|
||||
|
||||
mod issue16433 {
|
||||
// https://github.com/rust-lang/rust-clippy/issues/16433
|
||||
struct A {
|
||||
a: u32,
|
||||
b: u32,
|
||||
}
|
||||
|
||||
fn foo() {
|
||||
let a = A { a: 1, b: 1 };
|
||||
let A { a: first_arg, .. } = a else { return };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#![allow(unused_braces, unused_variables, dead_code)]
|
||||
#![allow(unused_braces, unused_variables, dead_code, irrefutable_let_patterns)]
|
||||
#![allow(
|
||||
clippy::collapsible_else_if,
|
||||
clippy::let_unit_value,
|
||||
@@ -250,3 +250,20 @@ fn issue9939b() {
|
||||
};
|
||||
assert!(erosion);
|
||||
}
|
||||
|
||||
mod issue16433 {
|
||||
// https://github.com/rust-lang/rust-clippy/issues/16433
|
||||
struct A {
|
||||
a: u32,
|
||||
b: u32,
|
||||
}
|
||||
|
||||
fn foo() {
|
||||
let a = A { a: 1, b: 1 };
|
||||
let first_arg = match a {
|
||||
//~^ manual_let_else
|
||||
A { a, .. } => a,
|
||||
_ => return,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,5 +171,15 @@ LL | | None => unreachable!("can't happen"),
|
||||
LL | | };
|
||||
| |______^ help: consider writing: `let Some(Issue9939b { earthquake: erosion, hurricane: _x }) = issue else { unreachable!("can't happen") };`
|
||||
|
||||
error: aborting due to 17 previous errors
|
||||
error: this could be rewritten as `let...else`
|
||||
--> tests/ui/manual_let_else_match.rs:263:9
|
||||
|
|
||||
LL | / let first_arg = match a {
|
||||
LL | |
|
||||
LL | | A { a, .. } => a,
|
||||
LL | | _ => return,
|
||||
LL | | };
|
||||
| |__________^ help: consider writing: `let A { a: first_arg, .. } = a else { return };`
|
||||
|
||||
error: aborting due to 18 previous errors
|
||||
|
||||
|
||||
@@ -104,6 +104,7 @@ pub extern "C" fn unmangled(i: bool) -> bool {
|
||||
!i
|
||||
}
|
||||
|
||||
fn main() {
|
||||
pub fn main() -> std::process::ExitCode {
|
||||
assert_eq!(1, pure(1));
|
||||
std::process::ExitCode::SUCCESS
|
||||
}
|
||||
|
||||
@@ -99,6 +99,7 @@ pub extern "C" fn unmangled(i: bool) -> bool {
|
||||
!i
|
||||
}
|
||||
|
||||
fn main() {
|
||||
pub fn main() -> std::process::ExitCode {
|
||||
assert_eq!(1, pure(1));
|
||||
std::process::ExitCode::SUCCESS
|
||||
}
|
||||
|
||||
@@ -546,3 +546,13 @@ fn issue15673() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#[expect(clippy::diverging_sub_expression, clippy::short_circuit_statement)]
|
||||
fn issue16462() {
|
||||
let mut n = 10;
|
||||
loop {
|
||||
println!("{n}");
|
||||
n -= 1;
|
||||
n >= 0 || break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -515,3 +515,12 @@ fn wrongly_unmangled_macros() -> Option<i32> {
|
||||
test_expr!(42)?;
|
||||
test_expr!(42)
|
||||
}
|
||||
|
||||
fn issue16429(b: i32) -> Option<i32> {
|
||||
let a = Some(5);
|
||||
let _ = if b == 1 {
|
||||
b
|
||||
} else { a? };
|
||||
|
||||
Some(0)
|
||||
}
|
||||
|
||||
@@ -635,3 +635,17 @@ macro_rules! test_expr {
|
||||
}
|
||||
test_expr!(42)
|
||||
}
|
||||
|
||||
fn issue16429(b: i32) -> Option<i32> {
|
||||
let a = Some(5);
|
||||
let _ = if b == 1 {
|
||||
b
|
||||
} else if let Some(x) = a {
|
||||
//~^ question_mark
|
||||
x
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
|
||||
Some(0)
|
||||
}
|
||||
|
||||
@@ -350,5 +350,17 @@ LL | | return None;
|
||||
LL | | }
|
||||
| |_____^ help: replace it with: `test_expr!(42)?;`
|
||||
|
||||
error: aborting due to 37 previous errors
|
||||
error: this block may be rewritten with the `?` operator
|
||||
--> tests/ui/question_mark.rs:643:12
|
||||
|
|
||||
LL | } else if let Some(x) = a {
|
||||
| ____________^
|
||||
LL | |
|
||||
LL | | x
|
||||
LL | | } else {
|
||||
LL | | return None;
|
||||
LL | | };
|
||||
| |_____^ help: replace it with: `{ a? }`
|
||||
|
||||
error: aborting due to 38 previous errors
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#![warn(clippy::str_split_at_newline)]
|
||||
#![allow(clippy::needless_lifetimes)]
|
||||
|
||||
use core::str::Split;
|
||||
use std::ops::Deref;
|
||||
|
||||
struct NotStr<'a> {
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#![warn(clippy::str_split_at_newline)]
|
||||
#![allow(clippy::needless_lifetimes)]
|
||||
|
||||
use core::str::Split;
|
||||
use std::ops::Deref;
|
||||
|
||||
struct NotStr<'a> {
|
||||
|
||||
+88
-29
@@ -1,65 +1,124 @@
|
||||
error: using `str.trim().split()` with hard-coded newlines
|
||||
--> tests/ui/str_split.rs:60:13
|
||||
--> tests/ui/str_split.rs:58:13
|
||||
|
|
||||
LL | let _ = s1.trim().split('\n');
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s1.lines()`
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::str-split-at-newline` implied by `-D warnings`
|
||||
= help: to override `-D warnings` add `#[allow(clippy::str_split_at_newline)]`
|
||||
help: use `str.lines()` instead
|
||||
|
|
||||
LL - let _ = s1.trim().split('\n');
|
||||
LL + let _ = s1.lines();
|
||||
|
|
||||
|
||||
error: using `str.trim().split()` with hard-coded newlines
|
||||
--> tests/ui/str_split.rs:61:13
|
||||
|
|
||||
LL | let _ = s1.trim().split("\n");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: use `str.lines()` instead
|
||||
|
|
||||
LL - let _ = s1.trim().split("\n");
|
||||
LL + let _ = s1.lines();
|
||||
|
|
||||
|
||||
error: using `str.trim().split()` with hard-coded newlines
|
||||
--> tests/ui/str_split.rs:63:13
|
||||
|
|
||||
LL | let _ = s1.trim().split("\n");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s1.lines()`
|
||||
|
||||
error: using `str.trim().split()` with hard-coded newlines
|
||||
--> tests/ui/str_split.rs:65:13
|
||||
|
|
||||
LL | let _ = s1.trim().split("\r\n");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s1.lines()`
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: use `str.lines()` instead
|
||||
|
|
||||
LL - let _ = s1.trim().split("\r\n");
|
||||
LL + let _ = s1.lines();
|
||||
|
|
||||
|
||||
error: using `str.trim().split()` with hard-coded newlines
|
||||
--> tests/ui/str_split.rs:69:13
|
||||
--> tests/ui/str_split.rs:67:13
|
||||
|
|
||||
LL | let _ = s2.trim().split('\n');
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s2.lines()`
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: use `str.lines()` instead
|
||||
|
|
||||
LL - let _ = s2.trim().split('\n');
|
||||
LL + let _ = s2.lines();
|
||||
|
|
||||
|
||||
error: using `str.trim().split()` with hard-coded newlines
|
||||
--> tests/ui/str_split.rs:70:13
|
||||
|
|
||||
LL | let _ = s2.trim().split("\n");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: use `str.lines()` instead
|
||||
|
|
||||
LL - let _ = s2.trim().split("\n");
|
||||
LL + let _ = s2.lines();
|
||||
|
|
||||
|
||||
error: using `str.trim().split()` with hard-coded newlines
|
||||
--> tests/ui/str_split.rs:72:13
|
||||
|
|
||||
LL | let _ = s2.trim().split("\n");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s2.lines()`
|
||||
|
||||
error: using `str.trim().split()` with hard-coded newlines
|
||||
--> tests/ui/str_split.rs:74:13
|
||||
|
|
||||
LL | let _ = s2.trim().split("\r\n");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s2.lines()`
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: use `str.lines()` instead
|
||||
|
|
||||
LL - let _ = s2.trim().split("\r\n");
|
||||
LL + let _ = s2.lines();
|
||||
|
|
||||
|
||||
error: using `str.trim().split()` with hard-coded newlines
|
||||
--> tests/ui/str_split.rs:79:13
|
||||
--> tests/ui/str_split.rs:77:13
|
||||
|
|
||||
LL | let _ = s3.trim().split('\n');
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s3.lines()`
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: use `str.lines()` instead
|
||||
|
|
||||
LL - let _ = s3.trim().split('\n');
|
||||
LL + let _ = s3.lines();
|
||||
|
|
||||
|
||||
error: using `str.trim().split()` with hard-coded newlines
|
||||
--> tests/ui/str_split.rs:80:13
|
||||
|
|
||||
LL | let _ = s3.trim().split("\n");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: use `str.lines()` instead
|
||||
|
|
||||
LL - let _ = s3.trim().split("\n");
|
||||
LL + let _ = s3.lines();
|
||||
|
|
||||
|
||||
error: using `str.trim().split()` with hard-coded newlines
|
||||
--> tests/ui/str_split.rs:82:13
|
||||
|
|
||||
LL | let _ = s3.trim().split("\n");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s3.lines()`
|
||||
|
||||
error: using `str.trim().split()` with hard-coded newlines
|
||||
--> tests/ui/str_split.rs:84:13
|
||||
|
|
||||
LL | let _ = s3.trim().split("\r\n");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s3.lines()`
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: use `str.lines()` instead
|
||||
|
|
||||
LL - let _ = s3.trim().split("\r\n");
|
||||
LL + let _ = s3.lines();
|
||||
|
|
||||
|
||||
error: using `str.trim().split()` with hard-coded newlines
|
||||
--> tests/ui/str_split.rs:88:13
|
||||
--> tests/ui/str_split.rs:86:13
|
||||
|
|
||||
LL | let _ = make_str!(s1).trim().split('\n');
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `make_str!(s1).lines()`
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: use `str.lines()` instead
|
||||
|
|
||||
LL - let _ = make_str!(s1).trim().split('\n');
|
||||
LL + let _ = make_str!(s1).lines();
|
||||
|
|
||||
|
||||
error: aborting due to 10 previous errors
|
||||
|
||||
|
||||
@@ -22,3 +22,32 @@ fn issue16271(key: &[u8]) {
|
||||
let _value = t!(str::from_utf8(key)).to_owned();
|
||||
//~^ str_to_string
|
||||
}
|
||||
|
||||
struct GenericWrapper<T>(T);
|
||||
|
||||
impl<T> GenericWrapper<T> {
|
||||
fn mapper<U, F: FnOnce(T) -> U>(self, f: F) -> U {
|
||||
f(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
fn issue16511(x: Option<&str>) {
|
||||
let _ = x.map(ToOwned::to_owned);
|
||||
//~^ str_to_string
|
||||
|
||||
let _ = x.map(ToOwned::to_owned);
|
||||
//~^ str_to_string
|
||||
|
||||
let _ = ["a", "b"].iter().map(ToOwned::to_owned);
|
||||
//~^ str_to_string
|
||||
|
||||
fn mapper<F: Fn(&str) -> String>(f: F) -> String {
|
||||
f("hello")
|
||||
}
|
||||
let _ = mapper(ToOwned::to_owned);
|
||||
//~^ str_to_string
|
||||
|
||||
let w = GenericWrapper("hello");
|
||||
let _ = w.mapper(ToOwned::to_owned);
|
||||
//~^ str_to_string
|
||||
}
|
||||
|
||||
@@ -22,3 +22,32 @@ macro_rules! t {
|
||||
let _value = t!(str::from_utf8(key)).to_string();
|
||||
//~^ str_to_string
|
||||
}
|
||||
|
||||
struct GenericWrapper<T>(T);
|
||||
|
||||
impl<T> GenericWrapper<T> {
|
||||
fn mapper<U, F: FnOnce(T) -> U>(self, f: F) -> U {
|
||||
f(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
fn issue16511(x: Option<&str>) {
|
||||
let _ = x.map(ToString::to_string);
|
||||
//~^ str_to_string
|
||||
|
||||
let _ = x.map(str::to_string);
|
||||
//~^ str_to_string
|
||||
|
||||
let _ = ["a", "b"].iter().map(ToString::to_string);
|
||||
//~^ str_to_string
|
||||
|
||||
fn mapper<F: Fn(&str) -> String>(f: F) -> String {
|
||||
f("hello")
|
||||
}
|
||||
let _ = mapper(ToString::to_string);
|
||||
//~^ str_to_string
|
||||
|
||||
let w = GenericWrapper("hello");
|
||||
let _ = w.mapper(ToString::to_string);
|
||||
//~^ str_to_string
|
||||
}
|
||||
|
||||
@@ -19,5 +19,35 @@ error: `to_string()` called on a `&str`
|
||||
LL | let _value = t!(str::from_utf8(key)).to_string();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t!(str::from_utf8(key)).to_owned()`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error: `ToString::to_string` used as `&str` to `String` converter
|
||||
--> tests/ui/str_to_string.rs:35:19
|
||||
|
|
||||
LL | let _ = x.map(ToString::to_string);
|
||||
| ^^^^^^^^^^^^^^^^^^^ help: try: `ToOwned::to_owned`
|
||||
|
||||
error: `ToString::to_string` used as `&str` to `String` converter
|
||||
--> tests/ui/str_to_string.rs:38:19
|
||||
|
|
||||
LL | let _ = x.map(str::to_string);
|
||||
| ^^^^^^^^^^^^^^ help: try: `ToOwned::to_owned`
|
||||
|
||||
error: `ToString::to_string` used as `&str` to `String` converter
|
||||
--> tests/ui/str_to_string.rs:41:35
|
||||
|
|
||||
LL | let _ = ["a", "b"].iter().map(ToString::to_string);
|
||||
| ^^^^^^^^^^^^^^^^^^^ help: try: `ToOwned::to_owned`
|
||||
|
||||
error: `ToString::to_string` used as `&str` to `String` converter
|
||||
--> tests/ui/str_to_string.rs:47:20
|
||||
|
|
||||
LL | let _ = mapper(ToString::to_string);
|
||||
| ^^^^^^^^^^^^^^^^^^^ help: try: `ToOwned::to_owned`
|
||||
|
||||
error: `ToString::to_string` used as `&str` to `String` converter
|
||||
--> tests/ui/str_to_string.rs:51:22
|
||||
|
|
||||
LL | let _ = w.mapper(ToString::to_string);
|
||||
| ^^^^^^^^^^^^^^^^^^^ help: try: `ToOwned::to_owned`
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
|
||||
@@ -46,3 +46,11 @@
|
||||
/// fn not_even_rust() { panic!("Ouch") }
|
||||
/// ```
|
||||
fn test_attr_in_doctests() {}
|
||||
|
||||
/// ```test_harness
|
||||
/// #[test]
|
||||
/// fn foo() {
|
||||
/// panic!();
|
||||
/// }
|
||||
/// ```
|
||||
pub fn issue16447() {}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#![feature(min_generic_const_args)]
|
||||
|
||||
trait AssocConstTrait {
|
||||
|
||||
type const ASSOC: usize;
|
||||
}
|
||||
fn assoc_const_args<T>()
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#![feature(min_generic_const_args)]
|
||||
|
||||
trait AssocConstTrait {
|
||||
|
||||
type const ASSOC: usize;
|
||||
}
|
||||
fn assoc_const_args<T>()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
error: these where clauses contain repeated elements
|
||||
--> tests/ui/trait_duplication_in_bounds_assoc_const_eq.rs:11:8
|
||||
--> tests/ui/trait_duplication_in_bounds_assoc_const_eq.rs:10:8
|
||||
|
|
||||
LL | T: AssocConstTrait<ASSOC = 0> + AssocConstTrait<ASSOC = 0>,
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `AssocConstTrait<ASSOC = 0>`
|
||||
|
||||
@@ -334,7 +334,7 @@ fn eq(&self, other: &Self) -> bool {
|
||||
}
|
||||
|
||||
// Not necessarily related to the issue but another FP from the http crate that was fixed with it:
|
||||
// https://docs.rs/http/latest/src/http/header/name.rs.html#1424
|
||||
// https://github.com/hyperium/http/blob/5f0c86642f1dc86f156da82b62aceb2f4fab20e1/src/header/name.rs#L1408-L1420
|
||||
// We used to simply peel refs from the LHS and RHS, so we couldn't differentiate
|
||||
// between `PartialEq<T> for &T` and `PartialEq<&T> for T` impls.
|
||||
#[derive(PartialEq)]
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
#![warn(clippy::unwrap_used)]
|
||||
#![allow(clippy::unnecessary_literal_unwrap)]
|
||||
|
||||
fn unwrap_option() {
|
||||
let opt = Some(0);
|
||||
let _ = opt.unwrap();
|
||||
//~^ unwrap_used
|
||||
}
|
||||
|
||||
fn unwrap_result() {
|
||||
let res: Result<u8, u8> = Ok(0);
|
||||
let _ = res.unwrap();
|
||||
//~^ unwrap_used
|
||||
|
||||
let _ = res.unwrap_err();
|
||||
//~^ unwrap_used
|
||||
}
|
||||
|
||||
fn main() {
|
||||
unwrap_option();
|
||||
unwrap_result();
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
error: used `unwrap()` on an `Option` value
|
||||
--> tests/ui/unwrap.rs:6:13
|
||||
|
|
||||
LL | let _ = opt.unwrap();
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
= note: if this value is `None`, it will panic
|
||||
= help: consider using `expect()` to provide a better panic message
|
||||
= note: `-D clippy::unwrap-used` implied by `-D warnings`
|
||||
= help: to override `-D warnings` add `#[allow(clippy::unwrap_used)]`
|
||||
|
||||
error: used `unwrap()` on a `Result` value
|
||||
--> tests/ui/unwrap.rs:12:13
|
||||
|
|
||||
LL | let _ = res.unwrap();
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
= note: if this value is an `Err`, it will panic
|
||||
= help: consider using `expect()` to provide a better panic message
|
||||
|
||||
error: used `unwrap_err()` on a `Result` value
|
||||
--> tests/ui/unwrap.rs:15:13
|
||||
|
|
||||
LL | let _ = res.unwrap_err();
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: if this value is an `Ok`, it will panic
|
||||
= help: consider using `expect_err()` to provide a better panic message
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
@@ -83,3 +83,15 @@ fn test(file: &str) {
|
||||
let _ = open!(file).expect_err("can open"); //~ expect_used
|
||||
}
|
||||
}
|
||||
|
||||
fn issue16484() {
|
||||
let opt = Some(());
|
||||
Option::unwrap(opt); //~ unwrap_used
|
||||
Option::expect(opt, "error message"); //~ expect_used
|
||||
|
||||
let res: Result<(), i32> = Ok(());
|
||||
Result::unwrap(res); //~ unwrap_used
|
||||
Result::expect(res, "error message"); //~ expect_used
|
||||
Result::unwrap_err(res); //~ unwrap_used
|
||||
Result::expect_err(res, "error message"); //~ expect_used
|
||||
}
|
||||
|
||||
@@ -82,5 +82,53 @@ LL | let _ = open!(file).expect_err("can open");
|
||||
|
|
||||
= note: if this value is an `Ok`, it will panic
|
||||
|
||||
error: aborting due to 10 previous errors
|
||||
error: used `unwrap()` on an `Option` value
|
||||
--> tests/ui/unwrap_expect_used.rs:89:5
|
||||
|
|
||||
LL | Option::unwrap(opt);
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: if this value is `None`, it will panic
|
||||
|
||||
error: used `expect()` on an `Option` value
|
||||
--> tests/ui/unwrap_expect_used.rs:90:5
|
||||
|
|
||||
LL | Option::expect(opt, "error message");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: if this value is `None`, it will panic
|
||||
|
||||
error: used `unwrap()` on a `Result` value
|
||||
--> tests/ui/unwrap_expect_used.rs:93:5
|
||||
|
|
||||
LL | Result::unwrap(res);
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: if this value is an `Err`, it will panic
|
||||
|
||||
error: used `expect()` on a `Result` value
|
||||
--> tests/ui/unwrap_expect_used.rs:94:5
|
||||
|
|
||||
LL | Result::expect(res, "error message");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: if this value is an `Err`, it will panic
|
||||
|
||||
error: used `unwrap_err()` on a `Result` value
|
||||
--> tests/ui/unwrap_expect_used.rs:95:5
|
||||
|
|
||||
LL | Result::unwrap_err(res);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: if this value is an `Ok`, it will panic
|
||||
|
||||
error: used `expect_err()` on a `Result` value
|
||||
--> tests/ui/unwrap_expect_used.rs:96:5
|
||||
|
|
||||
LL | Result::expect_err(res, "error message");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: if this value is an `Ok`, it will panic
|
||||
|
||||
error: aborting due to 16 previous errors
|
||||
|
||||
|
||||
@@ -42,6 +42,10 @@ mod foo {
|
||||
#[allow(deprecated)]
|
||||
pub use foo::Bar;
|
||||
|
||||
// don't lint on exported_private_dependencies for `use` items
|
||||
#[allow(exported_private_dependencies)]
|
||||
use {};
|
||||
|
||||
// This should not trigger the lint. There's lint level definitions inside the external derive
|
||||
// that would trigger the useless_attribute lint.
|
||||
#[derive(DeriveSomething)]
|
||||
|
||||
@@ -42,6 +42,10 @@ mod foo {
|
||||
#[allow(deprecated)]
|
||||
pub use foo::Bar;
|
||||
|
||||
// don't lint on exported_private_dependencies for `use` items
|
||||
#[allow(exported_private_dependencies)]
|
||||
use {};
|
||||
|
||||
// This should not trigger the lint. There's lint level definitions inside the external derive
|
||||
// that would trigger the useless_attribute lint.
|
||||
#[derive(DeriveSomething)]
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user