Merge commit '54a20a02ecd0e1352a871aa0990bcc8b8b03173e' into clippyup
This commit is contained in:
@@ -5,11 +5,11 @@
|
||||
|
||||
use crate::{is_expn_of, match_def_path, paths};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast;
|
||||
use rustc_ast::ast::{self, LitKind};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::{BorrowKind, Expr, ExprKind, StmtKind, UnOp};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::source_map::Span;
|
||||
use rustc_span::{sym, ExpnKind, Span, Symbol};
|
||||
|
||||
/// Converts a hir binary operator to the corresponding `ast` type.
|
||||
#[must_use]
|
||||
@@ -266,3 +266,107 @@ pub fn extract_assert_macro_args<'tcx>(e: &'tcx Expr<'tcx>) -> Option<Vec<&'tcx
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// A parsed `format!` expansion
|
||||
pub struct FormatExpn<'tcx> {
|
||||
/// Span of `format!(..)`
|
||||
pub call_site: Span,
|
||||
/// Inner `format_args!` expansion
|
||||
pub format_args: FormatArgsExpn<'tcx>,
|
||||
}
|
||||
|
||||
impl FormatExpn<'tcx> {
|
||||
/// Parses an expanded `format!` invocation
|
||||
pub fn parse(expr: &'tcx Expr<'tcx>) -> Option<Self> {
|
||||
if_chain! {
|
||||
if let ExprKind::Block(block, _) = expr.kind;
|
||||
if let [stmt] = block.stmts;
|
||||
if let StmtKind::Local(local) = stmt.kind;
|
||||
if let Some(init) = local.init;
|
||||
if let ExprKind::Call(_, [format_args]) = init.kind;
|
||||
let expn_data = expr.span.ctxt().outer_expn_data();
|
||||
if let ExpnKind::Macro(_, sym::format) = expn_data.kind;
|
||||
if let Some(format_args) = FormatArgsExpn::parse(format_args);
|
||||
then {
|
||||
Some(FormatExpn {
|
||||
call_site: expn_data.call_site,
|
||||
format_args,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A parsed `format_args!` expansion
|
||||
pub struct FormatArgsExpn<'tcx> {
|
||||
/// Span of the first argument, the format string
|
||||
pub format_string_span: Span,
|
||||
/// Values passed after the format string
|
||||
pub value_args: Vec<&'tcx Expr<'tcx>>,
|
||||
|
||||
/// String literal expressions which represent the format string split by "{}"
|
||||
pub format_string_parts: &'tcx [Expr<'tcx>],
|
||||
/// Symbols corresponding to [`format_string_parts`]
|
||||
pub format_string_symbols: Vec<Symbol>,
|
||||
/// Expressions like `ArgumentV1::new(arg0, Debug::fmt)`
|
||||
pub args: &'tcx [Expr<'tcx>],
|
||||
/// The final argument passed to `Arguments::new_v1_formatted`, if applicable
|
||||
pub fmt_expr: Option<&'tcx Expr<'tcx>>,
|
||||
}
|
||||
|
||||
impl FormatArgsExpn<'tcx> {
|
||||
/// Parses an expanded `format_args!` or `format_args_nl!` invocation
|
||||
pub fn parse(expr: &'tcx Expr<'tcx>) -> Option<Self> {
|
||||
if_chain! {
|
||||
if let ExpnKind::Macro(_, name) = expr.span.ctxt().outer_expn_data().kind;
|
||||
let name = name.as_str();
|
||||
if name.ends_with("format_args") || name.ends_with("format_args_nl");
|
||||
if let ExprKind::Call(_, args) = expr.kind;
|
||||
if let Some((strs_ref, args, fmt_expr)) = match args {
|
||||
// Arguments::new_v1
|
||||
[strs_ref, args] => Some((strs_ref, args, None)),
|
||||
// Arguments::new_v1_formatted
|
||||
[strs_ref, args, fmt_expr] => Some((strs_ref, args, Some(fmt_expr))),
|
||||
_ => None,
|
||||
};
|
||||
if let ExprKind::AddrOf(BorrowKind::Ref, _, strs_arr) = strs_ref.kind;
|
||||
if let ExprKind::Array(format_string_parts) = strs_arr.kind;
|
||||
if let Some(format_string_symbols) = format_string_parts
|
||||
.iter()
|
||||
.map(|e| {
|
||||
if let ExprKind::Lit(lit) = &e.kind {
|
||||
if let LitKind::Str(symbol, _style) = lit.node {
|
||||
return Some(symbol);
|
||||
}
|
||||
}
|
||||
None
|
||||
})
|
||||
.collect();
|
||||
if let ExprKind::AddrOf(BorrowKind::Ref, _, args) = args.kind;
|
||||
if let ExprKind::Match(args, [arm], _) = args.kind;
|
||||
if let ExprKind::Tup(value_args) = args.kind;
|
||||
if let Some(value_args) = value_args
|
||||
.iter()
|
||||
.map(|e| match e.kind {
|
||||
ExprKind::AddrOf(_, _, e) => Some(e),
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
if let ExprKind::Array(args) = arm.body.kind;
|
||||
then {
|
||||
Some(FormatArgsExpn {
|
||||
format_string_span: strs_ref.span,
|
||||
value_args,
|
||||
format_string_parts,
|
||||
format_string_symbols,
|
||||
args,
|
||||
fmt_expr,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1163,7 +1163,7 @@ pub fn is_try<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<&'tc
|
||||
/// Returns `true` if the lint is allowed in the current context
|
||||
///
|
||||
/// Useful for skipping long running code when it's unnecessary
|
||||
pub fn is_allowed(cx: &LateContext<'_>, lint: &'static Lint, id: HirId) -> bool {
|
||||
pub fn is_lint_allowed(cx: &LateContext<'_>, lint: &'static Lint, id: HirId) -> bool {
|
||||
cx.tcx.lint_level_at_node(lint, id).0 == Level::Allow
|
||||
}
|
||||
|
||||
@@ -1531,25 +1531,6 @@ pub fn fn_def_id(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<DefId> {
|
||||
}
|
||||
}
|
||||
|
||||
/// This function checks if any of the lints in the slice is enabled for the provided `HirId`.
|
||||
/// A lint counts as enabled with any of the levels: `Level::Forbid` | `Level::Deny` | `Level::Warn`
|
||||
///
|
||||
/// ```ignore
|
||||
/// #[deny(clippy::YOUR_AWESOME_LINT)]
|
||||
/// println!("Hello, World!"); // <- Clippy code: run_lints(cx, &[YOUR_AWESOME_LINT], id) == true
|
||||
///
|
||||
/// #[allow(clippy::YOUR_AWESOME_LINT)]
|
||||
/// println!("See you soon!"); // <- Clippy code: run_lints(cx, &[YOUR_AWESOME_LINT], id) == false
|
||||
/// ```
|
||||
pub fn run_lints(cx: &LateContext<'_>, lints: &[&'static Lint], id: HirId) -> bool {
|
||||
lints.iter().any(|lint| {
|
||||
matches!(
|
||||
cx.tcx.lint_level_at_node(lint, id),
|
||||
(Level::Forbid | Level::Deny | Level::Warn, _)
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns Option<String> where String is a textual representation of the type encapsulated in the
|
||||
/// slice iff the given expression is a slice of primitives (as defined in the
|
||||
/// `is_recursively_primitive_type` function) and None otherwise.
|
||||
|
||||
@@ -162,6 +162,9 @@ impl<'a> NumericLiteral<'a> {
|
||||
}
|
||||
|
||||
if let Some(suffix) = self.suffix {
|
||||
if output.ends_with('.') {
|
||||
output.push('0');
|
||||
}
|
||||
output.push('_');
|
||||
output.push_str(suffix);
|
||||
}
|
||||
|
||||
@@ -38,7 +38,6 @@ pub const DEFAULT_TRAIT_METHOD: [&str; 4] = ["core", "default", "Default", "defa
|
||||
pub const DEREF_MUT_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "DerefMut", "deref_mut"];
|
||||
pub const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"];
|
||||
pub const DIR_BUILDER: [&str; 3] = ["std", "fs", "DirBuilder"];
|
||||
pub const DISPLAY_FMT_METHOD: [&str; 4] = ["core", "fmt", "Display", "fmt"];
|
||||
pub const DISPLAY_TRAIT: [&str; 3] = ["core", "fmt", "Display"];
|
||||
pub const DOUBLE_ENDED_ITERATOR: [&str; 4] = ["core", "iter", "traits", "DoubleEndedIterator"];
|
||||
pub const DROP: [&str; 3] = ["core", "mem", "drop"];
|
||||
@@ -50,9 +49,6 @@ pub const F32_EPSILON: [&str; 4] = ["core", "f32", "<impl f32>", "EPSILON"];
|
||||
pub const F64_EPSILON: [&str; 4] = ["core", "f64", "<impl f64>", "EPSILON"];
|
||||
pub const FILE: [&str; 3] = ["std", "fs", "File"];
|
||||
pub const FILE_TYPE: [&str; 3] = ["std", "fs", "FileType"];
|
||||
pub const FMT_ARGUMENTS_NEW_V1: [&str; 4] = ["core", "fmt", "Arguments", "new_v1"];
|
||||
pub const FMT_ARGUMENTS_NEW_V1_FORMATTED: [&str; 4] = ["core", "fmt", "Arguments", "new_v1_formatted"];
|
||||
pub const FMT_ARGUMENTV1_NEW: [&str; 4] = ["core", "fmt", "ArgumentV1", "new"];
|
||||
pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"];
|
||||
pub const FROM_ITERATOR: [&str; 5] = ["core", "iter", "traits", "collect", "FromIterator"];
|
||||
pub const FROM_ITERATOR_METHOD: [&str; 6] = ["core", "iter", "traits", "collect", "FromIterator", "from_iter"];
|
||||
@@ -82,6 +78,7 @@ pub const ITER_REPEAT: [&str; 5] = ["core", "iter", "sources", "repeat", "repeat
|
||||
pub const KW_MODULE: [&str; 3] = ["rustc_span", "symbol", "kw"];
|
||||
#[cfg(feature = "internal-lints")]
|
||||
pub const LATE_CONTEXT: [&str; 2] = ["rustc_lint", "LateContext"];
|
||||
pub const LIBC_STRLEN: [&str; 2] = ["libc", "strlen"];
|
||||
pub const LINKED_LIST: [&str; 4] = ["alloc", "collections", "linked_list", "LinkedList"];
|
||||
#[cfg(any(feature = "internal-lints", feature = "metadata-collector-lint"))]
|
||||
pub const LINT: [&str; 2] = ["rustc_lint_defs", "Lint"];
|
||||
|
||||
@@ -14,8 +14,8 @@ use rustc_middle::ty::{self, AdtDef, IntTy, Ty, TypeFoldable, UintTy};
|
||||
use rustc_span::sym;
|
||||
use rustc_span::symbol::{Ident, Symbol};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_trait_selection::traits::query::normalize::AtExt;
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::query::normalize::AtExt;
|
||||
|
||||
use crate::{match_def_path, must_use_attr};
|
||||
|
||||
@@ -129,10 +129,11 @@ pub fn implements_trait<'tcx>(
|
||||
return false;
|
||||
}
|
||||
let ty_params = cx.tcx.mk_substs(ty_params.iter());
|
||||
cx.tcx.infer_ctxt().enter(|infcx|
|
||||
infcx.type_implements_trait(trait_id, ty, ty_params, cx.param_env)
|
||||
.must_apply_modulo_regions()
|
||||
)
|
||||
cx.tcx.infer_ctxt().enter(|infcx| {
|
||||
infcx
|
||||
.type_implements_trait(trait_id, ty, ty_params, cx.param_env)
|
||||
.must_apply_modulo_regions()
|
||||
})
|
||||
}
|
||||
|
||||
/// Checks whether this type implements `Drop`.
|
||||
@@ -235,6 +236,17 @@ pub fn is_recursively_primitive_type(ty: Ty<'_>) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if the type is a reference equals to a diagnostic item
|
||||
pub fn is_type_ref_to_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symbol) -> bool {
|
||||
match ty.kind() {
|
||||
ty::Ref(_, ref_ty, _) => match ref_ty.kind() {
|
||||
ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(diag_item, adt.did),
|
||||
_ => false,
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if the type is equal to a diagnostic item
|
||||
///
|
||||
/// If you change the signature, remember to update the internal lint `MatchTypeOnDiagItem`
|
||||
|
||||
@@ -199,3 +199,50 @@ pub fn contains_return_break_continue_macro(expression: &Expr<'_>) -> bool {
|
||||
recursive_visitor.visit_expr(expression);
|
||||
recursive_visitor.seen_return_break_continue
|
||||
}
|
||||
|
||||
pub struct UsedAfterExprVisitor<'a, 'tcx> {
|
||||
cx: &'a LateContext<'tcx>,
|
||||
expr: &'tcx Expr<'tcx>,
|
||||
definition: HirId,
|
||||
past_expr: bool,
|
||||
used_after_expr: bool,
|
||||
}
|
||||
impl<'a, 'tcx> UsedAfterExprVisitor<'a, 'tcx> {
|
||||
pub fn is_found(cx: &'a LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool {
|
||||
utils::path_to_local(expr).map_or(false, |definition| {
|
||||
let mut visitor = UsedAfterExprVisitor {
|
||||
cx,
|
||||
expr,
|
||||
definition,
|
||||
past_expr: false,
|
||||
used_after_expr: false,
|
||||
};
|
||||
utils::get_enclosing_block(cx, definition).map_or(false, |block| {
|
||||
visitor.visit_block(block);
|
||||
visitor.used_after_expr
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> intravisit::Visitor<'tcx> for UsedAfterExprVisitor<'a, 'tcx> {
|
||||
type Map = Map<'tcx>;
|
||||
|
||||
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
|
||||
NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
|
||||
if self.used_after_expr {
|
||||
return;
|
||||
}
|
||||
|
||||
if expr.hir_id == self.expr.hir_id {
|
||||
self.past_expr = true;
|
||||
} else if self.past_expr && utils::path_to_local_id(expr, self.definition) {
|
||||
self.used_after_expr = true;
|
||||
} else {
|
||||
intravisit::walk_expr(self, expr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user