Merge remote-tracking branch 'upstream/master' into rustup

This commit is contained in:
Eduardo Broto 2020-09-08 22:26:31 +02:00
commit e83190bdd4
39 changed files with 882 additions and 184 deletions

View file

@ -6,11 +6,113 @@ document.
## Unreleased / In Rust Nightly
[c2c07fa...master](https://github.com/rust-lang/rust-clippy/compare/c2c07fa...master)
[09bd400...master](https://github.com/rust-lang/rust-clippy/compare/09bd400...master)
## Rust 1.47
Current beta, release 2020-10-08
[c2c07fa...09bd400](https://github.com/rust-lang/rust-clippy/compare/c2c07fa...09bd400)
### New lints
* [`derive_ord_xor_partial_ord`] [#5848](https://github.com/rust-lang/rust-clippy/pull/5848)
* [`trait_duplication_in_bounds`] [#5852](https://github.com/rust-lang/rust-clippy/pull/5852)
* [`map_identity`] [#5694](https://github.com/rust-lang/rust-clippy/pull/5694)
* [`unit_return_expecting_ord`] [#5737](https://github.com/rust-lang/rust-clippy/pull/5737)
* [`pattern_type_mismatch`] [#4841](https://github.com/rust-lang/rust-clippy/pull/4841)
* [`repeat_once`] [#5773](https://github.com/rust-lang/rust-clippy/pull/5773)
* [`same_item_push`] [#5825](https://github.com/rust-lang/rust-clippy/pull/5825)
* [`needless_arbitrary_self_type`] [#5869](https://github.com/rust-lang/rust-clippy/pull/5869)
* [`match_like_matches_macro`] [#5769](https://github.com/rust-lang/rust-clippy/pull/5769)
* [`stable_sort_primitive`] [#5809](https://github.com/rust-lang/rust-clippy/pull/5809)
* [`blanket_clippy_restriction_lints`] [#5750](https://github.com/rust-lang/rust-clippy/pull/5750)
* [`option_if_let_else`] [#5301](https://github.com/rust-lang/rust-clippy/pull/5301)
### Moves and Deprecations
* Deprecate [`regex_macro`] lint
[#5760](https://github.com/rust-lang/rust-clippy/pull/5760)
* Move [`range_minus_one`] to `pedantic`
[#5752](https://github.com/rust-lang/rust-clippy/pull/5752)
### Enhancements
* Improve [`needless_collect`] by catching `collect` calls followed by `iter` or `into_iter` calls
[#5837](https://github.com/rust-lang/rust-clippy/pull/5837)
* [`panic`], [`todo`], [`unimplemented`] and [`unreachable`] now detect calls with formatting
[#5811](https://github.com/rust-lang/rust-clippy/pull/5811)
* Detect more cases of [`suboptimal_flops`] and [`imprecise_flops`]
[#5443](https://github.com/rust-lang/rust-clippy/pull/5443)
* Handle asymmetrical implementations of `PartialEq` in [`cmp_owned`]
[#5701](https://github.com/rust-lang/rust-clippy/pull/5701)
* Make it possible to allow [`unsafe_derive_deserialize`]
[#5870](https://github.com/rust-lang/rust-clippy/pull/5870)
* Catch `ord.min(a).max(b)` where a < b in [`min_max`]
[#5871](https://github.com/rust-lang/rust-clippy/pull/5871)
* Make [`clone_on_copy`] suggestion machine applicable
[#5745](https://github.com/rust-lang/rust-clippy/pull/5745)
* Enable [`len_zero`] on ranges now that `is_empty` is stable on them
[#5961](https://github.com/rust-lang/rust-clippy/pull/5961)
### False Positive Fixes
* Avoid triggering [`or_fun_call`] with const fns that take no arguments
[#5889](https://github.com/rust-lang/rust-clippy/pull/5889)
* Fix [`redundant_closure_call`] false positive for closures that have multiple calls
[#5800](https://github.com/rust-lang/rust-clippy/pull/5800)
* Don't lint cases involving `ManuallyDrop` in [`redundant_clone`]
[#5824](https://github.com/rust-lang/rust-clippy/pull/5824)
* Treat a single expression the same as a single statement in the 2nd arm of a match in [`single_match_else`]
[#5771](https://github.com/rust-lang/rust-clippy/pull/5771)
* Don't trigger [`unnested_or_patterns`] if the feature `or_patterns` is not enabled
[#5758](https://github.com/rust-lang/rust-clippy/pull/5758)
* Avoid linting if key borrows in [`unnecessary_sort_by`]
[#5756](https://github.com/rust-lang/rust-clippy/pull/5756)
* Consider `Try` impl for `Poll` when generating suggestions in [`try_err`]
[#5857](https://github.com/rust-lang/rust-clippy/pull/5857)
* Take input lifetimes into account in `manual_async_fn`
[#5859](https://github.com/rust-lang/rust-clippy/pull/5859)
* Fix multiple false positives in [`type_repetition_in_bounds`] and add a configuration option
[#5761](https://github.com/rust-lang/rust-clippy/pull/5761)
* Limit the [`suspicious_arithmetic_impl`] lint to one binary operation
[#5820](https://github.com/rust-lang/rust-clippy/pull/5820)
### Suggestion Fixes/Improvements
* Improve readability of [`shadow_unrelated`] suggestion by truncating the RHS snippet
[#5788](https://github.com/rust-lang/rust-clippy/pull/5788)
* Suggest `filter_map` instead of `flat_map` when mapping to `Option` in [`map_flatten`]
[#5846](https://github.com/rust-lang/rust-clippy/pull/5846)
* Ensure suggestion is shown correctly for long method call chains in [`iter_nth_zero`]
[#5793](https://github.com/rust-lang/rust-clippy/pull/5793)
* Drop borrow operator in suggestions of [`redundant_pattern_matching`]
[#5815](https://github.com/rust-lang/rust-clippy/pull/5815)
* Add suggestion for [`iter_skip_next`]
[#5843](https://github.com/rust-lang/rust-clippy/pull/5843)
* Improve [`collapsible_if`] fix suggestion
[#5732](https://github.com/rust-lang/rust-clippy/pull/5732)
### ICE Fixes
* Fix ICE caused by [`needless_collect`]
[#5877](https://github.com/rust-lang/rust-clippy/pull/5877)
* Fix ICE caused by [`unnested_or_patterns`]
[#5784](https://github.com/rust-lang/rust-clippy/pull/5784)
### Documentation Improvements
* Fix grammar of [`await_holding_lock`] documentation
[#5748](https://github.com/rust-lang/rust-clippy/pull/5748)
### Others
* Make lints adhere to the rustc dev guide
[#5888](https://github.com/rust-lang/rust-clippy/pull/5888)
## Rust 1.46
Current beta, release 2020-08-27
Current stable, released 2020-08-27
[7ea7cd1...c2c07fa](https://github.com/rust-lang/rust-clippy/compare/7ea7cd1...c2c07fa)
@ -72,7 +174,7 @@ Current beta, release 2020-08-27
## Rust 1.45
Current stable, released 2020-07-16
Released 2020-07-16
[891e1a8...7ea7cd1](https://github.com/rust-lang/rust-clippy/compare/891e1a8...7ea7cd1)
@ -1410,6 +1512,7 @@ Released 2018-09-13
[`assertions_on_constants`]: https://rust-lang.github.io/rust-clippy/master/index.html#assertions_on_constants
[`assign_op_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#assign_op_pattern
[`assign_ops`]: https://rust-lang.github.io/rust-clippy/master/index.html#assign_ops
[`async_yields_async`]: https://rust-lang.github.io/rust-clippy/master/index.html#async_yields_async
[`await_holding_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#await_holding_lock
[`bad_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#bad_bit_mask
[`bind_instead_of_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#bind_instead_of_map

View file

@ -0,0 +1,86 @@
use crate::utils::{implements_trait, snippet, span_lint_and_then};
use rustc_errors::Applicability;
use rustc_hir::{AsyncGeneratorKind, Body, BodyId, ExprKind, GeneratorKind, QPath};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
declare_clippy_lint! {
/// **What it does:** Checks for async blocks that yield values of types
/// that can themselves be awaited.
///
/// **Why is this bad?** An await is likely missing.
///
/// **Known problems:** None.
///
/// **Example:**
///
/// ```rust
/// async fn foo() {}
///
/// fn bar() {
/// let x = async {
/// foo()
/// };
/// }
/// ```
/// Use instead:
/// ```rust
/// async fn foo() {}
///
/// fn bar() {
/// let x = async {
/// foo().await
/// };
/// }
/// ```
pub ASYNC_YIELDS_ASYNC,
correctness,
"async blocks that return a type that can be awaited"
}
declare_lint_pass!(AsyncYieldsAsync => [ASYNC_YIELDS_ASYNC]);
impl<'tcx> LateLintPass<'tcx> for AsyncYieldsAsync {
fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) {
use AsyncGeneratorKind::{Block, Closure};
// For functions, with explicitly defined types, don't warn.
// XXXkhuey maybe we should?
if let Some(GeneratorKind::Async(Block | Closure)) = body.generator_kind {
if let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() {
let body_id = BodyId {
hir_id: body.value.hir_id,
};
let def_id = cx.tcx.hir().body_owner_def_id(body_id);
let typeck_results = cx.tcx.typeck(def_id);
let expr_ty = typeck_results.expr_ty(&body.value);
if implements_trait(cx, expr_ty, future_trait_def_id, &[]) {
let return_expr_span = match &body.value.kind {
// XXXkhuey there has to be a better way.
ExprKind::Block(block, _) => block.expr.map(|e| e.span),
ExprKind::Path(QPath::Resolved(_, path)) => Some(path.span),
_ => None,
};
if let Some(return_expr_span) = return_expr_span {
span_lint_and_then(
cx,
ASYNC_YIELDS_ASYNC,
return_expr_span,
"an async construct yields a type which is itself awaitable",
|db| {
db.span_label(body.value.span, "outer async construct");
db.span_label(return_expr_span, "awaitable value not awaited");
db.span_suggestion(
return_expr_span,
"consider awaiting this value",
format!("{}.await", snippet(cx, return_expr_span, "..")),
Applicability::MaybeIncorrect,
);
},
);
}
}
}
}
}
}

View file

@ -71,8 +71,9 @@ declare_clippy_lint! {
/// **What it does:** Checks for `extern crate` and `use` items annotated with
/// lint attributes.
///
/// This lint permits `#[allow(unused_imports)]`, `#[allow(deprecated)]` and
/// `#[allow(unreachable_pub)]` on `use` items and `#[allow(unused_imports)]` on
/// This lint permits `#[allow(unused_imports)]`, `#[allow(deprecated)]`,
/// `#[allow(unreachable_pub)]`, `#[allow(clippy::wildcard_imports)]` and
/// `#[allow(clippy::enum_glob_use)]` on `use` items and `#[allow(unused_imports)]` on
/// `extern crate` items with a `#[macro_use]` attribute.
///
/// **Why is this bad?** Lint attributes have no effect on crate imports. Most
@ -318,7 +319,8 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
if let Some(ident) = attr.ident() {
match &*ident.as_str() {
"allow" | "warn" | "deny" | "forbid" => {
// permit `unused_imports`, `deprecated` and `unreachable_pub` for `use` items
// permit `unused_imports`, `deprecated`, `unreachable_pub`,
// `clippy::wildcard_imports`, and `clippy::enum_glob_use` for `use` items
// and `unused_imports` for `extern crate` items with `macro_use`
for lint in lint_list {
match item.kind {
@ -327,6 +329,9 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
|| is_word(lint, sym!(deprecated))
|| is_word(lint, sym!(unreachable_pub))
|| is_word(lint, sym!(unused))
|| extract_clippy_lint(lint)
.map_or(false, |s| s == "wildcard_imports")
|| extract_clippy_lint(lint).map_or(false, |s| s == "enum_glob_use")
{
return;
}
@ -387,24 +392,25 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
}
}
fn check_clippy_lint_names(cx: &LateContext<'_>, ident: &str, items: &[NestedMetaItem]) {
fn extract_name(lint: &NestedMetaItem) -> Option<SymbolStr> {
if_chain! {
if let Some(meta_item) = lint.meta_item();
if meta_item.path.segments.len() > 1;
if let tool_name = meta_item.path.segments[0].ident;
if tool_name.as_str() == "clippy";
let lint_name = meta_item.path.segments.last().unwrap().ident.name;
then {
return Some(lint_name.as_str());
}
/// Returns the lint name if it is clippy lint.
fn extract_clippy_lint(lint: &NestedMetaItem) -> Option<SymbolStr> {
if_chain! {
if let Some(meta_item) = lint.meta_item();
if meta_item.path.segments.len() > 1;
if let tool_name = meta_item.path.segments[0].ident;
if tool_name.as_str() == "clippy";
let lint_name = meta_item.path.segments.last().unwrap().ident.name;
then {
return Some(lint_name.as_str());
}
None
}
None
}
fn check_clippy_lint_names(cx: &LateContext<'_>, ident: &str, items: &[NestedMetaItem]) {
let lint_store = cx.lints();
for lint in items {
if let Some(lint_name) = extract_name(lint) {
if let Some(lint_name) = extract_clippy_lint(lint) {
if let CheckLintNameResult::Tool(Err((None, _))) =
lint_store.check_lint_name(&lint_name, Some(sym!(clippy)))
{

View file

@ -38,37 +38,23 @@ impl<'tcx> LateLintPass<'tcx> for DefaultTraitAccess {
if let ExprKind::Path(ref qpath) = path.kind;
if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id();
if match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD);
// Detect and ignore <Foo as Default>::default() because these calls do explicitly name the type.
if let QPath::Resolved(None, _path) = qpath;
then {
match qpath {
QPath::Resolved(..) => {
if_chain! {
// Detect and ignore <Foo as Default>::default() because these calls do
// explicitly name the type.
if let ExprKind::Call(ref method, ref _args) = expr.kind;
if let ExprKind::Path(ref p) = method.kind;
if let QPath::Resolved(Some(_ty), _path) = p;
then {
return;
}
}
// TODO: Work out a way to put "whatever the imported way of referencing
// this type in this file" rather than a fully-qualified type.
let expr_ty = cx.typeck_results().expr_ty(expr);
if let ty::Adt(..) = expr_ty.kind() {
let replacement = format!("{}::default()", expr_ty);
span_lint_and_sugg(
cx,
DEFAULT_TRAIT_ACCESS,
expr.span,
&format!("calling `{}` is more clear than this expression", replacement),
"try",
replacement,
Applicability::Unspecified, // First resolve the TODO above
);
}
},
QPath::TypeRelative(..) | QPath::LangItem(..) => {},
let expr_ty = cx.typeck_results().expr_ty(expr);
if let ty::Adt(def, ..) = expr_ty.kind() {
// TODO: Work out a way to put "whatever the imported way of referencing
// this type in this file" rather than a fully-qualified type.
let replacement = format!("{}::default()", cx.tcx.def_path_str(def.did));
span_lint_and_sugg(
cx,
DEFAULT_TRAIT_ACCESS,
expr.span,
&format!("calling `{}` is more clear than this expression", replacement),
"try",
replacement,
Applicability::Unspecified, // First resolve the TODO above
);
}
}
}

View file

@ -374,7 +374,12 @@ impl<'tcx> Functions {
}
if line_count > self.max_lines {
span_lint(cx, TOO_MANY_LINES, span, "this function has a large number of lines")
span_lint(
cx,
TOO_MANY_LINES,
span,
&format!("this function has too many lines ({}/{})", line_count, self.max_lines),
)
}
}

View file

@ -154,6 +154,7 @@ mod arithmetic;
mod as_conversions;
mod assertions_on_constants;
mod assign_ops;
mod async_yields_async;
mod atomic_ordering;
mod attrs;
mod await_holding_lock;
@ -483,6 +484,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
&assertions_on_constants::ASSERTIONS_ON_CONSTANTS,
&assign_ops::ASSIGN_OP_PATTERN,
&assign_ops::MISREFACTORED_ASSIGN_OP,
&async_yields_async::ASYNC_YIELDS_ASYNC,
&atomic_ordering::INVALID_ATOMIC_ORDERING,
&attrs::BLANKET_CLIPPY_RESTRICTION_LINTS,
&attrs::DEPRECATED_CFG_ATTR,
@ -1099,6 +1101,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|| box unwrap_in_result::UnwrapInResult);
store.register_late_pass(|| box self_assignment::SelfAssignment);
store.register_late_pass(|| box float_equality_without_abs::FloatEqualityWithoutAbs);
store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync);
store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
LintId::of(&arithmetic::FLOAT_ARITHMETIC),
@ -1232,6 +1235,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&assertions_on_constants::ASSERTIONS_ON_CONSTANTS),
LintId::of(&assign_ops::ASSIGN_OP_PATTERN),
LintId::of(&assign_ops::MISREFACTORED_ASSIGN_OP),
LintId::of(&async_yields_async::ASYNC_YIELDS_ASYNC),
LintId::of(&atomic_ordering::INVALID_ATOMIC_ORDERING),
LintId::of(&attrs::BLANKET_CLIPPY_RESTRICTION_LINTS),
LintId::of(&attrs::DEPRECATED_CFG_ATTR),
@ -1675,6 +1679,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_group(true, "clippy::correctness", Some("clippy_correctness"), vec![
LintId::of(&approx_const::APPROX_CONSTANT),
LintId::of(&async_yields_async::ASYNC_YIELDS_ASYNC),
LintId::of(&atomic_ordering::INVALID_ATOMIC_ORDERING),
LintId::of(&attrs::DEPRECATED_SEMVER),
LintId::of(&attrs::MISMATCHED_TARGET_OS),

View file

@ -1140,43 +1140,52 @@ fn detect_same_item_push<'tcx>(
walk_expr(&mut same_item_push_visitor, body);
if same_item_push_visitor.should_lint {
if let Some((vec, pushed_item)) = same_item_push_visitor.vec_push {
// Make sure that the push does not involve possibly mutating values
if let PatKind::Wild = pat.kind {
let vec_str = snippet_with_macro_callsite(cx, vec.span, "");
let item_str = snippet_with_macro_callsite(cx, pushed_item.span, "");
if let ExprKind::Path(ref qpath) = pushed_item.kind {
if_chain! {
if let Res::Local(hir_id) = qpath_res(cx, qpath, pushed_item.hir_id);
let node = cx.tcx.hir().get(hir_id);
if let Node::Binding(pat) = node;
if let PatKind::Binding(bind_ann, ..) = pat.kind;
if !matches!(bind_ann, BindingAnnotation::RefMut | BindingAnnotation::Mutable);
then {
span_lint_and_help(
cx,
SAME_ITEM_PUSH,
vec.span,
"it looks like the same item is being pushed into this Vec",
None,
&format!(
"try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})",
item_str, vec_str, item_str
),
)
let vec_ty = cx.typeck_results().expr_ty(vec);
let ty = vec_ty.walk().nth(1).unwrap().expect_ty();
if cx
.tcx
.lang_items()
.clone_trait()
.map_or(false, |id| implements_trait(cx, ty, id, &[]))
{
// Make sure that the push does not involve possibly mutating values
if let PatKind::Wild = pat.kind {
let vec_str = snippet_with_macro_callsite(cx, vec.span, "");
let item_str = snippet_with_macro_callsite(cx, pushed_item.span, "");
if let ExprKind::Path(ref qpath) = pushed_item.kind {
if_chain! {
if let Res::Local(hir_id) = qpath_res(cx, qpath, pushed_item.hir_id);
let node = cx.tcx.hir().get(hir_id);
if let Node::Binding(pat) = node;
if let PatKind::Binding(bind_ann, ..) = pat.kind;
if !matches!(bind_ann, BindingAnnotation::RefMut | BindingAnnotation::Mutable);
then {
span_lint_and_help(
cx,
SAME_ITEM_PUSH,
vec.span,
"it looks like the same item is being pushed into this Vec",
None,
&format!(
"try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})",
item_str, vec_str, item_str
),
)
}
}
} else if mutated_variables(pushed_item, cx).map_or(false, |mutvars| mutvars.is_empty()) {
span_lint_and_help(
cx,
SAME_ITEM_PUSH,
vec.span,
"it looks like the same item is being pushed into this Vec",
None,
&format!(
"try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})",
item_str, vec_str, item_str
),
)
}
} else if mutated_variables(pushed_item, cx).map_or(false, |mutvars| mutvars.is_empty()) {
span_lint_and_help(
cx,
SAME_ITEM_PUSH,
vec.span,
"it looks like the same item is being pushed into this Vec",
None,
&format!(
"try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})",
item_str, vec_str, item_str
),
)
}
}
}

View file

@ -1324,20 +1324,20 @@ declare_clippy_lint! {
}
declare_clippy_lint! {
/// **What it does:** Warns when using push_str with a single-character string literal,
/// and push with a char would work fine.
/// **What it does:** Warns when using `push_str` with a single-character string literal,
/// and `push` with a `char` would work fine.
///
/// **Why is this bad?** It's less clear that we are pushing a single character
/// **Why is this bad?** It's less clear that we are pushing a single character.
///
/// **Known problems:** None
///
/// **Example:**
/// ```
/// ```rust
/// let mut string = String::new();
/// string.push_str("R");
/// ```
/// Could be written as
/// ```
/// ```rust
/// let mut string = String::new();
/// string.push('R');
/// ```

View file

@ -331,8 +331,9 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
if let Some(def_id) = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id();
if match_def_path(cx, def_id, &paths::TRANSMUTE);
then {
// Avoid suggesting from/to bits in const contexts.
// Avoid suggesting from/to bits and dereferencing raw pointers in const contexts.
// See https://github.com/rust-lang/rust/issues/73736 for progress on making them `const fn`.
// And see https://github.com/rust-lang/rust/issues/51911 for dereferencing raw pointers.
let const_context = in_constant(cx, e.hir_id);
let from_ty = cx.typeck_results().expr_ty(&args[0]);
@ -486,7 +487,8 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
Applicability::Unspecified,
);
} else {
if cx.tcx.erase_regions(&from_ty) != cx.tcx.erase_regions(&to_ty) {
if (cx.tcx.erase_regions(&from_ty) != cx.tcx.erase_regions(&to_ty))
&& !const_context {
span_lint_and_then(
cx,
TRANSMUTE_PTR_TO_PTR,

View file

@ -1,5 +1,4 @@
use crate::utils;
use crate::utils::paths;
use crate::utils::sugg::Sugg;
use if_chain::if_chain;
use rustc_errors::Applicability;
@ -171,12 +170,22 @@ fn mirrored_exprs(
}
fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<LintTrigger> {
// NOTE: Vectors of references are not supported. In order to avoid hitting https://github.com/rust-lang/rust/issues/34162,
// (different unnamed lifetimes for closure arg and return type) we need to make sure the suggested
// closure parameter is not a reference in case we suggest `Reverse`. Trying to destructure more
// than one level of references would add some extra complexity as we would have to compensate
// in the closure body.
if_chain! {
if let ExprKind::MethodCall(name_ident, _, args, _) = &expr.kind;
if let name = name_ident.ident.name.to_ident_string();
if name == "sort_by" || name == "sort_unstable_by";
if let [vec, Expr { kind: ExprKind::Closure(_, _, closure_body_id, _, _), .. }] = args;
if utils::match_type(cx, &cx.typeck_results().expr_ty(vec), &paths::VEC);
let vec_ty = cx.typeck_results().expr_ty(vec);
if utils::is_type_diagnostic_item(cx, vec_ty, sym!(vec_type));
let ty = vec_ty.walk().nth(1).unwrap().expect_ty(); // T in Vec<T>
if !matches!(&ty.kind(), ty::Ref(..));
if utils::is_copy(cx, ty);
if let closure_body = cx.tcx.hir().body(*closure_body_id);
if let &[
Param { pat: Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, ..},

View file

@ -191,7 +191,9 @@ pub fn eq_stmt(l: &Stmt, r: &Stmt) -> bool {
(Item(l), Item(r)) => eq_item(l, r, eq_item_kind),
(Expr(l), Expr(r)) | (Semi(l), Semi(r)) => eq_expr(l, r),
(Empty, Empty) => true,
(MacCall(l), MacCall(r)) => l.style == r.style && eq_mac_call(&l.mac, &r.mac) && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r)),
(MacCall(l), MacCall(r)) => {
l.style == r.style && eq_mac_call(&l.mac, &r.mac) && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
},
_ => false,
}
}

View file

@ -122,7 +122,7 @@ define_Conf! {
"IPv4", "IPv6",
"ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript",
"NaN", "NaNs",
"OAuth",
"OAuth", "GraphQL",
"OCaml",
"OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap",
"TensorFlow",

View file

@ -899,7 +899,7 @@ pub fn is_ctor_or_promotable_const_function(cx: &LateContext<'_>, expr: &Expr<'_
return match res {
def::Res::Def(DefKind::Variant | DefKind::Ctor(..), ..) => true,
// FIXME: check the constness of the arguments, see https://github.com/rust-lang/rust-clippy/pull/5682#issuecomment-638681210
def::Res::Def(DefKind::Fn, def_id) if has_no_arguments(cx, def_id) => {
def::Res::Def(DefKind::Fn | DefKind::AssocFn, def_id) if has_no_arguments(cx, def_id) => {
const_eval::is_const_fn(cx.tcx, def_id)
},
def::Res::Def(_, def_id) => cx.tcx.is_promotable_const_fn(def_id),
@ -1432,7 +1432,7 @@ pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<S
} else {
unreachable!()
}
}
},
_ => false,
};

View file

@ -132,7 +132,11 @@ impl<'a> Sugg<'a> {
pub fn ast(cx: &EarlyContext<'_>, expr: &ast::Expr, default: &'a str) -> Self {
use rustc_ast::ast::RangeLimits;
let snippet = snippet(cx, expr.span, default);
let snippet = if expr.span.from_expansion() {
snippet_with_macro_callsite(cx, expr.span, default)
} else {
snippet(cx, expr.span, default)
};
match expr.kind {
ast::ExprKind::AddrOf(..)

View file

@ -52,6 +52,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
deprecation: None,
module: "assign_ops",
},
Lint {
name: "async_yields_async",
group: "correctness",
desc: "async blocks that return a type that can be awaited",
deprecation: None,
module: "async_yields_async",
},
Lint {
name: "await_holding_lock",
group: "pedantic",

View file

@ -1,4 +1,4 @@
error: this function has a large number of lines
error: this function has too many lines (2/1)
--> $DIR/test.rs:18:1
|
LL | / fn too_many_lines() {
@ -9,7 +9,7 @@ LL | | }
|
= note: `-D clippy::too-many-lines` implied by `-D warnings`
error: this function has a large number of lines
error: this function has too many lines (2/1)
--> $DIR/test.rs:38:1
|
LL | / fn comment_before_code() {

View file

@ -0,0 +1,68 @@
// run-rustfix
// edition:2018
#![feature(async_closure)]
#![warn(clippy::async_yields_async)]
use core::future::Future;
use core::pin::Pin;
use core::task::{Context, Poll};
struct CustomFutureType;
impl Future for CustomFutureType {
type Output = u8;
fn poll(self: Pin<&mut Self>, _: &mut Context) -> Poll<Self::Output> {
Poll::Ready(3)
}
}
fn custom_future_type_ctor() -> CustomFutureType {
CustomFutureType
}
async fn f() -> CustomFutureType {
// Don't warn for functions since you have to explicitly declare their
// return types.
CustomFutureType
}
#[rustfmt::skip]
fn main() {
let _f = {
3
};
let _g = async {
3
};
let _h = async {
async {
3
}.await
};
let _i = async {
CustomFutureType.await
};
let _i = async || {
3
};
let _j = async || {
async {
3
}.await
};
let _k = async || {
CustomFutureType.await
};
let _l = async || CustomFutureType.await;
let _m = async || {
println!("I'm bored");
// Some more stuff
// Finally something to await
CustomFutureType.await
};
let _n = async || custom_future_type_ctor();
let _o = async || f();
}

View file

@ -0,0 +1,68 @@
// run-rustfix
// edition:2018
#![feature(async_closure)]
#![warn(clippy::async_yields_async)]
use core::future::Future;
use core::pin::Pin;
use core::task::{Context, Poll};
struct CustomFutureType;
impl Future for CustomFutureType {
type Output = u8;
fn poll(self: Pin<&mut Self>, _: &mut Context) -> Poll<Self::Output> {
Poll::Ready(3)
}
}
fn custom_future_type_ctor() -> CustomFutureType {
CustomFutureType
}
async fn f() -> CustomFutureType {
// Don't warn for functions since you have to explicitly declare their
// return types.
CustomFutureType
}
#[rustfmt::skip]
fn main() {
let _f = {
3
};
let _g = async {
3
};
let _h = async {
async {
3
}
};
let _i = async {
CustomFutureType
};
let _i = async || {
3
};
let _j = async || {
async {
3
}
};
let _k = async || {
CustomFutureType
};
let _l = async || CustomFutureType;
let _m = async || {
println!("I'm bored");
// Some more stuff
// Finally something to await
CustomFutureType
};
let _n = async || custom_future_type_ctor();
let _o = async || f();
}

View file

@ -0,0 +1,96 @@
error: an async construct yields a type which is itself awaitable
--> $DIR/async_yields_async.rs:40:9
|
LL | let _h = async {
| ____________________-
LL | | async {
| |_________^
LL | || 3
LL | || }
| ||_________^ awaitable value not awaited
LL | | };
| |_____- outer async construct
|
= note: `-D clippy::async-yields-async` implied by `-D warnings`
help: consider awaiting this value
|
LL | async {
LL | 3
LL | }.await
|
error: an async construct yields a type which is itself awaitable
--> $DIR/async_yields_async.rs:45:9
|
LL | let _i = async {
| ____________________-
LL | | CustomFutureType
| | ^^^^^^^^^^^^^^^^
| | |
| | awaitable value not awaited
| | help: consider awaiting this value: `CustomFutureType.await`
LL | | };
| |_____- outer async construct
error: an async construct yields a type which is itself awaitable
--> $DIR/async_yields_async.rs:51:9
|
LL | let _j = async || {
| _______________________-
LL | | async {
| |_________^
LL | || 3
LL | || }
| ||_________^ awaitable value not awaited
LL | | };
| |_____- outer async construct
|
help: consider awaiting this value
|
LL | async {
LL | 3
LL | }.await
|
error: an async construct yields a type which is itself awaitable
--> $DIR/async_yields_async.rs:56:9
|
LL | let _k = async || {
| _______________________-
LL | | CustomFutureType
| | ^^^^^^^^^^^^^^^^
| | |
| | awaitable value not awaited
| | help: consider awaiting this value: `CustomFutureType.await`
LL | | };
| |_____- outer async construct
error: an async construct yields a type which is itself awaitable
--> $DIR/async_yields_async.rs:58:23
|
LL | let _l = async || CustomFutureType;
| ^^^^^^^^^^^^^^^^
| |
| outer async construct
| awaitable value not awaited
| 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
|
LL | let _m = async || {
| _______________________-
LL | | println!("I'm bored");
LL | | // Some more stuff
LL | |
LL | | // Finally something to await
LL | | CustomFutureType
| | ^^^^^^^^^^^^^^^^
| | |
| | awaitable value not awaited
| | help: consider awaiting this value: `CustomFutureType.await`
LL | | };
| |_____- outer async construct
error: aborting due to 6 previous errors

View file

@ -135,4 +135,7 @@ fn main() {
if truth() {}
}
}
// Fix #5962
if matches!(true, true) && matches!(true, true) {}
}

View file

@ -149,4 +149,9 @@ fn main() {
if truth() {}
}
}
// Fix #5962
if matches!(true, true) {
if matches!(true, true) {}
}
}

View file

@ -118,5 +118,13 @@ LL | println!("Hello world!");
LL | }
|
error: aborting due to 7 previous errors
error: this `if` statement can be collapsed
--> $DIR/collapsible_if.rs:154:5
|
LL | / if matches!(true, true) {
LL | | if matches!(true, true) {}
LL | | }
| |_____^ help: collapse nested if block: `if matches!(true, true) && matches!(true, true) {}`
error: aborting due to 8 previous errors

View file

@ -0,0 +1,106 @@
// run-rustfix
#![allow(unused_imports)]
#![deny(clippy::default_trait_access)]
use std::default;
use std::default::Default as D2;
use std::string;
fn main() {
let s1: String = std::string::String::default();
let s2 = String::default();
let s3: String = std::string::String::default();
let s4: String = std::string::String::default();
let s5 = string::String::default();
let s6: String = std::string::String::default();
let s7 = std::string::String::default();
let s8: String = DefaultFactory::make_t_badly();
let s9: String = DefaultFactory::make_t_nicely();
let s10 = DerivedDefault::default();
let s11: GenericDerivedDefault<String> = GenericDerivedDefault::default();
let s12 = GenericDerivedDefault::<String>::default();
let s13 = TupleDerivedDefault::default();
let s14: TupleDerivedDefault = TupleDerivedDefault::default();
let s15: ArrayDerivedDefault = ArrayDerivedDefault::default();
let s16 = ArrayDerivedDefault::default();
let s17: TupleStructDerivedDefault = TupleStructDerivedDefault::default();
let s18 = TupleStructDerivedDefault::default();
let s19 = <DerivedDefault as Default>::default();
println!(
"[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}], [{:?}]",
s1,
s2,
s3,
s4,
s5,
s6,
s7,
s8,
s9,
s10,
s11,
s12,
s13,
s14,
s15,
s16,
s17,
s18,
s19,
);
}
struct DefaultFactory;
impl DefaultFactory {
pub fn make_t_badly<T: Default>() -> T {
Default::default()
}
pub fn make_t_nicely<T: Default>() -> T {
T::default()
}
}
#[derive(Debug, Default)]
struct DerivedDefault {
pub s: String,
}
#[derive(Debug, Default)]
struct GenericDerivedDefault<T: Default + std::fmt::Debug> {
pub s: T,
}
#[derive(Debug, Default)]
struct TupleDerivedDefault {
pub s: (String, String),
}
#[derive(Debug, Default)]
struct ArrayDerivedDefault {
pub s: [String; 10],
}
#[derive(Debug, Default)]
struct TupleStructDerivedDefault(String);

View file

@ -1,4 +1,7 @@
#![warn(clippy::default_trait_access)]
// run-rustfix
#![allow(unused_imports)]
#![deny(clippy::default_trait_access)]
use std::default;
use std::default::Default as D2;

View file

@ -1,49 +1,53 @@
error: calling `std::string::String::default()` is more clear than this expression
--> $DIR/default_trait_access.rs:8:22
--> $DIR/default_trait_access.rs:11:22
|
LL | let s1: String = Default::default();
| ^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()`
|
= note: `-D clippy::default-trait-access` implied by `-D warnings`
note: the lint level is defined here
--> $DIR/default_trait_access.rs:4:9
|
LL | #![deny(clippy::default_trait_access)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: calling `std::string::String::default()` is more clear than this expression
--> $DIR/default_trait_access.rs:12:22
--> $DIR/default_trait_access.rs:15:22
|
LL | let s3: String = D2::default();
| ^^^^^^^^^^^^^ help: try: `std::string::String::default()`
error: calling `std::string::String::default()` is more clear than this expression
--> $DIR/default_trait_access.rs:14:22
--> $DIR/default_trait_access.rs:17:22
|
LL | let s4: String = std::default::Default::default();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()`
error: calling `std::string::String::default()` is more clear than this expression
--> $DIR/default_trait_access.rs:18:22
--> $DIR/default_trait_access.rs:21:22
|
LL | let s6: String = default::Default::default();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()`
error: calling `GenericDerivedDefault<std::string::String>::default()` is more clear than this expression
--> $DIR/default_trait_access.rs:28:46
error: calling `GenericDerivedDefault::default()` is more clear than this expression
--> $DIR/default_trait_access.rs:31:46
|
LL | let s11: GenericDerivedDefault<String> = Default::default();
| ^^^^^^^^^^^^^^^^^^ help: try: `GenericDerivedDefault<std::string::String>::default()`
| ^^^^^^^^^^^^^^^^^^ help: try: `GenericDerivedDefault::default()`
error: calling `TupleDerivedDefault::default()` is more clear than this expression
--> $DIR/default_trait_access.rs:34:36
--> $DIR/default_trait_access.rs:37:36
|
LL | let s14: TupleDerivedDefault = Default::default();
| ^^^^^^^^^^^^^^^^^^ help: try: `TupleDerivedDefault::default()`
error: calling `ArrayDerivedDefault::default()` is more clear than this expression
--> $DIR/default_trait_access.rs:36:36
--> $DIR/default_trait_access.rs:39:36
|
LL | let s15: ArrayDerivedDefault = Default::default();
| ^^^^^^^^^^^^^^^^^^ help: try: `ArrayDerivedDefault::default()`
error: calling `TupleStructDerivedDefault::default()` is more clear than this expression
--> $DIR/default_trait_access.rs:40:42
--> $DIR/default_trait_access.rs:43:42
|
LL | let s17: TupleStructDerivedDefault = Default::default();
| ^^^^^^^^^^^^^^^^^^ help: try: `TupleStructDerivedDefault::default()`

View file

@ -49,6 +49,16 @@ fn test_emphasis() {
fn test_units() {
}
/// This tests allowed identifiers.
/// DirectX
/// ECMAScript
/// OAuth GraphQL
/// TeX LaTeX BibTeX BibLaTeX
/// 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].
@ -168,9 +178,6 @@ fn issue_1920() {}
/// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels
fn issue_1832() {}
/// Ok: CamelCase (It should not be surrounded by backticks)
fn issue_2395() {}
/// An iterator over mycrate::Collection's values.
/// It should not lint a `'static` lifetime in ticks.
fn issue_2210() {}

View file

@ -54,131 +54,137 @@ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the doc
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:58: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:52:22
--> $DIR/doc.rs:62: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:55:21
--> $DIR/doc.rs:65: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:65:5
--> $DIR/doc.rs:75:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: you should put `CamelCaseThing` between ticks in the documentation
--> $DIR/doc.rs:73:8
--> $DIR/doc.rs:83:8
|
LL | /// ## CamelCaseThing
| ^^^^^^^^^^^^^^
error: you should put `CamelCaseThing` between ticks in the documentation
--> $DIR/doc.rs:76:7
--> $DIR/doc.rs:86:7
|
LL | /// # CamelCaseThing
| ^^^^^^^^^^^^^^
error: you should put `CamelCaseThing` between ticks in the documentation
--> $DIR/doc.rs:78:22
--> $DIR/doc.rs:88: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:79:5
--> $DIR/doc.rs:89: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:86:5
--> $DIR/doc.rs:96: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:99:5
--> $DIR/doc.rs:109:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: you should put `FooBar` between ticks in the documentation
--> $DIR/doc.rs:110:43
--> $DIR/doc.rs:120:43
|
LL | /** E.g., serialization of an empty list: FooBar
| ^^^^^^
error: you should put `BarQuz` between ticks in the documentation
--> $DIR/doc.rs:115:5
--> $DIR/doc.rs:125: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:116:1
--> $DIR/doc.rs:126:1
|
LL | be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: you should put `FooBar` between ticks in the documentation
--> $DIR/doc.rs:121:43
--> $DIR/doc.rs:131:43
|
LL | /** E.g., serialization of an empty list: FooBar
| ^^^^^^
error: you should put `BarQuz` between ticks in the documentation
--> $DIR/doc.rs:126:5
--> $DIR/doc.rs:136: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:127:1
--> $DIR/doc.rs:137: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:138:5
--> $DIR/doc.rs:148: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:165:13
--> $DIR/doc.rs:175:13
|
LL | /// Not ok: http://www.unicode.org
| ^^^^^^^^^^^^^^^^^^^^^^
error: you should put bare URLs between `<`/`>` or make a proper Markdown link
--> $DIR/doc.rs:166:13
--> $DIR/doc.rs:176:13
|
LL | /// Not ok: https://www.unicode.org
| ^^^^^^^^^^^^^^^^^^^^^^^
error: you should put bare URLs between `<`/`>` or make a proper Markdown link
--> $DIR/doc.rs:167:13
--> $DIR/doc.rs:177:13
|
LL | /// Not ok: http://www.unicode.org/
| ^^^^^^^^^^^^^^^^^^^^^^
error: you should put bare URLs between `<`/`>` or make a proper Markdown link
--> $DIR/doc.rs:168:13
--> $DIR/doc.rs:178: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:174:22
--> $DIR/doc.rs:181:22
|
LL | /// An iterator over mycrate::Collection's values.
| ^^^^^^^^^^^^^^^^^^^
error: aborting due to 30 previous errors
error: aborting due to 31 previous errors

View file

@ -1,4 +1,4 @@
error: this function has a large number of lines
error: this function has too many lines (102/100)
--> $DIR/functions_maxlines.rs:58:1
|
LL | / fn bad_lines() {

View file

@ -58,12 +58,6 @@ fn or_fun_call() {
let without_default = Some(Foo);
without_default.unwrap_or_else(Foo::new);
let mut map = HashMap::<u64, String>::new();
map.entry(42).or_insert_with(String::new);
let mut btree = BTreeMap::<u64, String>::new();
btree.entry(42).or_insert_with(String::new);
let stringy = Some(String::from(""));
let _ = stringy.unwrap_or_else(|| "".to_owned());
@ -122,6 +116,17 @@ pub fn skip_const_fn_with_no_args() {
Some(42)
}
let _ = None.or(foo());
// See issue #5693.
let mut map = std::collections::HashMap::new();
map.insert(1, vec![1]);
map.entry(1).or_insert(vec![]);
let mut map = HashMap::<u64, String>::new();
map.entry(42).or_insert(String::new());
let mut btree = BTreeMap::<u64, String>::new();
btree.entry(42).or_insert(String::new());
}
fn main() {}

View file

@ -58,12 +58,6 @@ fn or_fun_call() {
let without_default = Some(Foo);
without_default.unwrap_or(Foo::new());
let mut map = HashMap::<u64, String>::new();
map.entry(42).or_insert(String::new());
let mut btree = BTreeMap::<u64, String>::new();
btree.entry(42).or_insert(String::new());
let stringy = Some(String::from(""));
let _ = stringy.unwrap_or("".to_owned());
@ -122,6 +116,17 @@ pub fn skip_const_fn_with_no_args() {
Some(42)
}
let _ = None.or(foo());
// See issue #5693.
let mut map = std::collections::HashMap::new();
map.insert(1, vec![1]);
map.entry(1).or_insert(vec![]);
let mut map = HashMap::<u64, String>::new();
map.entry(42).or_insert(String::new());
let mut btree = BTreeMap::<u64, String>::new();
btree.entry(42).or_insert(String::new());
}
fn main() {}

View file

@ -60,35 +60,23 @@ error: use of `unwrap_or` followed by a function call
LL | without_default.unwrap_or(Foo::new());
| ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(Foo::new)`
error: use of `or_insert` followed by a function call
--> $DIR/or_fun_call.rs:62:19
|
LL | map.entry(42).or_insert(String::new());
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)`
error: use of `or_insert` followed by a function call
--> $DIR/or_fun_call.rs:65:21
|
LL | btree.entry(42).or_insert(String::new());
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)`
error: use of `unwrap_or` followed by a function call
--> $DIR/or_fun_call.rs:68:21
--> $DIR/or_fun_call.rs:62:21
|
LL | let _ = stringy.unwrap_or("".to_owned());
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "".to_owned())`
error: use of `or` followed by a function call
--> $DIR/or_fun_call.rs:93:35
--> $DIR/or_fun_call.rs:87:35
|
LL | let _ = Some("a".to_string()).or(Some("b".to_string()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some("b".to_string()))`
error: use of `or` followed by a function call
--> $DIR/or_fun_call.rs:97:10
--> $DIR/or_fun_call.rs:91:10
|
LL | .or(Some(Bar(b, Duration::from_secs(2))));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some(Bar(b, Duration::from_secs(2))))`
error: aborting due to 15 previous errors
error: aborting due to 13 previous errors

View file

@ -94,4 +94,21 @@ fn main() {
vec13.push(item);
item += 10;
}
// Fix #5979
let mut vec14: Vec<std::fs::File> = Vec::new();
for _ in 0..10 {
vec14.push(std::fs::File::open("foobar").unwrap());
}
// Fix #5979
#[derive(Clone)]
struct S {}
trait T {}
impl T for S {}
let mut vec15: Vec<Box<dyn T>> = Vec::new();
for _ in 0..10 {
vec15.push(Box::new(S {}));
}
}

View file

@ -51,4 +51,12 @@ fn transmute_ptr_to_ptr() {
let _: &GenericParam<&LifetimeParam<'static>> = unsafe { std::mem::transmute(&GenericParam { t: &lp }) };
}
// dereferencing raw pointers in const contexts, should not lint as it's unstable (issue 5959)
const _: &() = {
struct ZST;
let zst = &ZST;
unsafe { std::mem::transmute::<&'static ZST, &'static ()>(zst) }
};
fn main() {}

View file

@ -25,17 +25,25 @@ fn unnecessary_sort_by() {
vec.sort_by(|_, b| b.cmp(&5));
vec.sort_by(|_, b| b.cmp(c));
vec.sort_unstable_by(|a, _| a.cmp(c));
// Ignore vectors of references
let mut vec: Vec<&&&isize> = vec![&&&3, &&&6, &&&1, &&&2, &&&5];
vec.sort_by(|a, b| (***a).abs().cmp(&(***b).abs()));
vec.sort_unstable_by(|a, b| (***a).abs().cmp(&(***b).abs()));
vec.sort_by(|a, b| b.cmp(a));
vec.sort_unstable_by(|a, b| b.cmp(a));
}
// Should not be linted to avoid hitting https://github.com/rust-lang/rust/issues/34162
// Do not suggest returning a reference to the closure parameter of `Vec::sort_by_key`
mod issue_5754 {
struct Test(String);
#[derive(Clone, Copy)]
struct Test(usize);
#[derive(PartialOrd, Ord, PartialEq, Eq)]
struct Wrapper<'a>(&'a str);
struct Wrapper<'a>(&'a usize);
impl Test {
fn name(&self) -> &str {
fn name(&self) -> &usize {
&self.0
}
@ -60,7 +68,33 @@ mod issue_5754 {
}
}
// `Vec::sort_by_key` closure parameter is `F: FnMut(&T) -> K`
// The suggestion is destructuring T and we know T is not a reference, so test that non-Copy T are
// not linted.
mod issue_6001 {
struct Test(String);
impl Test {
// Return an owned type so that we don't hit the fix for 5754
fn name(&self) -> String {
self.0.clone()
}
}
pub fn test() {
let mut args: Vec<Test> = vec![];
// Forward
args.sort_by(|a, b| a.name().cmp(&b.name()));
args.sort_unstable_by(|a, b| a.name().cmp(&b.name()));
// Reverse
args.sort_by(|a, b| b.name().cmp(&a.name()));
args.sort_unstable_by(|a, b| b.name().cmp(&a.name()));
}
}
fn main() {
unnecessary_sort_by();
issue_5754::test();
issue_6001::test();
}

View file

@ -25,17 +25,25 @@ fn unnecessary_sort_by() {
vec.sort_by(|_, b| b.cmp(&5));
vec.sort_by(|_, b| b.cmp(c));
vec.sort_unstable_by(|a, _| a.cmp(c));
// Ignore vectors of references
let mut vec: Vec<&&&isize> = vec![&&&3, &&&6, &&&1, &&&2, &&&5];
vec.sort_by(|a, b| (***a).abs().cmp(&(***b).abs()));
vec.sort_unstable_by(|a, b| (***a).abs().cmp(&(***b).abs()));
vec.sort_by(|a, b| b.cmp(a));
vec.sort_unstable_by(|a, b| b.cmp(a));
}
// Should not be linted to avoid hitting https://github.com/rust-lang/rust/issues/34162
// Do not suggest returning a reference to the closure parameter of `Vec::sort_by_key`
mod issue_5754 {
struct Test(String);
#[derive(Clone, Copy)]
struct Test(usize);
#[derive(PartialOrd, Ord, PartialEq, Eq)]
struct Wrapper<'a>(&'a str);
struct Wrapper<'a>(&'a usize);
impl Test {
fn name(&self) -> &str {
fn name(&self) -> &usize {
&self.0
}
@ -60,7 +68,33 @@ mod issue_5754 {
}
}
// `Vec::sort_by_key` closure parameter is `F: FnMut(&T) -> K`
// The suggestion is destructuring T and we know T is not a reference, so test that non-Copy T are
// not linted.
mod issue_6001 {
struct Test(String);
impl Test {
// Return an owned type so that we don't hit the fix for 5754
fn name(&self) -> String {
self.0.clone()
}
}
pub fn test() {
let mut args: Vec<Test> = vec![];
// Forward
args.sort_by(|a, b| a.name().cmp(&b.name()));
args.sort_unstable_by(|a, b| a.name().cmp(&b.name()));
// Reverse
args.sort_by(|a, b| b.name().cmp(&a.name()));
args.sort_unstable_by(|a, b| b.name().cmp(&a.name()));
}
}
fn main() {
unnecessary_sort_by();
issue_5754::test();
issue_6001::test();
}

View file

@ -49,6 +49,14 @@ mod a {
pub use self::b::C;
}
// don't lint on clippy::wildcard_imports for `use` items
#[allow(clippy::wildcard_imports)]
pub use std::io::prelude::*;
// don't lint on clippy::enum_glob_use for `use` items
#[allow(clippy::enum_glob_use)]
pub use std::cmp::Ordering::*;
fn test_indented_attr() {
#![allow(clippy::almost_swapped)]
use std::collections::HashSet;

View file

@ -49,6 +49,14 @@ mod a {
pub use self::b::C;
}
// don't lint on clippy::wildcard_imports for `use` items
#[allow(clippy::wildcard_imports)]
pub use std::io::prelude::*;
// don't lint on clippy::enum_glob_use for `use` items
#[allow(clippy::enum_glob_use)]
pub use std::cmp::Ordering::*;
fn test_indented_attr() {
#[allow(clippy::almost_swapped)]
use std::collections::HashSet;

View file

@ -13,7 +13,7 @@ LL | #[cfg_attr(feature = "cargo-clippy", allow(dead_code))]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if you just forgot a `!`, use: `#![cfg_attr(feature = "cargo-clippy", allow(dead_code)`
error: useless lint attribute
--> $DIR/useless_attribute.rs:53:5
--> $DIR/useless_attribute.rs:61:5
|
LL | #[allow(clippy::almost_swapped)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if you just forgot a `!`, use: `#![allow(clippy::almost_swapped)]`

View file

@ -1,7 +0,0 @@
#!/bin/sh
CARGO_TARGET_DIR=$(pwd)/target/
export CARGO_TARGET_DIR
echo 'Deprecated! `util/dev` usage is deprecated, please use `cargo dev` instead.'
cd clippy_dev && cargo run -- "$@"