summaryrefslogtreecommitdiffstats
path: root/src/tools/clippy/clippy_utils/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/clippy/clippy_utils/src/lib.rs')
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs84
1 files changed, 54 insertions, 30 deletions
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 8322df862..62da850a1 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -1,9 +1,9 @@
#![feature(array_chunks)]
#![feature(box_patterns)]
#![feature(control_flow_enum)]
-#![feature(let_else)]
#![feature(let_chains)]
#![feature(lint_reasons)]
+#![cfg_attr(bootstrap, feature(let_else))]
#![feature(once_cell)]
#![feature(rustc_private)]
#![recursion_limit = "512"]
@@ -28,6 +28,7 @@ extern crate rustc_infer;
extern crate rustc_lexer;
extern crate rustc_lint;
extern crate rustc_middle;
+extern crate rustc_parse_format;
extern crate rustc_session;
extern crate rustc_span;
extern crate rustc_target;
@@ -39,6 +40,7 @@ pub mod sym_helper;
pub mod ast_utils;
pub mod attrs;
+mod check_proc_macro;
pub mod comparisons;
pub mod consts;
pub mod diagnostics;
@@ -59,6 +61,7 @@ pub mod usage;
pub mod visitors;
pub use self::attrs::*;
+pub use self::check_proc_macro::{is_from_proc_macro, is_span_if, is_span_match};
pub use self::hir_utils::{
both, count_eq, eq_expr_value, hash_expr, hash_stmt, over, HirEqInterExpr, SpanlessEq, SpanlessHash,
};
@@ -85,6 +88,7 @@ use rustc_hir::{
Mutability, Node, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind,
TraitRef, TyKind, UnOp,
};
+use rustc_lexer::{tokenize, TokenKind};
use rustc_lint::{LateContext, Level, Lint, LintContext};
use rustc_middle::hir::place::PlaceBase;
use rustc_middle::ty as rustc_ty;
@@ -102,6 +106,7 @@ use rustc_semver::RustcVersion;
use rustc_session::Session;
use rustc_span::hygiene::{ExpnKind, MacroKind};
use rustc_span::source_map::original_sp;
+use rustc_span::source_map::SourceMap;
use rustc_span::sym;
use rustc_span::symbol::{kw, Symbol};
use rustc_span::{Span, DUMMY_SP};
@@ -187,7 +192,7 @@ pub fn find_binding_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<
let hir = cx.tcx.hir();
if_chain! {
if let Some(Node::Pat(pat)) = hir.find(hir_id);
- if matches!(pat.kind, PatKind::Binding(BindingAnnotation::Unannotated, ..));
+ if matches!(pat.kind, PatKind::Binding(BindingAnnotation::NONE, ..));
let parent = hir.get_parent_node(hir_id);
if let Some(Node::Local(local)) = hir.find(parent);
then {
@@ -332,7 +337,7 @@ pub fn qpath_generic_tys<'tcx>(qpath: &QPath<'tcx>) -> impl Iterator<Item = &'tc
.map_or(&[][..], |a| a.args)
.iter()
.filter_map(|a| match a {
- hir::GenericArg::Type(ty) => Some(ty),
+ hir::GenericArg::Type(ty) => Some(*ty),
_ => None,
})
}
@@ -370,15 +375,19 @@ pub fn match_qpath(path: &QPath<'_>, segments: &[&str]) -> bool {
/// If the expression is a path, resolves it to a `DefId` and checks if it matches the given path.
///
-/// Please use `is_expr_diagnostic_item` if the target is a diagnostic item.
+/// Please use `is_path_diagnostic_item` if the target is a diagnostic item.
pub fn is_expr_path_def_path(cx: &LateContext<'_>, expr: &Expr<'_>, segments: &[&str]) -> bool {
path_def_id(cx, expr).map_or(false, |id| match_def_path(cx, id, segments))
}
-/// If the expression is a path, resolves it to a `DefId` and checks if it matches the given
-/// diagnostic item.
-pub fn is_expr_diagnostic_item(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) -> bool {
- path_def_id(cx, expr).map_or(false, |id| cx.tcx.is_diagnostic_item(diag_item, id))
+/// If `maybe_path` is a path node which resolves to an item, resolves it to a `DefId` and checks if
+/// it matches the given diagnostic item.
+pub fn is_path_diagnostic_item<'tcx>(
+ cx: &LateContext<'_>,
+ maybe_path: &impl MaybePath<'tcx>,
+ diag_item: Symbol,
+) -> bool {
+ path_def_id(cx, maybe_path).map_or(false, |id| cx.tcx.is_diagnostic_item(diag_item, id))
}
/// THIS METHOD IS DEPRECATED and will eventually be removed since it does not match against the
@@ -1022,26 +1031,26 @@ pub fn can_move_expr_to_closure<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'
v.allow_closure.then_some(v.captures)
}
+/// Arguments of a method: the receiver and all the additional arguments.
+pub type MethodArguments<'tcx> = Vec<(&'tcx Expr<'tcx>, &'tcx [Expr<'tcx>])>;
+
/// Returns the method names and argument list of nested method call expressions that make up
/// `expr`. method/span lists are sorted with the most recent call first.
-pub fn method_calls<'tcx>(
- expr: &'tcx Expr<'tcx>,
- max_depth: usize,
-) -> (Vec<Symbol>, Vec<&'tcx [Expr<'tcx>]>, Vec<Span>) {
+pub fn method_calls<'tcx>(expr: &'tcx Expr<'tcx>, max_depth: usize) -> (Vec<Symbol>, MethodArguments<'tcx>, Vec<Span>) {
let mut method_names = Vec::with_capacity(max_depth);
let mut arg_lists = Vec::with_capacity(max_depth);
let mut spans = Vec::with_capacity(max_depth);
let mut current = expr;
for _ in 0..max_depth {
- if let ExprKind::MethodCall(path, args, _) = &current.kind {
- if args.iter().any(|e| e.span.from_expansion()) {
+ if let ExprKind::MethodCall(path, receiver, args, _) = &current.kind {
+ if receiver.span.from_expansion() || args.iter().any(|e| e.span.from_expansion()) {
break;
}
method_names.push(path.ident.name);
- arg_lists.push(&**args);
+ arg_lists.push((*receiver, &**args));
spans.push(path.ident.span);
- current = &args[0];
+ current = receiver;
} else {
break;
}
@@ -1056,18 +1065,18 @@ pub fn method_calls<'tcx>(
/// `method_chain_args(expr, &["bar", "baz"])` will return a `Vec`
/// containing the `Expr`s for
/// `.bar()` and `.baz()`
-pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[&str]) -> Option<Vec<&'a [Expr<'a>]>> {
+pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[&str]) -> Option<Vec<(&'a Expr<'a>, &'a [Expr<'a>])>> {
let mut current = expr;
let mut matched = Vec::with_capacity(methods.len());
for method_name in methods.iter().rev() {
// method chains are stored last -> first
- if let ExprKind::MethodCall(path, args, _) = current.kind {
+ if let ExprKind::MethodCall(path, receiver, args, _) = current.kind {
if path.ident.name.as_str() == *method_name {
- if args.iter().any(|e| e.span.from_expansion()) {
+ if receiver.span.from_expansion() || args.iter().any(|e| e.span.from_expansion()) {
return None;
}
- matched.push(args); // build up `matched` backwards
- current = &args[0]; // go to parent expression
+ matched.push((receiver, args)); // build up `matched` backwards
+ current = receiver; // go to parent expression
} else {
return None;
}
@@ -1112,7 +1121,7 @@ pub struct ContainsName {
}
impl<'tcx> Visitor<'tcx> for ContainsName {
- fn visit_name(&mut self, _: Span, name: Symbol) {
+ fn visit_name(&mut self, name: Symbol) {
if self.name == name {
self.result = true;
}
@@ -1230,8 +1239,10 @@ pub fn get_enclosing_loop_or_multi_call_closure<'tcx>(
ty_is_fn_once_param(cx.tcx, ty.skip_binder(), predicates).then_some(())
})
},
- ExprKind::MethodCall(_, args, _) => {
- let i = args.iter().position(|arg| arg.hir_id == id)?;
+ ExprKind::MethodCall(_, receiver, args, _) => {
+ let i = std::iter::once(receiver)
+ .chain(args.iter())
+ .position(|arg| arg.hir_id == id)?;
let id = cx.typeck_results().type_dependent_def_id(e.hir_id)?;
let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i];
ty_is_fn_once_param(cx.tcx, ty, cx.tcx.param_env(id).caller_bounds()).then_some(())
@@ -1541,7 +1552,8 @@ pub fn iter_input_pats<'tcx>(decl: &FnDecl<'_>, body: &'tcx Body<'_>) -> impl It
pub fn is_try<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
fn is_ok(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
if_chain! {
- if let PatKind::TupleStruct(ref path, pat, None) = arm.pat.kind;
+ if let PatKind::TupleStruct(ref path, pat, ddpos) = arm.pat.kind;
+ if ddpos.as_opt_usize().is_none();
if is_lang_ctor(cx, path, ResultOk);
if let PatKind::Binding(_, hir_id, _, None) = pat[0].kind;
if path_to_local_id(arm.body, hir_id);
@@ -1803,7 +1815,7 @@ pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool
}
};
- let mut expr = &func.value;
+ let mut expr = func.value;
loop {
match expr.kind {
#[rustfmt::skip]
@@ -1892,8 +1904,8 @@ pub fn std_or_core(cx: &LateContext<'_>) -> Option<&'static str> {
pub fn is_no_std_crate(cx: &LateContext<'_>) -> bool {
cx.tcx.hir().attrs(hir::CRATE_HIR_ID).iter().any(|attr| {
- if let ast::AttrKind::Normal(ref attr, _) = attr.kind {
- attr.path == sym::no_std
+ if let ast::AttrKind::Normal(ref normal) = attr.kind {
+ normal.item.path == sym::no_std
} else {
false
}
@@ -1902,8 +1914,8 @@ pub fn is_no_std_crate(cx: &LateContext<'_>) -> bool {
pub fn is_no_core_crate(cx: &LateContext<'_>) -> bool {
cx.tcx.hir().attrs(hir::CRATE_HIR_ID).iter().any(|attr| {
- if let ast::AttrKind::Normal(ref attr, _) = attr.kind {
- attr.path == sym::no_core
+ if let ast::AttrKind::Normal(ref normal) = attr.kind {
+ normal.item.path == sym::no_core
} else {
false
}
@@ -2272,6 +2284,18 @@ pub fn walk_to_expr_usage<'tcx, T>(
None
}
+/// Checks whether a given span has any comment token
+/// This checks for all types of comment: line "//", block "/**", doc "///" "//!"
+pub fn span_contains_comment(sm: &SourceMap, span: Span) -> bool {
+ let Ok(snippet) = sm.span_to_snippet(span) else { return false };
+ return tokenize(&snippet).any(|token| {
+ matches!(
+ token.kind,
+ TokenKind::BlockComment { .. } | TokenKind::LineComment { .. }
+ )
+ });
+}
+
macro_rules! op_utils {
($($name:ident $assign:ident)*) => {
/// Binary operation traits like `LangItem::Add`