1 // This file incorporates work covered by the following copyright and
3 // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
4 // file at the top-level directory of this distribution and at
5 // http://rust-lang.org/COPYRIGHT.
7 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
8 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
9 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
10 // option. This file may not be copied, modified, or distributed
11 // except according to those terms.
14 // Note: More specifically this lint is largely inspired (aka copied) from
18 // [`missing_doc`]: https://github.com/rust-lang/rust/blob/d6d05904697d89099b55da3331155392f1db9c00/src/librustc_lint/builtin.rs#L246
26 use syntax
::codemap
::Span
;
29 /// **What it does:** Warns if there is missing doc for any documentable item
30 /// (public or private).
32 /// **Why is this bad?** Doc is good. *rustc* has a `MISSING_DOCS`
33 /// allowed-by-default lint for
34 /// public members, but has no way to enforce documentation of private items.
35 /// This lint fixes that.
37 /// **Known problems:** None.
39 pub MISSING_DOCS_IN_PRIVATE_ITEMS
,
41 "detects missing documentation for public and private members"
44 pub struct MissingDoc
{
45 /// Stack of whether #[doc(hidden)] is set
46 /// at each level which has lint attributes.
47 doc_hidden_stack
: Vec
<bool
>,
50 impl ::std
::default::Default
for MissingDoc
{
51 fn default() -> Self {
57 pub fn new() -> Self {
59 doc_hidden_stack
: vec
![false],
63 fn doc_hidden(&self) -> bool
{
64 *self.doc_hidden_stack
66 .expect("empty doc_hidden_stack")
69 fn check_missing_docs_attrs(&self, cx
: &LateContext
, attrs
: &[ast
::Attribute
], sp
: Span
, desc
: &'
static str) {
70 // If we're building a test harness, then warning about
71 // documentation is probably not really relevant right now.
72 if cx
.sess().opts
.test
{
76 // `#[doc(hidden)]` disables missing_docs check.
77 if self.doc_hidden() {
87 .any(|a
| a
.is_value_str() && a
.name().map_or(false, |n
| n
== "doc"));
90 MISSING_DOCS_IN_PRIVATE_ITEMS
,
92 &format
!("missing documentation for {}", desc
),
98 impl LintPass
for MissingDoc
{
99 fn get_lints(&self) -> LintArray
{
100 lint_array
![MISSING_DOCS_IN_PRIVATE_ITEMS
]
104 impl<'a
, 'tcx
> LateLintPass
<'a
, 'tcx
> for MissingDoc
{
105 fn enter_lint_attrs(&mut self, _
: &LateContext
<'a
, 'tcx
>, attrs
: &'tcx
[ast
::Attribute
]) {
106 let doc_hidden
= self.doc_hidden() || attrs
.iter().any(|attr
| {
107 attr
.check_name("doc") && match attr
.meta_item_list() {
109 Some(l
) => attr
::list_contains_name(&l
[..], "hidden"),
112 self.doc_hidden_stack
.push(doc_hidden
);
115 fn exit_lint_attrs(&mut self, _
: &LateContext
<'a
, 'tcx
>, _
: &'tcx
[ast
::Attribute
]) {
116 self.doc_hidden_stack
.pop().expect("empty doc_hidden_stack");
119 fn check_crate(&mut self, cx
: &LateContext
<'a
, 'tcx
>, krate
: &'tcx hir
::Crate
) {
120 self.check_missing_docs_attrs(cx
, &krate
.attrs
, krate
.span
, "crate");
123 fn check_item(&mut self, cx
: &LateContext
<'a
, 'tcx
>, it
: &'tcx hir
::Item
) {
124 let desc
= match it
.node
{
125 hir
::ItemConst(..) => "a constant",
126 hir
::ItemEnum(..) => "an enum",
127 hir
::ItemFn(..) => "a function",
128 hir
::ItemMod(..) => "a module",
129 hir
::ItemStatic(..) => "a static",
130 hir
::ItemStruct(..) => "a struct",
131 hir
::ItemTrait(..) => "a trait",
132 hir
::ItemGlobalAsm(..) => "an assembly blob",
133 hir
::ItemTy(..) => "a type alias",
134 hir
::ItemUnion(..) => "a union",
135 hir
::ItemAutoImpl(..) |
136 hir
::ItemExternCrate(..) |
137 hir
::ItemForeignMod(..) |
139 hir
::ItemUse(..) => return,
142 self.check_missing_docs_attrs(cx
, &it
.attrs
, it
.span
, desc
);
145 fn check_trait_item(&mut self, cx
: &LateContext
<'a
, 'tcx
>, trait_item
: &'tcx hir
::TraitItem
) {
146 let desc
= match trait_item
.node
{
147 hir
::TraitItemKind
::Const(..) => "an associated constant",
148 hir
::TraitItemKind
::Method(..) => "a trait method",
149 hir
::TraitItemKind
::Type(..) => "an associated type",
152 self.check_missing_docs_attrs(cx
, &trait_item
.attrs
, trait_item
.span
, desc
);
155 fn check_impl_item(&mut self, cx
: &LateContext
<'a
, 'tcx
>, impl_item
: &'tcx hir
::ImplItem
) {
156 // If the method is an impl for a trait, don't doc.
157 let def_id
= cx
.tcx
.hir
.local_def_id(impl_item
.id
);
158 match cx
.tcx
.associated_item(def_id
).container
{
159 ty
::TraitContainer(_
) => return,
160 ty
::ImplContainer(cid
) => if cx
.tcx
.impl_trait_ref(cid
).is_some() {
165 let desc
= match impl_item
.node
{
166 hir
::ImplItemKind
::Const(..) => "an associated constant",
167 hir
::ImplItemKind
::Method(..) => "a method",
168 hir
::ImplItemKind
::Type(_
) => "an associated type",
170 self.check_missing_docs_attrs(cx
, &impl_item
.attrs
, impl_item
.span
, desc
);
173 fn check_struct_field(&mut self, cx
: &LateContext
<'a
, 'tcx
>, sf
: &'tcx hir
::StructField
) {
174 if !sf
.is_positional() {
175 self.check_missing_docs_attrs(cx
, &sf
.attrs
, sf
.span
, "a struct field");
179 fn check_variant(&mut self, cx
: &LateContext
<'a
, 'tcx
>, v
: &'tcx hir
::Variant
, _
: &hir
::Generics
) {
180 self.check_missing_docs_attrs(cx
, &v
.node
.attrs
, v
.span
, "a variant");