1
Fork 0

Merge pull request #1738 from Manishearth/serde

Update serde to 1.0
This commit is contained in:
Oliver Schneider 2017-05-10 08:55:36 +02:00 committed by GitHub
commit 3b3e47f451
11 changed files with 170 additions and 180 deletions

View file

@ -32,15 +32,15 @@ test = false
# begin automatic update # begin automatic update
clippy_lints = { version = "0.0.131", path = "clippy_lints" } clippy_lints = { version = "0.0.131", path = "clippy_lints" }
# end automatic update # end automatic update
cargo_metadata = "0.1.1" cargo_metadata = "0.2"
[dev-dependencies] [dev-dependencies]
compiletest_rs = "0.2.5" compiletest_rs = "0.2.5"
lazy_static = "0.1.15" lazy_static = "0.2"
regex = "0.2" regex = "0.2"
serde_derive = "0.9.1" serde_derive = "1.0"
clippy-mini-macro-test = { version = "0.1", path = "mini-macro" } clippy-mini-macro-test = { version = "0.1", path = "mini-macro" }
serde = "0.9.1" serde = "1.0"
[features] [features]
debugging = [] debugging = []

View file

@ -19,9 +19,12 @@ keywords = ["clippy", "lint", "plugin"]
matches = "0.1.2" matches = "0.1.2"
regex-syntax = "0.4.0" regex-syntax = "0.4.0"
semver = "0.6.0" semver = "0.6.0"
toml = "0.2" toml = "0.4"
unicode-normalization = "0.1" unicode-normalization = "0.1"
quine-mc_cluskey = "0.2.2" quine-mc_cluskey = "0.2.2"
serde = "1.0"
serde_derive = "1.0"
lazy_static = "0.2.8"
[features] [features]
debugging = [] debugging = []

View file

@ -44,6 +44,13 @@ extern crate rustc_const_math;
#[macro_use] #[macro_use]
extern crate matches as matches_macro; extern crate matches as matches_macro;
#[macro_use]
extern crate serde_derive;
extern crate serde;
#[macro_use]
extern crate lazy_static;
macro_rules! declare_restriction_lint { macro_rules! declare_restriction_lint {
{ pub $name:tt, $description:tt } => { { pub $name:tt, $description:tt } => {
declare_lint! { pub $name, Allow, $description } declare_lint! { pub $name, Allow, $description }
@ -124,7 +131,7 @@ pub mod ranges;
pub mod reference; pub mod reference;
pub mod regex; pub mod regex;
pub mod returns; pub mod returns;
pub mod serde; pub mod serde_api;
pub mod shadow; pub mod shadow;
pub mod should_assert_eq; pub mod should_assert_eq;
pub mod strings; pub mod strings;
@ -175,7 +182,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
reg.sess.struct_span_err(span, err) reg.sess.struct_span_err(span, err)
.span_note(span, "Clippy will use default configuration") .span_note(span, "Clippy will use default configuration")
.emit(); .emit();
utils::conf::Conf::default() toml::from_str("").expect("we never error on empty config files")
} }
}; };
@ -202,7 +209,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
); );
// end deprecated lints, do not remove this comment, its used in `update_lints` // end deprecated lints, do not remove this comment, its used in `update_lints`
reg.register_late_lint_pass(box serde::Serde); reg.register_late_lint_pass(box serde_api::Serde);
reg.register_early_lint_pass(box utils::internal_lints::Clippy); reg.register_early_lint_pass(box utils::internal_lints::Clippy);
reg.register_late_lint_pass(box utils::internal_lints::LintWithoutLintPass::default()); reg.register_late_lint_pass(box utils::internal_lints::LintWithoutLintPass::default());
reg.register_late_lint_pass(box utils::inspector::Pass); reg.register_late_lint_pass(box utils::inspector::Pass);
@ -266,7 +273,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
reg.register_late_lint_pass(box print::Pass); reg.register_late_lint_pass(box print::Pass);
reg.register_late_lint_pass(box vec::Pass); reg.register_late_lint_pass(box vec::Pass);
reg.register_early_lint_pass(box non_expressive_names::NonExpressiveNames { reg.register_early_lint_pass(box non_expressive_names::NonExpressiveNames {
max_single_char_names: conf.max_single_char_names, single_char_binding_names_threshold: conf.single_char_binding_names_threshold,
}); });
reg.register_late_lint_pass(box drop_forget_ref::Pass); reg.register_late_lint_pass(box drop_forget_ref::Pass);
reg.register_late_lint_pass(box empty_enum::EmptyEnum); reg.register_late_lint_pass(box empty_enum::EmptyEnum);
@ -488,7 +495,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
regex::TRIVIAL_REGEX, regex::TRIVIAL_REGEX,
returns::LET_AND_RETURN, returns::LET_AND_RETURN,
returns::NEEDLESS_RETURN, returns::NEEDLESS_RETURN,
serde::SERDE_API_MISUSE, serde_api::SERDE_API_MISUSE,
should_assert_eq::SHOULD_ASSERT_EQ, should_assert_eq::SHOULD_ASSERT_EQ,
strings::STRING_LIT_AS_BYTES, strings::STRING_LIT_AS_BYTES,
swap::ALMOST_SWAPPED, swap::ALMOST_SWAPPED,

