diff --git a/CHANGELOG.md b/CHANGELOG.md index f0e495961..7723b5583 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ # Change Log All notable changes to this project will be documented in this file. +## 0.0.86 — ? +* New lints: [`missing_docs_in_private_items`], [`zero_prefixed_literal`] + ## 0.0.85 — 2016-08-19 * Fix ICE with [`useless_attribute`] * [`useless_attribute`] ignores [`unused_imports`] on `use` statements @@ -238,6 +241,7 @@ All notable changes to this project will be documented in this file. [`mem_forget`]: https://github.com/Manishearth/rust-clippy/wiki#mem_forget [`min_max`]: https://github.com/Manishearth/rust-clippy/wiki#min_max [`misrefactored_assign_op`]: https://github.com/Manishearth/rust-clippy/wiki#misrefactored_assign_op +[`missing_docs_in_private_items`]: https://github.com/Manishearth/rust-clippy/wiki#missing_docs_in_private_items [`mixed_case_hex_literals`]: https://github.com/Manishearth/rust-clippy/wiki#mixed_case_hex_literals [`module_inception`]: https://github.com/Manishearth/rust-clippy/wiki#module_inception [`modulo_one`]: https://github.com/Manishearth/rust-clippy/wiki#modulo_one @@ -329,5 +333,6 @@ All notable changes to this project will be documented in this file. [`wrong_self_convention`]: https://github.com/Manishearth/rust-clippy/wiki#wrong_self_convention [`wrong_transmute`]: https://github.com/Manishearth/rust-clippy/wiki#wrong_transmute [`zero_divided_by_zero`]: https://github.com/Manishearth/rust-clippy/wiki#zero_divided_by_zero +[`zero_prefixed_literal`]: https://github.com/Manishearth/rust-clippy/wiki#zero_prefixed_literal [`zero_width_space`]: https://github.com/Manishearth/rust-clippy/wiki#zero_width_space diff --git a/README.md b/README.md index 401126165..64d2932ed 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Table of contents: ## Lints -There are 167 lints included in this crate: +There are 169 lints included in this crate: name | default | triggers on ---------------------------------------------------------------------------------------------------------------------|---------|---------------------------------------------------------------------------------------------------------------------------------- @@ -100,6 +100,7 @@ name [mem_forget](https://github.com/Manishearth/rust-clippy/wiki#mem_forget) | allow | `mem::forget` usage on `Drop` types, likely to cause memory leaks [min_max](https://github.com/Manishearth/rust-clippy/wiki#min_max) | warn | `min(_, max(_, _))` (or vice versa) with bounds clamping the result to a constant [misrefactored_assign_op](https://github.com/Manishearth/rust-clippy/wiki#misrefactored_assign_op) | warn | having a variable on both sides of an assign op +[missing_docs_in_private_items](https://github.com/Manishearth/rust-clippy/wiki#missing_docs_in_private_items) | allow | detects missing documentation for public and private members [mixed_case_hex_literals](https://github.com/Manishearth/rust-clippy/wiki#mixed_case_hex_literals) | warn | hex literals whose letter digits are not consistently upper- or lowercased [module_inception](https://github.com/Manishearth/rust-clippy/wiki#module_inception) | warn | modules that have the same name as their parent module [modulo_one](https://github.com/Manishearth/rust-clippy/wiki#modulo_one) | warn | taking a number modulo 1, which always returns 0 @@ -187,6 +188,7 @@ name [wrong_self_convention](https://github.com/Manishearth/rust-clippy/wiki#wrong_self_convention) | warn | defining a method named with an established prefix (like "into_") that takes `self` with the wrong convention [wrong_transmute](https://github.com/Manishearth/rust-clippy/wiki#wrong_transmute) | warn | transmutes that are confusing at best, undefined behaviour at worst and always useless [zero_divided_by_zero](https://github.com/Manishearth/rust-clippy/wiki#zero_divided_by_zero) | warn | usage of `0.0 / 0.0` to obtain NaN instead of std::f32::NaN or std::f64::NaN +[zero_prefixed_literal](https://github.com/Manishearth/rust-clippy/wiki#zero_prefixed_literal) | warn | integer literals starting with `0` [zero_width_space](https://github.com/Manishearth/rust-clippy/wiki#zero_width_space) | deny | using a zero-width space in a string literal, which is confusing More to come, please [file an issue](https://github.com/Manishearth/rust-clippy/issues) if you have ideas! diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 07d504f75..f7b1dcb40 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -10,7 +10,7 @@ #![feature(stmt_expr_attributes)] #![feature(type_macros)] -#![allow(indexing_slicing, shadow_reuse, unknown_lints)] +#![allow(indexing_slicing, shadow_reuse, unknown_lints, missing_docs_in_private_items)] #[macro_use] extern crate syntax; @@ -96,6 +96,7 @@ pub mod methods; pub mod minmax; pub mod misc; pub mod misc_early; +pub mod missing_doc; pub mod module_inception; pub mod mut_mut; pub mod mut_reference; @@ -260,6 +261,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) { reg.register_late_lint_pass(box assign_ops::AssignOps); reg.register_late_lint_pass(box let_if_seq::LetIfSeq); reg.register_late_lint_pass(box eval_order_dependence::EvalOrderDependence); + reg.register_late_lint_pass(box missing_doc::MissingDoc::new()); reg.register_lint_group("clippy_restrictions", vec![ arithmetic::FLOAT_ARITHMETIC, @@ -282,6 +284,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) { methods::WRONG_PUB_SELF_CONVENTION, misc::USED_UNDERSCORE_BINDING, misc_early::UNSEPARATED_LITERAL_SUFFIX, + missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS, mut_mut::MUT_MUT, mutex_atomic::MUTEX_INTEGER, non_expressive_names::SIMILAR_NAMES, @@ -387,6 +390,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) { misc_early::MIXED_CASE_HEX_LITERALS, misc_early::REDUNDANT_CLOSURE_CALL, misc_early::UNNEEDED_FIELD_PATTERN, + misc_early::ZERO_PREFIXED_LITERAL, module_inception::MODULE_INCEPTION, mut_reference::UNNECESSARY_MUT_PASSED, mutex_atomic::MUTEX_ATOMIC, diff --git a/clippy_lints/src/misc_early.rs b/clippy_lints/src/misc_early.rs index 63b27f48f..47b6854cf 100644 --- a/clippy_lints/src/misc_early.rs +++ b/clippy_lints/src/misc_early.rs @@ -105,6 +105,42 @@ declare_lint! { "literals whose suffix is not separated by an underscore" } +/// **What it does:** Warns if a integral constant literal starts with `0`. +/// +/// **Why is this bad?** In some languages (including the infamous C language and most of its +/// familly), this marks an octal constant. In Rust however, this is a decimal constant. This could +/// be confusing for both the writer and a reader of the constant. +/// +/// **Known problems:** None. +/// +/// **Example:** +/// +/// In Rust: +/// ```rust +/// fn main() { +/// let a = 0123; +/// println!("{}", a); +/// } +/// ``` +/// +/// prints `123`, while in C: +/// +/// ```c +/// #include +/// +/// int main() { +/// int a = 0123; +/// printf("%d\n", a); +/// } +/// ``` +/// +/// prints `83` (as `89 == 0o123` while `123 == 0o173`). +declare_lint! { + pub ZERO_PREFIXED_LITERAL, + Warn, + "integer literals starting with `0`" +} + #[derive(Copy, Clone)] pub struct MiscEarly; @@ -112,7 +148,8 @@ pub struct MiscEarly; impl LintPass for MiscEarly { fn get_lints(&self) -> LintArray { lint_array!(UNNEEDED_FIELD_PATTERN, DUPLICATE_UNDERSCORE_ARGUMENT, REDUNDANT_CLOSURE_CALL, - DOUBLE_NEG, MIXED_CASE_HEX_LITERALS, UNSEPARATED_LITERAL_SUFFIX) + DOUBLE_NEG, MIXED_CASE_HEX_LITERALS, UNSEPARATED_LITERAL_SUFFIX, + ZERO_PREFIXED_LITERAL) } } @@ -220,7 +257,7 @@ impl EarlyLintPass for MiscEarly { } ExprKind::Lit(ref lit) => { if_let_chain! {[ - let LitKind::Int(..) = lit.node, + let LitKind::Int(value, ..) = lit.node, let Some(src) = snippet_opt(cx, lit.span), let Some(firstch) = src.chars().next(), char::to_digit(firstch, 10).is_some() @@ -250,6 +287,15 @@ impl EarlyLintPass for MiscEarly { span_lint(cx, MIXED_CASE_HEX_LITERALS, lit.span, "inconsistent casing in hexadecimal literal"); } + } else if value != 0 && src.starts_with('0') { + span_lint_and_then(cx, + ZERO_PREFIXED_LITERAL, + lit.span, + "this is a decimal constant", + |db| { + db.span_suggestion(lit.span, "if you mean to use a decimal constant, remove the `0` to remove confusion:", src[1..].to_string()); + db.span_suggestion(lit.span, "if you mean to use an octal constant, use `0o`:", format!("0o{}", &src[1..])); + }); } }} if_let_chain! {[ diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs new file mode 100644 index 000000000..0871f5ab5 --- /dev/null +++ b/clippy_lints/src/missing_doc.rs @@ -0,0 +1,178 @@ +/* This file incorporates work covered by the following copyright and + * permission notice: + * Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT + * file at the top-level directory of this distribution and at + * http://rust-lang.org/COPYRIGHT. + * + * Licensed under the Apache License, Version 2.0 or the MIT license + * , at your + * option. This file may not be copied, modified, or distributed + * except according to those terms. + */ + +/* Note: More specifically this lint is largely inspired (aka copied) from *rustc*'s + * [`missing_doc`]. + * + * [`missing_doc`]: https://github.com/rust-lang/rust/blob/d6d05904697d89099b55da3331155392f1db9c00/src/librustc_lint/builtin.rs#L246 + */ + +use rustc::hir; +use rustc::lint::*; +use rustc::ty; +use syntax::ast; +use syntax::attr::{self, AttrMetaMethods}; +use syntax::codemap::Span; +use utils::in_macro; + +/// **What it does:** Warns if there is missing doc for any documentable item (public or private). +/// +/// **Why is this bad?** Doc is good. *rustc* has a `MISSING_DOCS` allowed-by-default lint for +/// public members, but has no way to enforce documentation of private items. This lint fixes that. +/// +/// **Known problems:** None. +declare_lint! { + pub MISSING_DOCS_IN_PRIVATE_ITEMS, + Allow, + "detects missing documentation for public and private members" +} + +pub struct MissingDoc { + /// Stack of whether #[doc(hidden)] is set + /// at each level which has lint attributes. + doc_hidden_stack: Vec, +} + +impl ::std::default::Default for MissingDoc { + fn default() -> MissingDoc { + MissingDoc::new() + } +} + +impl MissingDoc { + pub fn new() -> MissingDoc { + MissingDoc { + doc_hidden_stack: vec![false], + } + } + + fn doc_hidden(&self) -> bool { + *self.doc_hidden_stack.last().expect("empty doc_hidden_stack") + } + + fn check_missing_docs_attrs(&self, + cx: &LateContext, + attrs: &[ast::Attribute], + sp: Span, + desc: &'static str) { + // If we're building a test harness, then warning about + // documentation is probably not really relevant right now. + if cx.sess().opts.test { + return; + } + + // `#[doc(hidden)]` disables missing_docs check. + if self.doc_hidden() { + return; + } + + if in_macro(cx, sp) { + return; + } + + let has_doc = attrs.iter().any(|a| a.is_value_str() && a.name() == "doc"); + if !has_doc { + cx.span_lint(MISSING_DOCS_IN_PRIVATE_ITEMS, sp, + &format!("missing documentation for {}", desc)); + } + } +} + +impl LintPass for MissingDoc { + fn get_lints(&self) -> LintArray { + lint_array![MISSING_DOCS_IN_PRIVATE_ITEMS] + } +} + +impl LateLintPass for MissingDoc { + fn enter_lint_attrs(&mut self, _: &LateContext, attrs: &[ast::Attribute]) { + let doc_hidden = self.doc_hidden() || attrs.iter().any(|attr| { + attr.check_name("doc") && match attr.meta_item_list() { + None => false, + Some(l) => attr::contains_name(&l[..], "hidden"), + } + }); + self.doc_hidden_stack.push(doc_hidden); + } + + fn exit_lint_attrs(&mut self, _: &LateContext, _: &[ast::Attribute]) { + self.doc_hidden_stack.pop().expect("empty doc_hidden_stack"); + } + + fn check_crate(&mut self, cx: &LateContext, krate: &hir::Crate) { + self.check_missing_docs_attrs(cx, &krate.attrs, krate.span, "crate"); + } + + fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { + let desc = match it.node { + hir::ItemConst(..) => "a constant", + hir::ItemEnum(..) => "an enum", + hir::ItemFn(..) => "a function", + hir::ItemMod(..) => "a module", + hir::ItemStatic(..) => "a static", + hir::ItemStruct(..) => "a struct", + hir::ItemTrait(..) => "a trait", + hir::ItemTy(..) => "a type alias", + hir::ItemDefaultImpl(..) | + hir::ItemExternCrate(..) | + hir::ItemForeignMod(..) | + hir::ItemImpl(..) | + hir::ItemUse(..) => return, + }; + + self.check_missing_docs_attrs(cx, &it.attrs, it.span, desc); + } + + fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) { + let desc = match trait_item.node { + hir::ConstTraitItem(..) => "an associated constant", + hir::MethodTraitItem(..) => "a trait method", + hir::TypeTraitItem(..) => "an associated type", + }; + + self.check_missing_docs_attrs(cx, &trait_item.attrs, trait_item.span, desc); + } + + fn check_impl_item(&mut self, cx: &LateContext, impl_item: &hir::ImplItem) { + // If the method is an impl for a trait, don't doc. + let def_id = cx.tcx.map.local_def_id(impl_item.id); + match cx.tcx.impl_or_trait_items.borrow() + .get(&def_id) + .expect("missing method descriptor?!") + .container() { + ty::TraitContainer(_) => return, + ty::ImplContainer(cid) => { + if cx.tcx.impl_trait_ref(cid).is_some() { + return + } + } + } + + let desc = match impl_item.node { + hir::ImplItemKind::Const(..) => "an associated constant", + hir::ImplItemKind::Method(..) => "a method", + hir::ImplItemKind::Type(_) => "an associated type", + }; + self.check_missing_docs_attrs(cx, &impl_item.attrs, impl_item.span, desc); + } + + fn check_struct_field(&mut self, cx: &LateContext, sf: &hir::StructField) { + if !sf.is_positional() { + self.check_missing_docs_attrs(cx, &sf.attrs, sf.span, "a struct field"); + } + } + + fn check_variant(&mut self, cx: &LateContext, v: &hir::Variant, _: &hir::Generics) { + self.check_missing_docs_attrs(cx, &v.node.attrs, v.span, "a variant"); + } +} diff --git a/clippy_lints/src/utils/comparisons.rs b/clippy_lints/src/utils/comparisons.rs index b890a363f..a277226eb 100644 --- a/clippy_lints/src/utils/comparisons.rs +++ b/clippy_lints/src/utils/comparisons.rs @@ -1,14 +1,23 @@ +//! Utility functions about comparison operators. + +#![deny(missing_docs_in_private_items)] + use rustc::hir::{BinOp_, Expr}; #[derive(PartialEq, Eq, Debug, Copy, Clone)] +/// Represent a normalized comparison operator. pub enum Rel { + /// `<` Lt, + /// `<=` Le, + /// `==` Eq, + /// `!=` Ne, } -/// Put the expression in the form `lhs < rhs` or `lhs <= rhs`. +/// Put the expression in the form `lhs < rhs`, `lhs <= rhs`, `lhs == rhs` or `lhs != rhs`. pub fn normalize_comparison<'a>(op: BinOp_, lhs: &'a Expr, rhs: &'a Expr) -> Option<(Rel, &'a Expr, &'a Expr)> { match op { diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 033e2ea82..748d144da 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -1,3 +1,7 @@ +//! Read configurations files. + +#![deny(missing_docs_in_private_items)] + use std::{fmt, fs, io}; use std::io::Read; use syntax::{ast, codemap, ptr}; @@ -32,9 +36,20 @@ pub fn file(args: &[ptr::P]) -> Result), - Type(&'static str, &'static str, &'static str), + /// Type error. + Type( + /// The name of the key. + &'static str, + /// The expected type. + &'static str, + /// The type we got instead. + &'static str + ), + /// There is an unknown key is the file. UnknownKey(String), } diff --git a/clippy_lints/src/utils/higher.rs b/clippy_lints/src/utils/higher.rs index ab8b7d8b2..aed07471a 100644 --- a/clippy_lints/src/utils/higher.rs +++ b/clippy_lints/src/utils/higher.rs @@ -1,5 +1,7 @@ //! This module contains functions for retrieve the original AST from lowered `hir`. +#![deny(missing_docs_in_private_items)] + use rustc::hir; use rustc::lint::LateContext; use syntax::ast; @@ -33,14 +35,17 @@ pub fn binop(op: hir::BinOp_) -> ast::BinOpKind { /// Represent a range akin to `ast::ExprKind::Range`. #[derive(Debug, Copy, Clone)] pub struct Range<'a> { + /// The lower bound of the range, or `None` for ranges such as `..X`. pub start: Option<&'a hir::Expr>, + /// The upper bound of the range, or `None` for ranges such as `X..`. pub end: Option<&'a hir::Expr>, + /// Whether the interval is open or closed. pub limits: ast::RangeLimits, } /// Higher a `hir` range to something similar to `ast::ExprKind::Range`. pub fn range(expr: &hir::Expr) -> Option { - // To be removed when ranges get stable. + /// Skip unstable blocks. To be removed when ranges get stable. fn unwrap_unstable(expr: &hir::Expr) -> &hir::Expr { if let hir::ExprBlock(ref block) = expr.node { if block.rules == hir::BlockCheckMode::PushUnstableBlock || block.rules == hir::BlockCheckMode::PopUnstableBlock { @@ -53,6 +58,7 @@ pub fn range(expr: &hir::Expr) -> Option { expr } + /// Find the field named `name` in the field. Always return `Some` for convenience. fn get_field<'a>(name: &str, fields: &'a [hir::Field]) -> Option<&'a hir::Expr> { let expr = &fields.iter() .find(|field| field.name.node.as_str() == name) diff --git a/clippy_lints/src/utils/sugg.rs b/clippy_lints/src/utils/sugg.rs index 0bd356721..560ec491b 100644 --- a/clippy_lints/src/utils/sugg.rs +++ b/clippy_lints/src/utils/sugg.rs @@ -1,3 +1,6 @@ +//! Contains utility functions to generate suggestions. +#![deny(missing_docs_in_private_items)] + use rustc::hir; use rustc::lint::{EarlyContext, LateContext, LintContext}; use rustc_errors; @@ -35,6 +38,7 @@ impl<'a> Display for Sugg<'a> { #[allow(wrong_self_convention)] // ok, because of the function `as_ty` method impl<'a> Sugg<'a> { + /// Prepare a suggestion from an expression. pub fn hir_opt(cx: &LateContext, expr: &hir::Expr) -> Option> { snippet_opt(cx, expr.span).map(|snippet| { let snippet = Cow::Owned(snippet); @@ -72,10 +76,12 @@ impl<'a> Sugg<'a> { }) } + /// Convenience function around `hir_opt` for suggestions with a default text. pub fn hir(cx: &LateContext, expr: &hir::Expr, default: &'a str) -> Sugg<'a> { Self::hir_opt(cx, expr).unwrap_or_else(|| Sugg::NonParen(Cow::Borrowed(default))) } + /// Prepare a suggestion from an expression. pub fn ast(cx: &EarlyContext, expr: &ast::Expr, default: &'a str) -> Sugg<'a> { use syntax::ast::RangeLimits; @@ -193,12 +199,16 @@ impl<'a> std::ops::Not for Sugg<'a> { } } +/// Helper type to display either `foo` or `(foo)`. struct ParenHelper { + /// Whether parenthesis are needed. paren: bool, + /// The main thing to display. wrapped: T, } impl ParenHelper { + /// Build a `ParenHelper`. fn new(paren: bool, wrapped: T) -> Self { ParenHelper { paren: paren, @@ -230,14 +240,18 @@ pub fn make_unop(op: &str, expr: Sugg) -> Sugg<'static> { /// Precedence of shift operator relative to other arithmetic operation is often confusing so /// parenthesis will always be added for a mix of these. pub fn make_assoc(op: AssocOp, lhs: &Sugg, rhs: &Sugg) -> Sugg<'static> { + /// Whether the operator is a shift operator `<<` or `>>`. fn is_shift(op: &AssocOp) -> bool { matches!(*op, AssocOp::ShiftLeft | AssocOp::ShiftRight) } + /// Whether the operator is a arithmetic operator (`+`, `-`, `*`, `/`, `%`). fn is_arith(op: &AssocOp) -> bool { matches!(*op, AssocOp::Add | AssocOp::Subtract | AssocOp::Multiply | AssocOp::Divide | AssocOp::Modulus) } + /// Whether the operator `op` needs parenthesis with the operator `other` in the direction + /// `dir`. fn needs_paren(op: &AssocOp, other: &AssocOp, dir: Associativity) -> bool { other.precedence() < op.precedence() || (other.precedence() == op.precedence() && @@ -298,10 +312,15 @@ pub fn make_binop(op: ast::BinOpKind, lhs: &Sugg, rhs: &Sugg) -> Sugg<'static> { } #[derive(PartialEq, Eq)] +/// Operator associativity. enum Associativity { + /// The operator is both left-associative and right-associative. Both, + /// The operator is left-associative. Left, + /// The operator is not associative. None, + /// The operator is right-associative. Right, } @@ -383,6 +402,7 @@ fn indentation(cx: &T, span: Span) -> Option { } } +/// Convenience extension trait for `DiagnosticBuilder`. pub trait DiagnosticBuilderExt { /// Suggests to add an attribute to an item. /// diff --git a/src/lib.rs b/src/lib.rs index f5229d3cb..e0a6cc28a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,7 @@ #![feature(plugin_registrar)] #![feature(rustc_private)] #![allow(unknown_lints)] +#![allow(missing_docs_in_private_items)] extern crate rustc_plugin; use rustc_plugin::Registry; diff --git a/src/main.rs b/src/main.rs index e5043c927..efe6459f5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,8 @@ #![feature(box_syntax)] #![feature(rustc_private)] +#![allow(unknown_lints, missing_docs_in_private_items)] + extern crate clippy_lints; extern crate getopts; extern crate rustc; diff --git a/tests/compile-fail/enum_glob_use.rs b/tests/compile-fail/enum_glob_use.rs index 27f0ff245..12fd10431 100644 --- a/tests/compile-fail/enum_glob_use.rs +++ b/tests/compile-fail/enum_glob_use.rs @@ -1,7 +1,7 @@ #![feature(plugin)] #![plugin(clippy)] #![deny(clippy, clippy_pedantic)] -#![allow(unused_imports, dead_code)] +#![allow(unused_imports, dead_code, missing_docs_in_private_items)] use std::cmp::Ordering::*; //~ ERROR: don't use glob imports for enum variants diff --git a/tests/compile-fail/filter_methods.rs b/tests/compile-fail/filter_methods.rs index bee9688f5..20803c8d0 100644 --- a/tests/compile-fail/filter_methods.rs +++ b/tests/compile-fail/filter_methods.rs @@ -2,6 +2,8 @@ #![plugin(clippy)] #![deny(clippy, clippy_pedantic)] +#![allow(missing_docs_in_private_items)] + fn main() { let _: Vec<_> = vec![5; 6].into_iter() //~ERROR called `filter(p).map(q)` on an `Iterator` .filter(|&x| x == 0) diff --git a/tests/compile-fail/literals.rs b/tests/compile-fail/literals.rs index 7645fb56e..91a636469 100644 --- a/tests/compile-fail/literals.rs +++ b/tests/compile-fail/literals.rs @@ -2,6 +2,7 @@ #![plugin(clippy)] #![deny(mixed_case_hex_literals)] #![deny(unseparated_literal_suffix)] +#![deny(zero_prefixed_literal)] #![allow(dead_code)] fn main() { @@ -22,4 +23,13 @@ fn main() { let fail5 = 1234isize; //~ERROR integer type suffix should be separated let fail6 = 1234usize; //~ERROR integer type suffix should be separated let fail7 = 1.5f32; //~ERROR float type suffix should be separated + + let ok9 = 0; + let ok10 = 0_i64; + let fail8 = 0123; + //~^ERROR decimal constant + //~|HELP remove the `0` + //~|SUGGESTION = 123; + //~|HELP use `0o` + //~|SUGGESTION = 0o123; } diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs index 7235bad11..0412dfeca 100644 --- a/tests/compile-fail/methods.rs +++ b/tests/compile-fail/methods.rs @@ -3,7 +3,7 @@ #![plugin(clippy)] #![deny(clippy, clippy_pedantic)] -#![allow(blacklisted_name, unused, print_stdout, non_ascii_literal, new_without_default, new_without_default_derive)] +#![allow(blacklisted_name, unused, print_stdout, non_ascii_literal, new_without_default, new_without_default_derive, missing_docs_in_private_items)] use std::collections::BTreeMap; use std::collections::HashMap; diff --git a/tests/compile-fail/missing-doc.rs b/tests/compile-fail/missing-doc.rs new file mode 100644 index 000000000..acd86f18e --- /dev/null +++ b/tests/compile-fail/missing-doc.rs @@ -0,0 +1,202 @@ +/* This file incorporates work covered by the following copyright and + * permission notice: + * Copyright 2013 The Rust Project Developers. See the COPYRIGHT + * file at the top-level directory of this distribution and at + * http://rust-lang.org/COPYRIGHT. + * + * Licensed under the Apache License, Version 2.0 or the MIT license + * , at your + * option. This file may not be copied, modified, or distributed + * except according to those terms. + */ + +#![feature(plugin)] +#![plugin(clippy)] +#![deny(missing_docs_in_private_items)] + +// When denying at the crate level, be sure to not get random warnings from the +// injected intrinsics by the compiler. +#![allow(dead_code)] +#![feature(associated_type_defaults)] + +//! Some garbage docs for the crate here +#![doc="More garbage"] + +type Typedef = String; //~ ERROR: missing documentation for a type alias +pub type PubTypedef = String; //~ ERROR: missing documentation for a type alias + +struct Foo { //~ ERROR: missing documentation for a struct + a: isize, //~ ERROR: missing documentation for a struct field + b: isize, //~ ERROR: missing documentation for a struct field +} + +pub struct PubFoo { //~ ERROR: missing documentation for a struct + pub a: isize, //~ ERROR: missing documentation for a struct field + b: isize, //~ ERROR: missing documentation for a struct field +} + +#[allow(missing_docs_in_private_items)] +pub struct PubFoo2 { + pub a: isize, + pub c: isize, +} + +mod module_no_dox {} //~ ERROR: missing documentation for a module +pub mod pub_module_no_dox {} //~ ERROR: missing documentation for a module + +/// dox +pub fn foo() {} +pub fn foo2() {} //~ ERROR: missing documentation for a function +fn foo3() {} //~ ERROR: missing documentation for a function +#[allow(missing_docs_in_private_items)] pub fn foo4() {} + +/// dox +pub trait A { + /// dox + fn foo(&self); + /// dox + fn foo_with_impl(&self) {} +} + +#[allow(missing_docs_in_private_items)] +trait B { + fn foo(&self); + fn foo_with_impl(&self) {} +} + +pub trait C { //~ ERROR: missing documentation for a trait + fn foo(&self); //~ ERROR: missing documentation for a trait method + fn foo_with_impl(&self) {} //~ ERROR: missing documentation for a trait method +} + +#[allow(missing_docs_in_private_items)] +pub trait D { + fn dummy(&self) { } +} + +/// dox +pub trait E { + type AssociatedType; //~ ERROR: missing documentation for an associated type + type AssociatedTypeDef = Self; //~ ERROR: missing documentation for an associated type + + /// dox + type DocumentedType; + /// dox + type DocumentedTypeDef = Self; + /// dox + fn dummy(&self) {} +} + +impl Foo { + pub fn foo() {} //~ ERROR: missing documentation for a method + fn bar() {} //~ ERROR: missing documentation for a method +} + +impl PubFoo { + pub fn foo() {} //~ ERROR: missing documentation for a method + /// dox + pub fn foo1() {} + fn foo2() {} //~ ERROR: missing documentation for a method + #[allow(missing_docs_in_private_items)] pub fn foo3() {} +} + +#[allow(missing_docs_in_private_items)] +trait F { + fn a(); + fn b(&self); +} + +// should need to redefine documentation for implementations of traits +impl F for Foo { + fn a() {} + fn b(&self) {} +} + +// It sure is nice if doc(hidden) implies allow(missing_docs), and that it +// applies recursively +#[doc(hidden)] +mod a { + pub fn baz() {} + pub mod b { + pub fn baz() {} + } +} + +enum Baz { //~ ERROR: missing documentation for an enum + BazA { //~ ERROR: missing documentation for a variant + a: isize, //~ ERROR: missing documentation for a struct field + b: isize //~ ERROR: missing documentation for a struct field + }, + BarB //~ ERROR: missing documentation for a variant +} + +pub enum PubBaz { //~ ERROR: missing documentation for an enum + PubBazA { //~ ERROR: missing documentation for a variant + a: isize, //~ ERROR: missing documentation for a struct field + }, +} + +/// dox +pub enum PubBaz2 { + /// dox + PubBaz2A { + /// dox + a: isize, + }, +} + +#[allow(missing_docs_in_private_items)] +pub enum PubBaz3 { + PubBaz3A { + b: isize + }, +} + +#[doc(hidden)] +pub fn baz() {} + + +const FOO: u32 = 0; //~ ERROR: missing documentation for a const +/// dox +pub const FOO1: u32 = 0; +#[allow(missing_docs_in_private_items)] +pub const FOO2: u32 = 0; +#[doc(hidden)] +pub const FOO3: u32 = 0; +pub const FOO4: u32 = 0; //~ ERROR: missing documentation for a const + + +static BAR: u32 = 0; //~ ERROR: missing documentation for a static +/// dox +pub static BAR1: u32 = 0; +#[allow(missing_docs_in_private_items)] +pub static BAR2: u32 = 0; +#[doc(hidden)] +pub static BAR3: u32 = 0; +pub static BAR4: u32 = 0; //~ ERROR: missing documentation for a static + + +mod internal_impl { //~ ERROR: missing documentation for a module + /// dox + pub fn documented() {} + pub fn undocumented1() {} //~ ERROR: missing documentation for a function + pub fn undocumented2() {} //~ ERROR: missing documentation for a function + fn undocumented3() {} //~ ERROR: missing documentation for a function + /// dox + pub mod globbed { + /// dox + pub fn also_documented() {} + pub fn also_undocumented1() {} //~ ERROR: missing documentation for a function + fn also_undocumented2() {} //~ ERROR: missing documentation for a function + } +} +/// dox +pub mod public_interface { + pub use internal_impl::documented as foo; + pub use internal_impl::undocumented1 as bar; + pub use internal_impl::{documented, undocumented2}; + pub use internal_impl::globbed::*; +} + +fn main() {} //~ ERROR: missing documentation for a function diff --git a/tests/compile-fail/shadow.rs b/tests/compile-fail/shadow.rs index 1200e25cd..fae87cd97 100644 --- a/tests/compile-fail/shadow.rs +++ b/tests/compile-fail/shadow.rs @@ -1,8 +1,8 @@ #![feature(plugin)] #![plugin(clippy)] -#![allow(unused_parens, unused_variables)] #![deny(clippy, clippy_pedantic)] +#![allow(unused_parens, unused_variables, missing_docs_in_private_items)] fn id(x: T) -> T { x }