Merge commit 'e18101137866b79045fee0ef996e696e68c920b4' into clippyup

This commit is contained in:
flip1995 2021-11-04 12:52:36 +00:00
parent c2cbf55323
commit e674d0a599
220 changed files with 3219 additions and 1550 deletions

3
.github/deploy.sh vendored
View File

@ -13,7 +13,8 @@ cp util/gh-pages/lints.json out/master
if [[ -n $TAG_NAME ]]; then
echo "Save the doc for the current tag ($TAG_NAME) and point stable/ to it"
cp -Tr out/master "out/$TAG_NAME"
ln -sf "$TAG_NAME" out/stable
rm -f out/stable
ln -s "$TAG_NAME" out/stable
fi
if [[ $BETA = "true" ]]; then

View File

@ -6,11 +6,162 @@ document.
## Unreleased / In Rust Nightly
[7bfc26e...master](https://github.com/rust-lang/rust-clippy/compare/7bfc26e...master)
[b7f3f7f...master](https://github.com/rust-lang/rust-clippy/compare/b7f3f7f...master)
## Rust 1.57
Current beta, release 2021-12-02
[7bfc26e...b7f3f7f](https://github.com/rust-lang/rust-clippy/compare/7bfc26e...b7f3f7f)
### New Lints
* [`negative_feature_names`]
[#7539](https://github.com/rust-lang/rust-clippy/pull/7539)
* [`redundant_feature_names`]
[#7539](https://github.com/rust-lang/rust-clippy/pull/7539)
* [`mod_module_files`]
[#7543](https://github.com/rust-lang/rust-clippy/pull/7543)
* [`self_named_module_files`]
[#7543](https://github.com/rust-lang/rust-clippy/pull/7543)
* [`manual_split_once`]
[#7565](https://github.com/rust-lang/rust-clippy/pull/7565)
* [`derivable_impls`]
[#7570](https://github.com/rust-lang/rust-clippy/pull/7570)
* [`needless_option_as_deref`]
[#7596](https://github.com/rust-lang/rust-clippy/pull/7596)
* [`iter_not_returning_iterator`]
[#7610](https://github.com/rust-lang/rust-clippy/pull/7610)
* [`same_name_method`]
[#7653](https://github.com/rust-lang/rust-clippy/pull/7653)
* [`manual_assert`] [#7669](https://github.com/rust-lang/rust-clippy/pull/7669)
* [`non_send_fields_in_send_ty`]
[#7709](https://github.com/rust-lang/rust-clippy/pull/7709)
* [`equatable_if_let`]
[#7762](https://github.com/rust-lang/rust-clippy/pull/7762)
### Moves and Deprecations
* Move [`shadow_unrelated`] to `restriction`
[#7338](https://github.com/rust-lang/rust-clippy/pull/7338)
* Move [`option_if_let_else`] to `nursery`
[#7568](https://github.com/rust-lang/rust-clippy/pull/7568)
* Move [`branches_sharing_code`] to `nursery`
[#7595](https://github.com/rust-lang/rust-clippy/pull/7595)
* Rename `if_let_some_result` to [`match_result_ok`] which now also handles
`while let` cases [#7608](https://github.com/rust-lang/rust-clippy/pull/7608)
* Move [`many_single_char_names`] to `pedantic`
[#7671](https://github.com/rust-lang/rust-clippy/pull/7671)
* Move [`float_cmp`] to `pedantic`
[#7692](https://github.com/rust-lang/rust-clippy/pull/7692)
* Rename `box_vec` to [`box_collection`] and lint on more general cases
[#7693](https://github.com/rust-lang/rust-clippy/pull/7693)
* Uplift `invalid_atomic_ordering` to rustc
[rust-lang/rust#84039](https://github.com/rust-lang/rust/pull/84039)
### Enhancements
* Rewrite the `shadow*` lints, so that they find a lot more shadows and are not
limited to certain patterns
[#7338](https://github.com/rust-lang/rust-clippy/pull/7338)
* The `avoid-breaking-exported-api` configuration now also works for
[`box_collection`], [`redundant_allocation`], [`rc_buffer`], [`vec_box`],
[`option_option`], [`linkedlist`], [`rc_mutex`]
[#7560](https://github.com/rust-lang/rust-clippy/pull/7560)
* [`unnecessary_unwrap`]: Now also checks for `expect`s
[#7584](https://github.com/rust-lang/rust-clippy/pull/7584)
* [`disallowed_method`]: Allow adding a reason that will be displayed with the
lint message
[#7621](https://github.com/rust-lang/rust-clippy/pull/7621)
* [`approx_constant`]: Now checks the MSRV for `LOG10_2` and `LOG2_10`
[#7629](https://github.com/rust-lang/rust-clippy/pull/7629)
* [`approx_constant`]: Add `TAU`
[#7642](https://github.com/rust-lang/rust-clippy/pull/7642)
* [`needless_borrow`]: Now also lints on needless mutable borrows
[#7657](https://github.com/rust-lang/rust-clippy/pull/7657)
* [`missing_safety_doc`]: Now also lints on unsafe traits
[#7734](https://github.com/rust-lang/rust-clippy/pull/7734)
### False Positive Fixes
* [`manual_map`]: No longer lints when the option is borrowed in the match and
also consumed in the arm
[#7531](https://github.com/rust-lang/rust-clippy/pull/7531)
* [`filter_next`]: No longer lints if `filter` method is not the
`Iterator::filter` method
[#7562](https://github.com/rust-lang/rust-clippy/pull/7562)
* [`manual_flatten`]: No longer lints if expression is used after `if let`
[#7566](https://github.com/rust-lang/rust-clippy/pull/7566)
* [`option_if_let_else`]: Multiple fixes
[#7573](https://github.com/rust-lang/rust-clippy/pull/7573)
* `break` and `continue` statements local to the would-be closure are
allowed
* Don't lint in const contexts
* Don't lint when yield expressions are used
* Don't lint when the captures made by the would-be closure conflict with
the other branch
* Don't lint when a field of a local is used when the type could be
potentially moved from
* In some cases, don't lint when scrutinee expression conflicts with the
captures of the would-be closure
* [`redundant_allocation`]: No longer lints on `Box<Box<dyn T>>` which replaces
wide pointers with thin pointers
[#7592](https://github.com/rust-lang/rust-clippy/pull/7592)
* [`bool_assert_comparison`]: No longer lints on types that do not implement the
`Not` trait with `Output = bool`
[#7605](https://github.com/rust-lang/rust-clippy/pull/7605)
* [`mut_range_bound`]: No longer lints on range bound mutations, that are
immediately followed by a `break;`
[#7607](https://github.com/rust-lang/rust-clippy/pull/7607)
* [`mutable_key_type`]: Improve accuracy and document remaining false positives
and false negatives
[#7640](https://github.com/rust-lang/rust-clippy/pull/7640)
* [`redundant_closure`]: Rewrite the lint to fix various false positives and
false negatives [#7661](https://github.com/rust-lang/rust-clippy/pull/7661)
* [`large_enum_variant`]: No longer wrongly identifies the second largest
variant [#7677](https://github.com/rust-lang/rust-clippy/pull/7677)
* [`needless_return`]: No longer lints on let-else expressions
[#7685](https://github.com/rust-lang/rust-clippy/pull/7685)
* [`suspicious_else_formatting`]: No longer lints in proc-macros
[#7707](https://github.com/rust-lang/rust-clippy/pull/7707)
* [`excessive_precision`]: No longer lints when in some cases the float was
already written in the shortest form
[#7722](https://github.com/rust-lang/rust-clippy/pull/7722)
* [`doc_markdown`]: No longer lints on intra-doc links
[#7772](https://github.com/rust-lang/rust-clippy/pull/7772)
### Suggestion Fixes/Improvements
* [`unnecessary_operation`]: Recommend using an `assert!` instead of using a
function call in an indexing operation
[#7453](https://github.com/rust-lang/rust-clippy/pull/7453)
* [`manual_split_once`]: Produce semantically equivalent suggestion when
`rsplitn` is used [#7663](https://github.com/rust-lang/rust-clippy/pull/7663)
* [`while_let_on_iterator`]: Produce correct suggestion when using `&mut`
[#7690](https://github.com/rust-lang/rust-clippy/pull/7690)
* [`manual_assert`]: No better handles complex conditions
[#7741](https://github.com/rust-lang/rust-clippy/pull/7741)
* Correctly handle signs in exponents in numeric literals lints
[#7747](https://github.com/rust-lang/rust-clippy/pull/7747)
* [`suspicious_map`]: Now also suggests to use `inspect` as an alternative
[#7770](https://github.com/rust-lang/rust-clippy/pull/7770)
* Drop exponent from suggestion if it is 0 in numeric literals lints
[#7774](https://github.com/rust-lang/rust-clippy/pull/7774)
### ICE Fixes
* [`implicit_hasher`]
[#7761](https://github.com/rust-lang/rust-clippy/pull/7761)
### Others
* Clippy now uses the 2021
[Edition!](https://www.youtube.com/watch?v=q0aNduqb2Ro)
[#7664](https://github.com/rust-lang/rust-clippy/pull/7664)
## Rust 1.56
Current beta, release 2021-10-21
Current stable, released 2021-10-21
[74d1561...7bfc26e](https://github.com/rust-lang/rust-clippy/compare/74d1561...7bfc26e)
@ -74,13 +225,9 @@ Current beta, release 2021-10-21
* [`unnested_or_patterns`]: Removed `or_patterns` feature gate in the code
example [#7507](https://github.com/rust-lang/rust-clippy/pull/7507)
### New Lints
* Renamed Lint: `if_let_some_result` is now called [`match_result_ok`]. Now also handles `while let` case.
## Rust 1.55
Current stable, released 2021-09-09
Released 2021-09-09
[3ae8faf...74d1561](https://github.com/rust-lang/rust-clippy/compare/3ae8faf...74d1561)
@ -2748,7 +2895,6 @@ Released 2018-09-13
[`if_let_redundant_pattern_matching`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_redundant_pattern_matching
[`if_not_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_not_else
[`if_same_then_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_same_then_else
[`if_then_panic`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_then_panic
[`if_then_some_else_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none
[`ifs_same_cond`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond
[`implicit_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_clone
@ -2806,6 +2952,7 @@ Released 2018-09-13
[`lossy_float_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#lossy_float_literal
[`macro_use_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#macro_use_imports
[`main_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#main_recursion
[`manual_assert`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_assert
[`manual_async_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn
[`manual_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter_map
[`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map
@ -2976,6 +3123,7 @@ Released 2018-09-13
[`self_named_constructors`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_named_constructors
[`self_named_module_files`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_named_module_files
[`semicolon_if_nothing_returned`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_if_nothing_returned
[`separated_literal_suffix`]: https://rust-lang.github.io/rust-clippy/master/index.html#separated_literal_suffix
[`serde_api_misuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#serde_api_misuse
[`shadow_reuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_reuse
[`shadow_same`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_same
@ -3000,6 +3148,7 @@ Released 2018-09-13
[`string_extend_chars`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_extend_chars
[`string_from_utf8_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_from_utf8_as_bytes
[`string_lit_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_lit_as_bytes
[`string_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_slice
[`string_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_to_string
[`strlen_on_c_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#strlen_on_c_strings
[`struct_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#struct_excessive_bools
@ -3046,6 +3195,7 @@ Released 2018-09-13
[`uninit_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_vec
[`unit_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_arg
[`unit_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_cmp
[`unit_hash`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_hash
[`unit_return_expecting_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_return_expecting_ord
[`unnecessary_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_cast
[`unnecessary_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_filter_map

View File

@ -262,7 +262,9 @@ to be run inside the `rust` directory):
2. Checkout the commit from the latest available nightly. You can get it using `rustup check`.
3. Sync the changes to the rust-copy of Clippy to your Clippy fork:
```bash
# Make sure to change `your-github-name` to your github name in the following command
# Make sure to change `your-github-name` to your github name in the following command. Also be
# sure to either use a net-new branch, e.g. `sync-from-rust`, or delete the branch beforehand
# because changes cannot be fast forwarded
git subtree push -P src/tools/clippy git@github.com:your-github-name/rust-clippy sync-from-rust
```

View File

@ -28,7 +28,7 @@ tempfile = { version = "3.2", optional = true }
[dev-dependencies]
cargo_metadata = "0.14"
compiletest_rs = { version = "0.7", features = ["tmp"] }
compiletest_rs = { version = "0.7.1", features = ["tmp"] }
tester = "0.9"
regex = "1.5"
# This is used by the `collect-metadata` alias.

View File

@ -42,7 +42,8 @@ pub fn create(pass: Option<&str>, lint_name: Option<&str>, category: Option<&str
};
create_lint(&lint, msrv).context("Unable to create lint implementation")?;
create_test(&lint).context("Unable to create a test for the new lint")
create_test(&lint).context("Unable to create a test for the new lint")?;
add_lint(&lint, msrv).context("Unable to add lint to clippy_lints/src/lib.rs")
}
fn create_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> {
@ -80,6 +81,33 @@ fn create_test(lint: &LintData<'_>) -> io::Result<()> {
}
}
fn add_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> {
let path = "clippy_lints/src/lib.rs";
let mut lib_rs = fs::read_to_string(path).context("reading")?;
let comment_start = lib_rs.find("// add lints here,").expect("Couldn't find comment");
let new_lint = if enable_msrv {
format!(
"store.register_{lint_pass}_pass(move || Box::new({module_name}::{camel_name}::new(msrv)));\n ",
lint_pass = lint.pass,
module_name = lint.name,
camel_name = to_camel_case(lint.name),
)
} else {
format!(
"store.register_{lint_pass}_pass(|| Box::new({module_name}::{camel_name}));\n ",
lint_pass = lint.pass,
module_name = lint.name,
camel_name = to_camel_case(lint.name),
)
};
lib_rs.insert_str(comment_start, &new_lint);
fs::write(path, lib_rs).context("writing")
}
fn write_file<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result<()> {
fn inner(path: &Path, contents: &[u8]) -> io::Result<()> {
OpenOptions::new()
@ -151,7 +179,6 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
};
let lint_name = lint.name;
let pass_name = lint.pass;
let category = lint.category;
let name_camel = to_camel_case(lint.name);
let name_upper = lint_name.to_uppercase();
@ -228,18 +255,14 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
extract_msrv_attr!({context_import});
}}
// TODO: Register the lint pass in `clippy_lints/src/lib.rs`,
// e.g. store.register_{pass_name}_pass(move || Box::new({module_name}::{name_camel}::new(msrv)));
// TODO: Add MSRV level to `clippy_utils/src/msrvs.rs` if needed.
// TODO: Add MSRV test to `tests/ui/min_rust_version_attr.rs`.
// TODO: Update msrv config comment in `clippy_lints/src/utils/conf.rs`
"},
pass_type = pass_type,
pass_lifetimes = pass_lifetimes,
pass_name = pass_name,
name_upper = name_upper,
name_camel = name_camel,
module_name = lint_name,
context_import = context_import,
)
} else {
@ -248,16 +271,11 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
declare_lint_pass!({name_camel} => [{name_upper}]);
impl {pass_type}{pass_lifetimes} for {name_camel} {{}}
//
// TODO: Register the lint pass in `clippy_lints/src/lib.rs`,
// e.g. store.register_{pass_name}_pass(|| Box::new({module_name}::{name_camel}));
"},
pass_type = pass_type,
pass_lifetimes = pass_lifetimes,
pass_name = pass_name,
name_upper = name_upper,
name_camel = name_camel,
module_name = lint_name,
)
});

View File

@ -1,15 +1,88 @@
use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::span_lint;
use clippy_utils::expr_or_init;
use clippy_utils::ty::is_isize_or_usize;
use rustc_hir::Expr;
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, FloatTy, Ty};
use super::{utils, CAST_POSSIBLE_TRUNCATION};
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
fn constant_int(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<u128> {
if let Some((Constant::Int(c), _)) = constant(cx, cx.typeck_results(), expr) {
Some(c)
} else {
None
}
}
fn get_constant_bits(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<u64> {
constant_int(cx, expr).map(|c| u64::from(128 - c.leading_zeros()))
}
fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: bool) -> u64 {
match expr_or_init(cx, expr).kind {
ExprKind::Cast(inner, _) => apply_reductions(cx, nbits, inner, signed),
ExprKind::Block(block, _) => block.expr.map_or(nbits, |e| apply_reductions(cx, nbits, e, signed)),
ExprKind::Binary(op, left, right) => match op.node {
BinOpKind::Div => {
apply_reductions(cx, nbits, left, signed)
- (if signed {
0 // let's be conservative here
} else {
// by dividing by 1, we remove 0 bits, etc.
get_constant_bits(cx, right).map_or(0, |b| b.saturating_sub(1))
})
},
BinOpKind::Rem | BinOpKind::BitAnd => get_constant_bits(cx, right)
.unwrap_or(u64::max_value())
.min(apply_reductions(cx, nbits, left, signed)),
BinOpKind::Shr => {
apply_reductions(cx, nbits, left, signed)
- constant_int(cx, right).map_or(0, |s| u64::try_from(s).expect("shift too high"))
},
_ => nbits,
},
ExprKind::MethodCall(method, _, [left, right], _) => {
if signed {
return nbits;
}
let max_bits = if method.ident.as_str() == "min" {
get_constant_bits(cx, right)
} else {
None
};
apply_reductions(cx, nbits, left, signed).min(max_bits.unwrap_or(u64::max_value()))
},
ExprKind::MethodCall(method, _, [_, lo, hi], _) => {
if method.ident.as_str() == "clamp" {
//FIXME: make this a diagnostic item
if let (Some(lo_bits), Some(hi_bits)) = (get_constant_bits(cx, lo), get_constant_bits(cx, hi)) {
return lo_bits.max(hi_bits);
}
}
nbits
},
ExprKind::MethodCall(method, _, [_value], _) => {
if method.ident.name.as_str() == "signum" {
0 // do not lint if cast comes from a `signum` function
} else {
nbits
}
},
_ => nbits,
}
}
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
let msg = match (cast_from.is_integral(), cast_to.is_integral()) {
(true, true) => {
let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx);
let from_nbits = apply_reductions(
cx,
utils::int_ty_to_nbits(cast_from, cx.tcx),
cast_expr,
cast_from.is_signed(),
);
let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx);
let (should_lint, suffix) = match (is_isize_or_usize(cast_from), is_isize_or_usize(cast_to)) {

View File

@ -427,7 +427,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
fn_to_numeric_cast::check(cx, expr, cast_expr, cast_from, cast_to);
fn_to_numeric_cast_with_truncation::check(cx, expr, cast_expr, cast_from, cast_to);
if cast_from.is_numeric() && cast_to.is_numeric() && !in_external_macro(cx.sess(), expr.span) {
cast_possible_truncation::check(cx, expr, cast_from, cast_to);
cast_possible_truncation::check(cx, expr, cast_expr, cast_from, cast_to);
cast_possible_wrap::check(cx, expr, cast_from, cast_to);
cast_precision_loss::check(cx, expr, cast_from, cast_to);
cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to);

View File

@ -1,3 +1,6 @@
// NOTE: if you add a deprecated lint in this file, please add a corresponding test in
// tests/ui/deprecated.rs
/// This struct fakes the `Lint` declaration that is usually created by `declare_lint!`. This
/// enables the simple extraction of the metadata without changing the current deprecation
/// declaration.

View File

@ -126,7 +126,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
target_mut,
},
));
}
},
_ => (),
}
},

View File

@ -1,6 +1,6 @@
use clippy_utils::attrs::is_doc_hidden;
use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_note};
use clippy_utils::source::first_line_of_span;
use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_sugg};
use clippy_utils::source::{first_line_of_span, snippet_with_applicability};
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
use clippy_utils::{is_entrypoint_fn, is_expn_of, match_panic_def_id, method_chain_args, return_ty};
use if_chain::if_chain;
@ -10,7 +10,7 @@ use rustc_ast::token::CommentKind;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::sync::Lrc;
use rustc_errors::emitter::EmitterWriter;
use rustc_errors::Handler;
use rustc_errors::{Applicability, Handler};
use rustc_hir as hir;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_hir::{AnonConst, Expr, ExprKind, QPath};
@ -48,7 +48,7 @@ declare_clippy_lint! {
/// content are not linted.
///
/// In addition, when writing documentation comments, including `[]` brackets
/// inside a link text would trip the parser. Therfore, documenting link with
/// inside a link text would trip the parser. Therefore, documenting link with
/// `[`SmallVec<[T; INLINE_CAPACITY]>`]` and then [`SmallVec<[T; INLINE_CAPACITY]>`]: SmallVec
/// would fail.
///
@ -578,9 +578,12 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
// text "http://example.com" by pulldown-cmark
continue;
}
headers.safety |= in_heading && text.trim() == "Safety";
headers.errors |= in_heading && text.trim() == "Errors";
headers.panics |= in_heading && text.trim() == "Panics";
let trimmed_text = text.trim();
headers.safety |= in_heading && trimmed_text == "Safety";
headers.safety |= in_heading && trimmed_text == "Implementation safety";
headers.safety |= in_heading && trimmed_text == "Implementation Safety";
headers.errors |= in_heading && trimmed_text == "Errors";
headers.panics |= in_heading && trimmed_text == "Panics";
if in_code {
if is_rust {
let edition = edition.unwrap_or_else(|| cx.tcx.sess.edition());
@ -686,10 +689,18 @@ fn check_text(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, text: &str
for word in text.split(|c: char| c.is_whitespace() || c == '\'') {
// Trim punctuation as in `some comment (see foo::bar).`
// ^^
// Or even as in `_foo bar_` which is emphasized.
let word = word.trim_matches(|c: char| !c.is_alphanumeric());
// Or even as in `_foo bar_` which is emphasized. Also preserve `::` as a prefix/suffix.
let mut word = word.trim_matches(|c: char| !c.is_alphanumeric() && c != ':');
if valid_idents.contains(word) {
// Remove leading or trailing single `:` which may be part of a sentence.
if word.starts_with(':') && !word.starts_with("::") {
word = word.trim_start_matches(':');
}
if word.ends_with(':') && !word.ends_with("::") {
word = word.trim_end_matches(':');
}
if valid_idents.contains(word) || word.chars().all(|c| c == ':') {
continue;
}
@ -744,17 +755,22 @@ fn check_word(cx: &LateContext<'_>, word: &str, span: Span) {
}
}
// We assume that mixed-case words are not meant to be put inside bacticks. (Issue #2343)
// We assume that mixed-case words are not meant to be put inside backticks. (Issue #2343)
if has_underscore(word) && has_hyphen(word) {
return;
}
if has_underscore(word) || word.contains("::") || is_camel_case(word) {
span_lint(
let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg(
cx,
DOC_MARKDOWN,
span,
&format!("you should put `{}` between ticks in the documentation", word),
"item in documentation is missing backticks",
"try",
format!("`{}`", snippet_with_applicability(cx, span, "..", &mut applicability)),
applicability,
);
}
}
@ -793,9 +809,9 @@ impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> {
// check for `unwrap`
if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
let reciever_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
if is_type_diagnostic_item(self.cx, reciever_ty, sym::Option)
|| is_type_diagnostic_item(self.cx, reciever_ty, sym::Result)
let receiver_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
if is_type_diagnostic_item(self.cx, receiver_ty, sym::Option)
|| is_type_diagnostic_item(self.cx, receiver_ty, sym::Result)
{
self.panic_span = Some(expr.span);
}

View File

@ -245,11 +245,14 @@ fn try_parse_contains(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<(Map
ExprKind::MethodCall(
_,
_,
[map, Expr {
kind: ExprKind::AddrOf(_, _, key),
span: key_span,
..
}],
[
map,
Expr {
kind: ExprKind::AddrOf(_, _, key),
span: key_span,
..
},
],
_,
) if key_span.ctxt() == expr.span.ctxt() => {
let id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?;

View File

@ -1,8 +1,8 @@
//! lint on enum variants that are prefixed or suffixed by the same characters
use clippy_utils::camel_case;
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
use clippy_utils::source::is_present_in_source;
use clippy_utils::str_utils::{self, count_match_end, count_match_start};
use rustc_hir::{EnumDef, Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
@ -117,26 +117,6 @@ impl_lint_pass!(EnumVariantNames => [
MODULE_INCEPTION
]);
/// Returns the number of chars that match from the start
#[must_use]
fn partial_match(pre: &str, name: &str) -> usize {
let mut name_iter = name.chars();
let _ = name_iter.next_back(); // make sure the name is never fully matched
pre.chars().zip(name_iter).take_while(|&(l, r)| l == r).count()
}
/// Returns the number of chars that match from the end
#[must_use]
fn partial_rmatch(post: &str, name: &str) -> usize {
let mut name_iter = name.chars();
let _ = name_iter.next(); // make sure the name is never fully matched
post.chars()
.rev()
.zip(name_iter.rev())
.take_while(|&(l, r)| l == r)
.count()
}
fn check_variant(
cx: &LateContext<'_>,
threshold: u64,
@ -150,7 +130,7 @@ fn check_variant(
}
for var in def.variants {
let name = var.ident.name.as_str();
if partial_match(item_name, &name) == item_name_chars
if count_match_start(item_name, &name).char_count == item_name_chars
&& name.chars().nth(item_name_chars).map_or(false, |c| !c.is_lowercase())
&& name.chars().nth(item_name_chars + 1).map_or(false, |c| !c.is_numeric())
{
@ -161,7 +141,7 @@ fn check_variant(
"variant name starts with the enum's name",
);
}
if partial_rmatch(item_name, &name) == item_name_chars {
if count_match_end(item_name, &name).char_count == item_name_chars {
span_lint(
cx,
ENUM_VARIANT_NAMES,
@ -171,14 +151,14 @@ fn check_variant(
}
}
let first = &def.variants[0].ident.name.as_str();
let mut pre = &first[..camel_case::until(&*first)];
let mut post = &first[camel_case::from(&*first)..];
let mut pre = &first[..str_utils::camel_case_until(&*first).byte_index];
let mut post = &first[str_utils::camel_case_start(&*first).byte_index..];
for var in def.variants {
let name = var.ident.name.as_str();
let pre_match = partial_match(pre, &name);
let pre_match = count_match_start(pre, &name).byte_count;
pre = &pre[..pre_match];
let pre_camel = camel_case::until(pre);
let pre_camel = str_utils::camel_case_until(pre).byte_index;
pre = &pre[..pre_camel];
while let Some((next, last)) = name[pre.len()..].chars().zip(pre.chars().rev()).next() {
if next.is_numeric() {
@ -186,18 +166,18 @@ fn check_variant(
}
if next.is_lowercase() {
let last = pre.len() - last.len_utf8();
let last_camel = camel_case::until(&pre[..last]);
pre = &pre[..last_camel];
let last_camel = str_utils::camel_case_until(&pre[..last]);
pre = &pre[..last_camel.byte_index];
} else {
break;
}
}
let post_match = partial_rmatch(post, &name);
let post_end = post.len() - post_match;
let post_match = count_match_end(post, &name);
let post_end = post.len() - post_match.byte_count;
post = &post[post_end..];
let post_camel = camel_case::from(post);
post = &post[post_camel..];
let post_camel = str_utils::camel_case_start(post);
post = &post[post_camel.byte_index..];
}
let (what, value) = match (pre.is_empty(), post.is_empty()) {
(true, true) => return,
@ -266,14 +246,16 @@ impl LateLintPass<'_> for EnumVariantNames {
);
}
}
if item.vis.node.is_pub() {
let matching = partial_match(mod_camel, &item_camel);
let rmatching = partial_rmatch(mod_camel, &item_camel);
// The `module_name_repetitions` lint should only trigger if the item has the module in its
// name. Having the same name is accepted.
if item.vis.node.is_pub() && item_camel.len() > mod_camel.len() {
let matching = count_match_start(mod_camel, &item_camel);
let rmatching = count_match_end(mod_camel, &item_camel);
let nchars = mod_camel.chars().count();
let is_word_beginning = |c: char| c == '_' || c.is_uppercase() || c.is_numeric();
if matching == nchars {
if matching.char_count == nchars {
match item_camel.chars().nth(nchars) {
Some(c) if is_word_beginning(c) => span_lint(
cx,
@ -284,7 +266,7 @@ impl LateLintPass<'_> for EnumVariantNames {
_ => (),
}
}
if rmatching == nchars {
if rmatching.char_count == nchars {
span_lint(
cx,
MODULE_NAME_REPETITIONS,

View File

@ -169,13 +169,16 @@ fn check_inputs(cx: &LateContext<'_>, params: &[Param<'_>], call_args: &[Expr<'_
}
match *cx.typeck_results().expr_adjustments(arg) {
[] => true,
[Adjustment {
kind: Adjust::Deref(None),
..
}, Adjustment {
kind: Adjust::Borrow(AutoBorrow::Ref(_, mu2)),
..
}] => {
[
Adjustment {
kind: Adjust::Deref(None),
..
},
Adjustment {
kind: Adjust::Borrow(AutoBorrow::Ref(_, mu2)),
..
},
] => {
// re-borrow with the same mutability is allowed
let ty = cx.typeck_results().expr_ty(arg);
matches!(*ty.kind(), ty::Ref(.., mu1) if mu1 == mu2.into())

View File

@ -49,15 +49,19 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat {
let mut applicability = Applicability::MachineApplicable;
if format_args.value_args.is_empty() {
if_chain! {
if let [e] = &*format_args.format_string_parts;
if let ExprKind::Lit(lit) = &e.kind;
if let Some(s_src) = snippet_opt(cx, lit.span);
then {
// Simulate macro expansion, converting {{ and }} to { and }.
let s_expand = s_src.replace("{{", "{").replace("}}", "}");
let sugg = format!("{}.to_string()", s_expand);
span_useless_format(cx, call_site, sugg, applicability);
if format_args.format_string_parts.is_empty() {
span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability);
} else {
if_chain! {
if let [e] = &*format_args.format_string_parts;
if let ExprKind::Lit(lit) = &e.kind;
if let Some(s_src) = snippet_opt(cx, lit.span);
then {
// Simulate macro expansion, converting {{ and }} to { and }.
let s_expand = s_src.replace("{{", "{").replace("}}", "}");
let sugg = format!("{}.to_string()", s_expand);
span_useless_format(cx, call_site, sugg, applicability);
}
}
}
} else if let [value] = *format_args.value_args {
@ -89,6 +93,18 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat {
}
}
fn span_useless_format_empty(cx: &LateContext<'_>, span: Span, sugg: String, applicability: Applicability) {
span_lint_and_sugg(
cx,
USELESS_FORMAT,
span,
"useless use of `format!`",
"consider using `String::new()`",
sugg,
applicability,
);
}
fn span_useless_format(cx: &LateContext<'_>, span: Span, sugg: String, applicability: Applicability) {
span_lint_and_sugg(
cx,

View File

@ -2,9 +2,9 @@
//! on the condition
use clippy_utils::diagnostics::span_lint_and_help;
use rustc_ast::ast::{BinOpKind, Expr, ExprKind, UnOp};
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_middle::lint::in_external_macro;
use clippy_utils::is_else_clause;
use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
declare_clippy_lint! {
@ -46,14 +46,21 @@ declare_clippy_lint! {
declare_lint_pass!(IfNotElse => [IF_NOT_ELSE]);
impl EarlyLintPass for IfNotElse {
fn check_expr(&mut self, cx: &EarlyContext<'_>, item: &Expr) {
if in_external_macro(cx.sess, item.span) {
impl LateLintPass<'_> for IfNotElse {
fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) {
// While loops will be desugared to ExprKind::If. This will cause the lint to fire.
// To fix this, return early if this span comes from a macro or desugaring.
if item.span.from_expansion() {
return;
}
if let ExprKind::If(ref cond, _, Some(ref els)) = item.kind {
if let ExprKind::If(cond, _, Some(els)) = item.kind {
if let ExprKind::Block(..) = els.kind {
match cond.kind {
// Disable firing the lint in "else if" expressions.
if is_else_clause(cx.tcx, item) {
return;
}
match cond.peel_drop_temps().kind {
ExprKind::Unary(UnOp::Not, _) => {
span_lint_and_help(
cx,

View File

@ -89,7 +89,7 @@ impl IntPlusOne {
},
_ => None,
}
}
},
// case where `x + 1 <= ...` or `1 + x <= ...`
(BinOpKind::Le, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _)
if lhskind.node == BinOpKind::Add =>
@ -104,7 +104,7 @@ impl IntPlusOne {
},
_ => None,
}
}
},
// case where `... >= y - 1` or `... >= -1 + y`
(BinOpKind::Le, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs)) => {
match (rhskind.node, &rhslhs.kind, &rhsrhs.kind) {

View File

@ -1,5 +1,3 @@
use std::cmp::Ordering;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::layout::LayoutOf;
@ -7,11 +5,11 @@ use rustc_middle::ty::{self, IntTy, UintTy};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::Span;
use clippy_utils::comparisons;
use clippy_utils::comparisons::Rel;
use clippy_utils::consts::{constant, Constant};
use clippy_utils::consts::{constant_full_int, FullInt};
use clippy_utils::diagnostics::span_lint;
use clippy_utils::source::snippet;
use clippy_utils::{comparisons, sext};
declare_clippy_lint! {
/// ### What it does
@ -39,53 +37,6 @@ declare_clippy_lint! {
declare_lint_pass!(InvalidUpcastComparisons => [INVALID_UPCAST_COMPARISONS]);
#[derive(Copy, Clone, Debug, Eq)]
enum FullInt {
S(i128),
U(u128),
}
impl FullInt {
#[allow(clippy::cast_sign_loss)]
#[must_use]
fn cmp_s_u(s: i128, u: u128) -> Ordering {
if s < 0 {
Ordering::Less
} else if u > (i128::MAX as u128) {
Ordering::Greater
} else {
(s as u128).cmp(&u)
}
}
}
impl PartialEq for FullInt {
#[must_use]
fn eq(&self, other: &Self) -> bool {
self.partial_cmp(other).expect("`partial_cmp` only returns `Some(_)`") == Ordering::Equal
}
}
impl PartialOrd for FullInt {
#[must_use]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(match (self, other) {
(&Self::S(s), &Self::S(o)) => s.cmp(&o),
(&Self::U(s), &Self::U(o)) => s.cmp(&o),
(&Self::S(s), &Self::U(o)) => Self::cmp_s_u(s, o),
(&Self::U(s), &Self::S(o)) => Self::cmp_s_u(o, s).reverse(),
})
}
}
impl Ord for FullInt {
#[must_use]
fn cmp(&self, other: &Self) -> Ordering {
self.partial_cmp(other)
.expect("`partial_cmp` for FullInt can never return `None`")
}
}
fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_>, expr: &'a Expr<'_>) -> Option<(FullInt, FullInt)> {
if let ExprKind::Cast(cast_exp, _) = expr.kind {
let pre_cast_ty = cx.typeck_results().expr_ty(cast_exp);
@ -118,19 +69,6 @@ fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_>, expr: &'a Expr<'_>) ->
}
}
fn node_as_const_fullint<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<FullInt> {
let val = constant(cx, cx.typeck_results(), expr)?.0;
if let Constant::Int(const_int) = val {
match *cx.typeck_results().expr_ty(expr).kind() {
ty::Int(ity) => Some(FullInt::S(sext(cx.tcx, const_int, ity))),
ty::Uint(_) => Some(FullInt::U(const_int)),
_ => None,
}
} else {
None
}
}
fn err_upcast_comparison(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, always: bool) {
if let ExprKind::Cast(cast_val, _) = expr.kind {
span_lint(
@ -156,7 +94,7 @@ fn upcast_comparison_bounds_err<'tcx>(
invert: bool,
) {
if let Some((lb, ub)) = lhs_bounds {
if let Some(norm_rhs_val) = node_as_const_fullint(cx, rhs) {
if let Some(norm_rhs_val) = constant_full_int(cx, cx.typeck_results(), rhs) {
if rel == Rel::Eq || rel == Rel::Ne {
if norm_rhs_val < lb || norm_rhs_val > ub {
err_upcast_comparison(cx, span, lhs, rel == Rel::Ne);

View File

@ -76,7 +76,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
LintId::of(get_last_with_len::GET_LAST_WITH_LEN),
LintId::of(identity_op::IDENTITY_OP),
LintId::of(if_let_mutex::IF_LET_MUTEX),
LintId::of(if_then_panic::IF_THEN_PANIC),
LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING),
LintId::of(infinite_iter::INFINITE_ITER),
LintId::of(inherent_to_string::INHERENT_TO_STRING),
@ -218,6 +217,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
LintId::of(non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST),
LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS),
LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY),
LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS),
LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP),
LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL),
@ -282,6 +282,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
LintId::of(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS),
LintId::of(unicode::INVISIBLE_CHARACTERS),
LintId::of(uninit_vec::UNINIT_VEC),
LintId::of(unit_hash::UNIT_HASH),
LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
LintId::of(unit_types::UNIT_ARG),
LintId::of(unit_types::UNIT_CMP),

View File

@ -64,6 +64,7 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve
LintId::of(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS),
LintId::of(unicode::INVISIBLE_CHARACTERS),
LintId::of(uninit_vec::UNINIT_VEC),
LintId::of(unit_hash::UNIT_HASH),
LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
LintId::of(unit_types::UNIT_CMP),
LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS),

View File

@ -159,7 +159,6 @@ store.register_lints(&[
identity_op::IDENTITY_OP,
if_let_mutex::IF_LET_MUTEX,
if_not_else::IF_NOT_ELSE,
if_then_panic::IF_THEN_PANIC,
if_then_some_else_none::IF_THEN_SOME_ELSE_NONE,
implicit_hasher::IMPLICIT_HASHER,
implicit_return::IMPLICIT_RETURN,
@ -216,6 +215,7 @@ store.register_lints(&[
loops::WHILE_LET_ON_ITERATOR,
macro_use::MACRO_USE_IMPORTS,
main_recursion::MAIN_RECURSION,
manual_assert::MANUAL_ASSERT,
manual_async_fn::MANUAL_ASYNC_FN,
manual_map::MANUAL_MAP,
manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE,
@ -327,6 +327,7 @@ store.register_lints(&[
misc_early::DUPLICATE_UNDERSCORE_ARGUMENT,
misc_early::MIXED_CASE_HEX_LITERALS,
misc_early::REDUNDANT_PATTERN,
misc_early::SEPARATED_LITERAL_SUFFIX,
misc_early::UNNEEDED_FIELD_PATTERN,
misc_early::UNNEEDED_WILDCARD_PATTERN,
misc_early::UNSEPARATED_LITERAL_SUFFIX,
@ -431,6 +432,7 @@ store.register_lints(&[
strings::STRING_ADD_ASSIGN,
strings::STRING_FROM_UTF8_AS_BYTES,
strings::STRING_LIT_AS_BYTES,
strings::STRING_SLICE,
strings::STRING_TO_STRING,
strings::STR_TO_STRING,
strlen_on_c_strings::STRLEN_ON_C_STRINGS,
@ -476,6 +478,7 @@ store.register_lints(&[
unicode::NON_ASCII_LITERAL,
unicode::UNICODE_NOT_NFC,
uninit_vec::UNINIT_VEC,
unit_hash::UNIT_HASH,
unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD,
unit_types::LET_UNIT_VALUE,
unit_types::UNIT_ARG,

View File

@ -17,7 +17,6 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN),
LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL),
LintId::of(mutex_atomic::MUTEX_INTEGER),
LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY),
LintId::of(nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES),
LintId::of(option_if_let_else::OPTION_IF_LET_ELSE),
LintId::of(path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE),

View File

@ -48,6 +48,7 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
LintId::of(loops::EXPLICIT_INTO_ITER_LOOP),
LintId::of(loops::EXPLICIT_ITER_LOOP),
LintId::of(macro_use::MACRO_USE_IMPORTS),
LintId::of(manual_assert::MANUAL_ASSERT),
LintId::of(manual_ok_or::MANUAL_OK_OR),
LintId::of(match_on_vec_items::MATCH_ON_VEC_ITEMS),
LintId::of(matches::MATCH_BOOL),
@ -65,7 +66,6 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
LintId::of(methods::MAP_UNWRAP_OR),
LintId::of(misc::FLOAT_CMP),
LintId::of(misc::USED_UNDERSCORE_BINDING),
LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX),
LintId::of(mut_mut::MUT_MUT),
LintId::of(needless_bitwise_bool::NEEDLESS_BITWISE_BOOL),
LintId::of(needless_borrow::REF_BINDING_TO_REFERENCE),
@ -88,7 +88,6 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
LintId::of(transmute::TRANSMUTE_PTR_TO_PTR),
LintId::of(types::LINKEDLIST),
LintId::of(types::OPTION_OPTION),
LintId::of(unicode::NON_ASCII_LITERAL),
LintId::of(unicode::UNICODE_NOT_NFC),
LintId::of(unit_types::LET_UNIT_VALUE),
LintId::of(unnecessary_wraps::UNNECESSARY_WRAPS),

View File

@ -35,7 +35,9 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve
LintId::of(methods::GET_UNWRAP),
LintId::of(methods::UNWRAP_USED),
LintId::of(misc::FLOAT_CMP_CONST),
LintId::of(misc_early::SEPARATED_LITERAL_SUFFIX),
LintId::of(misc_early::UNNEEDED_FIELD_PATTERN),
LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX),
LintId::of(missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS),
LintId::of(missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES),
LintId::of(missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS),
@ -53,11 +55,13 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve
LintId::of(shadow::SHADOW_SAME),
LintId::of(shadow::SHADOW_UNRELATED),
LintId::of(strings::STRING_ADD),
LintId::of(strings::STRING_SLICE),
LintId::of(strings::STRING_TO_STRING),
LintId::of(strings::STR_TO_STRING),
LintId::of(types::RC_BUFFER),
LintId::of(types::RC_MUTEX),
LintId::of(undocumented_unsafe_blocks::UNDOCUMENTED_UNSAFE_BLOCKS),
LintId::of(unicode::NON_ASCII_LITERAL),
LintId::of(unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS),
LintId::of(unwrap_in_result::UNWRAP_IN_RESULT),
LintId::of(verbose_file_reads::VERBOSE_FILE_READS),

View File

@ -27,7 +27,6 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
LintId::of(functions::DOUBLE_MUST_USE),
LintId::of(functions::MUST_USE_UNIT),
LintId::of(functions::RESULT_UNIT_ERR),
LintId::of(if_then_panic::IF_THEN_PANIC),
LintId::of(inherent_to_string::INHERENT_TO_STRING),
LintId::of(len_zero::COMPARISON_TO_EMPTY),
LintId::of(len_zero::LEN_WITHOUT_IS_EMPTY),

View File

@ -15,6 +15,7 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec!
LintId::of(loops::MUT_RANGE_BOUND),
LintId::of(methods::SUSPICIOUS_MAP),
LintId::of(mut_key::MUTABLE_KEY_TYPE),
LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY),
LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
])

View File

@ -228,7 +228,6 @@ mod get_last_with_len;
mod identity_op;
mod if_let_mutex;
mod if_not_else;
mod if_then_panic;
mod if_then_some_else_none;
mod implicit_hasher;
mod implicit_return;
@ -255,6 +254,7 @@ mod literal_representation;
mod loops;
mod macro_use;
mod main_recursion;
mod manual_assert;
mod manual_async_fn;
mod manual_map;
mod manual_non_exhaustive;
@ -364,6 +364,7 @@ mod undocumented_unsafe_blocks;
mod undropped_manually_drops;
mod unicode;
mod uninit_vec;
mod unit_hash;
mod unit_return_expecting_ord;
mod unit_types;
mod unnamed_address;
@ -522,6 +523,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|| Box::new(collapsible_match::CollapsibleMatch));
store.register_late_pass(|| Box::new(unicode::Unicode));
store.register_late_pass(|| Box::new(uninit_vec::UninitVec));
store.register_late_pass(|| Box::new(unit_hash::UnitHash));
store.register_late_pass(|| Box::new(unit_return_expecting_ord::UnitReturnExpectingOrd));
store.register_late_pass(|| Box::new(strings::StringAdd));
store.register_late_pass(|| Box::new(implicit_return::ImplicitReturn));
@ -666,7 +668,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_early_pass(|| Box::new(double_parens::DoubleParens));
store.register_late_pass(|| Box::new(to_string_in_display::ToStringInDisplay::new()));
store.register_early_pass(|| Box::new(unsafe_removed_from_name::UnsafeNameRemoval));
store.register_early_pass(|| Box::new(if_not_else::IfNotElse));
store.register_early_pass(|| Box::new(else_if_without_else::ElseIfWithoutElse));
store.register_early_pass(|| Box::new(int_plus_one::IntPlusOne));
store.register_early_pass(|| Box::new(formatting::Formatting));
@ -720,6 +721,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|| Box::new(option_if_let_else::OptionIfLetElse));
store.register_late_pass(|| Box::new(future_not_send::FutureNotSend));
store.register_late_pass(|| Box::new(if_let_mutex::IfLetMutex));
store.register_late_pass(|| Box::new(if_not_else::IfNotElse));
store.register_late_pass(|| Box::new(equatable_if_let::PatternEquality));
store.register_late_pass(|| Box::new(mut_mutex_lock::MutMutexLock));
store.register_late_pass(|| Box::new(match_on_vec_items::MatchOnVecItems));
@ -770,14 +772,14 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(move || Box::new(self_named_constructors::SelfNamedConstructors));
store.register_late_pass(move || Box::new(feature_name::FeatureName));
store.register_late_pass(move || Box::new(iter_not_returning_iterator::IterNotReturningIterator));
store.register_late_pass(move || Box::new(if_then_panic::IfThenPanic));
store.register_late_pass(move || Box::new(manual_assert::ManualAssert));
let enable_raw_pointer_heuristic_for_send = conf.enable_raw_pointer_heuristic_for_send;
store.register_late_pass(move || Box::new(non_send_fields_in_send_ty::NonSendFieldInSendTy::new(enable_raw_pointer_heuristic_for_send)));
store.register_late_pass(move || Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks::default()));
store.register_late_pass(|| Box::new(match_str_case_mismatch::MatchStrCaseMismatch));
store.register_late_pass(move || Box::new(format_args::FormatArgs));
store.register_late_pass(|| Box::new(trailing_empty_array::TrailingEmptyArray));
// add lints here, do not remove this comment, it's used in `new_lint`
}
#[rustfmt::skip]
@ -828,6 +830,7 @@ fn register_removed_non_tool_lints(store: &mut rustc_lint::LintStore) {
///
/// Used in `./src/driver.rs`.
pub fn register_renamed(ls: &mut rustc_lint::LintStore) {
// NOTE: when renaming a lint, add a corresponding test to tests/ui/rename.rs
ls.register_renamed("clippy::stutter", "clippy::module_name_repetitions");
ls.register_renamed("clippy::new_without_default_derive", "clippy::new_without_default");
ls.register_renamed("clippy::cyclomatic_complexity", "clippy::cognitive_complexity");

View File

@ -378,11 +378,15 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
fn visit_ty(&mut self, ty: &'tcx Ty<'_>) {
match ty.kind {
TyKind::OpaqueDef(item, _) => {
TyKind::OpaqueDef(item, bounds) => {
let map = self.cx.tcx.hir();
let item = map.item(item);
walk_item(self, item);
walk_ty(self, ty);
self.lts.extend(bounds.iter().filter_map(|bound| match bound {
GenericArg::Lifetime(l) => Some(RefLt::Named(l.name.ident().name)),
_ => None,
}));
},
TyKind::BareFn(&BareFnTy { decl, .. }) => {
let mut sub_visitor = RefVisitor::new(self.cx);

View File

@ -338,7 +338,7 @@ pub(super) fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applic
sugg::Sugg::hir_with_applicability(cx, arg_inner, "_", applic_ref).maybe_par(),
meth_name,
)
}
},
_ => format!(
"{}.into_iter()",
sugg::Sugg::hir_with_applicability(cx, arg, "_", applic_ref).maybe_par()

View File

@ -26,14 +26,14 @@ declare_clippy_lint! {
/// let sad_people: Vec<&str> = vec![];
/// assert!(sad_people.is_empty(), "there are sad people: {:?}", sad_people);
/// ```
pub IF_THEN_PANIC,
style,
pub MANUAL_ASSERT,
pedantic,
"`panic!` and only a `panic!` in `if`-then statement"
}
declare_lint_pass!(IfThenPanic => [IF_THEN_PANIC]);
declare_lint_pass!(ManualAssert => [MANUAL_ASSERT]);
impl LateLintPass<'_> for IfThenPanic {
impl LateLintPass<'_> for ManualAssert {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
if_chain! {
if let Expr {
@ -54,23 +54,24 @@ impl LateLintPass<'_> for IfThenPanic {
if !cx.tcx.sess.source_map().is_multiline(cond.span);
then {
let span = if let Some(panic_expn) = PanicExpn::parse(semi) {
let call = if_chain! {
if let ExprKind::Block(block, _) = semi.kind;
if let Some(init) = block.expr;
then {
init
} else {
semi
}
};
let span = if let Some(panic_expn) = PanicExpn::parse(call) {
match *panic_expn.format_args.value_args {
[] => panic_expn.format_args.format_string_span,
[.., last] => panic_expn.format_args.format_string_span.to(last.span),
}
} else if let ExprKind::Call(_, [format_args]) = call.kind {
format_args.span
} else {
if_chain! {
if let ExprKind::Block(block, _) = semi.kind;
if let Some(init) = block.expr;
if let ExprKind::Call(_, [format_args]) = init.kind;
then {
format_args.span
} else {
return
}
}
return
};
let mut applicability = Applicability::MachineApplicable;
let sugg = snippet_with_applicability(cx, span, "..", &mut applicability);
@ -86,7 +87,7 @@ impl LateLintPass<'_> for IfThenPanic {
span_lint_and_sugg(
cx,
IF_THEN_PANIC,
MANUAL_ASSERT,
expr.span,
"only a `panic!` in `if`-then statement",
"try",

View File

@ -127,10 +127,10 @@ fn get_case_method(segment_ident_str: &str) -> Option<CaseMethod> {
fn verify_case<'a>(case_method: &'a CaseMethod, arms: &'a [Arm<'_>]) -> Option<(Span, SymbolStr)> {
let case_check = match case_method {
CaseMethod::LowerCase => |input: &str| -> bool { input.chars().all(char::is_lowercase) },
CaseMethod::AsciiLowerCase => |input: &str| -> bool { input.chars().all(|c| matches!(c, 'a'..='z')) },
CaseMethod::UpperCase => |input: &str| -> bool { input.chars().all(char::is_uppercase) },
CaseMethod::AsciiUppercase => |input: &str| -> bool { input.chars().all(|c| matches!(c, 'A'..='Z')) },
CaseMethod::LowerCase => |input: &str| -> bool { input.chars().all(|c| c.to_lowercase().next() == Some(c)) },
CaseMethod::AsciiLowerCase => |input: &str| -> bool { !input.chars().any(|c| c.is_ascii_uppercase()) },
CaseMethod::UpperCase => |input: &str| -> bool { input.chars().all(|c| c.to_uppercase().next() == Some(c)) },
CaseMethod::AsciiUppercase => |input: &str| -> bool { !input.chars().any(|c| c.is_ascii_lowercase()) },
};
for arm in arms {
@ -153,7 +153,7 @@ fn verify_case<'a>(case_method: &'a CaseMethod, arms: &'a [Arm<'_>]) -> Option<(
fn lint(cx: &LateContext<'_>, case_method: &CaseMethod, bad_case_span: Span, bad_case_str: &str) {
let (method_str, suggestion) = match case_method {
CaseMethod::LowerCase => ("to_lower_case", bad_case_str.to_lowercase()),
CaseMethod::LowerCase => ("to_lowercase", bad_case_str.to_lowercase()),
CaseMethod::AsciiLowerCase => ("to_ascii_lowercase", bad_case_str.to_ascii_lowercase()),
CaseMethod::UpperCase => ("to_uppercase", bad_case_str.to_uppercase()),
CaseMethod::AsciiUppercase => ("to_ascii_uppercase", bad_case_str.to_ascii_uppercase()),

View File

@ -1,4 +1,4 @@
use clippy_utils::consts::{constant, miri_to_const, Constant};
use clippy_utils::consts::{constant, constant_full_int, miri_to_const, FullInt};
use clippy_utils::diagnostics::{
multispan_sugg, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then,
};
@ -930,9 +930,8 @@ fn check_match_bool(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr:
fn check_overlapping_arms<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'_>, arms: &'tcx [Arm<'_>]) {
if arms.len() >= 2 && cx.typeck_results().expr_ty(ex).is_integral() {
let ranges = all_ranges(cx, arms, cx.typeck_results().expr_ty(ex));
let type_ranges = type_ranges(&ranges);
if !type_ranges.is_empty() {
if let Some((start, end)) = overlapping(&type_ranges) {
if !ranges.is_empty() {
if let Some((start, end)) = overlapping(&ranges) {
span_lint_and_note(
cx,
MATCH_OVERLAPPING_ARM,
@ -968,8 +967,7 @@ fn check_wild_err_arm<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm
}
if_chain! {
if matching_wild;
if let ExprKind::Block(block, _) = arm.body.kind;
if is_panic_block(block);
if is_panic_call(arm.body);
then {
// `Err(_)` or `Err(_e)` arm with `panic!` found
span_lint_and_note(cx,
@ -1172,14 +1170,19 @@ fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>])
}
// If the block contains only a `panic!` macro (as expression or statement)
fn is_panic_block(block: &Block<'_>) -> bool {
match (&block.expr, block.stmts.len(), block.stmts.first()) {
(&Some(exp), 0, _) => is_expn_of(exp.span, "panic").is_some() && is_expn_of(exp.span, "unreachable").is_none(),
(&None, 1, Some(stmt)) => {
is_expn_of(stmt.span, "panic").is_some() && is_expn_of(stmt.span, "unreachable").is_none()
},
_ => false,
}
fn is_panic_call(expr: &Expr<'_>) -> bool {
// Unwrap any wrapping blocks
let span = if let ExprKind::Block(block, _) = expr.kind {
match (&block.expr, block.stmts.len(), block.stmts.first()) {
(&Some(exp), 0, _) => exp.span,
(&None, 1, Some(stmt)) => stmt.span,
_ => return false,
}
} else {
expr.span
};
is_expn_of(span, "panic").is_some() && is_expn_of(span, "unreachable").is_none()
}
fn check_match_ref_pats<'a, 'b, I>(cx: &LateContext<'_>, ex: &Expr<'_>, pats: I, expr: &Expr<'_>)
@ -1601,7 +1604,7 @@ fn opt_parent_let<'a>(cx: &LateContext<'a>, ex: &Expr<'a>) -> Option<&'a Local<'
}
/// Gets all arms that are unbounded `PatRange`s.
fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) -> Vec<SpannedRange<Constant>> {
fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) -> Vec<SpannedRange<FullInt>> {
arms.iter()
.filter_map(|arm| {
if let Arm { pat, guard: None, .. } = *arm {
@ -1614,21 +1617,25 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
Some(rhs) => constant(cx, cx.typeck_results(), rhs)?.0,
None => miri_to_const(ty.numeric_max_val(cx.tcx)?)?,
};
let rhs = match range_end {
RangeEnd::Included => Bound::Included(rhs),
RangeEnd::Excluded => Bound::Excluded(rhs),
let lhs_val = lhs.int_value(cx, ty)?;
let rhs_val = rhs.int_value(cx, ty)?;
let rhs_bound = match range_end {
RangeEnd::Included => Bound::Included(rhs_val),
RangeEnd::Excluded => Bound::Excluded(rhs_val),
};
return Some(SpannedRange {
span: pat.span,
node: (lhs, rhs),
node: (lhs_val, rhs_bound),
});
}
if let PatKind::Lit(value) = pat.kind {
let value = constant(cx, cx.typeck_results(), value)?.0;
let value = constant_full_int(cx, cx.typeck_results(), value)?;
return Some(SpannedRange {
span: pat.span,
node: (value.clone(), Bound::Included(value)),
node: (value, Bound::Included(value)),
});
}
}
@ -1643,32 +1650,6 @@ pub struct SpannedRange<T> {
pub node: (T, Bound<T>),
}
type TypedRanges = Vec<SpannedRange<u128>>;
/// Gets all `Int` ranges or all `Uint` ranges. Mixed types are an error anyway
/// and other types than
/// `Uint` and `Int` probably don't make sense.
fn type_ranges(ranges: &[SpannedRange<Constant>]) -> TypedRanges {
ranges
.iter()
.filter_map(|range| match range.node {
(Constant::Int(start), Bound::Included(Constant::Int(end))) => Some(SpannedRange {
span: range.span,
node: (start, Bound::Included(end)),
}),
(Constant::Int(start), Bound::Excluded(Constant::Int(end))) => Some(SpannedRange {
span: range.span,
node: (start, Bound::Excluded(end)),
}),
(Constant::Int(start), Bound::Unbounded) => Some(SpannedRange {
span: range.span,
node: (start, Bound::Unbounded),
}),
_ => None,
})
.collect()
}
// Checks if arm has the form `None => None`
fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
matches!(arm.pat.kind, PatKind::Path(ref qpath) if is_lang_ctor(cx, qpath, OptionNone))

View File

@ -85,7 +85,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol,
if expr.hir_id == self_arg.hir_id && ty != cx.typeck_results().expr_ty_adjusted(expr) =>
{
return;
}
},
ExprKind::MethodCall(_, _, [self_arg, ..], _) if expr.hir_id == self_arg.hir_id => true,
ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar)
| ExprKind::Field(..)
@ -100,7 +100,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol,
) =>
{
return;
}
},
_ => false,
};

View File

@ -186,7 +186,7 @@ pub(super) fn check<'tcx>(
check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, None);
}
}
}
},
_ => (),
}
}

View File

@ -1,4 +1,3 @@
use super::MiscEarlyLints;
use clippy_utils::diagnostics::span_lint;
use rustc_ast::ast::{Expr, ExprKind, UnOp};
use rustc_lint::EarlyContext;
@ -6,18 +5,14 @@ use rustc_lint::EarlyContext;
use super::DOUBLE_NEG;
pub(super) fn check(cx: &EarlyContext<'_>, expr: &Expr) {
match expr.kind {
ExprKind::Unary(UnOp::Neg, ref inner) => {
if let ExprKind::Unary(UnOp::Neg, _) = inner.kind {
span_lint(
cx,
DOUBLE_NEG,
expr.span,
"`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op",
);
}
},
ExprKind::Lit(ref lit) => MiscEarlyLints::check_lit(cx, lit),
_ => (),
if let ExprKind::Unary(UnOp::Neg, ref inner) = expr.kind {
if let ExprKind::Unary(UnOp::Neg, _) = inner.kind {
span_lint(
cx,
DOUBLE_NEG,
expr.span,
"`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op",
);
}
}
}

View File

@ -0,0 +1,38 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use rustc_ast::ast::Lit;
use rustc_errors::Applicability;
use rustc_lint::EarlyContext;
use super::{SEPARATED_LITERAL_SUFFIX, UNSEPARATED_LITERAL_SUFFIX};
pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str, suffix: &str, sugg_type: &str) {
let maybe_last_sep_idx = if let Some(val) = lit_snip.len().checked_sub(suffix.len() + 1) {
val
} else {
return; // It's useless so shouldn't lint.
};
// Do not lint when literal is unsuffixed.
if !suffix.is_empty() {
if lit_snip.as_bytes()[maybe_last_sep_idx] == b'_' {
span_lint_and_sugg(
cx,
SEPARATED_LITERAL_SUFFIX,
lit.span,
&format!("{} type suffix should not be separated by an underscore", sugg_type),
"remove the underscore",
format!("{}{}", &lit_snip[..maybe_last_sep_idx], suffix),
Applicability::MachineApplicable,
);
} else {
span_lint_and_sugg(
cx,
UNSEPARATED_LITERAL_SUFFIX,
lit.span,
&format!("{} type suffix should be separated by an underscore", sugg_type),
"add an underscore",
format!("{}_{}", &lit_snip[..=maybe_last_sep_idx], suffix),
Applicability::MachineApplicable,
);
}
}
}

View File

@ -1,15 +1,15 @@
mod builtin_type_shadow;
mod double_neg;
mod literal_suffix;
mod mixed_case_hex_literals;
mod redundant_pattern;
mod unneeded_field_pattern;
mod unneeded_wildcard_pattern;
mod unseparated_literal_suffix;
mod zero_prefixed_literal;
use clippy_utils::diagnostics::span_lint;
use clippy_utils::source::snippet_opt;
use rustc_ast::ast::{Expr, Generics, Lit, LitFloatType, LitIntType, LitKind, NodeId, Pat, PatKind};
use rustc_ast::ast::{Expr, ExprKind, Generics, Lit, LitFloatType, LitIntType, LitKind, NodeId, Pat, PatKind};
use rustc_ast::visit::FnKind;
use rustc_data_structures::fx::FxHashMap;
use rustc_lint::{EarlyContext, EarlyLintPass};
@ -115,9 +115,11 @@ declare_clippy_lint! {
/// ### What it does
/// Warns if literal suffixes are not separated by an
/// underscore.
/// To enforce unseparated literal suffix style,
/// see the `separated_literal_suffix` lint.
///
/// ### Why is this bad?
/// It is much less readable.
/// Suffix style should be consistent.
///
/// ### Example
/// ```rust
@ -128,10 +130,32 @@ declare_clippy_lint! {
/// let y = 123832_i32;
/// ```
pub UNSEPARATED_LITERAL_SUFFIX,
pedantic,
restriction,
"literals whose suffix is not separated by an underscore"
}
declare_clippy_lint! {
/// ### What it does
/// Warns if literal suffixes are separated by an underscore.
/// To enforce separated literal suffix style,
/// see the `unseparated_literal_suffix` lint.
///
/// ### Why is this bad?
/// Suffix style should be consistent.
///
/// ### Example
/// ```rust
/// // Bad
/// let y = 123832_i32;
///
/// // Good
/// let y = 123832i32;
/// ```
pub SEPARATED_LITERAL_SUFFIX,
restriction,
"literals whose suffix is separated by an underscore"
}
declare_clippy_lint! {
/// ### What it does
/// Warns if an integral constant literal starts with `0`.
@ -260,6 +284,7 @@ declare_lint_pass!(MiscEarlyLints => [
DOUBLE_NEG,
MIXED_CASE_HEX_LITERALS,
UNSEPARATED_LITERAL_SUFFIX,
SEPARATED_LITERAL_SUFFIX,
ZERO_PREFIXED_LITERAL,
BUILTIN_TYPE_SHADOW,
REDUNDANT_PATTERN,
@ -310,6 +335,10 @@ impl EarlyLintPass for MiscEarlyLints {
if in_external_macro(cx.sess, expr.span) {
return;
}
if let ExprKind::Lit(ref lit) = expr.kind {
MiscEarlyLints::check_lit(cx, lit);
}
double_neg::check(cx, expr);
}
}
@ -332,7 +361,7 @@ impl MiscEarlyLints {
LitIntType::Unsigned(ty) => ty.name_str(),
LitIntType::Unsuffixed => "",
};
unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "integer");
literal_suffix::check(cx, lit, &lit_snip, suffix, "integer");
if lit_snip.starts_with("0x") {
mixed_case_hex_literals::check(cx, lit, suffix, &lit_snip);
} else if lit_snip.starts_with("0b") || lit_snip.starts_with("0o") {
@ -342,7 +371,7 @@ impl MiscEarlyLints {
}
} else if let LitKind::Float(_, LitFloatType::Suffixed(float_ty)) = lit.kind {
let suffix = float_ty.name_str();
unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "float");
literal_suffix::check(cx, lit, &lit_snip, suffix, "float");
}
}
}

View File

@ -1,26 +0,0 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use rustc_ast::ast::Lit;
use rustc_errors::Applicability;
use rustc_lint::EarlyContext;
use super::UNSEPARATED_LITERAL_SUFFIX;
pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str, suffix: &str, sugg_type: &str) {
let maybe_last_sep_idx = if let Some(val) = lit_snip.len().checked_sub(suffix.len() + 1) {
val
} else {
return; // It's useless so shouldn't lint.
};
// Do not lint when literal is unsuffixed.
if !suffix.is_empty() && lit_snip.as_bytes()[maybe_last_sep_idx] != b'_' {
span_lint_and_sugg(
cx,
UNSEPARATED_LITERAL_SUFFIX,
lit.span,
&format!("{} type suffix should be separated by an underscore", sugg_type),
"add an underscore",
format!("{}_{}", &lit_snip[..=maybe_last_sep_idx], suffix),
Applicability::MachineApplicable,
);
}
}

View File

@ -106,7 +106,7 @@ impl EarlyLintPass for ModStyle {
}
process_paths_for_mod_files(path, &mut folder_segments, &mut mod_folders);
check_self_named_mod_exists(cx, path, file);
}
},
_ => {},
}
}

View File

@ -107,14 +107,18 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow {
if let ExprKind::AddrOf(BorrowKind::Ref, mutability, inner) = e.kind {
if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(inner).kind() {
for adj3 in cx.typeck_results().expr_adjustments(e).windows(3) {
if let [Adjustment {
kind: Adjust::Deref(_), ..
}, Adjustment {
kind: Adjust::Deref(_), ..
}, Adjustment {
kind: Adjust::Borrow(_),
..
}] = *adj3
if let [
Adjustment {
kind: Adjust::Deref(_), ..
},
Adjustment {
kind: Adjust::Deref(_), ..
},
Adjustment {
kind: Adjust::Borrow(_),
..
},
] = *adj3
{
let help_msg_ty = if matches!(mutability, Mutability::Not) {
format!("&{}", ty)

View File

@ -44,7 +44,7 @@ declare_clippy_lint! {
/// Use thread-safe types like [`std::sync::Arc`](https://doc.rust-lang.org/std/sync/struct.Arc.html)
/// or specify correct bounds on generic type parameters (`T: Send`).
pub NON_SEND_FIELDS_IN_SEND_TY,
nursery,
suspicious,
"there is field that does not implement `Send` in a `Send` struct"
}

View File

@ -22,7 +22,7 @@ declare_clippy_lint! {
/// expression).
///
/// ### Why is this bad?
/// Using the dedicated functions of the Option type is clearer and
/// Using the dedicated functions of the `Option` type is clearer and
/// more concise than an `if let` expression.
///
/// ### Known problems

View File

@ -3,16 +3,16 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
use clippy_utils::ptr::get_spans;
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::{is_type_diagnostic_item, match_type, walk_ptrs_hir_ty};
use clippy_utils::ty::walk_ptrs_hir_ty;
use clippy_utils::{expr_path_res, is_lint_allowed, match_any_diagnostic_items, paths};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::def::Res;
use rustc_hir::{
BinOpKind, BodyId, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, HirId, Impl, ImplItem, ImplItemKind, Item,
ItemKind, Lifetime, MutTy, Mutability, Node, PathSegment, QPath, TraitFn, TraitItem, TraitItemKind, Ty, TyKind,
BinOpKind, BodyId, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, Impl, ImplItem, ImplItemKind, Item, ItemKind,
Lifetime, MutTy, Mutability, Node, PathSegment, QPath, TraitFn, TraitItem, TraitItemKind, Ty, TyKind,
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;
use rustc_span::symbol::Symbol;
@ -153,7 +153,7 @@ declare_lint_pass!(Ptr => [PTR_ARG, CMP_NULL, MUT_FROM_REF, INVALID_NULL_PTR_USA
impl<'tcx> LateLintPass<'tcx> for Ptr {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
if let ItemKind::Fn(ref sig, _, body_id) = item.kind {
check_fn(cx, sig.decl, item.hir_id(), Some(body_id));
check_fn(cx, sig.decl, Some(body_id));
}
}
@ -165,7 +165,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
return; // ignore trait impls
}
}
check_fn(cx, sig.decl, item.hir_id(), Some(body_id));
check_fn(cx, sig.decl, Some(body_id));
}
}
@ -176,7 +176,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
} else {
None
};
check_fn(cx, sig.decl, item.hir_id(), body_id);
check_fn(cx, sig.decl, body_id);
}
}
@ -244,13 +244,10 @@ fn check_invalid_ptr_usage<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
}
#[allow(clippy::too_many_lines)]
fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id: Option<BodyId>) {
let fn_def_id = cx.tcx.hir().local_def_id(fn_id);
let sig = cx.tcx.fn_sig(fn_def_id);
let fn_ty = sig.skip_binder();
fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, opt_body_id: Option<BodyId>) {
let body = opt_body_id.map(|id| cx.tcx.hir().body(id));
for (idx, (arg, ty)) in decl.inputs.iter().zip(fn_ty.inputs()).enumerate() {
for (idx, arg) in decl.inputs.iter().enumerate() {
// Honor the allow attribute on parameters. See issue 5644.
if let Some(body) = &body {
if is_lint_allowed(cx, PTR_ARG, body.params[idx].hir_id) {
@ -258,8 +255,20 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id:
}
}
if let ty::Ref(_, ty, Mutability::Not) = ty.kind() {
if is_type_diagnostic_item(cx, ty, sym::Vec) {
let (item_name, path) = if_chain! {
if let TyKind::Rptr(_, MutTy { ty, mutbl: Mutability::Not }) = arg.kind;
if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind;
if let Res::Def(_, did) = path.res;
if let Some(item_name) = cx.tcx.get_diagnostic_name(did);
then {
(item_name, path)
} else {
continue
}
};
match item_name {
sym::Vec => {
if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_owned()")]) {
span_lint_and_then(
cx,
@ -289,7 +298,8 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id:
},
);
}
} else if is_type_diagnostic_item(cx, ty, sym::String) {
},
sym::String => {
if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_string()"), ("as_str", "")]) {
span_lint_and_then(
cx,
@ -311,7 +321,8 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id:
},
);
}
} else if is_type_diagnostic_item(cx, ty, sym::PathBuf) {
},
sym::PathBuf => {
if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_path_buf()"), ("as_path", "")]) {
span_lint_and_then(
cx,
@ -338,11 +349,10 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id:
},
);
}
} else if match_type(cx, ty, &paths::COW) {
},
sym::Cow => {
if_chain! {
if let TyKind::Rptr(_, MutTy { ty, ..} ) = arg.kind;
if let TyKind::Path(QPath::Resolved(None, pp)) = ty.kind;
if let [ref bx] = *pp.segments;
if let [ref bx] = *path.segments;
if let Some(params) = bx.args;
if !params.parenthesized;
if let Some(inner) = params.args.iter().find_map(|arg| match arg {
@ -363,7 +373,8 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id:
);
}
}
}
},
_ => {},
}
}

View File

@ -172,23 +172,17 @@ impl QuestionMark {
}
}
fn expression_returns_unmodified_err(
cx: &LateContext<'_>,
expression: &Expr<'_>,
origin_hir_id: &Expr<'_>,
) -> bool {
match expression.kind {
fn expression_returns_unmodified_err(cx: &LateContext<'_>, expr: &Expr<'_>, cond_expr: &Expr<'_>) -> bool {
match expr.kind {
ExprKind::Block(block, _) => {
if let Some(return_expression) = Self::return_expression(block) {
return Self::expression_returns_unmodified_err(cx, return_expression, origin_hir_id);
return Self::expression_returns_unmodified_err(cx, return_expression, cond_expr);
}
false
},
ExprKind::Ret(Some(expr)) | ExprKind::Call(expr, _) => {
Self::expression_returns_unmodified_err(cx, expr, origin_hir_id)
},
ExprKind::Path(_) => path_to_local(expression) == path_to_local(origin_hir_id),
ExprKind::Ret(Some(ret_expr)) => Self::expression_returns_unmodified_err(cx, ret_expr, cond_expr),
ExprKind::Path(_) => path_to_local(expr) == path_to_local(cond_expr),
_ => false,
}
}

View File

@ -107,51 +107,87 @@ declare_clippy_lint! {
"calling `as_bytes` on a string literal instead of using a byte string literal"
}
declare_lint_pass!(StringAdd => [STRING_ADD, STRING_ADD_ASSIGN]);
declare_clippy_lint! {
/// ### What it does
/// Checks for slice operations on strings
///
/// ### Why is this bad?
/// UTF-8 characters span multiple bytes, and it is easy to inadvertently confuse character
/// counts and string indices. This may lead to panics, and should warrant some test cases
/// containing wide UTF-8 characters. This lint is most useful in code that should avoid
/// panics at all costs.
///
/// ### Known problems
/// Probably lots of false positives. If an index comes from a known valid position (e.g.
/// obtained via `char_indices` over the same string), it is totally OK.
///
/// # Example
/// ```rust,should_panic
/// &"Ölkanne"[1..];
/// ```
pub STRING_SLICE,
restriction,
"slicing a string"
}
declare_lint_pass!(StringAdd => [STRING_ADD, STRING_ADD_ASSIGN, STRING_SLICE]);
impl<'tcx> LateLintPass<'tcx> for StringAdd {
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
if in_external_macro(cx.sess(), e.span) {
return;
}
if let ExprKind::Binary(
Spanned {
node: BinOpKind::Add, ..
},
left,
_,
) = e.kind
{
if is_string(cx, left) {
if !is_lint_allowed(cx, STRING_ADD_ASSIGN, e.hir_id) {
let parent = get_parent_expr(cx, e);
if let Some(p) = parent {
if let ExprKind::Assign(target, _, _) = p.kind {
// avoid duplicate matches
if SpanlessEq::new(cx).eq_expr(target, left) {
return;
match e.kind {
ExprKind::Binary(
Spanned {
node: BinOpKind::Add, ..
},
left,
_,
) => {
if is_string(cx, left) {
if !is_lint_allowed(cx, STRING_ADD_ASSIGN, e.hir_id) {
let parent = get_parent_expr(cx, e);
if let Some(p) = parent {
if let ExprKind::Assign(target, _, _) = p.kind {
// avoid duplicate matches
if SpanlessEq::new(cx).eq_expr(target, left) {
return;
}
}
}
}
span_lint(
cx,
STRING_ADD,
e.span,
"you added something to a string. Consider using `String::push_str()` instead",
);
}
span_lint(
cx,
STRING_ADD,
e.span,
"you added something to a string. Consider using `String::push_str()` instead",
);
}
} else if let ExprKind::Assign(target, src, _) = e.kind {
if is_string(cx, target) && is_add(cx, src, target) {
span_lint(
cx,
STRING_ADD_ASSIGN,
e.span,
"you assigned the result of adding something to this string. Consider using \
`String::push_str()` instead",
);
}
},
ExprKind::Assign(target, src, _) => {
if is_string(cx, target) && is_add(cx, src, target) {
span_lint(
cx,
STRING_ADD_ASSIGN,
e.span,
"you assigned the result of adding something to this string. Consider using \
`String::push_str()` instead",
);
}
},
ExprKind::Index(target, _idx) => {
let e_ty = cx.typeck_results().expr_ty(target).peel_refs();
if matches!(e_ty.kind(), ty::Str) || is_type_diagnostic_item(cx, e_ty, sym::String) {
span_lint(
cx,
STRING_SLICE,
e.span,
"indexing into a string may panic if the index is within a UTF-8 character",
);
}
},
_ => {},
}
}
}

View File

@ -145,8 +145,9 @@ impl UndocumentedUnsafeBlocks {
let file_name = source_map.span_to_filename(between_span);
let source_file = source_map.get_source_file(&file_name)?;
let lex_start = (between_span.lo().0 + 1) as usize;
let src_str = source_file.src.as_ref()?[lex_start..between_span.hi().0 as usize].to_string();
let lex_start = (between_span.lo().0 - source_file.start_pos.0 + 1) as usize;
let lex_end = (between_span.hi().0 - source_file.start_pos.0) as usize;
let src_str = source_file.src.as_ref()?[lex_start..lex_end].to_string();
let mut pos = 0;
let mut comment = false;

View File

@ -45,7 +45,7 @@ declare_clippy_lint! {
/// let x = String::from("\u{20ac}");
/// ```
pub NON_ASCII_LITERAL,
pedantic,
restriction,
"using any literal non-ASCII chars in a string literal instead of using the `\\u` escape"
}

View File

@ -0,0 +1,77 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::sym;
declare_clippy_lint! {
/// ### What it does
/// Detects `().hash(_)`.
///
/// ### Why is this bad?
/// Hashing a unit value doesn't do anything as the implementation of `Hash` for `()` is a no-op.
///
/// ### Example
/// ```rust
/// # use std::hash::Hash;
/// # use std::collections::hash_map::DefaultHasher;
/// # enum Foo { Empty, WithValue(u8) }
/// # use Foo::*;
/// # let mut state = DefaultHasher::new();
/// # let my_enum = Foo::Empty;
/// match my_enum {
/// Empty => ().hash(&mut state),
/// WithValue(x) => x.hash(&mut state),
/// }
/// ```
/// Use instead:
/// ```rust
/// # use std::hash::Hash;
/// # use std::collections::hash_map::DefaultHasher;
/// # enum Foo { Empty, WithValue(u8) }
/// # use Foo::*;
/// # let mut state = DefaultHasher::new();
/// # let my_enum = Foo::Empty;
/// match my_enum {
/// Empty => 0_u8.hash(&mut state),
/// WithValue(x) => x.hash(&mut state),
/// }
/// ```
pub UNIT_HASH,
correctness,
"hashing a unit value, which does nothing"
}
declare_lint_pass!(UnitHash => [UNIT_HASH]);
impl LateLintPass<'tcx> for UnitHash {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
if_chain! {
if let ExprKind::MethodCall(name_ident, _, args, _) = &expr.kind;
if name_ident.ident.name == sym::hash;
if let [recv, state_param] = args;
if cx.typeck_results().expr_ty(recv).is_unit();
then {
span_lint_and_then(
cx,
UNIT_HASH,
expr.span,
"this call to `hash` on the unit type will do nothing",
|diag| {
diag.span_suggestion(
expr.span,
"remove the call to `hash` or consider using",
format!(
"0_u8.hash({})",
snippet(cx, state_param.span, ".."),
),
Applicability::MaybeIncorrect,
);
diag.note("the implementation of `Hash` for `()` is a no-op");
}
);
}
}
}
}

View File

@ -13,7 +13,7 @@ use rustc_span::{sym, Span};
declare_clippy_lint! {
/// ### What it does
/// Checks for functions of type Result that contain `expect()` or `unwrap()`
/// Checks for functions of type `Result` that contain `expect()` or `unwrap()`
///
/// ### Why is this bad?
/// These functions promote recoverable errors to non-recoverable errors which may be undesirable in code bases which wish to avoid panics.

View File

@ -288,10 +288,10 @@ define_Conf! {
///
/// The list of imports to always rename, a fully qualified path followed by the rename.
(enforced_import_renames: Vec<crate::utils::conf::Rename> = Vec::new()),
/// Lint: RESTRICTED_SCRIPTS.
/// Lint: DISALLOWED_SCRIPT_IDENTS.
///
/// The list of unicode scripts allowed to be used in the scope.
(allowed_scripts: Vec<String> = vec!["Latin".to_string()]),
(allowed_scripts: Vec<String> = ["Latin"].iter().map(ToString::to_string).collect()),
/// Lint: NON_SEND_FIELDS_IN_SEND_TY.
///
/// Whether to apply the raw pointer heuristic to determine if a type is `Send`.

View File

@ -512,12 +512,21 @@ fn extract_attr_docs(cx: &LateContext<'_>, item: &Item<'_>) -> Option<String> {
let mut lines = attrs.iter().filter_map(ast::Attribute::doc_str);
let mut docs = String::from(&*lines.next()?.as_str());
let mut in_code_block = false;
let mut is_code_block_rust = false;
for line in lines {
docs.push('\n');
let line = line.as_str();
let line = &*line;
// Rustdoc hides code lines starting with `# ` and this removes them from Clippy's lint list :)
if is_code_block_rust && line.trim_start().starts_with("# ") {
continue;
}
// The line should be represented in the lint list, even if it's just an empty line
docs.push('\n');
if let Some(info) = line.trim_start().strip_prefix("```") {
in_code_block = !in_code_block;
is_code_block_rust = false;
if in_code_block {
let lang = info
.trim()
@ -528,6 +537,8 @@ fn extract_attr_docs(cx: &LateContext<'_>, item: &Item<'_>) -> Option<String> {
.unwrap_or("rust");
docs.push_str("```");
docs.push_str(lang);
is_code_block_rust = lang == "rust";
continue;
}
}

View File

@ -1,117 +0,0 @@
/// Returns the index of the character after the first camel-case component of `s`.
#[must_use]
pub fn until(s: &str) -> usize {
let mut iter = s.char_indices();
if let Some((_, first)) = iter.next() {
if !first.is_uppercase() {
return 0;
}
} else {
return 0;
}
let mut up = true;
let mut last_i = 0;
for (i, c) in iter {
if up {
if c.is_lowercase() {
up = false;
} else {
return last_i;
}
} else if c.is_uppercase() {
up = true;
last_i = i;
} else if !c.is_lowercase() {
return i;
}
}
if up { last_i } else { s.len() }
}
/// Returns index of the last camel-case component of `s`.
#[must_use]
pub fn from(s: &str) -> usize {
let mut iter = s.char_indices().rev();
if let Some((_, first)) = iter.next() {
if !first.is_lowercase() {
return s.len();
}
} else {
return s.len();
}
let mut down = true;
let mut last_i = s.len();
for (i, c) in iter {
if down {
if c.is_uppercase() {
down = false;
last_i = i;
} else if !c.is_lowercase() {
return last_i;
}
} else if c.is_lowercase() {
down = true;
} else if c.is_uppercase() {
last_i = i;
} else {
return last_i;
}
}
last_i
}
#[cfg(test)]
mod test {
use super::{from, until};
#[test]
fn from_full() {
assert_eq!(from("AbcDef"), 0);
assert_eq!(from("Abc"), 0);
assert_eq!(from("ABcd"), 0);
assert_eq!(from("ABcdEf"), 0);
assert_eq!(from("AabABcd"), 0);
}
#[test]
fn from_partial() {
assert_eq!(from("abcDef"), 3);
assert_eq!(from("aDbc"), 1);
assert_eq!(from("aabABcd"), 3);
}
#[test]
fn from_not() {
assert_eq!(from("AbcDef_"), 7);
assert_eq!(from("AbcDD"), 5);
}
#[test]
fn from_caps() {
assert_eq!(from("ABCD"), 4);
}
#[test]
fn until_full() {
assert_eq!(until("AbcDef"), 6);
assert_eq!(until("Abc"), 3);
}
#[test]
fn until_not() {
assert_eq!(until("abcDef"), 0);
assert_eq!(until("aDbc"), 0);
}
#[test]
fn until_partial() {
assert_eq!(until("AbcDef_"), 6);
assert_eq!(until("CallTypeC"), 8);
assert_eq!(until("AbcDD"), 3);
}
#[test]
fn until_caps() {
assert_eq!(until("ABCD"), 0);
}
}

View File

@ -155,6 +155,19 @@ impl Constant {
_ => None,
}
}
/// Returns the integer value or `None` if `self` or `val_type` is not integer type.
pub fn int_value(&self, cx: &LateContext<'_>, val_type: Ty<'_>) -> Option<FullInt> {
if let Constant::Int(const_int) = *self {
match *val_type.kind() {
ty::Int(ity) => Some(FullInt::S(sext(cx.tcx, const_int, ity))),
ty::Uint(_) => Some(FullInt::U(const_int)),
_ => None,
}
} else {
None
}
}
}
/// Parses a `LitKind` to a `Constant`.
@ -202,6 +215,52 @@ pub fn constant_simple<'tcx>(
constant(lcx, typeck_results, e).and_then(|(cst, res)| if res { None } else { Some(cst) })
}
pub fn constant_full_int(
lcx: &LateContext<'tcx>,
typeck_results: &ty::TypeckResults<'tcx>,
e: &Expr<'_>,
) -> Option<FullInt> {
constant_simple(lcx, typeck_results, e)?.int_value(lcx, typeck_results.expr_ty(e))
}
#[derive(Copy, Clone, Debug, Eq)]
pub enum FullInt {
S(i128),
U(u128),
}
impl PartialEq for FullInt {
#[must_use]
fn eq(&self, other: &Self) -> bool {
self.cmp(other) == Ordering::Equal
}
}
impl PartialOrd for FullInt {
#[must_use]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for FullInt {
#[must_use]
fn cmp(&self, other: &Self) -> Ordering {
use FullInt::{S, U};
fn cmp_s_u(s: i128, u: u128) -> Ordering {
u128::try_from(s).map_or(Ordering::Less, |x| x.cmp(&u))
}
match (*self, *other) {
(S(s), S(o)) => s.cmp(&o),
(U(s), U(o)) => s.cmp(&o),
(S(s), U(o)) => cmp_s_u(s, o),
(U(s), S(o)) => cmp_s_u(o, s).reverse(),
}
}
}
/// Creates a `ConstEvalLateContext` from the given `LateContext` and `TypeckResults`.
pub fn constant_context<'a, 'tcx>(
lcx: &'a LateContext<'tcx>,

View File

@ -72,7 +72,7 @@ pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: impl Into<Mult
/// 6 | let other_f64_nan = 0.0f64 / 0.0;
/// | ^^^^^^^^^^^^
/// |
/// = help: Consider using `f64::NAN` if you would like a constant representing NaN
/// = help: consider using `f64::NAN` if you would like a constant representing NaN
/// ```
pub fn span_lint_and_help<'a, T: LintContext>(
cx: &'a T,

View File

@ -1,14 +1,14 @@
//! This module contains functions that retrieves specifiec elements.
//! This module contains functions that retrieve specific elements.
#![deny(clippy::missing_docs_in_private_items)]
use crate::ty::is_type_diagnostic_item;
use crate::{is_expn_of, last_path_segment, match_def_path, paths};
use crate::{is_expn_of, last_path_segment, match_def_path, path_to_local_id, paths};
use if_chain::if_chain;
use rustc_ast::ast::{self, LitKind};
use rustc_hir as hir;
use rustc_hir::{
Arm, Block, BorrowKind, Expr, ExprKind, HirId, LoopSource, MatchSource, Node, Pat, QPath, StmtKind, UnOp,
Arm, Block, BorrowKind, Expr, ExprKind, HirId, LoopSource, MatchSource, Node, Pat, PatKind, QPath, StmtKind, UnOp,
};
use rustc_lint::LateContext;
use rustc_span::{sym, symbol, ExpnKind, Span, Symbol};
@ -513,6 +513,8 @@ pub struct FormatArgsExpn<'tcx> {
pub format_string_parts: &'tcx [Expr<'tcx>],
/// Symbols corresponding to [`Self::format_string_parts`]
pub format_string_symbols: Vec<Symbol>,
/// Match arm patterns, the `arg0`, etc. from the next field `args`
pub arg_names: &'tcx [Pat<'tcx>],
/// Expressions like `ArgumentV1::new(arg0, Debug::fmt)`
pub args: &'tcx [Expr<'tcx>],
/// The final argument passed to `Arguments::new_v1_formatted`, if applicable
@ -557,6 +559,7 @@ impl FormatArgsExpn<'tcx> {
_ => None,
})
.collect();
if let PatKind::Tuple(arg_names, None) = arm.pat.kind;
if let ExprKind::Array(args) = arm.body.kind;
then {
Some(FormatArgsExpn {
@ -564,6 +567,7 @@ impl FormatArgsExpn<'tcx> {
value_args,
format_string_parts,
format_string_symbols,
arg_names,
args,
fmt_expr,
})
@ -587,9 +591,15 @@ impl FormatArgsExpn<'tcx> {
if let Some(position_field) = fields.iter().find(|f| f.ident.name == sym::position);
if let ExprKind::Lit(lit) = &position_field.expr.kind;
if let LitKind::Int(position, _) = lit.node;
if let Ok(i) = usize::try_from(position);
let arg = &self.args[i];
if let ExprKind::Call(_, [arg_name, _]) = arg.kind;
if let Some(j) = self
.arg_names
.iter()
.position(|pat| path_to_local_id(arg_name, pat.hir_id));
then {
let i = usize::try_from(position).unwrap();
Some(FormatArgsArg { value: self.value_args[i], arg: &self.args[i], fmt: Some(fmt) })
Some(FormatArgsArg { value: self.value_args[j], arg, fmt: Some(fmt) })
} else {
None
}
@ -718,9 +728,7 @@ impl PanicExpn<'tcx> {
/// Parses an expanded `panic!` invocation
pub fn parse(expr: &'tcx Expr<'tcx>) -> Option<Self> {
if_chain! {
if let ExprKind::Block(block, _) = expr.kind;
if let Some(init) = block.expr;
if let ExprKind::Call(_, [format_args]) = init.kind;
if let ExprKind::Call(_, [format_args]) = expr.kind;
let expn_data = expr.span.ctxt().outer_expn_data();
if let Some(format_args) = FormatArgsExpn::parse(format_args);
then {
@ -770,13 +778,13 @@ pub fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -
}
return Some(VecInitKind::WithExprCapacity(arg.hir_id));
}
}
},
ExprKind::Path(QPath::Resolved(_, path))
if match_def_path(cx, path.res.opt_def_id()?, &paths::DEFAULT_TRAIT_METHOD)
&& is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Vec) =>
{
return Some(VecInitKind::Default);
}
},
_ => (),
}
}

View File

@ -37,7 +37,6 @@ pub mod sym_helper;
#[allow(clippy::module_name_repetitions)]
pub mod ast_utils;
pub mod attrs;
pub mod camel_case;
pub mod comparisons;
pub mod consts;
pub mod diagnostics;
@ -50,6 +49,7 @@ pub mod paths;
pub mod ptr;
pub mod qualify_min_const_fn;
pub mod source;
pub mod str_utils;
pub mod sugg;
pub mod ty;
pub mod usage;
@ -712,7 +712,7 @@ pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
/// Checks if the top level expression can be moved into a closure as is.
/// Currently checks for:
/// * Break/Continue outside the given loop HIR ids.
/// * Yield/Return statments.
/// * Yield/Return statements.
/// * Inline assembly.
/// * Usages of a field of a local where the type of the local can be partially moved.
///
@ -844,10 +844,13 @@ pub fn capture_local_usage(cx: &LateContext<'tcx>, e: &Expr<'_>) -> CaptureKind
let mut capture_expr_ty = e;
for (parent_id, parent) in cx.tcx.hir().parent_iter(e.hir_id) {
if let [Adjustment {
kind: Adjust::Deref(_) | Adjust::Borrow(AutoBorrow::Ref(..)),
target,
}, ref adjust @ ..] = *cx
if let [
Adjustment {
kind: Adjust::Deref(_) | Adjust::Borrow(AutoBorrow::Ref(..)),
target,
},
ref adjust @ ..,
] = *cx
.typeck_results()
.adjustments()
.get(child_id)
@ -1232,9 +1235,7 @@ pub fn get_enclosing_loop_or_closure(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Opti
for (_, node) in tcx.hir().parent_iter(expr.hir_id) {
match node {
Node::Expr(
e
@
Expr {
e @ Expr {
kind: ExprKind::Loop(..) | ExprKind::Closure(..),
..
},
@ -1692,10 +1693,12 @@ pub fn is_async_fn(kind: FnKind<'_>) -> bool {
pub fn get_async_fn_body(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'tcx Expr<'tcx>> {
if let ExprKind::Call(
_,
&[Expr {
kind: ExprKind::Closure(_, _, body, _, _),
..
}],
&[
Expr {
kind: ExprKind::Closure(_, _, body, _, _),
..
},
],
) = body.value.kind
{
if let ExprKind::Block(
@ -2123,7 +2126,7 @@ pub fn is_in_test_function(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
vis.found
}
/// Checks whether item either has `test` attribute appelied, or
/// Checks whether item either has `test` attribute applied, or
/// is a module with `test` in its name.
///
/// Note: If you use this function, please add a `#[test]` case in `tests/ui_test`.

View File

@ -0,0 +1,230 @@
/// Dealing with sting indices can be hard, this struct ensures that both the
/// character and byte index are provided for correct indexing.
#[derive(Debug, Default, PartialEq, Eq)]
pub struct StrIndex {
pub char_index: usize,
pub byte_index: usize,
}
impl StrIndex {
pub fn new(char_index: usize, byte_index: usize) -> Self {
Self { char_index, byte_index }
}
}
/// Returns the index of the character after the first camel-case component of `s`.
///
/// ```
/// assert_eq!(camel_case_until("AbcDef"), StrIndex::new(6, 6));
/// assert_eq!(camel_case_until("ABCD"), StrIndex::new(0, 0));
/// assert_eq!(camel_case_until("AbcDD"), StrIndex::new(3, 3));
/// assert_eq!(camel_case_until("Abc\u{f6}\u{f6}DD"), StrIndex::new(5, 7));
/// ```
#[must_use]
pub fn camel_case_until(s: &str) -> StrIndex {
let mut iter = s.char_indices().enumerate();
if let Some((_char_index, (_, first))) = iter.next() {
if !first.is_uppercase() {
return StrIndex::new(0, 0);
}
} else {
return StrIndex::new(0, 0);
}
let mut up = true;
let mut last_index = StrIndex::new(0, 0);
for (char_index, (byte_index, c)) in iter {
if up {
if c.is_lowercase() {
up = false;
} else {
return last_index;
}
} else if c.is_uppercase() {
up = true;
last_index.byte_index = byte_index;
last_index.char_index = char_index;
} else if !c.is_lowercase() {
return StrIndex::new(char_index, byte_index);
}
}
if up {
last_index
} else {
StrIndex::new(s.chars().count(), s.len())
}
}
/// Returns index of the last camel-case component of `s`.
///
/// ```
/// assert_eq!(camel_case_start("AbcDef"), StrIndex::new(0, 0));
/// assert_eq!(camel_case_start("abcDef"), StrIndex::new(3, 3));
/// assert_eq!(camel_case_start("ABCD"), StrIndex::new(4, 4));
/// assert_eq!(camel_case_start("abcd"), StrIndex::new(4, 4));
/// assert_eq!(camel_case_start("\u{f6}\u{f6}cd"), StrIndex::new(4, 6));
/// ```
#[must_use]
pub fn camel_case_start(s: &str) -> StrIndex {
let char_count = s.chars().count();
let range = 0..char_count;
let mut iter = range.rev().zip(s.char_indices().rev());
if let Some((char_index, (_, first))) = iter.next() {
if !first.is_lowercase() {
return StrIndex::new(char_index, s.len());
}
} else {
return StrIndex::new(char_count, s.len());
}
let mut down = true;
let mut last_index = StrIndex::new(char_count, s.len());
for (char_index, (byte_index, c)) in iter {
if down {
if c.is_uppercase() {
down = false;
last_index.byte_index = byte_index;
last_index.char_index = char_index;
} else if !c.is_lowercase() {
return last_index;
}
} else if c.is_lowercase() {
down = true;
} else if c.is_uppercase() {
last_index.byte_index = byte_index;
last_index.char_index = char_index;
} else {
return last_index;
}
}
last_index
}
/// Dealing with sting comparison can be complicated, this struct ensures that both the
/// character and byte count are provided for correct indexing.
#[derive(Debug, Default, PartialEq, Eq)]
pub struct StrCount {
pub char_count: usize,
pub byte_count: usize,
}
impl StrCount {
pub fn new(char_count: usize, byte_count: usize) -> Self {
Self { char_count, byte_count }
}
}
/// Returns the number of chars that match from the start
///
/// ```
/// assert_eq!(count_match_start("hello_mouse", "hello_penguin"), StrCount::new(6, 6));
/// assert_eq!(count_match_start("hello_clippy", "bye_bugs"), StrCount::new(0, 0));
/// assert_eq!(count_match_start("hello_world", "hello_world"), StrCount::new(11, 11));
/// assert_eq!(count_match_start("T\u{f6}ffT\u{f6}ff", "T\u{f6}ff"), StrCount::new(4, 5));
/// ```
#[must_use]
pub fn count_match_start(str1: &str, str2: &str) -> StrCount {
// (char_index, char1)
let char_count = str1.chars().count();
let iter1 = (0..=char_count).zip(str1.chars());
// (byte_index, char2)
let iter2 = str2.char_indices();
iter1
.zip(iter2)
.take_while(|((_, c1), (_, c2))| c1 == c2)
.last()
.map_or_else(StrCount::default, |((char_index, _), (byte_index, character))| {
StrCount::new(char_index + 1, byte_index + character.len_utf8())
})
}
/// Returns the number of chars and bytes that match from the end
///
/// ```
/// assert_eq!(count_match_end("hello_cat", "bye_cat"), StrCount::new(4, 4));
/// assert_eq!(count_match_end("if_item_thing", "enum_value"), StrCount::new(0, 0));
/// assert_eq!(count_match_end("Clippy", "Clippy"), StrCount::new(6, 6));
/// assert_eq!(count_match_end("MyT\u{f6}ff", "YourT\u{f6}ff"), StrCount::new(4, 5));
/// ```
#[must_use]
pub fn count_match_end(str1: &str, str2: &str) -> StrCount {
let char_count = str1.chars().count();
if char_count == 0 {
return StrCount::default();
}
// (char_index, char1)
let iter1 = (0..char_count).rev().zip(str1.chars().rev());
// (byte_index, char2)
let byte_count = str2.len();
let iter2 = str2.char_indices().rev();
iter1
.zip(iter2)
.take_while(|((_, c1), (_, c2))| c1 == c2)
.last()
.map_or_else(StrCount::default, |((char_index, _), (byte_index, _))| {
StrCount::new(char_count - char_index, byte_count - byte_index)
})
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn camel_case_start_full() {
assert_eq!(camel_case_start("AbcDef"), StrIndex::new(0, 0));
assert_eq!(camel_case_start("Abc"), StrIndex::new(0, 0));
assert_eq!(camel_case_start("ABcd"), StrIndex::new(0, 0));
assert_eq!(camel_case_start("ABcdEf"), StrIndex::new(0, 0));
assert_eq!(camel_case_start("AabABcd"), StrIndex::new(0, 0));
}
#[test]
fn camel_case_start_partial() {
assert_eq!(camel_case_start("abcDef"), StrIndex::new(3, 3));
assert_eq!(camel_case_start("aDbc"), StrIndex::new(1, 1));
assert_eq!(camel_case_start("aabABcd"), StrIndex::new(3, 3));
assert_eq!(camel_case_start("\u{f6}\u{f6}AabABcd"), StrIndex::new(2, 4));
}
#[test]
fn camel_case_start_not() {
assert_eq!(camel_case_start("AbcDef_"), StrIndex::new(7, 7));
assert_eq!(camel_case_start("AbcDD"), StrIndex::new(5, 5));
assert_eq!(camel_case_start("all_small"), StrIndex::new(9, 9));
assert_eq!(camel_case_start("\u{f6}_all_small"), StrIndex::new(11, 12));
}
#[test]
fn camel_case_start_caps() {
assert_eq!(camel_case_start("ABCD"), StrIndex::new(4, 4));
}
#[test]
fn camel_case_until_full() {
assert_eq!(camel_case_until("AbcDef"), StrIndex::new(6, 6));
assert_eq!(camel_case_until("Abc"), StrIndex::new(3, 3));
assert_eq!(camel_case_until("Abc\u{f6}\u{f6}\u{f6}"), StrIndex::new(6, 9));
}
#[test]
fn camel_case_until_not() {
assert_eq!(camel_case_until("abcDef"), StrIndex::new(0, 0));
assert_eq!(camel_case_until("aDbc"), StrIndex::new(0, 0));
}
#[test]
fn camel_case_until_partial() {
assert_eq!(camel_case_until("AbcDef_"), StrIndex::new(6, 6));
assert_eq!(camel_case_until("CallTypeC"), StrIndex::new(8, 8));
assert_eq!(camel_case_until("AbcDD"), StrIndex::new(3, 3));
assert_eq!(camel_case_until("Abc\u{f6}\u{f6}DD"), StrIndex::new(5, 7));
}
#[test]
fn until_caps() {
assert_eq!(camel_case_until("ABCD"), StrIndex::new(0, 0));
}
}

View File

@ -16,6 +16,7 @@ because that's clearly a non-descriptive name.
- [Edition 2018 tests](#edition-2018-tests)
- [Testing manually](#testing-manually)
- [Lint declaration](#lint-declaration)
- [Lint registration](#lint-registration)
- [Lint passes](#lint-passes)
- [Emitting a lint](#emitting-a-lint)
- [Adding the lint logic](#adding-the-lint-logic)
@ -43,9 +44,9 @@ take a look at our [lint naming guidelines][lint_naming]. To get started on this
lint you can run `cargo dev new_lint --name=foo_functions --pass=early
--category=pedantic` (category will default to nursery if not provided). This
command will create two files: `tests/ui/foo_functions.rs` and
`clippy_lints/src/foo_functions.rs`, as well as run `cargo dev update_lints` to
register the new lint. For cargo lints, two project hierarchies (fail/pass) will
be created by default under `tests/ui-cargo`.
`clippy_lints/src/foo_functions.rs`, as well as
[registering the lint](#lint-registration). For cargo lints, two project
hierarchies (fail/pass) will be created by default under `tests/ui-cargo`.
Next, we'll open up these files and add our lint!
@ -220,32 +221,34 @@ declare_lint_pass!(FooFunctions => [FOO_FUNCTIONS]);
impl EarlyLintPass for FooFunctions {}
```
Normally after declaring the lint, we have to run `cargo dev update_lints`,
which updates some files, so Clippy knows about the new lint. Since we used
`cargo dev new_lint ...` to generate the lint declaration, this was done
automatically. While `update_lints` automates most of the things, it doesn't
automate everything. We will have to register our lint pass manually in the
`register_plugins` function in `clippy_lints/src/lib.rs`:
[declare_clippy_lint]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L60
[example_lint_page]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure
[lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints
[category_level_mapping]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L110
## Lint registration
When using `cargo dev new_lint`, the lint is automatically registered and
nothing more has to be done.
When declaring a new lint by hand and `cargo dev update_lints` is used, the lint
pass may have to be registered manually in the `register_plugins` function in
`clippy_lints/src/lib.rs`:
```rust
store.register_early_pass(|| box foo_functions::FooFunctions);
store.register_early_pass(|| Box::new(foo_functions::FooFunctions));
```
As one may expect, there is a corresponding `register_late_pass` method
available as well. Without a call to one of `register_early_pass` or
`register_late_pass`, the lint pass in question will not be run.
One reason that `cargo dev` does not automate this step is that multiple lints
can use the same lint pass, so registering the lint pass may already be done
when adding a new lint. Another reason that this step is not automated is that
the order that the passes are registered determines the order the passes
actually run, which in turn affects the order that any emitted lints are output
in.
[declare_clippy_lint]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L60
[example_lint_page]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure
[lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints
[category_level_mapping]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L110
One reason that `cargo dev update_lints` does not automate this step is that
multiple lints can use the same lint pass, so registering the lint pass may
already be done when adding a new lint. Another reason that this step is not
automated is that the order that the passes are registered determines the order
the passes actually run, which in turn affects the order that any emitted lints
are output in.
## Lint passes
@ -564,7 +567,8 @@ in the following steps:
/// <The configuration field doc comment>
(configuration_ident: Type = DefaultValue),
```
The doc comment will be automatically added to the lint documentation.
The doc comment is automatically added to the documentation of the listed lints. The default
value will be formatted using the `Debug` implementation of the type.
2. Adding the configuration value to the lint impl struct:
1. This first requires the definition of a lint impl struct. Lint impl structs are usually
generated with the `declare_lint_pass!` macro. This struct needs to be defined manually

View File

@ -1,3 +1,3 @@
[toolchain]
channel = "nightly-2021-10-21"
channel = "nightly-2021-11-04"
components = ["llvm-tools-preview", "rustc-dev", "rust-src"]

View File

@ -104,7 +104,10 @@ fn extern_flags() -> String {
}
fn default_config() -> compiletest::Config {
let mut config = compiletest::Config::default();
let mut config = compiletest::Config {
edition: Some("2021".into()),
..compiletest::Config::default()
};
if let Ok(filters) = env::var("TESTNAME") {
config.filters = filters.split(',').map(std::string::ToString::to_string).collect();

View File

@ -1,7 +1,10 @@
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![warn(rust_2018_idioms, unused_lifetimes)]
#![allow(clippy::assertions_on_constants)]
#![feature(path_file_prefix)]
use std::cmp::Ordering;
use std::ffi::OsStr;
use std::fs::{self, DirEntry};
use std::path::Path;
@ -21,29 +24,39 @@ fn test_missing_tests() {
}
}
/*
Test for missing files.
Since rs files are alphabetically before stderr/stdout, we can sort by the full name
and iter in that order. If we've seen the file stem for the first time and it's not
a rust file, it means the rust file has to be missing.
*/
// Test for missing files.
fn explore_directory(dir: &Path) -> Vec<String> {
let mut missing_files: Vec<String> = Vec::new();
let mut current_file = String::new();
let mut files: Vec<DirEntry> = fs::read_dir(dir).unwrap().filter_map(Result::ok).collect();
files.sort_by_key(std::fs::DirEntry::path);
files.sort_by(|x, y| {
match x.path().file_prefix().cmp(&y.path().file_prefix()) {
Ordering::Equal => (),
ord => return ord,
}
// Sort rs files before the others if they share the same prefix. So when we see
// the file prefix for the first time and it's not a rust file, it means the rust
// file has to be missing.
match (
x.path().extension().and_then(OsStr::to_str),
y.path().extension().and_then(OsStr::to_str),
) {
(Some("rs"), _) => Ordering::Less,
(_, Some("rs")) => Ordering::Greater,
_ => Ordering::Equal,
}
});
for entry in &files {
let path = entry.path();
if path.is_dir() {
missing_files.extend(explore_directory(&path));
} else {
let file_stem = path.file_stem().unwrap().to_str().unwrap().to_string();
let file_prefix = path.file_prefix().unwrap().to_str().unwrap().to_string();
if let Some(ext) = path.extension() {
match ext.to_str().unwrap() {
"rs" => current_file = file_stem.clone(),
"rs" => current_file = file_prefix.clone(),
"stderr" | "stdout" => {
if file_stem != current_file {
if file_prefix != current_file {
missing_files.push(path.to_str().unwrap().to_string());
}
},

View File

@ -1,5 +1,3 @@
// edition:2018
#![warn(clippy::too_many_lines)]
// This function should be considered one line.

View File

@ -1,5 +1,5 @@
error: this function has too many lines (2/1)
--> $DIR/test.rs:20:1
--> $DIR/test.rs:18:1
|
LL | / fn too_many_lines() {
LL | | println!("This is bad.");
@ -10,7 +10,7 @@ LL | | }
= note: `-D clippy::too-many-lines` implied by `-D warnings`
error: this function has too many lines (4/1)
--> $DIR/test.rs:26:1
--> $DIR/test.rs:24:1
|
LL | / async fn async_too_many_lines() {
LL | | println!("This is bad.");
@ -19,7 +19,7 @@ LL | | }
| |_^
error: this function has too many lines (4/1)
--> $DIR/test.rs:32:1
--> $DIR/test.rs:30:1
|
LL | / fn closure_too_many_lines() {
LL | | let _ = {
@ -30,7 +30,7 @@ LL | | }
| |_^
error: this function has too many lines (2/1)
--> $DIR/test.rs:54:1
--> $DIR/test.rs:52:1
|
LL | / fn comment_before_code() {
LL | | let _ = "test";

View File

@ -1,3 +1,4 @@
//FIXME: suggestions are wrongly expanded, this should be fixed along with #7843
#![allow(non_fmt_panics)]
macro_rules! assert_const {
@ -6,7 +7,6 @@ macro_rules! assert_const {
debug_assert!($len < 0);
};
}
fn main() {
assert!(true);
assert!(false);
@ -14,7 +14,7 @@ fn main() {
assert!(false, "false message");
let msg = "panic message";
assert!(false, msg.to_uppercase());
assert!(false, "{}", msg.to_uppercase());
const B: bool = true;
assert!(B);

View File

@ -26,22 +26,13 @@ LL | assert!(true, "true message");
= help: remove it
= note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
error: `assert!(false, "false message")` should probably be replaced
error: `assert!(false, $crate::const_format_args!($($t)+))` should probably be replaced
--> $DIR/assertions_on_constants.rs:14:5
|
LL | assert!(false, "false message");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: use `panic!("false message")` or `unreachable!("false message")`
= note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
error: `assert!(false, msg.to_uppercase())` should probably be replaced
--> $DIR/assertions_on_constants.rs:17:5
|
LL | assert!(false, msg.to_uppercase());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: use `panic!(msg.to_uppercase())` or `unreachable!(msg.to_uppercase())`
= help: use `panic!($crate::const_format_args!($($t)+))` or `unreachable!($crate::const_format_args!($($t)+))`
= note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
error: `assert!(true)` will be optimized out by the compiler
@ -62,13 +53,13 @@ LL | assert!(C);
= help: use `panic!()` or `unreachable!()`
= note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
error: `assert!(false, "C message")` should probably be replaced
error: `assert!(false, $crate::const_format_args!($($t)+))` should probably be replaced
--> $DIR/assertions_on_constants.rs:24:5
|
LL | assert!(C, "C message");
| ^^^^^^^^^^^^^^^^^^^^^^^
|
= help: use `panic!("C message")` or `unreachable!("C message")`
= help: use `panic!($crate::const_format_args!($($t)+))` or `unreachable!($crate::const_format_args!($($t)+))`
= note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
error: `debug_assert!(true)` will be optimized out by the compiler
@ -80,5 +71,5 @@ LL | debug_assert!(true);
= help: remove it
= note: this error originates in the macro `$crate::assert` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 9 previous errors
error: aborting due to 8 previous errors

View File

@ -1,5 +1,4 @@
// run-rustfix
// edition:2018
#![feature(async_closure)]
#![warn(clippy::async_yields_async)]

View File

@ -1,5 +1,4 @@
// run-rustfix
// edition:2018
#![feature(async_closure)]
#![warn(clippy::async_yields_async)]

View File

@ -1,5 +1,5 @@
error: an async construct yields a type which is itself awaitable
--> $DIR/async_yields_async.rs:40:9
--> $DIR/async_yields_async.rs:39:9
|
LL | let _h = async {
| ____________________-
@ -20,7 +20,7 @@ LL + }.await
|
error: an async construct yields a type which is itself awaitable
--> $DIR/async_yields_async.rs:45:9
--> $DIR/async_yields_async.rs:44:9
|
LL | let _i = async {
| ____________________-
@ -33,7 +33,7 @@ LL | | };
| |_____- outer async construct
error: an async construct yields a type which is itself awaitable
--> $DIR/async_yields_async.rs:51:9
--> $DIR/async_yields_async.rs:50:9
|
LL | let _j = async || {
| _______________________-
@ -53,7 +53,7 @@ LL + }.await
|
error: an async construct yields a type which is itself awaitable
--> $DIR/async_yields_async.rs:56:9
--> $DIR/async_yields_async.rs:55:9
|
LL | let _k = async || {
| _______________________-
@ -66,7 +66,7 @@ LL | | };
| |_____- outer async construct
error: an async construct yields a type which is itself awaitable
--> $DIR/async_yields_async.rs:58:23
--> $DIR/async_yields_async.rs:57:23
|
LL | let _l = async || CustomFutureType;
| ^^^^^^^^^^^^^^^^
@ -76,7 +76,7 @@ LL | let _l = async || CustomFutureType;
| help: consider awaiting this value: `CustomFutureType.await`
error: an async construct yields a type which is itself awaitable
--> $DIR/async_yields_async.rs:64:9
--> $DIR/async_yields_async.rs:63:9
|
LL | let _m = async || {
| _______________________-

View File

@ -1,4 +1,3 @@
// edition:2018
#![warn(clippy::await_holding_lock)]
use std::sync::Mutex;

View File

@ -1,12 +1,12 @@
error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await
--> $DIR/await_holding_lock.rs:7:9
--> $DIR/await_holding_lock.rs:6:9
|
LL | let guard = x.lock().unwrap();
| ^^^^^
|
= note: `-D clippy::await-holding-lock` implied by `-D warnings`
note: these are all the await points this lock is held through
--> $DIR/await_holding_lock.rs:7:5
--> $DIR/await_holding_lock.rs:6:5
|
LL | / let guard = x.lock().unwrap();
LL | | baz().await
@ -14,13 +14,13 @@ LL | | }
| |_^
error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await
--> $DIR/await_holding_lock.rs:28:9
--> $DIR/await_holding_lock.rs:27:9
|
LL | let guard = x.lock().unwrap();
| ^^^^^
|
note: these are all the await points this lock is held through
--> $DIR/await_holding_lock.rs:28:5
--> $DIR/await_holding_lock.rs:27:5
|
LL | / let guard = x.lock().unwrap();
LL | |
@ -32,13 +32,13 @@ LL | | }
| |_^
error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await
--> $DIR/await_holding_lock.rs:41:13
--> $DIR/await_holding_lock.rs:40:13
|
LL | let guard = x.lock().unwrap();
| ^^^^^
|
note: these are all the await points this lock is held through
--> $DIR/await_holding_lock.rs:41:9
--> $DIR/await_holding_lock.rs:40:9
|
LL | / let guard = x.lock().unwrap();
LL | | baz().await
@ -46,13 +46,13 @@ LL | | };
| |_____^
error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await
--> $DIR/await_holding_lock.rs:53:13
--> $DIR/await_holding_lock.rs:52:13
|
LL | let guard = x.lock().unwrap();
| ^^^^^
|
note: these are all the await points this lock is held through
--> $DIR/await_holding_lock.rs:53:9
--> $DIR/await_holding_lock.rs:52:9
|
LL | / let guard = x.lock().unwrap();
LL | | baz().await

View File

@ -1,4 +1,3 @@
// edition:2018
#![warn(clippy::await_holding_refcell_ref)]
use std::cell::RefCell;

View File

@ -1,12 +1,12 @@
error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await
--> $DIR/await_holding_refcell_ref.rs:7:9
--> $DIR/await_holding_refcell_ref.rs:6:9
|
LL | let b = x.borrow();
| ^
|
= note: `-D clippy::await-holding-refcell-ref` implied by `-D warnings`
note: these are all the await points this ref is held through
--> $DIR/await_holding_refcell_ref.rs:7:5
--> $DIR/await_holding_refcell_ref.rs:6:5
|
LL | / let b = x.borrow();
LL | | baz().await
@ -14,13 +14,13 @@ LL | | }
| |_^
error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await
--> $DIR/await_holding_refcell_ref.rs:12:9
--> $DIR/await_holding_refcell_ref.rs:11:9
|
LL | let b = x.borrow_mut();
| ^
|
note: these are all the await points this ref is held through
--> $DIR/await_holding_refcell_ref.rs:12:5
--> $DIR/await_holding_refcell_ref.rs:11:5
|
LL | / let b = x.borrow_mut();
LL | | baz().await
@ -28,13 +28,13 @@ LL | | }
| |_^
error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await
--> $DIR/await_holding_refcell_ref.rs:33:9
--> $DIR/await_holding_refcell_ref.rs:32:9
|
LL | let b = x.borrow_mut();
| ^
|
note: these are all the await points this ref is held through
--> $DIR/await_holding_refcell_ref.rs:33:5
--> $DIR/await_holding_refcell_ref.rs:32:5
|
LL | / let b = x.borrow_mut();
LL | |
@ -46,13 +46,13 @@ LL | | }
| |_^
error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await
--> $DIR/await_holding_refcell_ref.rs:45:9
--> $DIR/await_holding_refcell_ref.rs:44:9
|
LL | let b = x.borrow_mut();
| ^
|
note: these are all the await points this ref is held through
--> $DIR/await_holding_refcell_ref.rs:45:5
--> $DIR/await_holding_refcell_ref.rs:44:5
|
LL | / let b = x.borrow_mut();
LL | |
@ -64,13 +64,13 @@ LL | | }
| |_^
error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await
--> $DIR/await_holding_refcell_ref.rs:60:13
--> $DIR/await_holding_refcell_ref.rs:59:13
|
LL | let b = x.borrow_mut();
| ^
|
note: these are all the await points this ref is held through
--> $DIR/await_holding_refcell_ref.rs:60:9
--> $DIR/await_holding_refcell_ref.rs:59:9
|
LL | / let b = x.borrow_mut();
LL | | baz().await
@ -78,13 +78,13 @@ LL | | };
| |_____^
error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await
--> $DIR/await_holding_refcell_ref.rs:72:13
--> $DIR/await_holding_refcell_ref.rs:71:13
|
LL | let b = x.borrow_mut();
| ^
|
note: these are all the await points this ref is held through
--> $DIR/await_holding_refcell_ref.rs:72:9
--> $DIR/await_holding_refcell_ref.rs:71:9
|
LL | / let b = x.borrow_mut();
LL | | baz().await

View File

@ -92,4 +92,27 @@ fn main() {
(1i64).checked_rem_euclid(-1i64).unwrap() as u64;
(1i64).checked_rem_euclid(-1i64).unwrap() as u128;
(1isize).checked_rem_euclid(-1isize).unwrap() as usize;
// no lint for `cast_possible_truncation`
// with `signum` method call (see issue #5395)
let x: i64 = 5;
let _ = x.signum() as i32;
let s = x.signum();
let _ = s as i32;
// Test for signed min
(-99999999999i64).min(1) as i8; // should be linted because signed
// Test for various operations that remove enough bits for the result to fit
(999999u64 & 1) as u8;
(999999u64 % 15) as u8;
(999999u64 / 0x1_0000_0000_0000) as u16;
({ 999999u64 >> 56 }) as u8;
({
let x = 999999u64;
x.min(1)
}) as u8;
999999u64.clamp(0, 255) as u8;
999999u64.clamp(0, 256) as u8; // should still be linted
}

View File

@ -138,5 +138,17 @@ error: casting `isize` to `usize` may lose the sign of the value
LL | -1isize as usize;
| ^^^^^^^^^^^^^^^^
error: aborting due to 22 previous errors
error: casting `i64` to `i8` may truncate the value
--> $DIR/cast.rs:105:5
|
LL | (-99999999999i64).min(1) as i8; // should be linted because signed
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: casting `u64` to `u8` may truncate the value
--> $DIR/cast.rs:117:5
|
LL | 999999u64.clamp(0, 256) as u8; // should still be linted
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 24 previous errors

View File

@ -0,0 +1,3 @@
fn zero() {
unsafe { 0 };
}

View File

@ -7,7 +7,6 @@
// in type inference.
#![feature(trivial_bounds)]
#![allow(unused)]
trait A {}
impl A for i32 {}
@ -22,9 +21,9 @@ where
fn unsized_local()
where
for<'a> Dst<A + 'a>: Sized,
for<'a> Dst<dyn A + 'a>: Sized,
{
let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>);
let x: Dst<dyn A> = *(Box::new(Dst { x: 1 }) as Box<Dst<dyn A>>);
}
fn return_str() -> str

View File

@ -1,30 +1,34 @@
error: trait objects without an explicit `dyn` are deprecated
--> $DIR/ice-3969.rs:25:17
error: trait bound str: std::marker::Sized does not depend on any type or lifetime parameters
--> $DIR/ice-3969.rs:20:10
|
LL | for<'a> Dst<A + 'a>: Sized,
| ^^^^^^ help: use `dyn`: `dyn A + 'a`
LL | str: Sized;
| ^^^^^
|
= note: `-D bare-trait-objects` implied by `-D warnings`
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
= note: `-D trivial-bounds` implied by `-D warnings`
error: trait objects without an explicit `dyn` are deprecated
--> $DIR/ice-3969.rs:27:16
error: trait bound for<'a> Dst<(dyn A + 'a)>: std::marker::Sized does not depend on any type or lifetime parameters
--> $DIR/ice-3969.rs:24:30
|
LL | let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>);
| ^ help: use `dyn`: `dyn A`
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
LL | for<'a> Dst<dyn A + 'a>: Sized,
| ^^^^^
error: trait objects without an explicit `dyn` are deprecated
--> $DIR/ice-3969.rs:27:57
error: trait bound str: std::marker::Sized does not depend on any type or lifetime parameters
--> $DIR/ice-3969.rs:31:10
|
LL | let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>);
| ^ help: use `dyn`: `dyn A`
LL | str: Sized,
| ^^^^^
error: trait bound std::string::String: std::ops::Neg does not depend on any type or lifetime parameters
--> $DIR/ice-3969.rs:38:13
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
LL | String: ::std::ops::Neg<Output = String>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 3 previous errors
error: trait bound i32: std::iter::Iterator does not depend on any type or lifetime parameters
--> $DIR/ice-3969.rs:45:10
|
LL | i32: Iterator,
| ^^^^^^^^
error: aborting due to 5 previous errors

View File

@ -1,5 +1,3 @@
// edition:2018
// Regression test for https://github.com/rust-lang/rust-clippy/issues/5207
pub async fn bar<'a, T: 'a>(_: T) {}

View File

@ -1,6 +1,5 @@
// originally from glacier fixed/77919.rs
// encountered errors resolving bounds after type-checking
trait TypeVal<T> {
const VAL: T;
}

View File

@ -1,16 +1,20 @@
error[E0412]: cannot find type `PhantomData` in this scope
--> $DIR/ice-6252.rs:9:9
--> $DIR/ice-6252.rs:8:9
|
LL | _n: PhantomData,
| ^^^^^^^^^^^ not found in this scope
|
help: consider importing this struct
help: consider importing one of these items
|
LL | use core::marker::PhantomData;
|
LL | use serde::__private::PhantomData;
|
LL | use std::marker::PhantomData;
|
error[E0412]: cannot find type `VAL` in this scope
--> $DIR/ice-6252.rs:11:63
--> $DIR/ice-6252.rs:10:63
|
LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
| - ^^^ not found in this scope
@ -18,7 +22,7 @@ LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
| help: you might be missing a type parameter: `, VAL`
error[E0046]: not all trait items implemented, missing: `VAL`
--> $DIR/ice-6252.rs:11:1
--> $DIR/ice-6252.rs:10:1
|
LL | const VAL: T;
| ------------- `VAL` from trait

View File

@ -1,4 +1,3 @@
// edition:2018
#![allow(clippy::never_loop)]
async fn f() {

View File

@ -0,0 +1,7 @@
#![warn(clippy::undocumented_unsafe_blocks)]
#![allow(clippy::no_effect)]
#[path = "auxiliary/ice-7868-aux.rs"]
mod zero;
fn main() {}

View File

@ -0,0 +1,15 @@
error: unsafe block missing a safety comment
--> $DIR/auxiliary/ice-7868-aux.rs:2:5
|
LL | unsafe { 0 };
| ^^^^^^^^^^^^
|
= note: `-D clippy::undocumented-unsafe-blocks` implied by `-D warnings`
help: consider adding a safety comment
|
LL ~ // Safety: ...
LL ~ unsafe { 0 };
|
error: aborting due to previous error

View File

@ -0,0 +1,7 @@
enum Tila {
TyöAlkoi,
TyöKeskeytyi,
TyöValmis,
}
fn main() {}

View File

@ -0,0 +1,15 @@
error: all variants have the same prefix: `Työ`
--> $DIR/ice-7869.rs:1:1
|
LL | / enum Tila {
LL | | TyöAlkoi,
LL | | TyöKeskeytyi,
LL | | TyöValmis,
LL | | }
| |_^
|
= note: `-D clippy::enum-variant-names` implied by `-D warnings`
= help: remove the prefixes and use full paths to the variants instead of glob imports
error: aborting due to previous error

View File

@ -1,5 +1,3 @@
// edition:2018
use serde::Deserialize;
/// Tests that we do not lint for unused underscores in a `MacroAttribute`

View File

@ -1,9 +1,9 @@
// compile-flags: --edition=2018
#![feature(custom_inner_attributes)]
#![rustfmt::skip]
#![warn(clippy::debug_assert_with_mut_call)]
#![allow(clippy::redundant_closure_call)]
struct S;
impl S {

View File

@ -1,19 +1,18 @@
#[warn(clippy::unstable_as_slice)]
#[warn(clippy::unstable_as_mut_slice)]
#[warn(clippy::misaligned_transmute)]
#[warn(clippy::unused_collect)]
#[warn(clippy::invalid_ref)]
#[warn(clippy::into_iter_on_array)]
#[warn(clippy::unused_label)]
#[warn(clippy::regex_macro)]
#[warn(clippy::drop_bounds)]
#[warn(clippy::temporary_cstring_as_ptr)]
#[warn(clippy::panic_params)]
#[warn(clippy::unknown_clippy_lints)]
#[warn(clippy::find_map)]
#[warn(clippy::filter_map)]
#[warn(clippy::pub_enum_variant_names)]
#[warn(clippy::wrong_pub_self_convention)]
#[warn(clippy::invalid_atomic_ordering)]
#![warn(clippy::should_assert_eq)]
#![warn(clippy::extend_from_slice)]
#![warn(clippy::range_step_by_zero)]
#![warn(clippy::unstable_as_slice)]
#![warn(clippy::unstable_as_mut_slice)]
#![warn(clippy::misaligned_transmute)]
#![warn(clippy::assign_ops)]
#![warn(clippy::if_let_redundant_pattern_matching)]
#![warn(clippy::unsafe_vector_initialization)]
#![warn(clippy::unused_collect)]
#![warn(clippy::replace_consts)]
#![warn(clippy::regex_macro)]
#![warn(clippy::find_map)]
#![warn(clippy::filter_map)]
#![warn(clippy::pub_enum_variant_names)]
#![warn(clippy::wrong_pub_self_convention)]
fn main() {}

View File

@ -1,106 +1,100 @@
error: lint `clippy::unstable_as_slice` has been removed: `Vec::as_slice` has been stabilized in 1.7
--> $DIR/deprecated.rs:1:8
error: lint `clippy::should_assert_eq` has been removed: `assert!()` will be more flexible with RFC 2011
--> $DIR/deprecated.rs:1:9
|
LL | #[warn(clippy::unstable_as_slice)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
LL | #![warn(clippy::should_assert_eq)]
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `-D renamed-and-removed-lints` implied by `-D warnings`
error: lint `clippy::unstable_as_mut_slice` has been removed: `Vec::as_mut_slice` has been stabilized in 1.7
--> $DIR/deprecated.rs:2:8
error: lint `clippy::extend_from_slice` has been removed: `.extend_from_slice(_)` is a faster way to extend a Vec by a slice
--> $DIR/deprecated.rs:2:9
|
LL | #[warn(clippy::unstable_as_mut_slice)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | #![warn(clippy::extend_from_slice)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: lint `clippy::range_step_by_zero` has been removed: `iterator.step_by(0)` panics nowadays
--> $DIR/deprecated.rs:3:9
|
LL | #![warn(clippy::range_step_by_zero)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: lint `clippy::unstable_as_slice` has been removed: `Vec::as_slice` has been stabilized in 1.7
--> $DIR/deprecated.rs:4:9
|
LL | #![warn(clippy::unstable_as_slice)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: lint `clippy::unstable_as_mut_slice` has been removed: `Vec::as_mut_slice` has been stabilized in 1.7
--> $DIR/deprecated.rs:5:9
|
LL | #![warn(clippy::unstable_as_mut_slice)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: lint `clippy::misaligned_transmute` has been removed: this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr
--> $DIR/deprecated.rs:3:8
--> $DIR/deprecated.rs:6:9
|
LL | #[warn(clippy::misaligned_transmute)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | #![warn(clippy::misaligned_transmute)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: lint `clippy::assign_ops` has been removed: using compound assignment operators (e.g., `+=`) is harmless
--> $DIR/deprecated.rs:7:9
|
LL | #![warn(clippy::assign_ops)]
| ^^^^^^^^^^^^^^^^^^
error: lint `clippy::if_let_redundant_pattern_matching` has been removed: this lint has been changed to redundant_pattern_matching
--> $DIR/deprecated.rs:8:9
|
LL | #![warn(clippy::if_let_redundant_pattern_matching)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: lint `clippy::unsafe_vector_initialization` has been removed: the replacement suggested by this lint had substantially different behavior
--> $DIR/deprecated.rs:9:9
|
LL | #![warn(clippy::unsafe_vector_initialization)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: lint `clippy::unused_collect` has been removed: `collect` has been marked as #[must_use] in rustc and that covers all cases of this lint
--> $DIR/deprecated.rs:4:8
--> $DIR/deprecated.rs:10:9
|
LL | #[warn(clippy::unused_collect)]
| ^^^^^^^^^^^^^^^^^^^^^^
LL | #![warn(clippy::unused_collect)]
| ^^^^^^^^^^^^^^^^^^^^^^
error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
--> $DIR/deprecated.rs:5:8
error: lint `clippy::replace_consts` has been removed: associated-constants `MIN`/`MAX` of integers are preferred to `{min,max}_value()` and module constants
--> $DIR/deprecated.rs:11:9
|
LL | #[warn(clippy::invalid_ref)]
| ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
--> $DIR/deprecated.rs:6:8
|
LL | #[warn(clippy::into_iter_on_array)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
error: lint `clippy::unused_label` has been renamed to `unused_labels`
--> $DIR/deprecated.rs:7:8
|
LL | #[warn(clippy::unused_label)]
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
LL | #![warn(clippy::replace_consts)]
| ^^^^^^^^^^^^^^^^^^^^^^
error: lint `clippy::regex_macro` has been removed: the regex! macro has been removed from the regex crate in 2018
--> $DIR/deprecated.rs:8:8
--> $DIR/deprecated.rs:12:9
|
LL | #[warn(clippy::regex_macro)]
| ^^^^^^^^^^^^^^^^^^^
error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
--> $DIR/deprecated.rs:9:8
|
LL | #[warn(clippy::drop_bounds)]
| ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
--> $DIR/deprecated.rs:10:8
|
LL | #[warn(clippy::temporary_cstring_as_ptr)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
--> $DIR/deprecated.rs:11:8
|
LL | #[warn(clippy::panic_params)]
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
--> $DIR/deprecated.rs:12:8
|
LL | #[warn(clippy::unknown_clippy_lints)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
LL | #![warn(clippy::regex_macro)]
| ^^^^^^^^^^^^^^^^^^^
error: lint `clippy::find_map` has been removed: this lint has been replaced by `manual_find_map`, a more specific lint
--> $DIR/deprecated.rs:13:8
--> $DIR/deprecated.rs:13:9
|
LL | #[warn(clippy::find_map)]
| ^^^^^^^^^^^^^^^^
LL | #![warn(clippy::find_map)]
| ^^^^^^^^^^^^^^^^
error: lint `clippy::filter_map` has been removed: this lint has been replaced by `manual_filter_map`, a more specific lint
--> $DIR/deprecated.rs:14:8
--> $DIR/deprecated.rs:14:9
|
LL | #[warn(clippy::filter_map)]
| ^^^^^^^^^^^^^^^^^^
LL | #![warn(clippy::filter_map)]
| ^^^^^^^^^^^^^^^^^^
error: lint `clippy::pub_enum_variant_names` has been removed: set the `avoid-breaking-exported-api` config option to `false` to enable the `enum_variant_names` lint for public items
--> $DIR/deprecated.rs:15:8
--> $DIR/deprecated.rs:15:9
|
LL | #[warn(clippy::pub_enum_variant_names)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | #![warn(clippy::pub_enum_variant_names)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: lint `clippy::wrong_pub_self_convention` has been removed: set the `avoid-breaking-exported-api` config option to `false` to enable the `wrong_self_convention` lint for public items
--> $DIR/deprecated.rs:16:8
--> $DIR/deprecated.rs:16:9
|
LL | #[warn(clippy::wrong_pub_self_convention)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | #![warn(clippy::wrong_pub_self_convention)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
--> $DIR/deprecated.rs:17:8
|
LL | #[warn(clippy::invalid_atomic_ordering)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
error: aborting due to 17 previous errors
error: aborting due to 16 previous errors

View File

@ -1,6 +1,5 @@
#![warn(clippy::diverging_sub_expression)]
#![allow(clippy::match_same_arms, clippy::logic_bug)]
#[allow(clippy::empty_loop)]
fn diverge() -> ! {
loop {}

View File

@ -1,5 +1,5 @@
error: sub-expression diverges
--> $DIR/diverging_sub_expression.rs:20:10
--> $DIR/diverging_sub_expression.rs:19:10
|
LL | b || diverge();
| ^^^^^^^^^
@ -7,34 +7,42 @@ LL | b || diverge();
= note: `-D clippy::diverging-sub-expression` implied by `-D warnings`
error: sub-expression diverges
--> $DIR/diverging_sub_expression.rs:21:10
--> $DIR/diverging_sub_expression.rs:20:10
|
LL | b || A.foo();
| ^^^^^^^
error: sub-expression diverges
--> $DIR/diverging_sub_expression.rs:30:26
--> $DIR/diverging_sub_expression.rs:29:26
|
LL | 6 => true || return,
| ^^^^^^
error: sub-expression diverges
--> $DIR/diverging_sub_expression.rs:31:26
--> $DIR/diverging_sub_expression.rs:30:26
|
LL | 7 => true || continue,
| ^^^^^^^^
error: sub-expression diverges
--> $DIR/diverging_sub_expression.rs:34:26
--> $DIR/diverging_sub_expression.rs:33:26
|
LL | 3 => true || diverge(),
| ^^^^^^^^^
error: sub-expression diverges
--> $DIR/diverging_sub_expression.rs:39:26
--> $DIR/diverging_sub_expression.rs:36:30
|
LL | _ => true || panic!("boo"),
| ^^^^^^^^^^^^^
|
= note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
error: sub-expression diverges
--> $DIR/diverging_sub_expression.rs:38:26
|
LL | _ => true || break,
| ^^^^^
error: aborting due to 6 previous errors
error: aborting due to 7 previous errors

View File

@ -0,0 +1,215 @@
// run-rustfix
//! This file tests for the `DOC_MARKDOWN` lint.
#![allow(dead_code, incomplete_features)]
#![warn(clippy::doc_markdown)]
#![feature(custom_inner_attributes, generic_const_exprs, const_option)]
#![rustfmt::skip]
/// The `foo_bar` function does _nothing_. See also `foo::bar`. (note the dot there)
/// Markdown is _weird_. I mean _really weird_. This \_ is ok. So is `_`. But not `Foo::some_fun`
/// which should be reported only once despite being __doubly bad__.
/// Here be `::a::global:path`, and _`::another::global::path`_. :: is not a path though.
/// Import an item from `::awesome::global::blob::` (Intended postfix)
/// These are the options for `::Cat`: (Intended trailing single colon, shouldn't be linted)
/// That's not code ~`NotInCodeBlock`~.
/// `be_sure_we_got_to_the_end_of_it`
fn foo_bar() {
}
/// That one tests multiline ticks.
/// ```rust
/// foo_bar FOO_BAR
/// _foo bar_
/// ```
///
/// ~~~rust
/// foo_bar FOO_BAR
/// _foo bar_
/// ~~~
/// `be_sure_we_got_to_the_end_of_it`
fn multiline_codeblock() {
}
/// This _is a test for
/// multiline
/// emphasis_.
/// `be_sure_we_got_to_the_end_of_it`
fn test_emphasis() {
}
/// This tests units. See also #835.
/// kiB MiB GiB TiB PiB EiB
/// kib Mib Gib Tib Pib Eib
/// kB MB GB TB PB EB
/// kb Mb Gb Tb Pb Eb
/// 32kiB 32MiB 32GiB 32TiB 32PiB 32EiB
/// 32kib 32Mib 32Gib 32Tib 32Pib 32Eib
/// 32kB 32MB 32GB 32TB 32PB 32EB
/// 32kb 32Mb 32Gb 32Tb 32Pb 32Eb
/// NaN
/// `be_sure_we_got_to_the_end_of_it`
fn test_units() {
}
/// This tests allowed identifiers.
/// KiB MiB GiB TiB PiB EiB
/// DirectX
/// ECMAScript
/// GPLv2 GPLv3
/// GitHub GitLab
/// IPv4 IPv6
/// ClojureScript CoffeeScript JavaScript PureScript TypeScript
/// NaN NaNs
/// OAuth GraphQL
/// OCaml
/// OpenGL OpenMP OpenSSH OpenSSL OpenStreetMap OpenDNS
/// WebGL
/// TensorFlow
/// TrueType
/// iOS macOS FreeBSD
/// TeX LaTeX BibTeX BibLaTeX
/// MinGW
/// CamelCase (see also #2395)
/// `be_sure_we_got_to_the_end_of_it`
fn test_allowed() {
}
/// This test has [a `link_with_underscores`][chunked-example] inside it. See #823.
/// See also [the issue tracker](https://github.com/rust-lang/rust-clippy/search?q=clippy::doc_markdown&type=Issues)
/// on GitHub (which is a camel-cased word, but is OK). And here is another [inline link][inline_link].
/// It can also be [`inline_link2`].
///
/// [chunked-example]: https://en.wikipedia.org/wiki/Chunked_transfer_encoding#Example
/// [inline_link]: https://foobar
/// [inline_link2]: https://foobar
/// The `main` function is the entry point of the program. Here it only calls the `foo_bar` and
/// `multiline_ticks` functions.
///
/// expression of the type `_ <bit_op> m <cmp_op> c` (where `<bit_op>`
/// is one of {`&`, '|'} and `<cmp_op>` is one of {`!=`, `>=`, `>` ,
/// `be_sure_we_got_to_the_end_of_it`
fn main() {
foo_bar();
multiline_codeblock();
test_emphasis();
test_units();
}
/// ## `CamelCaseThing`
/// Talks about `CamelCaseThing`. Titles should be ignored; see issue #897.
///
/// # `CamelCaseThing`
///
/// Not a title #897 `CamelCaseThing`
/// `be_sure_we_got_to_the_end_of_it`
fn issue897() {
}
/// I am confused by brackets? (`x_y`)
/// I am confused by brackets? (foo `x_y`)
/// I am confused by brackets? (`x_y` foo)
/// `be_sure_we_got_to_the_end_of_it`
fn issue900() {
}
/// Diesel queries also have a similar problem to [Iterator][iterator], where
/// /// More talking
/// returning them from a function requires exposing the implementation of that
/// function. The [`helper_types`][helper_types] module exists to help with this,
/// but you might want to hide the return type or have it conditionally change.
/// Boxing can achieve both.
///
/// [iterator]: https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html
/// [helper_types]: ../helper_types/index.html
/// `be_sure_we_got_to_the_end_of_it`
fn issue883() {
}
/// `foo_bar
/// baz_quz`
/// [foo
/// bar](https://doc.rust-lang.org/stable/std/iter/trait.IteratorFooBar.html)
fn multiline() {
}
/** E.g., serialization of an empty list: `FooBar`
```
That's in a code block: `PackedNode`
```
And `BarQuz` too.
`be_sure_we_got_to_the_end_of_it`
*/
fn issue1073() {
}
/** E.g., serialization of an empty list: `FooBar`
```
That's in a code block: PackedNode
```
And `BarQuz` too.
`be_sure_we_got_to_the_end_of_it`
*/
fn issue1073_alt() {
}
/// Tests more than three quotes:
/// ````
/// DoNotWarn
/// ```
/// StillDont
/// ````
/// `be_sure_we_got_to_the_end_of_it`
fn four_quotes() {
}
#[cfg_attr(feature = "a", doc = " ```")]
#[cfg_attr(not(feature = "a"), doc = " ```ignore")]
/// fn main() {
/// let s = "localhost:10000".to_string();
/// println!("{}", s);
/// }
/// ```
fn issue_1469() {}
/**
* This is a doc comment that should not be a list
*This would also be an error under a strict common mark interpretation
*/
fn issue_1920() {}
/// An iterator over `mycrate::Collection`'s values.
/// It should not lint a `'static` lifetime in ticks.
fn issue_2210() {}
/// This should not cause the lint to trigger:
/// #REQ-data-family.lint_partof_exists
fn issue_2343() {}
/// This should not cause an ICE:
/// __|_ _|__||_|
fn pulldown_cmark_crash() {}
/// This should not lint
/// (regression test for #7758)
/// [plain text][path::to::item]
fn intra_doc_link() {}
// issue #7033 - generic_const_exprs ICE
struct S<T, const N: usize>
where [(); N.checked_next_power_of_two().unwrap()]: {
arr: [T; N.checked_next_power_of_two().unwrap()],
n: usize,
}
impl<T: Copy + Default, const N: usize> S<T, N>
where [(); N.checked_next_power_of_two().unwrap()]: {
fn new() -> Self {
Self {
arr: [T::default(); N.checked_next_power_of_two().unwrap()],
n: 0,
}
}
}

View File

@ -1,3 +1,4 @@
// run-rustfix
//! This file tests for the `DOC_MARKDOWN` lint.
#![allow(dead_code, incomplete_features)]
@ -8,7 +9,9 @@
/// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
/// Markdown is _weird_. I mean _really weird_. This \_ is ok. So is `_`. But not Foo::some_fun
/// which should be reported only once despite being __doubly bad__.
/// Here be ::a::global:path.
/// Here be ::a::global:path, and _::another::global::path_. :: is not a path though.
/// Import an item from ::awesome::global::blob:: (Intended postfix)
/// These are the options for ::Cat: (Intended trailing single colon, shouldn't be linted)
/// That's not code ~NotInCodeBlock~.
/// be_sure_we_got_to_the_end_of_it
fn foo_bar() {
@ -162,12 +165,6 @@ fn issue1073_alt() {
fn four_quotes() {
}
/// See [NIST SP 800-56A, revision 2].
///
/// [NIST SP 800-56A, revision 2]:
/// https://github.com/rust-lang/rust-clippy/issues/902#issuecomment-261919419
fn issue_902_comment() {}
#[cfg_attr(feature = "a", doc = " ```")]
#[cfg_attr(not(feature = "a"), doc = " ```ignore")]
/// fn main() {
@ -183,14 +180,6 @@ fn issue_1469() {}
*/
fn issue_1920() {}
/// Ok: <http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels>
///
/// Not ok: http://www.unicode.org
/// Not ok: https://www.unicode.org
/// Not ok: http://www.unicode.org/
/// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels
fn issue_1832() {}
/// An iterator over mycrate::Collection's values.
/// It should not lint a `'static` lifetime in ticks.
fn issue_2210() {}

View File

@ -0,0 +1,184 @@
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:9:9
|
LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
| ^^^^^^^ help: try: ``foo_bar``
|
= note: `-D clippy::doc-markdown` implied by `-D warnings`
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:9:51
|
LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
| ^^^^^^^^ help: try: ``foo::bar``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:10:83
|
LL | /// Markdown is _weird_. I mean _really weird_. This /_ is ok. So is `_`. But not Foo::some_fun
| ^^^^^^^^^^^^^ help: try: ``Foo::some_fun``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:12:13
|
LL | /// Here be ::a::global:path, and _::another::global::path_. :: is not a path though.
| ^^^^^^^^^^^^^^^^ help: try: ``::a::global:path``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:12:36
|
LL | /// Here be ::a::global:path, and _::another::global::path_. :: is not a path though.
| ^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``::another::global::path``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:13:25
|
LL | /// Import an item from ::awesome::global::blob:: (Intended postfix)
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``::awesome::global::blob::``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:14:31
|
LL | /// These are the options for ::Cat: (Intended trailing single colon, shouldn't be linted)
| ^^^^^ help: try: ``::Cat``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:15:22
|
LL | /// That's not code ~NotInCodeBlock~.
| ^^^^^^^^^^^^^^ help: try: ``NotInCodeBlock``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:16:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:30:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:37:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:51:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:74:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:78:22
|
LL | /// This test has [a link_with_underscores][chunked-example] inside it. See #823.
| ^^^^^^^^^^^^^^^^^^^^^ help: try: ``link_with_underscores``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:81:21
|
LL | /// It can also be [inline_link2].
| ^^^^^^^^^^^^ help: try: ``inline_link2``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:91:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:99:8
|
LL | /// ## CamelCaseThing
| ^^^^^^^^^^^^^^ help: try: ``CamelCaseThing``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:102:7
|
LL | /// # CamelCaseThing
| ^^^^^^^^^^^^^^ help: try: ``CamelCaseThing``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:104:22
|
LL | /// Not a title #897 CamelCaseThing
| ^^^^^^^^^^^^^^ help: try: ``CamelCaseThing``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:105:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:112:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:125:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:136:43
|
LL | /** E.g., serialization of an empty list: FooBar
| ^^^^^^ help: try: ``FooBar``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:141:5
|
LL | And BarQuz too.
| ^^^^^^ help: try: ``BarQuz``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:142:1
|
LL | be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:147:43
|
LL | /** E.g., serialization of an empty list: FooBar
| ^^^^^^ help: try: ``FooBar``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:152:5
|
LL | And BarQuz too.
| ^^^^^^ help: try: ``BarQuz``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:153:1
|
LL | be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:164:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:183:22
|
LL | /// An iterator over mycrate::Collection's values.
| ^^^^^^^^^^^^^^^^^^^ help: try: ``mycrate::Collection``
error: aborting due to 30 previous errors

View File

@ -1,190 +0,0 @@
error: you should put `foo_bar` between ticks in the documentation
--> $DIR/doc.rs:8:9
|
LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
| ^^^^^^^
|
= note: `-D clippy::doc-markdown` implied by `-D warnings`
error: you should put `foo::bar` between ticks in the documentation
--> $DIR/doc.rs:8:51
|
LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
| ^^^^^^^^
error: you should put `Foo::some_fun` between ticks in the documentation
--> $DIR/doc.rs:9:83
|
LL | /// Markdown is _weird_. I mean _really weird_. This /_ is ok. So is `_`. But not Foo::some_fun
| ^^^^^^^^^^^^^
error: you should put `a::global:path` between ticks in the documentation
--> $DIR/doc.rs:11:15
|
LL | /// Here be ::a::global:path.
| ^^^^^^^^^^^^^^
error: you should put `NotInCodeBlock` between ticks in the documentation
--> $DIR/doc.rs:12:22
|
LL | /// That's not code ~NotInCodeBlock~.
| ^^^^^^^^^^^^^^
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
--> $DIR/doc.rs:13:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
--> $DIR/doc.rs:27:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
--> $DIR/doc.rs:34:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
--> $DIR/doc.rs:48:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
--> $DIR/doc.rs:71:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: you should put `link_with_underscores` between ticks in the documentation
--> $DIR/doc.rs:75:22
|
LL | /// This test has [a link_with_underscores][chunked-example] inside it. See #823.
| ^^^^^^^^^^^^^^^^^^^^^
error: you should put `inline_link2` between ticks in the documentation
--> $DIR/doc.rs:78:21
|
LL | /// It can also be [inline_link2].
| ^^^^^^^^^^^^
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
--> $DIR/doc.rs:88:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: you should put `CamelCaseThing` between ticks in the documentation
--> $DIR/doc.rs:96:8
|
LL | /// ## CamelCaseThing
| ^^^^^^^^^^^^^^
error: you should put `CamelCaseThing` between ticks in the documentation
--> $DIR/doc.rs:99:7
|
LL | /// # CamelCaseThing
| ^^^^^^^^^^^^^^
error: you should put `CamelCaseThing` between ticks in the documentation
--> $DIR/doc.rs:101:22
|
LL | /// Not a title #897 CamelCaseThing
| ^^^^^^^^^^^^^^
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
--> $DIR/doc.rs:102:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
--> $DIR/doc.rs:109:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
--> $DIR/doc.rs:122:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: you should put `FooBar` between ticks in the documentation
--> $DIR/doc.rs:133:43
|
LL | /** E.g., serialization of an empty list: FooBar
| ^^^^^^
error: you should put `BarQuz` between ticks in the documentation
--> $DIR/doc.rs:138:5
|
LL | And BarQuz too.
| ^^^^^^
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
--> $DIR/doc.rs:139:1
|
LL | be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: you should put `FooBar` between ticks in the documentation
--> $DIR/doc.rs:144:43
|
LL | /** E.g., serialization of an empty list: FooBar
| ^^^^^^
error: you should put `BarQuz` between ticks in the documentation
--> $DIR/doc.rs:149:5
|
LL | And BarQuz too.
| ^^^^^^
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
--> $DIR/doc.rs:150:1
|
LL | be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
--> $DIR/doc.rs:161:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: you should put bare URLs between `<`/`>` or make a proper Markdown link
--> $DIR/doc.rs:188:13
|
LL | /// Not ok: http://www.unicode.org
| ^^^^^^^^^^^^^^^^^^^^^^
error: you should put bare URLs between `<`/`>` or make a proper Markdown link
--> $DIR/doc.rs:189:13
|
LL | /// Not ok: https://www.unicode.org
| ^^^^^^^^^^^^^^^^^^^^^^^
error: you should put bare URLs between `<`/`>` or make a proper Markdown link
--> $DIR/doc.rs:190:13
|
LL | /// Not ok: http://www.unicode.org/
| ^^^^^^^^^^^^^^^^^^^^^^
error: you should put bare URLs between `<`/`>` or make a proper Markdown link
--> $DIR/doc.rs:191:13
|
LL | /// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: you should put `mycrate::Collection` between ticks in the documentation
--> $DIR/doc.rs:194:22
|
LL | /// An iterator over mycrate::Collection's values.
| ^^^^^^^^^^^^^^^^^^^
error: aborting due to 31 previous errors

View File

@ -0,0 +1,9 @@
/// Ok: <http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels>
///
/// Not ok: http://www.unicode.org
/// Not ok: https://www.unicode.org
/// Not ok: http://www.unicode.org/
/// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels
fn issue_1832() {}
fn main() {}

View File

@ -0,0 +1,7 @@
/// See [NIST SP 800-56A, revision 2].
///
/// [NIST SP 800-56A, revision 2]:
/// https://github.com/rust-lang/rust-clippy/issues/902#issuecomment-261919419
fn issue_902_comment() {}
fn main() {}

View File

@ -18,11 +18,11 @@ LL | /// This paragraph has `unbalanced_tick marks and should stop_linting.
|
= help: a backtick may be missing a pair
error: you should put `should_be` between ticks in the documentation
error: item in documentation is missing backticks
--> $DIR/unbalanced_ticks.rs:15:32
|
LL | /// This paragraph is fine and should_be linted normally.
| ^^^^^^^^^
| ^^^^^^^^^ help: try: ``should_be``
error: backticks are unbalanced
--> $DIR/unbalanced_ticks.rs:17:1
@ -32,11 +32,11 @@ LL | /// Double unbalanced backtick from ``here to here` should lint.
|
= help: a backtick may be missing a pair
error: you should put `not_fine` between ticks in the documentation
error: item in documentation is missing backticks
--> $DIR/unbalanced_ticks.rs:30:8
|
LL | /// ## not_fine
| ^^^^^^^^
| ^^^^^^^^ help: try: ``not_fine``
error: backticks are unbalanced
--> $DIR/unbalanced_ticks.rs:32:1
@ -54,11 +54,11 @@ LL | /// - This `item has unbalanced tick marks
|
= help: a backtick may be missing a pair
error: you should put `backticks_here` between ticks in the documentation
error: item in documentation is missing backticks
--> $DIR/unbalanced_ticks.rs:35:23
|
LL | /// - This item needs backticks_here
| ^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^ help: try: ``backticks_here``
error: aborting due to 8 previous errors

View File

@ -1,4 +1,3 @@
// edition:2018
#![warn(clippy::missing_errors_doc)]
#![allow(clippy::result_unit_err)]
#![allow(clippy::unnecessary_wraps)]

View File

@ -1,5 +1,5 @@
error: docs for function returning `Result` missing `# Errors` section
--> $DIR/doc_errors.rs:8:1
--> $DIR/doc_errors.rs:7:1
|
LL | / pub fn pub_fn_missing_errors_header() -> Result<(), ()> {
LL | | unimplemented!();
@ -9,7 +9,7 @@ LL | | }
= note: `-D clippy::missing-errors-doc` implied by `-D warnings`
error: docs for function returning `Result` missing `# Errors` section
--> $DIR/doc_errors.rs:12:1
--> $DIR/doc_errors.rs:11:1
|
LL | / pub async fn async_pub_fn_missing_errors_header() -> Result<(), ()> {
LL | | unimplemented!();
@ -17,7 +17,7 @@ LL | | }
| |_^
error: docs for function returning `Result` missing `# Errors` section
--> $DIR/doc_errors.rs:17:1
--> $DIR/doc_errors.rs:16:1
|
LL | / pub fn pub_fn_returning_io_result() -> io::Result<()> {
LL | | unimplemented!();
@ -25,7 +25,7 @@ LL | | }
| |_^
error: docs for function returning `Result` missing `# Errors` section
--> $DIR/doc_errors.rs:22:1
--> $DIR/doc_errors.rs:21:1
|
LL | / pub async fn async_pub_fn_returning_io_result() -> io::Result<()> {
LL | | unimplemented!();
@ -33,7 +33,7 @@ LL | | }
| |_^
error: docs for function returning `Result` missing `# Errors` section
--> $DIR/doc_errors.rs:52:5
--> $DIR/doc_errors.rs:51:5
|
LL | / pub fn pub_method_missing_errors_header() -> Result<(), ()> {
LL | | unimplemented!();
@ -41,7 +41,7 @@ LL | | }
| |_____^
error: docs for function returning `Result` missing `# Errors` section
--> $DIR/doc_errors.rs:57:5
--> $DIR/doc_errors.rs:56:5
|
LL | / pub async fn async_pub_method_missing_errors_header() -> Result<(), ()> {
LL | | unimplemented!();
@ -49,7 +49,7 @@ LL | | }
| |_____^
error: docs for function returning `Result` missing `# Errors` section
--> $DIR/doc_errors.rs:86:5
--> $DIR/doc_errors.rs:85:5
|
LL | fn trait_method_missing_errors_header() -> Result<(), ()>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Some files were not shown because too many files have changed in this diff Show More