方法检查
在某些情况下,我们可能希望在开发 lint 时检查方法。我们可能对两种问题感到好奇
- 调用:表达式是否调用了特定的方法?
- 定义:
impl
是否定义了一个方法?
检查 expr
是否调用特定方法
假设我们有一个 expr
,我们可以通过对 ExprKind
进行模式匹配来检查它是否调用了特定方法,例如 our_fancy_method
,我们可以通过 expr.kind
访问 ExprKind
。
#![allow(unused)] fn main() { use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_span::sym; use clippy_utils::is_trait_method; impl<'tcx> LateLintPass<'tcx> for OurFancyMethodLint { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { // Check our expr is calling a method with pattern matching if let hir::ExprKind::MethodCall(path, _, [self_arg, ..]) = &expr.kind // Check if the name of this method is `our_fancy_method` && path.ident.name.as_str() == "our_fancy_method" // We can check the type of the self argument whenever necessary. // (It's necessary if we want to check that method is specifically belonging to a specific trait, // for example, a `map` method could belong to user-defined trait instead of to `Iterator`) // See the next section for more information. && is_trait_method(cx, self_arg, sym::OurFancyTrait) { println!("`expr` is a method call for `our_fancy_method`"); } } } }
仔细查看 ExprKind
枚举变体 MethodCall
,以获取有关模式匹配的更多信息。正如在定义 Lint 中提到的,如果读者希望探索更多,methods
lint 类型充满了与 MethodCall
的模式匹配。
检查 impl
块是否实现了一个方法
有时我们想检查是否调用了某个方法,而其他时候我们想知道我们的 Ty
是否定义了一个方法。
要检查我们的 impl
块是否定义了一个方法 our_fancy_method
,我们将利用 check_impl_item
方法,该方法在我们喜爱的 LateLintPass
中可用(有关更多信息,请参阅 Clippy 书中的 “Lint Passes” 章节)。此方法为我们提供了一个 ImplItem
结构,它表示 impl
块中的任何内容。
让我们看看我们如何检查类型上 our_fancy_method
的实现
#![allow(unused)] fn main() { use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::return_ty; use rustc_hir::{ImplItem, ImplItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_span::symbol::sym; impl<'tcx> LateLintPass<'tcx> for MyTypeImpl { fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) { // Check if item is a method/function if let ImplItemKind::Fn(ref signature, _) = impl_item.kind // Check the method is named `our_fancy_method` && impl_item.ident.name.as_str() == "our_fancy_method" // We can also check it has a parameter `self` && signature.decl.implicit_self.has_implicit_self() // We can go even further and even check if its return type is `String` && is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym::String) { println!("`our_fancy_method` is implemented!"); } } } }