View file

@ -4,7 +4,7 @@ use std::char;
use syntax::ast::*; use syntax::ast::*;
use syntax::codemap::Span; use syntax::codemap::Span;
use syntax::visit::FnKind; use syntax::visit::FnKind;
use utils::{constants, span_lint, span_help_and_lint, snippet, snippet_opt, span_lint_and_then}; use utils::{constants, span_lint, span_help_and_lint, snippet, snippet_opt, span_lint_and_then, in_external_macro};
/// **What it does:** Checks for structure field patterns bound to wildcards. /// **What it does:** Checks for structure field patterns bound to wildcards.
/// ///
@ -267,6 +267,9 @@ impl EarlyLintPass for MiscEarly {
} }
fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) { fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) {
if in_external_macro(cx, expr.span) {
return;
}
match expr.node { match expr.node {
ExprKind::Call(ref paren, _) => { ExprKind::Call(ref paren, _) => {
if let ExprKind::Paren(ref closure) = paren.node { if let ExprKind::Paren(ref closure) = paren.node {
@ -290,7 +293,38 @@ impl EarlyLintPass for MiscEarly {
"`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op"); "`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op");
} }
}, },
ExprKind::Lit(ref lit) => { ExprKind::Lit(ref lit) => self.check_lit(cx, lit),
_ => (),
}
}
fn check_block(&mut self, cx: &EarlyContext, block: &Block) {
for w in block.stmts.windows(2) {
if_let_chain! {[
let StmtKind::Local(ref local) = w[0].node,
let Option::Some(ref t) = local.init,
let ExprKind::Closure(_, _, _, _) = t.node,
let PatKind::Ident(_, sp_ident, _) = local.pat.node,
let StmtKind::Semi(ref second) = w[1].node,
let ExprKind::Assign(_, ref call) = second.node,
let ExprKind::Call(ref closure, _) = call.node,
let ExprKind::Path(_, ref path) = closure.node
], {
if sp_ident.node == (&path.segments[0]).identifier {
span_lint(
cx,
REDUNDANT_CLOSURE_CALL,
second.span,
"Closure called just once immediately after it was declared",
);
}
}}
}
}
}
impl MiscEarly {
fn check_lit(&self, cx: &EarlyContext, lit: &Lit) {
if_let_chain! {[ if_let_chain! {[
let LitKind::Int(value, ..) = lit.node, let LitKind::Int(value, ..) = lit.node,
let Some(src) = snippet_opt(cx, lit.span), let Some(src) = snippet_opt(cx, lit.span),
@ -361,32 +395,5 @@ impl EarlyLintPass for MiscEarly {
prev = ch; prev = ch;
} }
}} }}
},
_ => (),
}
}
fn check_block(&mut self, cx: &EarlyContext, block: &Block) {
for w in block.stmts.windows(2) {
if_let_chain! {[
let StmtKind::Local(ref local) = w[0].node,
let Option::Some(ref t) = local.init,
let ExprKind::Closure(_, _, _, _) = t.node,
let PatKind::Ident(_, sp_ident, _) = local.pat.node,
let StmtKind::Semi(ref second) = w[1].node,
let ExprKind::Assign(_, ref call) = second.node,
let ExprKind::Call(ref closure, _) = call.node,
let ExprKind::Path(_, ref path) = closure.node
], {
if sp_ident.node == (&path.segments[0]).identifier {
span_lint(
cx,
REDUNDANT_CLOSURE_CALL,
second.span,
"Closure called just once immediately after it was declared",
);
}
}}
}
} }
} }

