]> git.lizzy.rs Git - rust.git/blob - src/librustc_lint/builtin.rs
Rollup merge of #63146 - Mark-Simulacrum:clean-attr, r=petrochenkov
[rust.git] / src / librustc_lint / builtin.rs
1 //! Lints in the Rust compiler.
2 //!
3 //! This contains lints which can feasibly be implemented as their own
4 //! AST visitor. Also see `rustc::lint::builtin`, which contains the
5 //! definitions of lints that are emitted directly inside the main
6 //! compiler.
7 //!
8 //! To add a new lint to rustc, declare it here using `declare_lint!()`.
9 //! Then add code to emit the new lint in the appropriate circumstances.
10 //! You can do that in an existing `LintPass` if it makes sense, or in a
11 //! new `LintPass`, or using `Session::add_lint` elsewhere in the
12 //! compiler. Only do the latter if the check can't be written cleanly as a
13 //! `LintPass` (also, note that such lints will need to be defined in
14 //! `rustc::lint::builtin`, not here).
15 //!
16 //! If you define a new `EarlyLintPass`, you will also need to add it to the
17 //! `add_early_builtin!` or `add_early_builtin_with_new!` invocation in
18 //! `lib.rs`. Use the former for unit-like structs and the latter for structs
19 //! with a `pub fn new()`.
20 //!
21 //! If you define a new `LateLintPass`, you will also need to add it to the
22 //! `late_lint_methods!` invocation in `lib.rs`.
23
24 use rustc::hir::def::{Res, DefKind};
25 use rustc::hir::def_id::{DefId, LOCAL_CRATE};
26 use rustc::ty::{self, Ty, TyCtxt};
27 use rustc::{lint, util};
28 use hir::Node;
29 use util::nodemap::HirIdSet;
30 use lint::{LateContext, LintContext, LintArray};
31 use lint::{LintPass, LateLintPass, EarlyLintPass, EarlyContext};
32
33 use rustc::util::nodemap::FxHashSet;
34
35 use syntax::tokenstream::{TokenTree, TokenStream};
36 use syntax::ast::{self, Expr};
37 use syntax::ptr::P;
38 use syntax::attr::{self, HasAttrs, AttributeTemplate};
39 use syntax::source_map::Spanned;
40 use syntax::edition::Edition;
41 use syntax::feature_gate::{self, AttributeGate, AttributeType};
42 use syntax::feature_gate::{Stability, deprecated_attributes};
43 use syntax_pos::{BytePos, Span, SyntaxContext};
44 use syntax::symbol::{Symbol, kw, sym};
45 use syntax::errors::{Applicability, DiagnosticBuilder};
46 use syntax::print::pprust::expr_to_string;
47 use syntax::visit::FnKind;
48
49 use rustc::hir::{self, GenericParamKind, PatKind};
50
51 use crate::nonstandard_style::{MethodLateContext, method_context};
52
53 use log::debug;
54
55 // hardwired lints from librustc
56 pub use lint::builtin::*;
57
58 declare_lint! {
59     WHILE_TRUE,
60     Warn,
61     "suggest using `loop { }` instead of `while true { }`"
62 }
63
64 declare_lint_pass!(WhileTrue => [WHILE_TRUE]);
65
66 /// Traverse through any amount of parenthesis and return the first non-parens expression.
67 fn pierce_parens(mut expr: &ast::Expr) -> &ast::Expr {
68     while let ast::ExprKind::Paren(sub) = &expr.node {
69         expr = sub;
70     }
71     expr
72 }
73
74 impl EarlyLintPass for WhileTrue {
75     fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
76         if let ast::ExprKind::While(cond, ..) = &e.node {
77             if let ast::ExprKind::Lit(ref lit) = pierce_parens(cond).node {
78                 if let ast::LitKind::Bool(true) = lit.node {
79                     if lit.span.ctxt() == SyntaxContext::empty() {
80                         let msg = "denote infinite loops with `loop { ... }`";
81                         let condition_span = cx.sess.source_map().def_span(e.span);
82                         cx.struct_span_lint(WHILE_TRUE, condition_span, msg)
83                             .span_suggestion_short(
84                                 condition_span,
85                                 "use `loop`",
86                                 "loop".to_owned(),
87                                 Applicability::MachineApplicable
88                             )
89                             .emit();
90                     }
91                 }
92             }
93         }
94     }
95 }
96
97 declare_lint! {
98     BOX_POINTERS,
99     Allow,
100     "use of owned (Box type) heap memory"
101 }
102
103 declare_lint_pass!(BoxPointers => [BOX_POINTERS]);
104
105 impl BoxPointers {
106     fn check_heap_type(&self, cx: &LateContext<'_, '_>, span: Span, ty: Ty<'_>) {
107         for leaf_ty in ty.walk() {
108             if leaf_ty.is_box() {
109                 let m = format!("type uses owned (Box type) pointers: {}", ty);
110                 cx.span_lint(BOX_POINTERS, span, &m);
111             }
112         }
113     }
114 }
115
116 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoxPointers {
117     fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item) {
118         match it.node {
119             hir::ItemKind::Fn(..) |
120             hir::ItemKind::Ty(..) |
121             hir::ItemKind::Enum(..) |
122             hir::ItemKind::Struct(..) |
123             hir::ItemKind::Union(..) => {
124                 let def_id = cx.tcx.hir().local_def_id(it.hir_id);
125                 self.check_heap_type(cx, it.span, cx.tcx.type_of(def_id))
126             }
127             _ => ()
128         }
129
130         // If it's a struct, we also have to check the fields' types
131         match it.node {
132             hir::ItemKind::Struct(ref struct_def, _) |
133             hir::ItemKind::Union(ref struct_def, _) => {
134                 for struct_field in struct_def.fields() {
135                     let def_id = cx.tcx.hir().local_def_id(struct_field.hir_id);
136                     self.check_heap_type(cx, struct_field.span,
137                                          cx.tcx.type_of(def_id));
138                 }
139             }
140             _ => (),
141         }
142     }
143
144     fn check_expr(&mut self, cx: &LateContext<'_, '_>, e: &hir::Expr) {
145         let ty = cx.tables.node_type(e.hir_id);
146         self.check_heap_type(cx, e.span, ty);
147     }
148 }
149
150 declare_lint! {
151     NON_SHORTHAND_FIELD_PATTERNS,
152     Warn,
153     "using `Struct { x: x }` instead of `Struct { x }` in a pattern"
154 }
155
156 declare_lint_pass!(NonShorthandFieldPatterns => [NON_SHORTHAND_FIELD_PATTERNS]);
157
158 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonShorthandFieldPatterns {
159     fn check_pat(&mut self, cx: &LateContext<'_, '_>, pat: &hir::Pat) {
160         if let PatKind::Struct(ref qpath, ref field_pats, _) = pat.node {
161             let variant = cx.tables.pat_ty(pat).ty_adt_def()
162                                    .expect("struct pattern type is not an ADT")
163                                    .variant_of_res(cx.tables.qpath_res(qpath, pat.hir_id));
164             for fieldpat in field_pats {
165                 if fieldpat.node.is_shorthand {
166                     continue;
167                 }
168                 if fieldpat.span.ctxt().outer_expn_info().is_some() {
169                     // Don't lint if this is a macro expansion: macro authors
170                     // shouldn't have to worry about this kind of style issue
171                     // (Issue #49588)
172                     continue;
173                 }
174                 if let PatKind::Binding(_, _, ident, None) = fieldpat.node.pat.node {
175                     if cx.tcx.find_field_index(ident, &variant) ==
176                        Some(cx.tcx.field_index(fieldpat.node.hir_id, cx.tables)) {
177                         let mut err = cx.struct_span_lint(NON_SHORTHAND_FIELD_PATTERNS,
178                                      fieldpat.span,
179                                      &format!("the `{}:` in this pattern is redundant", ident));
180                         let subspan = cx.tcx.sess.source_map().span_through_char(fieldpat.span,
181                                                                                  ':');
182                         err.span_suggestion_short(
183                             subspan,
184                             "remove this",
185                             ident.to_string(),
186                             Applicability::MachineApplicable
187                         );
188                         err.emit();
189                     }
190                 }
191             }
192         }
193     }
194 }
195
196 declare_lint! {
197     UNSAFE_CODE,
198     Allow,
199     "usage of `unsafe` code"
200 }
201
202 declare_lint_pass!(UnsafeCode => [UNSAFE_CODE]);
203
204 impl UnsafeCode {
205     fn report_unsafe(&self, cx: &EarlyContext<'_>, span: Span, desc: &'static str) {
206         // This comes from a macro that has `#[allow_internal_unsafe]`.
207         if span.allows_unsafe() {
208             return;
209         }
210
211         cx.span_lint(UNSAFE_CODE, span, desc);
212     }
213 }
214
215 impl EarlyLintPass for UnsafeCode {
216     fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
217         if attr.check_name(sym::allow_internal_unsafe) {
218             self.report_unsafe(cx, attr.span, "`allow_internal_unsafe` allows defining \
219                                                macros using unsafe without triggering \
220                                                the `unsafe_code` lint at their call site");
221         }
222     }
223
224     fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
225         if let ast::ExprKind::Block(ref blk, _) = e.node {
226             // Don't warn about generated blocks; that'll just pollute the output.
227             if blk.rules == ast::BlockCheckMode::Unsafe(ast::UserProvided) {
228                 self.report_unsafe(cx, blk.span, "usage of an `unsafe` block");
229             }
230         }
231     }
232
233     fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) {
234         match it.node {
235             ast::ItemKind::Trait(_, ast::Unsafety::Unsafe, ..) => {
236                 self.report_unsafe(cx, it.span, "declaration of an `unsafe` trait")
237             }
238
239             ast::ItemKind::Impl(ast::Unsafety::Unsafe, ..) => {
240                 self.report_unsafe(cx, it.span, "implementation of an `unsafe` trait")
241             }
242
243             _ => return,
244         }
245     }
246
247     fn check_fn(&mut self,
248                 cx: &EarlyContext<'_>,
249                 fk: FnKind<'_>,
250                 _: &ast::FnDecl,
251                 span: Span,
252                 _: ast::NodeId) {
253         match fk {
254             FnKind::ItemFn(_, ast::FnHeader { unsafety: ast::Unsafety::Unsafe, .. }, ..) => {
255                 self.report_unsafe(cx, span, "declaration of an `unsafe` function")
256             }
257
258             FnKind::Method(_, sig, ..) => {
259                 if sig.header.unsafety == ast::Unsafety::Unsafe {
260                     self.report_unsafe(cx, span, "implementation of an `unsafe` method")
261                 }
262             }
263
264             _ => (),
265         }
266     }
267
268     fn check_trait_item(&mut self, cx: &EarlyContext<'_>, item: &ast::TraitItem) {
269         if let ast::TraitItemKind::Method(ref sig, None) = item.node {
270             if sig.header.unsafety == ast::Unsafety::Unsafe {
271                 self.report_unsafe(cx, item.span, "declaration of an `unsafe` method")
272             }
273         }
274     }
275 }
276
277 declare_lint! {
278     pub MISSING_DOCS,
279     Allow,
280     "detects missing documentation for public members",
281     report_in_external_macro: true
282 }
283
284 pub struct MissingDoc {
285     /// Stack of whether `#[doc(hidden)]` is set at each level which has lint attributes.
286     doc_hidden_stack: Vec<bool>,
287
288     /// Private traits or trait items that leaked through. Don't check their methods.
289     private_traits: FxHashSet<hir::HirId>,
290 }
291
292 impl_lint_pass!(MissingDoc => [MISSING_DOCS]);
293
294 fn has_doc(attr: &ast::Attribute) -> bool {
295     if !attr.check_name(sym::doc) {
296         return false;
297     }
298
299     if attr.is_value_str() {
300         return true;
301     }
302
303     if let Some(list) = attr.meta_item_list() {
304         for meta in list {
305             if meta.check_name(sym::include) || meta.check_name(sym::hidden) {
306                 return true;
307             }
308         }
309     }
310
311     false
312 }
313
314 impl MissingDoc {
315     pub fn new() -> MissingDoc {
316         MissingDoc {
317             doc_hidden_stack: vec![false],
318             private_traits: FxHashSet::default(),
319         }
320     }
321
322     fn doc_hidden(&self) -> bool {
323         *self.doc_hidden_stack.last().expect("empty doc_hidden_stack")
324     }
325
326     fn check_missing_docs_attrs(&self,
327                                 cx: &LateContext<'_, '_>,
328                                 id: Option<hir::HirId>,
329                                 attrs: &[ast::Attribute],
330                                 sp: Span,
331                                 desc: &'static str) {
332         // If we're building a test harness, then warning about
333         // documentation is probably not really relevant right now.
334         if cx.sess().opts.test {
335             return;
336         }
337
338         // `#[doc(hidden)]` disables missing_docs check.
339         if self.doc_hidden() {
340             return;
341         }
342
343         // Only check publicly-visible items, using the result from the privacy pass.
344         // It's an option so the crate root can also use this function (it doesn't
345         // have a `NodeId`).
346         if let Some(id) = id {
347             if !cx.access_levels.is_exported(id) {
348                 return;
349             }
350         }
351
352         let has_doc = attrs.iter().any(|a| has_doc(a));
353         if !has_doc {
354             cx.span_lint(MISSING_DOCS,
355                          cx.tcx.sess.source_map().def_span(sp),
356                          &format!("missing documentation for {}", desc));
357         }
358     }
359 }
360
361 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc {
362     fn enter_lint_attrs(&mut self, _: &LateContext<'_, '_>, attrs: &[ast::Attribute]) {
363         let doc_hidden = self.doc_hidden() ||
364                          attrs.iter().any(|attr| {
365             attr.check_name(sym::doc) &&
366             match attr.meta_item_list() {
367                 None => false,
368                 Some(l) => attr::list_contains_name(&l, sym::hidden),
369             }
370         });
371         self.doc_hidden_stack.push(doc_hidden);
372     }
373
374     fn exit_lint_attrs(&mut self, _: &LateContext<'_, '_>, _attrs: &[ast::Attribute]) {
375         self.doc_hidden_stack.pop().expect("empty doc_hidden_stack");
376     }
377
378     fn check_crate(&mut self, cx: &LateContext<'_, '_>, krate: &hir::Crate) {
379         self.check_missing_docs_attrs(cx, None, &krate.attrs, krate.span, "crate");
380
381         for macro_def in &krate.exported_macros {
382             let has_doc = macro_def.attrs.iter().any(|a| has_doc(a));
383             if !has_doc {
384                 cx.span_lint(MISSING_DOCS,
385                              cx.tcx.sess.source_map().def_span(macro_def.span),
386                              "missing documentation for macro");
387             }
388         }
389     }
390
391     fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item) {
392         let desc = match it.node {
393             hir::ItemKind::Fn(..) => "a function",
394             hir::ItemKind::Mod(..) => "a module",
395             hir::ItemKind::Enum(..) => "an enum",
396             hir::ItemKind::Struct(..) => "a struct",
397             hir::ItemKind::Union(..) => "a union",
398             hir::ItemKind::Trait(.., ref trait_item_refs) => {
399                 // Issue #11592: traits are always considered exported, even when private.
400                 if let hir::VisibilityKind::Inherited = it.vis.node {
401                     self.private_traits.insert(it.hir_id);
402                     for trait_item_ref in trait_item_refs {
403                         self.private_traits.insert(trait_item_ref.id.hir_id);
404                     }
405                     return;
406                 }
407                 "a trait"
408             }
409             hir::ItemKind::Ty(..) => "a type alias",
410             hir::ItemKind::Impl(.., Some(ref trait_ref), _, ref impl_item_refs) => {
411                 // If the trait is private, add the impl items to `private_traits` so they don't get
412                 // reported for missing docs.
413                 let real_trait = trait_ref.path.res.def_id();
414                 if let Some(hir_id) = cx.tcx.hir().as_local_hir_id(real_trait) {
415                     match cx.tcx.hir().find(hir_id) {
416                         Some(Node::Item(item)) => {
417                             if let hir::VisibilityKind::Inherited = item.vis.node {
418                                 for impl_item_ref in impl_item_refs {
419                                     self.private_traits.insert(impl_item_ref.id.hir_id);
420                                 }
421                             }
422                         }
423                         _ => {}
424                     }
425                 }
426                 return;
427             }
428             hir::ItemKind::Const(..) => "a constant",
429             hir::ItemKind::Static(..) => "a static",
430             _ => return,
431         };
432
433         self.check_missing_docs_attrs(cx, Some(it.hir_id), &it.attrs, it.span, desc);
434     }
435
436     fn check_trait_item(&mut self, cx: &LateContext<'_, '_>, trait_item: &hir::TraitItem) {
437         if self.private_traits.contains(&trait_item.hir_id) {
438             return;
439         }
440
441         let desc = match trait_item.node {
442             hir::TraitItemKind::Const(..) => "an associated constant",
443             hir::TraitItemKind::Method(..) => "a trait method",
444             hir::TraitItemKind::Type(..) => "an associated type",
445         };
446
447         self.check_missing_docs_attrs(cx,
448                                       Some(trait_item.hir_id),
449                                       &trait_item.attrs,
450                                       trait_item.span,
451                                       desc);
452     }
453
454     fn check_impl_item(&mut self, cx: &LateContext<'_, '_>, impl_item: &hir::ImplItem) {
455         // If the method is an impl for a trait, don't doc.
456         if method_context(cx, impl_item.hir_id) == MethodLateContext::TraitImpl {
457             return;
458         }
459
460         let desc = match impl_item.node {
461             hir::ImplItemKind::Const(..) => "an associated constant",
462             hir::ImplItemKind::Method(..) => "a method",
463             hir::ImplItemKind::Type(_) => "an associated type",
464             hir::ImplItemKind::OpaqueTy(_) => "an associated `impl Trait` type",
465         };
466         self.check_missing_docs_attrs(cx,
467                                       Some(impl_item.hir_id),
468                                       &impl_item.attrs,
469                                       impl_item.span,
470                                       desc);
471     }
472
473     fn check_struct_field(&mut self, cx: &LateContext<'_, '_>, sf: &hir::StructField) {
474         if !sf.is_positional() {
475             self.check_missing_docs_attrs(cx,
476                                           Some(sf.hir_id),
477                                           &sf.attrs,
478                                           sf.span,
479                                           "a struct field")
480         }
481     }
482
483     fn check_variant(&mut self, cx: &LateContext<'_, '_>, v: &hir::Variant, _: &hir::Generics) {
484         self.check_missing_docs_attrs(cx,
485                                       Some(v.node.id),
486                                       &v.node.attrs,
487                                       v.span,
488                                       "a variant");
489     }
490 }
491
492 declare_lint! {
493     pub MISSING_COPY_IMPLEMENTATIONS,
494     Allow,
495     "detects potentially-forgotten implementations of `Copy`"
496 }
497
498 declare_lint_pass!(MissingCopyImplementations => [MISSING_COPY_IMPLEMENTATIONS]);
499
500 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingCopyImplementations {
501     fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &hir::Item) {
502         if !cx.access_levels.is_reachable(item.hir_id) {
503             return;
504         }
505         let (def, ty) = match item.node {
506             hir::ItemKind::Struct(_, ref ast_generics) => {
507                 if !ast_generics.params.is_empty() {
508                     return;
509                 }
510                 let def = cx.tcx.adt_def(cx.tcx.hir().local_def_id(item.hir_id));
511                 (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[])))
512             }
513             hir::ItemKind::Union(_, ref ast_generics) => {
514                 if !ast_generics.params.is_empty() {
515                     return;
516                 }
517                 let def = cx.tcx.adt_def(cx.tcx.hir().local_def_id(item.hir_id));
518                 (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[])))
519             }
520             hir::ItemKind::Enum(_, ref ast_generics) => {
521                 if !ast_generics.params.is_empty() {
522                     return;
523                 }
524                 let def = cx.tcx.adt_def(cx.tcx.hir().local_def_id(item.hir_id));
525                 (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[])))
526             }
527             _ => return,
528         };
529         if def.has_dtor(cx.tcx) {
530             return;
531         }
532         let param_env = ty::ParamEnv::empty();
533         if ty.is_copy_modulo_regions(cx.tcx, param_env, item.span) {
534             return;
535         }
536         if param_env.can_type_implement_copy(cx.tcx, ty).is_ok() {
537             cx.span_lint(MISSING_COPY_IMPLEMENTATIONS,
538                          item.span,
539                          "type could implement `Copy`; consider adding `impl \
540                           Copy`")
541         }
542     }
543 }
544
545 declare_lint! {
546     MISSING_DEBUG_IMPLEMENTATIONS,
547     Allow,
548     "detects missing implementations of fmt::Debug"
549 }
550
551 #[derive(Default)]
552 pub struct MissingDebugImplementations {
553     impling_types: Option<HirIdSet>,
554 }
555
556 impl_lint_pass!(MissingDebugImplementations => [MISSING_DEBUG_IMPLEMENTATIONS]);
557
558 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDebugImplementations {
559     fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &hir::Item) {
560         if !cx.access_levels.is_reachable(item.hir_id) {
561             return;
562         }
563
564         match item.node {
565             hir::ItemKind::Struct(..) |
566             hir::ItemKind::Union(..) |
567             hir::ItemKind::Enum(..) => {}
568             _ => return,
569         }
570
571         let debug = match cx.tcx.lang_items().debug_trait() {
572             Some(debug) => debug,
573             None => return,
574         };
575
576         if self.impling_types.is_none() {
577             let mut impls = HirIdSet::default();
578             cx.tcx.for_each_impl(debug, |d| {
579                 if let Some(ty_def) = cx.tcx.type_of(d).ty_adt_def() {
580                     if let Some(hir_id) = cx.tcx.hir().as_local_hir_id(ty_def.did) {
581                         impls.insert(hir_id);
582                     }
583                 }
584             });
585
586             self.impling_types = Some(impls);
587             debug!("{:?}", self.impling_types);
588         }
589
590         if !self.impling_types.as_ref().unwrap().contains(&item.hir_id) {
591             cx.span_lint(MISSING_DEBUG_IMPLEMENTATIONS,
592                          item.span,
593                          "type does not implement `fmt::Debug`; consider adding `#[derive(Debug)]` \
594                           or a manual implementation")
595         }
596     }
597 }
598
599 declare_lint! {
600     pub ANONYMOUS_PARAMETERS,
601     Allow,
602     "detects anonymous parameters"
603 }
604
605 declare_lint_pass!(
606     /// Checks for use of anonymous parameters (RFC 1685).
607     AnonymousParameters => [ANONYMOUS_PARAMETERS]
608 );
609
610 impl EarlyLintPass for AnonymousParameters {
611     fn check_trait_item(&mut self, cx: &EarlyContext<'_>, it: &ast::TraitItem) {
612         match it.node {
613             ast::TraitItemKind::Method(ref sig, _) => {
614                 for arg in sig.decl.inputs.iter() {
615                     match arg.pat.node {
616                         ast::PatKind::Ident(_, ident, None) => {
617                             if ident.name == kw::Invalid {
618                                 let ty_snip = cx
619                                     .sess
620                                     .source_map()
621                                     .span_to_snippet(arg.ty.span);
622
623                                 let (ty_snip, appl) = if let Ok(snip) = ty_snip {
624                                     (snip, Applicability::MachineApplicable)
625                                 } else {
626                                     ("<type>".to_owned(), Applicability::HasPlaceholders)
627                                 };
628
629                                 cx.struct_span_lint(
630                                     ANONYMOUS_PARAMETERS,
631                                     arg.pat.span,
632                                     "anonymous parameters are deprecated and will be \
633                                      removed in the next edition."
634                                 ).span_suggestion(
635                                     arg.pat.span,
636                                     "Try naming the parameter or explicitly \
637                                     ignoring it",
638                                     format!("_: {}", ty_snip),
639                                     appl
640                                 ).emit();
641                             }
642                         }
643                         _ => (),
644                     }
645                 }
646             },
647             _ => (),
648         }
649     }
650 }
651
652 /// Check for use of attributes which have been deprecated.
653 #[derive(Clone)]
654 pub struct DeprecatedAttr {
655     // This is not free to compute, so we want to keep it around, rather than
656     // compute it for every attribute.
657     depr_attrs: Vec<&'static (Symbol, AttributeType, AttributeTemplate, AttributeGate)>,
658 }
659
660 impl_lint_pass!(DeprecatedAttr => []);
661
662 impl DeprecatedAttr {
663     pub fn new() -> DeprecatedAttr {
664         DeprecatedAttr {
665             depr_attrs: deprecated_attributes(),
666         }
667     }
668 }
669
670 impl EarlyLintPass for DeprecatedAttr {
671     fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
672         for &&(n, _, _, ref g) in &self.depr_attrs {
673             if attr.ident().map(|ident| ident.name) == Some(n) {
674                 if let &AttributeGate::Gated(Stability::Deprecated(link, suggestion),
675                                              ref name,
676                                              ref reason,
677                                              _) = g {
678                     let msg = format!("use of deprecated attribute `{}`: {}. See {}",
679                                       name, reason, link);
680                     let mut err = cx.struct_span_lint(DEPRECATED, attr.span, &msg);
681                     err.span_suggestion_short(
682                         attr.span,
683                         suggestion.unwrap_or("remove this attribute"),
684                         String::new(),
685                         Applicability::MachineApplicable
686                     );
687                     err.emit();
688                 }
689                 return;
690             }
691         }
692     }
693 }
694
695 declare_lint! {
696     pub UNUSED_DOC_COMMENTS,
697     Warn,
698     "detects doc comments that aren't used by rustdoc"
699 }
700
701 declare_lint_pass!(UnusedDocComment => [UNUSED_DOC_COMMENTS]);
702
703 impl UnusedDocComment {
704     fn warn_if_doc(
705         &self,
706         cx: &EarlyContext<'_>,
707         node_span: Span,
708         node_kind: &str,
709         is_macro_expansion: bool,
710         attrs: &[ast::Attribute]
711     ) {
712         let mut attrs = attrs.into_iter().peekable();
713
714         // Accumulate a single span for sugared doc comments.
715         let mut sugared_span: Option<Span> = None;
716
717         while let Some(attr) = attrs.next() {
718             if attr.is_sugared_doc {
719                 sugared_span = Some(
720                     sugared_span.map_or_else(
721                         || attr.span,
722                         |span| span.with_hi(attr.span.hi()),
723                     ),
724                 );
725             }
726
727             if attrs.peek().map(|next_attr| next_attr.is_sugared_doc).unwrap_or_default() {
728                 continue;
729             }
730
731             let span = sugared_span.take().unwrap_or_else(|| attr.span);
732
733             if attr.check_name(sym::doc) {
734                 let mut err = cx.struct_span_lint(UNUSED_DOC_COMMENTS, span, "unused doc comment");
735
736                 err.span_label(
737                     node_span,
738                     format!("rustdoc does not generate documentation for {}", node_kind)
739                 );
740
741                 if is_macro_expansion {
742                     err.help("to document an item produced by a macro, \
743                               the macro must produce the documentation as part of its expansion");
744                 }
745
746                 err.emit();
747             }
748         }
749     }
750 }
751
752 impl EarlyLintPass for UnusedDocComment {
753     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
754         if let ast::ItemKind::Mac(..) = item.node {
755             self.warn_if_doc(cx, item.span, "macro expansions", true, &item.attrs);
756         }
757     }
758
759     fn check_stmt(&mut self, cx: &EarlyContext<'_>, stmt: &ast::Stmt) {
760         let (kind, is_macro_expansion) = match stmt.node {
761             ast::StmtKind::Local(..) => ("statements", false),
762             ast::StmtKind::Item(..) => ("inner items", false),
763             ast::StmtKind::Mac(..) => ("macro expansions", true),
764             // expressions will be reported by `check_expr`.
765             ast::StmtKind::Semi(..) |
766             ast::StmtKind::Expr(..) => return,
767         };
768
769         self.warn_if_doc(cx, stmt.span, kind, is_macro_expansion, stmt.node.attrs());
770     }
771
772     fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &ast::Arm) {
773         let arm_span = arm.pats[0].span.with_hi(arm.body.span.hi());
774         self.warn_if_doc(cx, arm_span, "match arms", false, &arm.attrs);
775     }
776
777     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
778         self.warn_if_doc(cx, expr.span, "expressions", false, &expr.attrs);
779     }
780 }
781
782 declare_lint! {
783     PLUGIN_AS_LIBRARY,
784     Warn,
785     "compiler plugin used as ordinary library in non-plugin crate"
786 }
787
788 declare_lint_pass!(PluginAsLibrary => [PLUGIN_AS_LIBRARY]);
789
790 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PluginAsLibrary {
791     fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item) {
792         if cx.tcx.plugin_registrar_fn(LOCAL_CRATE).is_some() {
793             // We're compiling a plugin; it's fine to link other plugins.
794             return;
795         }
796
797         match it.node {
798             hir::ItemKind::ExternCrate(..) => (),
799             _ => return,
800         };
801
802         let def_id = cx.tcx.hir().local_def_id(it.hir_id);
803         let prfn = match cx.tcx.extern_mod_stmt_cnum(def_id) {
804             Some(cnum) => cx.tcx.plugin_registrar_fn(cnum),
805             None => {
806                 // Probably means we aren't linking the crate for some reason.
807                 //
808                 // Not sure if / when this could happen.
809                 return;
810             }
811         };
812
813         if prfn.is_some() {
814             cx.span_lint(PLUGIN_AS_LIBRARY,
815                          it.span,
816                          "compiler plugin used as an ordinary library");
817         }
818     }
819 }
820
821 declare_lint! {
822     NO_MANGLE_CONST_ITEMS,
823     Deny,
824     "const items will not have their symbols exported"
825 }
826
827 declare_lint! {
828     NO_MANGLE_GENERIC_ITEMS,
829     Warn,
830     "generic items must be mangled"
831 }
832
833 declare_lint_pass!(InvalidNoMangleItems => [NO_MANGLE_CONST_ITEMS, NO_MANGLE_GENERIC_ITEMS]);
834
835 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidNoMangleItems {
836     fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item) {
837         match it.node {
838             hir::ItemKind::Fn(.., ref generics, _) => {
839                 if let Some(no_mangle_attr) = attr::find_by_name(&it.attrs, sym::no_mangle) {
840                     for param in &generics.params {
841                         match param.kind {
842                             GenericParamKind::Lifetime { .. } => {}
843                             GenericParamKind::Type { .. } |
844                             GenericParamKind::Const { .. } => {
845                                 let mut err = cx.struct_span_lint(
846                                     NO_MANGLE_GENERIC_ITEMS,
847                                     it.span,
848                                     "functions generic over types or consts must be mangled",
849                                 );
850                                 err.span_suggestion_short(
851                                     no_mangle_attr.span,
852                                     "remove this attribute",
853                                     String::new(),
854                                     // Use of `#[no_mangle]` suggests FFI intent; correct
855                                     // fix may be to monomorphize source by hand
856                                     Applicability::MaybeIncorrect
857                                 );
858                                 err.emit();
859                                 break;
860                             }
861                         }
862                     }
863                 }
864             }
865             hir::ItemKind::Const(..) => {
866                 if attr::contains_name(&it.attrs, sym::no_mangle) {
867                     // Const items do not refer to a particular location in memory, and therefore
868                     // don't have anything to attach a symbol to
869                     let msg = "const items should never be `#[no_mangle]`";
870                     let mut err = cx.struct_span_lint(NO_MANGLE_CONST_ITEMS, it.span, msg);
871
872                     // account for "pub const" (#45562)
873                     let start = cx.tcx.sess.source_map().span_to_snippet(it.span)
874                         .map(|snippet| snippet.find("const").unwrap_or(0))
875                         .unwrap_or(0) as u32;
876                     // `const` is 5 chars
877                     let const_span = it.span.with_hi(BytePos(it.span.lo().0 + start + 5));
878                     err.span_suggestion(
879                         const_span,
880                         "try a static value",
881                         "pub static".to_owned(),
882                         Applicability::MachineApplicable
883                     );
884                     err.emit();
885                 }
886             }
887             _ => {}
888         }
889     }
890 }
891
892 declare_lint! {
893     MUTABLE_TRANSMUTES,
894     Deny,
895     "mutating transmuted &mut T from &T may cause undefined behavior"
896 }
897
898 declare_lint_pass!(MutableTransmutes => [MUTABLE_TRANSMUTES]);
899
900 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutableTransmutes {
901     fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &hir::Expr) {
902         use rustc_target::spec::abi::Abi::RustIntrinsic;
903
904         let msg = "mutating transmuted &mut T from &T may cause undefined behavior, \
905                    consider instead using an UnsafeCell";
906         match get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (&ty1.sty, &ty2.sty)) {
907             Some((&ty::Ref(_, _, from_mt), &ty::Ref(_, _, to_mt))) => {
908                 if to_mt == hir::Mutability::MutMutable &&
909                    from_mt == hir::Mutability::MutImmutable {
910                     cx.span_lint(MUTABLE_TRANSMUTES, expr.span, msg);
911                 }
912             }
913             _ => (),
914         }
915
916         fn get_transmute_from_to<'a, 'tcx>
917             (cx: &LateContext<'a, 'tcx>,
918              expr: &hir::Expr)
919              -> Option<(Ty<'tcx>, Ty<'tcx>)> {
920             let def = if let hir::ExprKind::Path(ref qpath) = expr.node {
921                 cx.tables.qpath_res(qpath, expr.hir_id)
922             } else {
923                 return None;
924             };
925             if let Res::Def(DefKind::Fn, did) = def {
926                 if !def_id_is_transmute(cx, did) {
927                     return None;
928                 }
929                 let sig = cx.tables.node_type(expr.hir_id).fn_sig(cx.tcx);
930                 let from = sig.inputs().skip_binder()[0];
931                 let to = *sig.output().skip_binder();
932                 return Some((from, to));
933             }
934             None
935         }
936
937         fn def_id_is_transmute(cx: &LateContext<'_, '_>, def_id: DefId) -> bool {
938             cx.tcx.fn_sig(def_id).abi() == RustIntrinsic &&
939             cx.tcx.item_name(def_id) == sym::transmute
940         }
941     }
942 }
943
944 declare_lint! {
945     UNSTABLE_FEATURES,
946     Allow,
947     "enabling unstable features (deprecated. do not use)"
948 }
949
950 declare_lint_pass!(
951     /// Forbids using the `#[feature(...)]` attribute
952     UnstableFeatures => [UNSTABLE_FEATURES]
953 );
954
955 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnstableFeatures {
956     fn check_attribute(&mut self, ctx: &LateContext<'_, '_>, attr: &ast::Attribute) {
957         if attr.check_name(sym::feature) {
958             if let Some(items) = attr.meta_item_list() {
959                 for item in items {
960                     ctx.span_lint(UNSTABLE_FEATURES, item.span(), "unstable feature");
961                 }
962             }
963         }
964     }
965 }
966
967 declare_lint! {
968     UNIONS_WITH_DROP_FIELDS,
969     Warn,
970     "use of unions that contain fields with possibly non-trivial drop code"
971 }
972
973 declare_lint_pass!(
974     /// Lint for unions that contain fields with possibly non-trivial destructors.
975     UnionsWithDropFields => [UNIONS_WITH_DROP_FIELDS]
976 );
977
978 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnionsWithDropFields {
979     fn check_item(&mut self, ctx: &LateContext<'_, '_>, item: &hir::Item) {
980         if let hir::ItemKind::Union(ref vdata, _) = item.node {
981             for field in vdata.fields() {
982                 let field_ty = ctx.tcx.type_of(
983                     ctx.tcx.hir().local_def_id(field.hir_id));
984                 if field_ty.needs_drop(ctx.tcx, ctx.param_env) {
985                     ctx.span_lint(UNIONS_WITH_DROP_FIELDS,
986                                   field.span,
987                                   "union contains a field with possibly non-trivial drop code, \
988                                    drop code of union fields is ignored when dropping the union");
989                     return;
990                 }
991             }
992         }
993     }
994 }
995
996 declare_lint! {
997     pub UNREACHABLE_PUB,
998     Allow,
999     "`pub` items not reachable from crate root"
1000 }
1001
1002 declare_lint_pass!(
1003     /// Lint for items marked `pub` that aren't reachable from other crates.
1004     UnreachablePub => [UNREACHABLE_PUB]
1005 );
1006
1007 impl UnreachablePub {
1008     fn perform_lint(&self, cx: &LateContext<'_, '_>, what: &str, id: hir::HirId,
1009                     vis: &hir::Visibility, span: Span, exportable: bool) {
1010         let mut applicability = Applicability::MachineApplicable;
1011         match vis.node {
1012             hir::VisibilityKind::Public if !cx.access_levels.is_reachable(id) => {
1013                 if span.ctxt().outer_expn_info().is_some() {
1014                     applicability = Applicability::MaybeIncorrect;
1015                 }
1016                 let def_span = cx.tcx.sess.source_map().def_span(span);
1017                 let mut err = cx.struct_span_lint(UNREACHABLE_PUB, def_span,
1018                                                   &format!("unreachable `pub` {}", what));
1019                 let replacement = if cx.tcx.features().crate_visibility_modifier {
1020                     "crate"
1021                 } else {
1022                     "pub(crate)"
1023                 }.to_owned();
1024
1025                 err.span_suggestion(
1026                     vis.span,
1027                     "consider restricting its visibility",
1028                     replacement,
1029                     applicability,
1030                 );
1031                 if exportable {
1032                     err.help("or consider exporting it for use by other crates");
1033                 }
1034                 err.emit();
1035             },
1036             _ => {}
1037         }
1038     }
1039 }
1040
1041 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnreachablePub {
1042     fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &hir::Item) {
1043         self.perform_lint(cx, "item", item.hir_id, &item.vis, item.span, true);
1044     }
1045
1046     fn check_foreign_item(&mut self, cx: &LateContext<'_, '_>, foreign_item: &hir::ForeignItem) {
1047         self.perform_lint(cx, "item", foreign_item.hir_id, &foreign_item.vis,
1048                           foreign_item.span, true);
1049     }
1050
1051     fn check_struct_field(&mut self, cx: &LateContext<'_, '_>, field: &hir::StructField) {
1052         self.perform_lint(cx, "field", field.hir_id, &field.vis, field.span, false);
1053     }
1054
1055     fn check_impl_item(&mut self, cx: &LateContext<'_, '_>, impl_item: &hir::ImplItem) {
1056         self.perform_lint(cx, "item", impl_item.hir_id, &impl_item.vis, impl_item.span, false);
1057     }
1058 }
1059
1060 declare_lint! {
1061     TYPE_ALIAS_BOUNDS,
1062     Warn,
1063     "bounds in type aliases are not enforced"
1064 }
1065
1066 declare_lint_pass!(
1067     /// Lint for trait and lifetime bounds in type aliases being mostly ignored.
1068     /// They are relevant when using associated types, but otherwise neither checked
1069     /// at definition site nor enforced at use site.
1070     TypeAliasBounds => [TYPE_ALIAS_BOUNDS]
1071 );
1072
1073 impl TypeAliasBounds {
1074     fn is_type_variable_assoc(qpath: &hir::QPath) -> bool {
1075         match *qpath {
1076             hir::QPath::TypeRelative(ref ty, _) => {
1077                 // If this is a type variable, we found a `T::Assoc`.
1078                 match ty.node {
1079                     hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => {
1080                         match path.res {
1081                             Res::Def(DefKind::TyParam, _) => true,
1082                             _ => false
1083                         }
1084                     }
1085                     _ => false
1086                 }
1087             }
1088             hir::QPath::Resolved(..) => false,
1089         }
1090     }
1091
1092     fn suggest_changing_assoc_types(ty: &hir::Ty, err: &mut DiagnosticBuilder<'_>) {
1093         // Access to associates types should use `<T as Bound>::Assoc`, which does not need a
1094         // bound.  Let's see if this type does that.
1095
1096         // We use a HIR visitor to walk the type.
1097         use rustc::hir::intravisit::{self, Visitor};
1098         struct WalkAssocTypes<'a, 'db> {
1099             err: &'a mut DiagnosticBuilder<'db>
1100         }
1101         impl<'a, 'db, 'v> Visitor<'v> for WalkAssocTypes<'a, 'db> {
1102             fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'v>
1103             {
1104                 intravisit::NestedVisitorMap::None
1105             }
1106
1107             fn visit_qpath(&mut self, qpath: &'v hir::QPath, id: hir::HirId, span: Span) {
1108                 if TypeAliasBounds::is_type_variable_assoc(qpath) {
1109                     self.err.span_help(span,
1110                         "use fully disambiguated paths (i.e., `<T as Trait>::Assoc`) to refer to \
1111                          associated types in type aliases");
1112                 }
1113                 intravisit::walk_qpath(self, qpath, id, span)
1114             }
1115         }
1116
1117         // Let's go for a walk!
1118         let mut visitor = WalkAssocTypes { err };
1119         visitor.visit_ty(ty);
1120     }
1121 }
1122
1123 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeAliasBounds {
1124     fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &hir::Item) {
1125         let (ty, type_alias_generics) = match item.node {
1126             hir::ItemKind::Ty(ref ty, ref generics) => (&*ty, generics),
1127             _ => return,
1128         };
1129         let mut suggested_changing_assoc_types = false;
1130         // There must not be a where clause
1131         if !type_alias_generics.where_clause.predicates.is_empty() {
1132             let spans : Vec<_> = type_alias_generics.where_clause.predicates.iter()
1133                 .map(|pred| pred.span()).collect();
1134             let mut err = cx.struct_span_lint(TYPE_ALIAS_BOUNDS, spans,
1135                 "where clauses are not enforced in type aliases");
1136             err.help("the clause will not be checked when the type alias is used, \
1137                       and should be removed");
1138             if !suggested_changing_assoc_types {
1139                 TypeAliasBounds::suggest_changing_assoc_types(ty, &mut err);
1140                 suggested_changing_assoc_types = true;
1141             }
1142             err.emit();
1143         }
1144         // The parameters must not have bounds
1145         for param in type_alias_generics.params.iter() {
1146             let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
1147             if !spans.is_empty() {
1148                 let mut err = cx.struct_span_lint(
1149                     TYPE_ALIAS_BOUNDS,
1150                     spans,
1151                     "bounds on generic parameters are not enforced in type aliases",
1152                 );
1153                 err.help("the bound will not be checked when the type alias is used, \
1154                           and should be removed");
1155                 if !suggested_changing_assoc_types {
1156                     TypeAliasBounds::suggest_changing_assoc_types(ty, &mut err);
1157                     suggested_changing_assoc_types = true;
1158                 }
1159                 err.emit();
1160             }
1161         }
1162     }
1163 }
1164
1165 declare_lint_pass!(
1166     /// Lint constants that are erroneous.
1167     /// Without this lint, we might not get any diagnostic if the constant is
1168     /// unused within this crate, even though downstream crates can't use it
1169     /// without producing an error.
1170     UnusedBrokenConst => []
1171 );
1172
1173 fn check_const(cx: &LateContext<'_, '_>, body_id: hir::BodyId) {
1174     let def_id = cx.tcx.hir().body_owner_def_id(body_id);
1175     let param_env = if cx.tcx.is_static(def_id) {
1176         // Use the same param_env as `codegen_static_initializer`, to reuse the cache.
1177         ty::ParamEnv::reveal_all()
1178     } else {
1179         cx.tcx.param_env(def_id)
1180     };
1181     let cid = ::rustc::mir::interpret::GlobalId {
1182         instance: ty::Instance::mono(cx.tcx, def_id),
1183         promoted: None
1184     };
1185     // trigger the query once for all constants since that will already report the errors
1186     // FIXME: Use ensure here
1187     let _ = cx.tcx.const_eval(param_env.and(cid));
1188 }
1189
1190 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedBrokenConst {
1191     fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item) {
1192         match it.node {
1193             hir::ItemKind::Const(_, body_id) => {
1194                 check_const(cx, body_id);
1195             },
1196             hir::ItemKind::Static(_, _, body_id) => {
1197                 check_const(cx, body_id);
1198             },
1199             _ => {},
1200         }
1201     }
1202 }
1203
1204 declare_lint! {
1205     TRIVIAL_BOUNDS,
1206     Warn,
1207     "these bounds don't depend on an type parameters"
1208 }
1209
1210 declare_lint_pass!(
1211     /// Lint for trait and lifetime bounds that don't depend on type parameters
1212     /// which either do nothing, or stop the item from being used.
1213     TrivialConstraints => [TRIVIAL_BOUNDS]
1214 );
1215
1216 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TrivialConstraints {
1217     fn check_item(
1218         &mut self,
1219         cx: &LateContext<'a, 'tcx>,
1220         item: &'tcx hir::Item,
1221     ) {
1222         use rustc::ty::fold::TypeFoldable;
1223         use rustc::ty::Predicate::*;
1224
1225         if cx.tcx.features().trivial_bounds {
1226             let def_id = cx.tcx.hir().local_def_id(item.hir_id);
1227             let predicates = cx.tcx.predicates_of(def_id);
1228             for &(predicate, span) in &predicates.predicates {
1229                 let predicate_kind_name = match predicate {
1230                     Trait(..) => "Trait",
1231                     TypeOutlives(..) |
1232                     RegionOutlives(..) => "Lifetime",
1233
1234                     // Ignore projections, as they can only be global
1235                     // if the trait bound is global
1236                     Projection(..) |
1237                     // Ignore bounds that a user can't type
1238                     WellFormed(..) |
1239                     ObjectSafe(..) |
1240                     ClosureKind(..) |
1241                     Subtype(..) |
1242                     ConstEvaluatable(..) => continue,
1243                 };
1244                 if predicate.is_global() {
1245                     cx.span_lint(
1246                         TRIVIAL_BOUNDS,
1247                         span,
1248                         &format!("{} bound {} does not depend on any type \
1249                                 or lifetime parameters", predicate_kind_name, predicate),
1250                     );
1251                 }
1252             }
1253         }
1254     }
1255 }
1256
1257 declare_lint_pass!(
1258     /// Does nothing as a lint pass, but registers some `Lint`s
1259     /// which are used by other parts of the compiler.
1260     SoftLints => [
1261         WHILE_TRUE,
1262         BOX_POINTERS,
1263         NON_SHORTHAND_FIELD_PATTERNS,
1264         UNSAFE_CODE,
1265         MISSING_DOCS,
1266         MISSING_COPY_IMPLEMENTATIONS,
1267         MISSING_DEBUG_IMPLEMENTATIONS,
1268         ANONYMOUS_PARAMETERS,
1269         UNUSED_DOC_COMMENTS,
1270         PLUGIN_AS_LIBRARY,
1271         NO_MANGLE_CONST_ITEMS,
1272         NO_MANGLE_GENERIC_ITEMS,
1273         MUTABLE_TRANSMUTES,
1274         UNSTABLE_FEATURES,
1275         UNIONS_WITH_DROP_FIELDS,
1276         UNREACHABLE_PUB,
1277         TYPE_ALIAS_BOUNDS,
1278         TRIVIAL_BOUNDS
1279     ]
1280 );
1281
1282 declare_lint! {
1283     pub ELLIPSIS_INCLUSIVE_RANGE_PATTERNS,
1284     Warn,
1285     "`...` range patterns are deprecated"
1286 }
1287
1288 #[derive(Default)]
1289 pub struct EllipsisInclusiveRangePatterns {
1290     /// If `Some(_)`, suppress all subsequent pattern
1291     /// warnings for better diagnostics.
1292     node_id: Option<ast::NodeId>,
1293 }
1294
1295 impl_lint_pass!(EllipsisInclusiveRangePatterns => [ELLIPSIS_INCLUSIVE_RANGE_PATTERNS]);
1296
1297 impl EarlyLintPass for EllipsisInclusiveRangePatterns {
1298     fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &ast::Pat) {
1299         if self.node_id.is_some() {
1300             // Don't recursively warn about patterns inside range endpoints.
1301             return
1302         }
1303
1304         use self::ast::{PatKind, RangeEnd, RangeSyntax::DotDotDot};
1305
1306         /// If `pat` is a `...` pattern, return the start and end of the range, as well as the span
1307         /// corresponding to the ellipsis.
1308         fn matches_ellipsis_pat(pat: &ast::Pat) -> Option<(&P<Expr>, &P<Expr>, Span)> {
1309             match &pat.node {
1310                 PatKind::Range(a, b, Spanned { span, node: RangeEnd::Included(DotDotDot), .. }) => {
1311                     Some((a, b, *span))
1312                 }
1313                 _ => None,
1314             }
1315         }
1316
1317         let (parenthesise, endpoints) = match &pat.node {
1318             PatKind::Ref(subpat, _) => (true, matches_ellipsis_pat(&subpat)),
1319             _ => (false, matches_ellipsis_pat(pat)),
1320         };
1321
1322         if let Some((start, end, join)) = endpoints {
1323             let msg = "`...` range patterns are deprecated";
1324             let suggestion = "use `..=` for an inclusive range";
1325             if parenthesise {
1326                 self.node_id = Some(pat.id);
1327                 let mut err = cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, pat.span, msg);
1328                 err.span_suggestion(
1329                     pat.span,
1330                     suggestion,
1331                     format!("&({}..={})", expr_to_string(&start), expr_to_string(&end)),
1332                     Applicability::MachineApplicable,
1333                 );
1334                 err.emit();
1335             } else {
1336                 let mut err = cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, join, msg);
1337                 err.span_suggestion_short(
1338                     join,
1339                     suggestion,
1340                     "..=".to_owned(),
1341                     Applicability::MachineApplicable,
1342                 );
1343                 err.emit();
1344             };
1345         }
1346     }
1347
1348     fn check_pat_post(&mut self, _cx: &EarlyContext<'_>, pat: &ast::Pat) {
1349         if let Some(node_id) = self.node_id {
1350             if pat.id == node_id {
1351                 self.node_id = None
1352             }
1353         }
1354     }
1355 }
1356
1357 declare_lint! {
1358     UNNAMEABLE_TEST_ITEMS,
1359     Warn,
1360     "detects an item that cannot be named being marked as `#[test_case]`",
1361     report_in_external_macro: true
1362 }
1363
1364 pub struct UnnameableTestItems {
1365     boundary: hir::HirId, // HirId of the item under which things are not nameable
1366     items_nameable: bool,
1367 }
1368
1369 impl_lint_pass!(UnnameableTestItems => [UNNAMEABLE_TEST_ITEMS]);
1370
1371 impl UnnameableTestItems {
1372     pub fn new() -> Self {
1373         Self {
1374             boundary: hir::DUMMY_HIR_ID,
1375             items_nameable: true
1376         }
1377     }
1378 }
1379
1380 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnnameableTestItems {
1381     fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item) {
1382         if self.items_nameable {
1383             if let hir::ItemKind::Mod(..) = it.node {}
1384             else {
1385                 self.items_nameable = false;
1386                 self.boundary = it.hir_id;
1387             }
1388             return;
1389         }
1390
1391         if let Some(attr) = attr::find_by_name(&it.attrs, sym::rustc_test_marker) {
1392             cx.struct_span_lint(
1393                 UNNAMEABLE_TEST_ITEMS,
1394                 attr.span,
1395                 "cannot test inner items",
1396             ).emit();
1397         }
1398     }
1399
1400     fn check_item_post(&mut self, _cx: &LateContext<'_, '_>, it: &hir::Item) {
1401         if !self.items_nameable && self.boundary == it.hir_id {
1402             self.items_nameable = true;
1403         }
1404     }
1405 }
1406
1407 declare_lint! {
1408     pub KEYWORD_IDENTS,
1409     Allow,
1410     "detects edition keywords being used as an identifier"
1411 }
1412
1413 declare_lint_pass!(
1414     /// Check for uses of edition keywords used as an identifier.
1415     KeywordIdents => [KEYWORD_IDENTS]
1416 );
1417
1418 struct UnderMacro(bool);
1419
1420 impl KeywordIdents {
1421     fn check_tokens(&mut self, cx: &EarlyContext<'_>, tokens: TokenStream) {
1422         for tt in tokens.into_trees() {
1423             match tt {
1424                 // Only report non-raw idents.
1425                 TokenTree::Token(token) => if let Some((ident, false)) = token.ident() {
1426                     self.check_ident_token(cx, UnderMacro(true), ident);
1427                 }
1428                 TokenTree::Delimited(_, _, tts) => {
1429                     self.check_tokens(cx, tts)
1430                 },
1431             }
1432         }
1433     }
1434
1435     fn check_ident_token(&mut self,
1436                          cx: &EarlyContext<'_>,
1437                          UnderMacro(under_macro): UnderMacro,
1438                          ident: ast::Ident)
1439     {
1440         let next_edition = match cx.sess.edition() {
1441             Edition::Edition2015 => {
1442                 match ident.name {
1443                     kw::Async | kw::Await | kw::Try => Edition::Edition2018,
1444
1445                     // rust-lang/rust#56327: Conservatively do not
1446                     // attempt to report occurrences of `dyn` within
1447                     // macro definitions or invocations, because `dyn`
1448                     // can legitimately occur as a contextual keyword
1449                     // in 2015 code denoting its 2018 meaning, and we
1450                     // do not want rustfix to inject bugs into working
1451                     // code by rewriting such occurrences.
1452                     //
1453                     // But if we see `dyn` outside of a macro, we know
1454                     // its precise role in the parsed AST and thus are
1455                     // assured this is truly an attempt to use it as
1456                     // an identifier.
1457                     kw::Dyn if !under_macro => Edition::Edition2018,
1458
1459                     _ => return,
1460                 }
1461             }
1462
1463             // There are no new keywords yet for the 2018 edition and beyond.
1464             _ => return,
1465         };
1466
1467         // Don't lint `r#foo`.
1468         if cx.sess.parse_sess.raw_identifier_spans.borrow().contains(&ident.span) {
1469             return;
1470         }
1471
1472         let mut lint = cx.struct_span_lint(
1473             KEYWORD_IDENTS,
1474             ident.span,
1475             &format!("`{}` is a keyword in the {} edition",
1476                      ident.as_str(),
1477                      next_edition),
1478         );
1479         lint.span_suggestion(
1480             ident.span,
1481             "you can use a raw identifier to stay compatible",
1482             format!("r#{}", ident.as_str()),
1483             Applicability::MachineApplicable,
1484         );
1485         lint.emit()
1486     }
1487 }
1488
1489 impl EarlyLintPass for KeywordIdents {
1490     fn check_mac_def(&mut self, cx: &EarlyContext<'_>, mac_def: &ast::MacroDef, _id: ast::NodeId) {
1491         self.check_tokens(cx, mac_def.stream());
1492     }
1493     fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &ast::Mac) {
1494         self.check_tokens(cx, mac.node.tts.clone().into());
1495     }
1496     fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: ast::Ident) {
1497         self.check_ident_token(cx, UnderMacro(false), ident);
1498     }
1499 }
1500
1501 declare_lint_pass!(ExplicitOutlivesRequirements => [EXPLICIT_OUTLIVES_REQUIREMENTS]);
1502
1503 impl ExplicitOutlivesRequirements {
1504     fn lifetimes_outliving_lifetime<'tcx>(
1505         inferred_outlives: &'tcx [ty::Predicate<'tcx>],
1506         index: u32,
1507     ) -> Vec<ty::Region<'tcx>> {
1508         inferred_outlives.iter().filter_map(|pred| {
1509             match pred {
1510                 ty::Predicate::RegionOutlives(outlives) => {
1511                     let outlives = outlives.skip_binder();
1512                     match outlives.0 {
1513                         ty::ReEarlyBound(ebr) if ebr.index == index => {
1514                             Some(outlives.1)
1515                         }
1516                         _ => None,
1517                     }
1518                 }
1519                 _ => None
1520             }
1521         }).collect()
1522     }
1523
1524     fn lifetimes_outliving_type<'tcx>(
1525         inferred_outlives: &'tcx [ty::Predicate<'tcx>],
1526         index: u32,
1527     ) -> Vec<ty::Region<'tcx>> {
1528         inferred_outlives.iter().filter_map(|pred| {
1529             match pred {
1530                 ty::Predicate::TypeOutlives(outlives) => {
1531                     let outlives = outlives.skip_binder();
1532                     if outlives.0.is_param(index) {
1533                         Some(outlives.1)
1534                     } else {
1535                         None
1536                     }
1537                 }
1538                 _ => None
1539             }
1540         }).collect()
1541     }
1542
1543     fn collect_outlived_lifetimes<'tcx>(
1544         &self,
1545         param: &'tcx hir::GenericParam,
1546         tcx: TyCtxt<'tcx>,
1547         inferred_outlives: &'tcx [ty::Predicate<'tcx>],
1548         ty_generics: &'tcx ty::Generics,
1549     ) -> Vec<ty::Region<'tcx>> {
1550         let index = ty_generics.param_def_id_to_index[
1551             &tcx.hir().local_def_id(param.hir_id)];
1552
1553         match param.kind {
1554             hir::GenericParamKind::Lifetime { .. } => {
1555                 Self::lifetimes_outliving_lifetime(inferred_outlives, index)
1556             }
1557             hir::GenericParamKind::Type { .. } => {
1558                 Self::lifetimes_outliving_type(inferred_outlives, index)
1559             }
1560             hir::GenericParamKind::Const { .. } => Vec::new(),
1561         }
1562     }
1563
1564
1565     fn collect_outlives_bound_spans<'tcx>(
1566         &self,
1567         tcx: TyCtxt<'tcx>,
1568         bounds: &hir::GenericBounds,
1569         inferred_outlives: &[ty::Region<'tcx>],
1570         infer_static: bool,
1571     ) -> Vec<(usize, Span)> {
1572         use rustc::middle::resolve_lifetime::Region;
1573
1574         bounds
1575             .iter()
1576             .enumerate()
1577             .filter_map(|(i, bound)| {
1578                 if let hir::GenericBound::Outlives(lifetime) = bound {
1579                     let is_inferred = match tcx.named_region(lifetime.hir_id) {
1580                         Some(Region::Static) if infer_static => {
1581                             inferred_outlives.iter()
1582                                 .any(|r| if let ty::ReStatic = r { true } else { false })
1583                         }
1584                         Some(Region::EarlyBound(index, ..)) => inferred_outlives
1585                             .iter()
1586                             .any(|r| {
1587                                 if let ty::ReEarlyBound(ebr) = r {
1588                                     ebr.index == index
1589                                 } else {
1590                                     false
1591                                 }
1592                             }),
1593                         _ => false,
1594                     };
1595                     if is_inferred {
1596                         Some((i, bound.span()))
1597                     } else {
1598                         None
1599                     }
1600                 } else {
1601                     None
1602                 }
1603             })
1604             .collect()
1605     }
1606
1607     fn consolidate_outlives_bound_spans(
1608         &self,
1609         lo: Span,
1610         bounds: &hir::GenericBounds,
1611         bound_spans: Vec<(usize, Span)>
1612     ) -> Vec<Span> {
1613         if bounds.is_empty() {
1614             return Vec::new();
1615         }
1616         if bound_spans.len() == bounds.len() {
1617             let (_, last_bound_span) = bound_spans[bound_spans.len()-1];
1618             // If all bounds are inferable, we want to delete the colon, so
1619             // start from just after the parameter (span passed as argument)
1620             vec![lo.to(last_bound_span)]
1621         } else {
1622             let mut merged = Vec::new();
1623             let mut last_merged_i = None;
1624
1625             let mut from_start = true;
1626             for (i, bound_span) in bound_spans {
1627                 match last_merged_i {
1628                     // If the first bound is inferable, our span should also eat the leading `+`.
1629                     None if i == 0 => {
1630                         merged.push(bound_span.to(bounds[1].span().shrink_to_lo()));
1631                         last_merged_i = Some(0);
1632                     },
1633                     // If consecutive bounds are inferable, merge their spans
1634                     Some(h) if i == h+1 => {
1635                         if let Some(tail) = merged.last_mut() {
1636                             // Also eat the trailing `+` if the first
1637                             // more-than-one bound is inferable
1638                             let to_span = if from_start && i < bounds.len() {
1639                                 bounds[i+1].span().shrink_to_lo()
1640                             } else {
1641                                 bound_span
1642                             };
1643                             *tail = tail.to(to_span);
1644                             last_merged_i = Some(i);
1645                         } else {
1646                             bug!("another bound-span visited earlier");
1647                         }
1648                     },
1649                     _ => {
1650                         // When we find a non-inferable bound, subsequent inferable bounds
1651                         // won't be consecutive from the start (and we'll eat the leading
1652                         // `+` rather than the trailing one)
1653                         from_start = false;
1654                         merged.push(bounds[i-1].span().shrink_to_hi().to(bound_span));
1655                         last_merged_i = Some(i);
1656                     }
1657                 }
1658             }
1659             merged
1660         }
1661     }
1662 }
1663
1664 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ExplicitOutlivesRequirements {
1665     fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item) {
1666         use rustc::middle::resolve_lifetime::Region;
1667
1668         let infer_static = cx.tcx.features().infer_static_outlives_requirements;
1669         let def_id = cx.tcx.hir().local_def_id(item.hir_id);
1670         if let hir::ItemKind::Struct(_, ref hir_generics)
1671             | hir::ItemKind::Enum(_, ref hir_generics)
1672             | hir::ItemKind::Union(_, ref hir_generics) = item.node
1673         {
1674             let inferred_outlives = cx.tcx.inferred_outlives_of(def_id);
1675             if inferred_outlives.is_empty() {
1676                 return;
1677             }
1678
1679             let ty_generics = cx.tcx.generics_of(def_id);
1680
1681             let mut bound_count = 0;
1682             let mut lint_spans = Vec::new();
1683
1684             for param in &hir_generics.params {
1685                 let has_lifetime_bounds = param.bounds.iter().any(|bound| {
1686                     if let hir::GenericBound::Outlives(_) = bound {
1687                         true
1688                     } else {
1689                         false
1690                     }
1691                 });
1692                 if !has_lifetime_bounds {
1693                     continue;
1694                 }
1695
1696                 let relevant_lifetimes = self.collect_outlived_lifetimes(
1697                     param,
1698                     cx.tcx,
1699                     inferred_outlives,
1700                     ty_generics,
1701                 );
1702                 if relevant_lifetimes.is_empty() {
1703                     continue;
1704                 }
1705
1706                 let bound_spans = self.collect_outlives_bound_spans(
1707                     cx.tcx, &param.bounds, &relevant_lifetimes, infer_static,
1708                 );
1709                 bound_count += bound_spans.len();
1710                 lint_spans.extend(
1711                     self.consolidate_outlives_bound_spans(
1712                         param.span.shrink_to_hi(), &param.bounds, bound_spans
1713                     )
1714                 );
1715             }
1716
1717             let mut where_lint_spans = Vec::new();
1718             let mut dropped_predicate_count = 0;
1719             let num_predicates = hir_generics.where_clause.predicates.len();
1720             for (i, where_predicate) in hir_generics.where_clause.predicates.iter().enumerate() {
1721                 let (relevant_lifetimes, bounds, span) = match where_predicate {
1722                     hir::WherePredicate::RegionPredicate(predicate) => {
1723                         if let Some(Region::EarlyBound(index, ..))
1724                             = cx.tcx.named_region(predicate.lifetime.hir_id)
1725                         {
1726                             (
1727                                 Self::lifetimes_outliving_lifetime(inferred_outlives, index),
1728                                 &predicate.bounds,
1729                                 predicate.span,
1730                             )
1731                         } else {
1732                             continue;
1733                         }
1734                     }
1735                     hir::WherePredicate::BoundPredicate(predicate) => {
1736                         // FIXME we can also infer bounds on associated types,
1737                         // and should check for them here.
1738                         match predicate.bounded_ty.node {
1739                             hir::TyKind::Path(hir::QPath::Resolved(
1740                                 None,
1741                                 ref path,
1742                             )) => {
1743                                 if let Res::Def(DefKind::TyParam, def_id) = path.res {
1744                                     let index = ty_generics.param_def_id_to_index[&def_id];
1745                                     (
1746                                         Self::lifetimes_outliving_type(inferred_outlives, index),
1747                                         &predicate.bounds,
1748                                         predicate.span,
1749                                     )
1750                                 } else {
1751                                     continue;
1752                                 }
1753                             },
1754                             _ => { continue; }
1755                         }
1756                     }
1757                     _ => continue,
1758                 };
1759                 if relevant_lifetimes.is_empty() {
1760                     continue;
1761                 }
1762
1763                 let bound_spans = self.collect_outlives_bound_spans(
1764                     cx.tcx, bounds, &relevant_lifetimes, infer_static,
1765                 );
1766                 bound_count += bound_spans.len();
1767
1768                 let drop_predicate = bound_spans.len() == bounds.len();
1769                 if drop_predicate {
1770                     dropped_predicate_count += 1;
1771                 }
1772
1773                 // If all the bounds on a predicate were inferable and there are
1774                 // further predicates, we want to eat the trailing comma.
1775                 if drop_predicate && i + 1 < num_predicates {
1776                     let next_predicate_span = hir_generics.where_clause.predicates[i + 1].span();
1777                     where_lint_spans.push(
1778                         span.to(next_predicate_span.shrink_to_lo())
1779                     );
1780                 } else {
1781                     where_lint_spans.extend(
1782                         self.consolidate_outlives_bound_spans(
1783                             span.shrink_to_lo(),
1784                             bounds,
1785                             bound_spans
1786                         )
1787                     );
1788                 }
1789             }
1790
1791             // If all predicates are inferable, drop the entire clause
1792             // (including the `where`)
1793             if num_predicates > 0 && dropped_predicate_count == num_predicates {
1794                 let where_span = hir_generics.where_clause.span()
1795                     .expect("span of (nonempty) where clause should exist");
1796                 // Extend the where clause back to the closing `>` of the
1797                 // generics, except for tuple struct, which have the `where`
1798                 // after the fields of the struct.
1799                 let full_where_span = if let hir::ItemKind::Struct(hir::VariantData::Tuple(..), _)
1800                         = item.node
1801                 {
1802                     where_span
1803                 } else {
1804                     hir_generics.span.shrink_to_hi().to(where_span)
1805                 };
1806                 lint_spans.push(
1807                     full_where_span
1808                 );
1809             } else {
1810                 lint_spans.extend(where_lint_spans);
1811             }
1812
1813             if !lint_spans.is_empty() {
1814                 let mut err = cx.struct_span_lint(
1815                     EXPLICIT_OUTLIVES_REQUIREMENTS,
1816                     lint_spans.clone(),
1817                     "outlives requirements can be inferred"
1818                 );
1819                 err.multipart_suggestion(
1820                     if bound_count == 1 {
1821                         "remove this bound"
1822                     } else {
1823                         "remove these bounds"
1824                     },
1825                     lint_spans.into_iter().map(|span| (span, "".to_owned())).collect::<Vec<_>>(),
1826                     Applicability::MachineApplicable
1827                 );
1828                 err.emit();
1829             }
1830         }
1831     }
1832 }
1833
1834 declare_lint! {
1835     pub INCOMPLETE_FEATURES,
1836     Warn,
1837     "incomplete features that may function improperly in some or all cases"
1838 }
1839
1840 declare_lint_pass!(
1841     /// Check for used feature gates in `INCOMPLETE_FEATURES` in `feature_gate.rs`.
1842     IncompleteFeatures => [INCOMPLETE_FEATURES]
1843 );
1844
1845 impl EarlyLintPass for IncompleteFeatures {
1846     fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
1847         let features = cx.sess.features_untracked();
1848         features.declared_lang_features
1849             .iter().map(|(name, span, _)| (name, span))
1850             .chain(features.declared_lib_features.iter().map(|(name, span)| (name, span)))
1851             .filter(|(name, _)| feature_gate::INCOMPLETE_FEATURES.iter().any(|f| name == &f))
1852             .for_each(|(name, &span)| {
1853                 cx.struct_span_lint(
1854                     INCOMPLETE_FEATURES,
1855                     span,
1856                     &format!(
1857                         "the feature `{}` is incomplete and may cause the compiler to crash",
1858                         name,
1859                     )
1860                 )
1861                 .emit();
1862             });
1863     }
1864 }