Merge remote-tracking branch 'upstream/master' into sync-from-rust
This commit is contained in:
commit
da86067775
23 changed files with 629 additions and 62 deletions
86
clippy_lints/src/async_yields_async.rs
Normal file
86
clippy_lints/src/async_yields_async.rs
Normal 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,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -55,8 +55,8 @@ impl<'tcx> LateLintPass<'tcx> for DefaultTraitAccess {
|
|||
// 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);
|
||||
if let ty::Adt(def, ..) = expr_ty.kind {
|
||||
let replacement = format!("{}::default()", cx.tcx.def_path_str(def.did));
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
DEFAULT_TRAIT_ACCESS,
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
/// ```
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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(..)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue