diff options
| author | flip1995 <philipp.krones@embecosm.com> | 2021-07-15 10:44:10 +0200 |
|---|---|---|
| committer | flip1995 <philipp.krones@embecosm.com> | 2021-07-15 10:44:10 +0200 |
| commit | e7bc41176e19930e4c3de355ae53bb915306f299 (patch) | |
| tree | da2a0c63728c524edcc51175f1dd75c4ee667b3d /src/tools/clippy/clippy_utils | |
| parent | b9197978a90be6f7570741eabe2da175fec75375 (diff) | |
| parent | 54a20a02ecd0e1352a871aa0990bcc8b8b03173e (diff) | |
| download | rust-e7bc41176e19930e4c3de355ae53bb915306f299.tar.gz rust-e7bc41176e19930e4c3de355ae53bb915306f299.zip | |
Merge commit '54a20a02ecd0e1352a871aa0990bcc8b8b03173e' into clippyup
Diffstat (limited to 'src/tools/clippy/clippy_utils')
| -rw-r--r-- | src/tools/clippy/clippy_utils/src/higher.rs | 108 | ||||
| -rw-r--r-- | src/tools/clippy/clippy_utils/src/lib.rs | 21 | ||||
| -rw-r--r-- | src/tools/clippy/clippy_utils/src/numeric_literal.rs | 3 | ||||
| -rw-r--r-- | src/tools/clippy/clippy_utils/src/paths.rs | 5 | ||||
| -rw-r--r-- | src/tools/clippy/clippy_utils/src/ty.rs | 22 | ||||
| -rw-r--r-- | src/tools/clippy/clippy_utils/src/usage.rs | 47 |
6 files changed, 175 insertions, 31 deletions
diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs index 8be36756b33..3e3e472e99f 100644 --- a/src/tools/clippy/clippy_utils/src/higher.rs +++ b/src/tools/clippy/clippy_utils/src/higher.rs @@ -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 + } + } + } +} diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 2f10472180f..6db221ab0fd 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -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. diff --git a/src/tools/clippy/clippy_utils/src/numeric_literal.rs b/src/tools/clippy/clippy_utils/src/numeric_literal.rs index 546706d51d7..4a28c7dd9a0 100644 --- a/src/tools/clippy/clippy_utils/src/numeric_literal.rs +++ b/src/tools/clippy/clippy_utils/src/numeric_literal.rs @@ -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); } diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs index b913d1ce8b1..c960eec3064 100644 --- a/src/tools/clippy/clippy_utils/src/paths.rs +++ b/src/tools/clippy/clippy_utils/src/paths.rs @@ -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"]; diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index 8857e77d898..3f5c5604d43 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -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` diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs index 2c55021ac88..182d8cb11ea 100644 --- a/src/tools/clippy/clippy_utils/src/usage.rs +++ b/src/tools/clippy/clippy_utils/src/usage.rs @@ -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); + } + } +} |
