# Trait Checking

Besides type checking, we might want to examine if a specific type `Ty` implements certain trait when implementing a lint. There are three approaches to achieve this, depending on if the target trait that we want to examine has a diagnostic item, lang item, or neither.

## Using Diagnostic Items

As explained in the Rust Compiler Development Guide, diagnostic items are introduced for identifying types via Symbols.

For instance, if we want to examine whether an expression implements the `Iterator` trait, we could simply write the following code, providing the `LateContext` (`cx`), our expression at hand, and the symbol of the trait in question:

    #![allow(unused)]
    fn main() {
    use clippy_utils::is_trait_method;
    use rustc_hir::Expr;
    use rustc_lint::{LateContext, LateLintPass};
    use rustc_span::symbol::sym;

    impl LateLintPass<'_> for CheckIteratorTraitLint {
        fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
    		let implements_iterator = cx.tcx.get_diagnostic_item(sym::Iterator).map_or(false, |id| {
        		implements_trait(cx, cx.typeck_results().expr_ty(arg), id, &[])
    		});
    		if implements_iterator {
    			// [...]
    		}

        }
    }
    }

> Note: Refer to this index for all the defined `Symbol`s.

## Using Lang Items

Besides diagnostic items, we can also use `lang_items`. Take a look at the documentation to find that `LanguageItems` contains all language items defined in the compiler.

Using one of its `*_trait` method, we could obtain the DefId of any specific item, such as `Clone`, `Copy`, `Drop`, `Eq`, which are familiar to many Rustaceans.

For instance, if we want to examine whether an expression `expr` implements `Drop` trait, we could access `LanguageItems` via our `LateContext`'s TyCtxt, which provides a `lang_items` method that will return the id of `Drop` trait to us. Then, by calling Clippy utils function `implements_trait` we can check that the `Ty` of the `expr` implements the trait:

    #![allow(unused)]
    fn main() {
    use clippy_utils::implements_trait;
    use rustc_hir::Expr;
    use rustc_lint::{LateContext, LateLintPass};

    impl LateLintPass<'_> for CheckDropTraitLint {
        fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
            let ty = cx.typeck_results().expr_ty(expr);
            if cx.tcx.lang_items()
                .drop_trait()
                .map_or(false, |id| implements_trait(cx, ty, id, &[])) {
                    println!("`expr` implements `Drop` trait!");
                }
        }
    }
    }

## Using Type Path

If neither diagnostic item nor a language item is available, we can use `clippy_utils::paths` with the `match_trait_method` to determine trait implementation.

> Note: This approach should be avoided if possible, the best thing to do would be to make a PR to `rust-lang/rust` adding a diagnostic item.

Below, we check if the given `expr` implements the `Iterator`'s trait method `cloned` :

    #![allow(unused)]
    fn main() {
    use clippy_utils::{match_trait_method, paths};
    use rustc_hir::Expr;
    use rustc_lint::{LateContext, LateLintPass};

    impl LateLintPass<'_> for CheckTokioAsyncReadExtTrait {
        fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
            if match_trait_method(cx, expr, &paths::CORE_ITER_CLONED) {
                println!("`expr` implements `CORE_ITER_CLONED` trait!");
            }
        }
    }
    }