View file

@ -43,7 +43,7 @@ declare_lint! {
} }
pub struct NonExpressiveNames { pub struct NonExpressiveNames {
pub max_single_char_names: u64, pub single_char_binding_names_threshold: u64,
} }
impl LintPass for NonExpressiveNames { impl LintPass for NonExpressiveNames {
@ -127,7 +127,7 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> {
return; return;
} }
self.0.single_char_names.push(c); self.0.single_char_names.push(c);
if self.0.single_char_names.len() as u64 >= self.0.lint.max_single_char_names { if self.0.single_char_names.len() as u64 >= self.0.lint.single_char_binding_names_threshold {
span_lint(self.0.cx, span_lint(self.0.cx,
MANY_SINGLE_CHAR_NAMES, MANY_SINGLE_CHAR_NAMES,
span, span,

View file

@ -6,6 +6,7 @@ use std::{env, fmt, fs, io, path};
use std::io::Read; use std::io::Read;
use syntax::{ast, codemap}; use syntax::{ast, codemap};
use toml; use toml;
use std::sync::Mutex;
/// Get the configuration file from arguments. /// Get the configuration file from arguments.
pub fn file_from_args(args: &[codemap::Spanned<ast::NestedMetaItemKind>]) pub fn file_from_args(args: &[codemap::Spanned<ast::NestedMetaItemKind>])
@ -34,8 +35,8 @@ pub fn file_from_args(args: &[codemap::Spanned<ast::NestedMetaItemKind>])
pub enum Error { pub enum Error {
/// An I/O error. /// An I/O error.
Io(io::Error), Io(io::Error),
/// The file is not valid TOML. /// Not valid toml or doesn't fit the expected conf format
Toml(Vec<toml::ParserError>), Toml(String),
/// Type error. /// Type error.
Type(/// The name of the key. Type(/// The name of the key.
&'static str, &'static str,
@ -51,19 +52,7 @@ impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self { match *self {
Error::Io(ref err) => err.fmt(f), Error::Io(ref err) => err.fmt(f),
Error::Toml(ref errs) => { Error::Toml(ref err) => err.fmt(f),
let mut first = true;
for err in errs {
if !first {
try!(", ".fmt(f));
first = false;
}
try!(err.fmt(f));
}
Ok(())
},
Error::Type(key, expected, got) => { Error::Type(key, expected, got) => {
write!(f, "`{}` is expected to be a `{}` but is a `{}`", key, expected, got) write!(f, "`{}` is expected to be a `{}` but is a `{}`", key, expected, got)
}, },
@ -78,55 +67,45 @@ impl From<io::Error> for Error {
} }
} }
lazy_static! {
static ref ERRORS: Mutex<Vec<Error>> = Mutex::new(Vec::new());
}
macro_rules! define_Conf { macro_rules! define_Conf {
($(#[$doc: meta] ($toml_name: tt, $rust_name: ident, $default: expr => $($ty: tt)+),)+) => { ($(#[$doc: meta] ($rust_name: ident, $rust_name_str: expr, $default: expr => $($ty: tt)+),)+) => {
pub use self::helpers::Conf;
mod helpers {
/// Type used to store lint configuration. /// Type used to store lint configuration.
#[derive(Deserialize)]
#[serde(rename_all="kebab-case")]
#[serde(deny_unknown_fields)]
pub struct Conf { pub struct Conf {
$(#[$doc] pub $rust_name: define_Conf!(TY $($ty)+),)+ $(#[$doc] #[serde(default=$rust_name_str)] #[serde(with=$rust_name_str)] pub $rust_name: define_Conf!(TY $($ty)+),)+
#[allow(dead_code)]
#[serde(default)]
third_party: Option<::toml::Value>,
} }
impl Default for Conf {
fn default() -> Conf {
Conf {
$($rust_name: define_Conf!(DEFAULT $($ty)+, $default),)+
}
}
}
impl Conf {
/// Set the property `name` (which must be the `toml` name) to the given value
#[allow(cast_sign_loss)]
fn set(&mut self, name: String, value: toml::Value) -> Result<(), Error> {
match name.as_str() {
$( $(
define_Conf!(PAT $toml_name) => { mod $rust_name {
if let Some(value) = define_Conf!(CONV $($ty)+, value) { use serde;
self.$rust_name = value; use serde::Deserialize;
} pub fn deserialize<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<define_Conf!(TY $($ty)+), D::Error> {
else { type T = define_Conf!(TY $($ty)+);
return Err(Error::Type(define_Conf!(EXPR $toml_name), Ok(T::deserialize(deserializer).unwrap_or_else(|e| {
stringify!($($ty)+), ::utils::conf::ERRORS.lock().expect("no threading here").push(::utils::conf::Error::Toml(e.to_string()));
value.type_str())); super::$rust_name()
} }))
},
)+
"third-party" => {
// for external tools such as clippy-service
return Ok(());
}
_ => {
return Err(Error::UnknownKey(name));
} }
} }
Ok(()) fn $rust_name() -> define_Conf!(TY $($ty)+) {
define_Conf!(DEFAULT $($ty)+, $default)
} }
)+
} }
}; };
// hack to convert tts // hack to convert tts
(PAT $pat: pat) => { $pat };
(EXPR $e: expr) => { $e };
(TY $ty: ty) => { $ty }; (TY $ty: ty) => { $ty };
// how to read the value? // how to read the value?
@ -139,7 +118,7 @@ macro_rules! define_Conf {
}; };
(CONV String, $value: expr) => { $value.as_str().map(Into::into) }; (CONV String, $value: expr) => { $value.as_str().map(Into::into) };
(CONV Vec<String>, $value: expr) => {{ (CONV Vec<String>, $value: expr) => {{
let slice = $value.as_slice(); let slice = $value.as_array();
if let Some(slice) = slice { if let Some(slice) = slice {
if slice.iter().any(|v| v.as_str().is_none()) { if slice.iter().any(|v| v.as_str().is_none()) {
@ -159,11 +138,11 @@ macro_rules! define_Conf {
define_Conf! { define_Conf! {
/// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about /// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about
("blacklisted-names", blacklisted_names, ["foo", "bar", "baz", "quux"] => Vec<String>), (blacklisted_names, "blacklisted_names", ["foo", "bar", "baz", "quux"] => Vec<String>),
/// Lint: CYCLOMATIC_COMPLEXITY. The maximum cyclomatic complexity a function can have /// Lint: CYCLOMATIC_COMPLEXITY. The maximum cyclomatic complexity a function can have
("cyclomatic-complexity-threshold", cyclomatic_complexity_threshold, 25 => u64), (cyclomatic_complexity_threshold, "cyclomatic_complexity_threshold", 25 => u64),
/// Lint: DOC_MARKDOWN. The list of words this lint should not consider as identifiers needing ticks /// Lint: DOC_MARKDOWN. The list of words this lint should not consider as identifiers needing ticks
("doc-valid-idents", doc_valid_idents, [ (doc_valid_idents, "doc_valid_idents", [
"KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB",
"DirectX", "DirectX",
"ECMAScript", "ECMAScript",
@ -180,17 +159,17 @@ define_Conf! {
"MinGW", "MinGW",
] => Vec<String>), ] => Vec<String>),
/// Lint: TOO_MANY_ARGUMENTS. The maximum number of argument a function or method can have /// Lint: TOO_MANY_ARGUMENTS. The maximum number of argument a function or method can have
("too-many-arguments-threshold", too_many_arguments_threshold, 7 => u64), (too_many_arguments_threshold, "too_many_arguments_threshold", 7 => u64),
/// Lint: TYPE_COMPLEXITY. The maximum complexity a type can have /// Lint: TYPE_COMPLEXITY. The maximum complexity a type can have
("type-complexity-threshold", type_complexity_threshold, 250 => u64), (type_complexity_threshold, "type_complexity_threshold", 250 => u64),
/// Lint: MANY_SINGLE_CHAR_NAMES. The maximum number of single char bindings a scope may have /// Lint: MANY_SINGLE_CHAR_NAMES. The maximum number of single char bindings a scope may have
("single-char-binding-names-threshold", max_single_char_names, 5 => u64), (single_char_binding_names_threshold, "single_char_binding_names_threshold", 5 => u64),
/// Lint: BOXED_LOCAL. The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap /// Lint: BOXED_LOCAL. The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap
("too-large-for-stack", too_large_for_stack, 200 => u64), (too_large_for_stack, "too_large_for_stack", 200 => u64),
/// Lint: ENUM_VARIANT_NAMES. The minimum number of enum variants for the lints about variant names to trigger /// Lint: ENUM_VARIANT_NAMES. The minimum number of enum variants for the lints about variant names to trigger
("enum-variant-name-threshold", enum_variant_name_threshold, 3 => u64), (enum_variant_name_threshold, "enum_variant_name_threshold", 3 => u64),
/// Lint: LARGE_ENUM_VARIANT. The maximum size of a emum's variant to avoid box suggestion /// Lint: LARGE_ENUM_VARIANT. The maximum size of a emum's variant to avoid box suggestion
("enum-variant-size-threshold", enum_variant_size_threshold, 200 => u64), (enum_variant_size_threshold, "enum_variant_size_threshold", 200 => u64),
} }
/// Search for the configuration file. /// Search for the configuration file.
@ -225,17 +204,21 @@ pub fn lookup_conf_file() -> io::Result<Option<path::PathBuf>> {
} }
} }
/// Produces a `Conf` filled with the default values and forwards the errors
///
/// Used internally for convenience
fn default(errors: Vec<Error>) -> (Conf, Vec<Error>) {
(toml::from_str("").expect("we never error on empty config files"), errors)
}
/// Read the `toml` configuration file. /// Read the `toml` configuration file.
/// ///
/// In case of error, the function tries to continue as much as possible. /// In case of error, the function tries to continue as much as possible.
pub fn read(path: Option<&path::Path>) -> (Conf, Vec<Error>) { pub fn read(path: Option<&path::Path>) -> (Conf, Vec<Error>) {
let mut conf = Conf::default();
let mut errors = Vec::new();
let path = if let Some(path) = path { let path = if let Some(path) = path {
path path
} else { } else {
return (conf, errors); return default(Vec::new())
}; };
let file = match fs::File::open(path) { let file = match fs::File::open(path) {
@ -243,31 +226,21 @@ pub fn read(path: Option<&path::Path>) -> (Conf, Vec<Error>) {
let mut buf = String::new(); let mut buf = String::new();
if let Err(err) = file.read_to_string(&mut buf) { if let Err(err) = file.read_to_string(&mut buf) {
errors.push(err.into()); return default(vec![err.into()])
return (conf, errors);
} }
buf buf
}, },
Err(err) => { Err(err) => return default(vec![err.into()]),
errors.push(err.into()); };
return (conf, errors);
assert!(ERRORS.lock().expect("no threading -> mutex always safe").is_empty());
match toml::from_str(&file) {
Ok(toml) => (toml, ERRORS.lock().expect("no threading -> mutex always safe").split_off(0)),
Err(e) => {
let mut errors = ERRORS.lock().expect("no threading -> mutex always safe").split_off(0);
errors.push(Error::Toml(e.to_string()));
default(errors)
}, },
};
let mut parser = toml::Parser::new(&file);
let toml = if let Some(toml) = parser.parse() {
toml
} else {
errors.push(Error::Toml(parser.errors));
return (conf, errors);
};
for (key, value) in toml {
if let Err(err) = conf.set(key, value) {
errors.push(err);
} }
} }
(conf, errors)
}

View file

@ -1,4 +1,4 @@
error: error reading Clippy's configuration file: expected `=`, but found `t` error: error reading Clippy's configuration file: expected an equals, found an identifier at line 1
error: aborting due to previous error error: aborting due to previous error

View file

@ -1,4 +1,4 @@
error: error reading Clippy's configuration file: `blacklisted-names` is expected to be a `Vec < String >` but is a `integer` error: error reading Clippy's configuration file: invalid type: integer `42`, expected a sequence
error: aborting due to previous error error: aborting due to previous error

View file

@ -1,4 +1,4 @@
error: error reading Clippy's configuration file: unknown key `foobar` error: error reading Clippy's configuration file: unknown field `foobar`, expected one of `blacklisted-names`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `third-party`
error: aborting due to previous error error: aborting due to previous error

View file

@ -7,7 +7,7 @@ extern crate serde;
struct A; struct A;
impl serde::de::Visitor for A { impl<'de> serde::de::Visitor<'de> for A {
type Value = (); type Value = ();
fn expecting(&self, _: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { fn expecting(&self, _: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
@ -29,7 +29,7 @@ impl serde::de::Visitor for A {
struct B; struct B;
impl serde::de::Visitor for B { impl<'de> serde::de::Visitor<'de> for B {
type Value = (); type Value = ();
fn expecting(&self, _: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { fn expecting(&self, _: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {