]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/serde_api.rs
Auto merge of #3596 - xfix:remove-crate-from-paths, r=flip1995
[rust.git] / clippy_lints / src / serde_api.rs
1 // Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution.
3 //
4 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7 // option. This file may not be copied, modified, or distributed
8 // except according to those terms.
9
10 use crate::utils::{get_trait_def_id, paths, span_lint};
11 use rustc::hir::*;
12 use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
13 use rustc::{declare_tool_lint, lint_array};
14
15 /// **What it does:** Checks for mis-uses of the serde API.
16 ///
17 /// **Why is this bad?** Serde is very finnicky about how its API should be
18 /// used, but the type system can't be used to enforce it (yet?).
19 ///
20 /// **Known problems:** None.
21 ///
22 /// **Example:** Implementing `Visitor::visit_string` but not
23 /// `Visitor::visit_str`.
24 declare_clippy_lint! {
25     pub SERDE_API_MISUSE,
26     correctness,
27     "various things that will negatively affect your serde experience"
28 }
29
30 #[derive(Copy, Clone)]
31 pub struct Serde;
32
33 impl LintPass for Serde {
34     fn get_lints(&self) -> LintArray {
35         lint_array!(SERDE_API_MISUSE)
36     }
37 }
38
39 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Serde {
40     fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
41         if let ItemKind::Impl(_, _, _, _, Some(ref trait_ref), _, ref items) = item.node {
42             let did = trait_ref.path.def.def_id();
43             if let Some(visit_did) = get_trait_def_id(cx, &paths::SERDE_DE_VISITOR) {
44                 if did == visit_did {
45                     let mut seen_str = None;
46                     let mut seen_string = None;
47                     for item in items {
48                         match &*item.ident.as_str() {
49                             "visit_str" => seen_str = Some(item.span),
50                             "visit_string" => seen_string = Some(item.span),
51                             _ => {},
52                         }
53                     }
54                     if let Some(span) = seen_string {
55                         if seen_str.is_none() {
56                             span_lint(
57                                 cx,
58                                 SERDE_API_MISUSE,
59                                 span,
60                                 "you should not implement `visit_string` without also implementing `visit_str`",
61                             );
62                         }
63                     }
64                 }
65             }
66         }
67     }
68 }