]> git.lizzy.rs Git - rust.git/blob - src/librustc/lint/internal.rs
3ae07968296999195523894c8624b124c59a383e
[rust.git] / src / librustc / lint / internal.rs
1 //! Some lints that are only useful in the compiler or crates that use compiler internals, such as
2 //! Clippy.
3
4 use crate::hir::{def::Def, HirId, Path, QPath, Ty, TyKind};
5 use crate::lint::{
6     EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintArray, LintContext, LintPass,
7 };
8 use errors::Applicability;
9 use rustc_data_structures::fx::FxHashMap;
10 use syntax::ast::Ident;
11
12 declare_lint! {
13     pub DEFAULT_HASH_TYPES,
14     Allow,
15     "forbid HashMap and HashSet and suggest the FxHash* variants"
16 }
17
18 pub struct DefaultHashTypes {
19     map: FxHashMap<String, String>,
20 }
21
22 impl DefaultHashTypes {
23     pub fn new() -> Self {
24         let mut map = FxHashMap::default();
25         map.insert("HashMap".to_string(), "FxHashMap".to_string());
26         map.insert("HashSet".to_string(), "FxHashSet".to_string());
27         Self { map }
28     }
29 }
30
31 impl LintPass for DefaultHashTypes {
32     fn get_lints(&self) -> LintArray {
33         lint_array!(DEFAULT_HASH_TYPES)
34     }
35
36     fn name(&self) -> &'static str {
37         "DefaultHashTypes"
38     }
39 }
40
41 impl EarlyLintPass for DefaultHashTypes {
42     fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: Ident) {
43         let ident_string = ident.to_string();
44         if let Some(replace) = self.map.get(&ident_string) {
45             let msg = format!(
46                 "Prefer {} over {}, it has better performance",
47                 replace, ident_string
48             );
49             let mut db = cx.struct_span_lint(DEFAULT_HASH_TYPES, ident.span, &msg);
50             db.span_suggestion(
51                 ident.span,
52                 "use",
53                 replace.to_string(),
54                 Applicability::MaybeIncorrect, // FxHashMap, ... needs another import
55             );
56             db.note(&format!(
57                 "a `use rustc_data_structures::fx::{}` may be necessary",
58                 replace
59             ))
60             .emit();
61         }
62     }
63 }
64
65 declare_lint! {
66     pub USAGE_OF_TY_TYKIND,
67     Allow,
68     "Usage of `ty::TyKind` outside of the `ty::sty` module"
69 }
70
71 pub struct TyKindUsage;
72
73 impl LintPass for TyKindUsage {
74     fn get_lints(&self) -> LintArray {
75         lint_array!(USAGE_OF_TY_TYKIND)
76     }
77
78     fn name(&self) -> &'static str {
79         "TyKindUsage"
80     }
81 }
82
83 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TyKindUsage {
84     fn check_path(&mut self, cx: &LateContext<'_, '_>, path: &'tcx Path, _: HirId) {
85         let segments_iter = path.segments.iter().rev().skip(1).rev();
86
87         if let Some(last) = segments_iter.clone().last() {
88             if last.ident.as_str() == "TyKind" {
89                 let path = Path {
90                     span: path.span.with_hi(last.ident.span.hi()),
91                     def: path.def,
92                     segments: segments_iter.cloned().collect(),
93                 };
94
95                 match last.def {
96                     Some(Def::Err) => (),
97                     Some(def)
98                         if def
99                             .def_id()
100                             .match_path(cx.tcx, &["rustc", "ty", "sty", "TyKind"]) =>
101                     {
102                         cx.struct_span_lint(
103                             USAGE_OF_TY_TYKIND,
104                             path.span,
105                             "usage of `ty::TyKind::<kind>`",
106                         )
107                         .span_suggestion(
108                             path.span,
109                             "try using ty::<kind> directly",
110                             "ty".to_string(),
111                             Applicability::MaybeIncorrect, // ty maybe needs an import
112                         )
113                         .emit();
114                     }
115                     _ => (),
116                 }
117             }
118         }
119     }
120
121     fn check_ty(&mut self, cx: &LateContext<'_, '_>, ty: &'tcx Ty) {
122         if let TyKind::Path(qpath) = &ty.node {
123             if let QPath::Resolved(_, path) = qpath {
124                 if let Some(last) = path.segments.iter().last() {
125                     if last.ident.as_str() == "TyKind" {
126                         if let Some(def) = last.def {
127                             if def
128                                 .def_id()
129                                 .match_path(cx.tcx, &["rustc", "ty", "sty", "TyKind"])
130                             {
131                                 cx.struct_span_lint(
132                                     USAGE_OF_TY_TYKIND,
133                                     path.span,
134                                     "usage of `ty::TyKind`",
135                                 )
136                                 .help("try using `ty::Ty` instead")
137                                 .emit();
138                             }
139                         }
140                     }
141                 }
142             }
143         }
144     }
145 }