]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_lint/builtin.rs
improve unused doc comment diagnostic reporting
[rust.git] / src / librustc_lint / builtin.rs
index ac10b6403bd132e6a7d30c08350cb3b2fc8cb454..284bfcd4014911f68530c7847e7e670ae2bb53e6 100644 (file)
@@ -26,7 +26,7 @@
 use rustc::ty::{self, Ty};
 use rustc::{lint, util};
 use hir::Node;
-use util::nodemap::NodeSet;
+use util::nodemap::HirIdSet;
 use lint::{LateContext, LintContext, LintArray};
 use lint::{LintPass, LateLintPass, EarlyLintPass, EarlyContext};
 
@@ -137,7 +137,7 @@ fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item) {
             hir::ItemKind::Enum(..) |
             hir::ItemKind::Struct(..) |
             hir::ItemKind::Union(..) => {
-                let def_id = cx.tcx.hir().local_def_id(it.id);
+                let def_id = cx.tcx.hir().local_def_id_from_hir_id(it.hir_id);
                 self.check_heap_type(cx, it.span, cx.tcx.type_of(def_id))
             }
             _ => ()
@@ -148,7 +148,7 @@ fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item) {
             hir::ItemKind::Struct(ref struct_def, _) |
             hir::ItemKind::Union(ref struct_def, _) => {
                 for struct_field in struct_def.fields() {
-                    let def_id = cx.tcx.hir().local_def_id(struct_field.id);
+                    let def_id = cx.tcx.hir().local_def_id_from_hir_id(struct_field.hir_id);
                     self.check_heap_type(cx, struct_field.span,
                                          cx.tcx.type_of(def_id));
                 }
@@ -198,7 +198,7 @@ fn check_pat(&mut self, cx: &LateContext<'_, '_>, pat: &hir::Pat) {
                     // (Issue #49588)
                     continue;
                 }
-                if let PatKind::Binding(_, _, _, ident, None) = fieldpat.node.pat.node {
+                if let PatKind::Binding(_, _, ident, None) = fieldpat.node.pat.node {
                     if cx.tcx.find_field_index(ident, &variant) ==
                        Some(cx.tcx.field_index(fieldpat.node.hir_id, cx.tables)) {
                         let mut err = cx.struct_span_lint(NON_SHORTHAND_FIELD_PATTERNS,
@@ -324,7 +324,7 @@ pub struct MissingDoc {
     doc_hidden_stack: Vec<bool>,
 
     /// Private traits or trait items that leaked through. Don't check their methods.
-    private_traits: FxHashSet<ast::NodeId>,
+    private_traits: FxHashSet<hir::HirId>,
 }
 
 fn has_doc(attr: &ast::Attribute) -> bool {
@@ -361,7 +361,7 @@ fn doc_hidden(&self) -> bool {
 
     fn check_missing_docs_attrs(&self,
                                 cx: &LateContext<'_, '_>,
-                                id: Option<ast::NodeId>,
+                                id: Option<hir::HirId>,
                                 attrs: &[ast::Attribute],
                                 sp: Span,
                                 desc: &'static str) {
@@ -380,7 +380,8 @@ fn check_missing_docs_attrs(&self,
         // It's an option so the crate root can also use this function (it doesn't
         // have a NodeId).
         if let Some(id) = id {
-            if !cx.access_levels.is_exported(id) {
+            let node_id = cx.tcx.hir().hir_to_node_id(id);
+            if !cx.access_levels.is_exported(node_id) {
                 return;
             }
         }
@@ -444,9 +445,9 @@ fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item) {
             hir::ItemKind::Trait(.., ref trait_item_refs) => {
                 // Issue #11592, traits are always considered exported, even when private.
                 if let hir::VisibilityKind::Inherited = it.vis.node {
-                    self.private_traits.insert(it.id);
+                    self.private_traits.insert(it.hir_id);
                     for trait_item_ref in trait_item_refs {
-                        self.private_traits.insert(trait_item_ref.id.node_id);
+                        self.private_traits.insert(trait_item_ref.id.hir_id);
                     }
                     return;
                 }
@@ -457,12 +458,12 @@ fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item) {
                 // If the trait is private, add the impl items to private_traits so they don't get
                 // reported for missing docs.
                 let real_trait = trait_ref.path.def.def_id();
-                if let Some(node_id) = cx.tcx.hir().as_local_node_id(real_trait) {
-                    match cx.tcx.hir().find(node_id) {
+                if let Some(hir_id) = cx.tcx.hir().as_local_hir_id(real_trait) {
+                    match cx.tcx.hir().find_by_hir_id(hir_id) {
                         Some(Node::Item(item)) => {
                             if let hir::VisibilityKind::Inherited = item.vis.node {
                                 for impl_item_ref in impl_item_refs {
-                                    self.private_traits.insert(impl_item_ref.id.node_id);
+                                    self.private_traits.insert(impl_item_ref.id.hir_id);
                                 }
                             }
                         }
@@ -476,11 +477,11 @@ fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item) {
             _ => return,
         };
 
-        self.check_missing_docs_attrs(cx, Some(it.id), &it.attrs, it.span, desc);
+        self.check_missing_docs_attrs(cx, Some(it.hir_id), &it.attrs, it.span, desc);
     }
 
     fn check_trait_item(&mut self, cx: &LateContext<'_, '_>, trait_item: &hir::TraitItem) {
-        if self.private_traits.contains(&trait_item.id) {
+        if self.private_traits.contains(&trait_item.hir_id) {
             return;
         }
 
@@ -491,7 +492,7 @@ fn check_trait_item(&mut self, cx: &LateContext<'_, '_>, trait_item: &hir::Trait
         };
 
         self.check_missing_docs_attrs(cx,
-                                      Some(trait_item.id),
+                                      Some(trait_item.hir_id),
                                       &trait_item.attrs,
                                       trait_item.span,
                                       desc);
@@ -510,7 +511,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'_, '_>, impl_item: &hir::ImplIte
             hir::ImplItemKind::Existential(_) => "an associated existential type",
         };
         self.check_missing_docs_attrs(cx,
-                                      Some(impl_item.id),
+                                      Some(impl_item.hir_id),
                                       &impl_item.attrs,
                                       impl_item.span,
                                       desc);
@@ -519,7 +520,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'_, '_>, impl_item: &hir::ImplIte
     fn check_struct_field(&mut self, cx: &LateContext<'_, '_>, sf: &hir::StructField) {
         if !sf.is_positional() {
             self.check_missing_docs_attrs(cx,
-                                          Some(sf.id),
+                                          Some(sf.hir_id),
                                           &sf.attrs,
                                           sf.span,
                                           "a struct field")
@@ -528,7 +529,7 @@ fn check_struct_field(&mut self, cx: &LateContext<'_, '_>, sf: &hir::StructField
 
     fn check_variant(&mut self, cx: &LateContext<'_, '_>, v: &hir::Variant, _: &hir::Generics) {
         self.check_missing_docs_attrs(cx,
-                                      Some(v.node.data.id()),
+                                      Some(v.node.data.hir_id()),
                                       &v.node.attrs,
                                       v.span,
                                       "a variant");
@@ -556,7 +557,8 @@ fn get_lints(&self) -> LintArray {
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingCopyImplementations {
     fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &hir::Item) {
-        if !cx.access_levels.is_reachable(item.id) {
+        let node_id = cx.tcx.hir().hir_to_node_id(item.hir_id);
+        if !cx.access_levels.is_reachable(node_id) {
             return;
         }
         let (def, ty) = match item.node {
@@ -564,21 +566,21 @@ fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &hir::Item) {
                 if !ast_generics.params.is_empty() {
                     return;
                 }
-                let def = cx.tcx.adt_def(cx.tcx.hir().local_def_id(item.id));
+                let def = cx.tcx.adt_def(cx.tcx.hir().local_def_id_from_hir_id(item.hir_id));
                 (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[])))
             }
             hir::ItemKind::Union(_, ref ast_generics) => {
                 if !ast_generics.params.is_empty() {
                     return;
                 }
-                let def = cx.tcx.adt_def(cx.tcx.hir().local_def_id(item.id));
+                let def = cx.tcx.adt_def(cx.tcx.hir().local_def_id_from_hir_id(item.hir_id));
                 (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[])))
             }
             hir::ItemKind::Enum(_, ref ast_generics) => {
                 if !ast_generics.params.is_empty() {
                     return;
                 }
-                let def = cx.tcx.adt_def(cx.tcx.hir().local_def_id(item.id));
+                let def = cx.tcx.adt_def(cx.tcx.hir().local_def_id_from_hir_id(item.hir_id));
                 (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[])))
             }
             _ => return,
@@ -606,7 +608,7 @@ fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &hir::Item) {
 }
 
 pub struct MissingDebugImplementations {
-    impling_types: Option<NodeSet>,
+    impling_types: Option<HirIdSet>,
 }
 
 impl MissingDebugImplementations {
@@ -627,7 +629,8 @@ fn get_lints(&self) -> LintArray {
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDebugImplementations {
     fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &hir::Item) {
-        if !cx.access_levels.is_reachable(item.id) {
+        let node_id = cx.tcx.hir().hir_to_node_id(item.hir_id);
+        if !cx.access_levels.is_reachable(node_id) {
             return;
         }
 
@@ -644,11 +647,11 @@ fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &hir::Item) {
         };
 
         if self.impling_types.is_none() {
-            let mut impls = NodeSet::default();
+            let mut impls = HirIdSet::default();
             cx.tcx.for_each_impl(debug, |d| {
                 if let Some(ty_def) = cx.tcx.type_of(d).ty_adt_def() {
-                    if let Some(node_id) = cx.tcx.hir().as_local_node_id(ty_def.did) {
-                        impls.insert(node_id);
+                    if let Some(hir_id) = cx.tcx.hir().as_local_hir_id(ty_def.did) {
+                        impls.insert(hir_id);
                     }
                 }
             });
@@ -657,7 +660,7 @@ fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &hir::Item) {
             debug!("{:?}", self.impling_types);
         }
 
-        if !self.impling_types.as_ref().unwrap().contains(&item.id) {
+        if !self.impling_types.as_ref().unwrap().contains(&item.hir_id) {
             cx.span_lint(MISSING_DEBUG_IMPLEMENTATIONS,
                          item.span,
                          "type does not implement `fmt::Debug`; consider adding #[derive(Debug)] \
@@ -799,27 +802,50 @@ fn get_lints(&self) -> LintArray {
 }
 
 impl UnusedDocComment {
-    fn warn_if_doc<'a, 'tcx,
-                   I: Iterator<Item=&'a ast::Attribute>,
-                   C: LintContext<'tcx>>(&self, mut attrs: I, cx: &C) {
-        if let Some(attr) = attrs.find(|a| a.is_value_str() && a.check_name("doc")) {
-            cx.struct_span_lint(UNUSED_DOC_COMMENTS, attr.span, "doc comment not used by rustdoc")
-              .emit();
+    fn warn_if_doc(&self, cx: &EarlyContext, attrs: &[ast::Attribute]) {
+        let mut attrs = attrs.into_iter().peekable();
+
+        // Accumulate a single span for sugared doc comments.
+        let mut sugared_span: Option<Span> = None;
+
+        while let Some(attr) = attrs.next() {
+            if attr.is_sugared_doc {
+                sugared_span = Some(
+                    sugared_span.map_or_else(
+                        || attr.span,
+                        |span| span.with_hi(attr.span.hi()),
+                    ),
+                );
+            }
+
+            if attrs.peek().map(|next_attr| next_attr.is_sugared_doc).unwrap_or_default() {
+                continue;
+            }
+
+            let span = sugared_span.take().unwrap_or_else(|| attr.span);
+
+            if attr.name() == "doc" {
+                cx.struct_span_lint(
+                    UNUSED_DOC_COMMENTS,
+                    span,
+                    "doc comment not used by rustdoc",
+                ).emit();
+            }
         }
     }
 }
 
 impl EarlyLintPass for UnusedDocComment {
     fn check_local(&mut self, cx: &EarlyContext<'_>, decl: &ast::Local) {
-        self.warn_if_doc(decl.attrs.iter(), cx);
+        self.warn_if_doc(cx, &decl.attrs);
     }
 
     fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &ast::Arm) {
-        self.warn_if_doc(arm.attrs.iter(), cx);
+        self.warn_if_doc(cx, &arm.attrs);
     }
 
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
-        self.warn_if_doc(expr.attrs.iter(), cx);
+        self.warn_if_doc(cx, &expr.attrs);
     }
 }
 
@@ -854,7 +880,7 @@ fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item) {
             _ => return,
         };
 
-        let def_id = cx.tcx.hir().local_def_id(it.id);
+        let def_id = cx.tcx.hir().local_def_id_from_hir_id(it.hir_id);
         let prfn = match cx.tcx.extern_mod_stmt_cnum(def_id) {
             Some(cnum) => cx.tcx.plugin_registrar_fn(cnum),
             None => {
@@ -1074,7 +1100,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnionsWithDropFields {
     fn check_item(&mut self, ctx: &LateContext<'_, '_>, item: &hir::Item) {
         if let hir::ItemKind::Union(ref vdata, _) = item.node {
             for field in vdata.fields() {
-                let field_ty = ctx.tcx.type_of(ctx.tcx.hir().local_def_id(field.id));
+                let field_ty = ctx.tcx.type_of(
+                    ctx.tcx.hir().local_def_id_from_hir_id(field.hir_id));
                 if field_ty.needs_drop(ctx.tcx, ctx.param_env) {
                     ctx.span_lint(UNIONS_WITH_DROP_FIELDS,
                                   field.span,
@@ -1108,11 +1135,12 @@ fn get_lints(&self) -> LintArray {
 }
 
 impl UnreachablePub {
-    fn perform_lint(&self, cx: &LateContext<'_, '_>, what: &str, id: ast::NodeId,
+    fn perform_lint(&self, cx: &LateContext<'_, '_>, what: &str, id: hir::HirId,
                     vis: &hir::Visibility, span: Span, exportable: bool) {
         let mut applicability = Applicability::MachineApplicable;
+        let node_id = cx.tcx.hir().hir_to_node_id(id);
         match vis.node {
-            hir::VisibilityKind::Public if !cx.access_levels.is_reachable(id) => {
+            hir::VisibilityKind::Public if !cx.access_levels.is_reachable(node_id) => {
                 if span.ctxt().outer().expn_info().is_some() {
                     applicability = Applicability::MaybeIncorrect;
                 }
@@ -1144,20 +1172,20 @@ fn perform_lint(&self, cx: &LateContext<'_, '_>, what: &str, id: ast::NodeId,
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnreachablePub {
     fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &hir::Item) {
-        self.perform_lint(cx, "item", item.id, &item.vis, item.span, true);
+        self.perform_lint(cx, "item", item.hir_id, &item.vis, item.span, true);
     }
 
     fn check_foreign_item(&mut self, cx: &LateContext<'_, '_>, foreign_item: &hir::ForeignItem) {
-        self.perform_lint(cx, "item", foreign_item.id, &foreign_item.vis,
+        self.perform_lint(cx, "item", foreign_item.hir_id, &foreign_item.vis,
                           foreign_item.span, true);
     }
 
     fn check_struct_field(&mut self, cx: &LateContext<'_, '_>, field: &hir::StructField) {
-        self.perform_lint(cx, "field", field.id, &field.vis, field.span, false);
+        self.perform_lint(cx, "field", field.hir_id, &field.vis, field.span, false);
     }
 
     fn check_impl_item(&mut self, cx: &LateContext<'_, '_>, impl_item: &hir::ImplItem) {
-        self.perform_lint(cx, "item", impl_item.id, &impl_item.vis, impl_item.span, false);
+        self.perform_lint(cx, "item", impl_item.hir_id, &impl_item.vis, impl_item.span, false);
     }
 }
 
@@ -1352,7 +1380,7 @@ fn check_item(
 
 
         if cx.tcx.features().trivial_bounds {
-            let def_id = cx.tcx.hir().local_def_id(item.id);
+            let def_id = cx.tcx.hir().local_def_id_from_hir_id(item.hir_id);
             let predicates = cx.tcx.predicates_of(def_id);
             for &(predicate, span) in &predicates.predicates {
                 let predicate_kind_name = match predicate {
@@ -1492,14 +1520,14 @@ fn matches_ellipsis_pat(pat: &ast::Pat) -> Option<(&P<Expr>, &P<Expr>, Span)> {
 }
 
 pub struct UnnameableTestItems {
-    boundary: ast::NodeId, // NodeId of the item under which things are not nameable
+    boundary: hir::HirId, // HirId of the item under which things are not nameable
     items_nameable: bool,
 }
 
 impl UnnameableTestItems {
     pub fn new() -> Self {
         Self {
-            boundary: ast::DUMMY_NODE_ID,
+            boundary: hir::DUMMY_HIR_ID,
             items_nameable: true
         }
     }
@@ -1521,7 +1549,7 @@ fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item) {
             if let hir::ItemKind::Mod(..) = it.node {}
             else {
                 self.items_nameable = false;
-                self.boundary = it.id;
+                self.boundary = it.hir_id;
             }
             return;
         }
@@ -1536,7 +1564,7 @@ fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item) {
     }
 
     fn check_item_post(&mut self, _cx: &LateContext<'_, '_>, it: &hir::Item) {
-        if !self.items_nameable && self.boundary == it.id {
+        if !self.items_nameable && self.boundary == it.hir_id {
             self.items_nameable = true;
         }
     }
@@ -1786,7 +1814,7 @@ fn consolidate_outlives_bound_spans(
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ExplicitOutlivesRequirements {
     fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item) {
         let infer_static = cx.tcx.features().infer_static_outlives_requirements;
-        let def_id = cx.tcx.hir().local_def_id(item.id);
+        let def_id = cx.tcx.hir().local_def_id_from_hir_id(item.hir_id);
         if let hir::ItemKind::Struct(_, ref generics) = item.node {
             let mut bound_count = 0;
             let mut lint_spans = Vec::new();