145 lines
4.5 KiB
Rust
Raw Normal View History

extern crate regex;
#[macro_use]
extern crate lazy_static;
use regex::Regex;
use std::ffi::OsStr;
use std::fs;
use std::io::prelude::*;
lazy_static! {
static ref DEC_CLIPPY_LINT_RE: Regex = Regex::new(r#"declare_clippy_lint!\s*[\{(]\s*pub\s+(?P<name>[A-Z_][A-Z_0-9]*)\s*,\s*(?P<cat>[a-z_]+)\s*,\s*"(?P<desc>(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})]"#).unwrap();
static ref DEC_DEPRECATED_LINT_RE: Regex = Regex::new(r#"declare_deprecated_lint!\s*[{(]\s*pub\s+(?P<name>[A-Z_][A-Z_0-9]*)\s*,\s*"(?P<desc>(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})]"#).unwrap();
static ref NL_ESCAPE_RE: Regex = Regex::new(r#"\\\n\s*"#).unwrap();
pub static ref DOCS_LINK: String = "https://rust-lang-nursery.github.io/rust-clippy/master/index.html".to_string();
}
#[derive(Clone, PartialEq, Debug)]
pub struct Lint {
pub name: String,
pub group: String,
pub desc: String,
pub deprecation: Option<String>,
pub module: String,
}
impl Lint {
pub fn new(name: &str, group: &str, desc: &str, deprecation: Option<&str>, module: &str) -> Lint {
Lint {
name: name.to_lowercase(),
group: group.to_string(),
desc: NL_ESCAPE_RE.replace(&desc.replace("\\\"", "\""), "").to_string(),
deprecation: deprecation.map(|d| d.to_string()),
module: module.to_string(),
}
}
pub fn active_lints(lints: &[Lint]) -> Vec<Lint> {
lints.iter().filter(|l| l.deprecation.is_none()).cloned().collect::<Vec<Lint>>()
}
pub fn in_lint_group(group: &str, lints: &[Lint]) -> Vec<Lint> {
lints.iter().filter(|l| l.group == group).cloned().collect::<Vec<Lint>>()
}
}
pub fn collect_all() -> Vec<Lint> {
let mut lints = vec![];
for direntry in lint_files() {
lints.append(&mut collect_from_file(&direntry));
}
lints
}
fn collect_from_file(direntry: &fs::DirEntry) -> Vec<Lint> {
let mut file = fs::File::open(direntry.path()).unwrap();
let mut content = String::new();
file.read_to_string(&mut content).unwrap();
parse_contents(&content, direntry.path().file_stem().unwrap().to_str().unwrap())
}
fn parse_contents(content: &str, filename: &str) -> Vec<Lint> {
let mut lints: Vec<Lint> = DEC_CLIPPY_LINT_RE
.captures_iter(&content)
.map(|m| Lint::new(&m["name"], &m["cat"], &m["desc"], None, filename))
.collect();
let mut deprecated = DEC_DEPRECATED_LINT_RE
.captures_iter(&content)
.map(|m| Lint::new( &m["name"], "Deprecated", &m["desc"], Some(&m["desc"]), filename))
.collect();
lints.append(&mut deprecated);
lints
}
/// Collects all .rs files in the `clippy_lints/src` directory
fn lint_files() -> Vec<fs::DirEntry> {
let paths = fs::read_dir("../clippy_lints/src").unwrap();
paths
.filter_map(|f| f.ok())
.filter(|f| f.path().extension() == Some(OsStr::new("rs")))
.collect::<Vec<fs::DirEntry>>()
}
#[test]
fn test_parse_contents() {
let result = parse_contents(
r#"
declare_clippy_lint! {
pub PTR_ARG,
style,
"really long \
text"
}
declare_clippy_lint!{
pub DOC_MARKDOWN,
pedantic,
"single line"
}
/// some doc comment
declare_deprecated_lint! {
pub SHOULD_ASSERT_EQ,
"`assert!()` will be more flexible with RFC 2011"
}
"#,
"module_name");
let expected = vec![
Lint::new("ptr_arg", "style", "really long text", None, "module_name"),
Lint::new("doc_markdown", "pedantic", "single line", None, "module_name"),
Lint::new(
"should_assert_eq",
"Deprecated",
"`assert!()` will be more flexible with RFC 2011",
Some("`assert!()` will be more flexible with RFC 2011"),
"module_name"
),
];
assert_eq!(expected, result);
}
#[test]
fn test_active_lints() {
let lints = vec![
Lint::new("should_assert_eq", "Deprecated", "abc", Some("Reason"), "module_name"),
Lint::new("should_assert_eq2", "Not Deprecated", "abc", None, "module_name")
];
let expected = vec![
Lint::new("should_assert_eq2", "Not Deprecated", "abc", None, "module_name")
];
assert_eq!(expected, Lint::active_lints(&lints));
}
#[test]
fn test_in_lint_group() {
let lints = vec![
Lint::new("ptr_arg", "style", "really long text", None, "module_name"),
Lint::new("doc_markdown", "pedantic", "single line", None, "module_name"),
];
let expected = vec![
Lint::new("ptr_arg", "style", "really long text", None, "module_name")
];
assert_eq!(expected, Lint::in_lint_group("style", &lints));
}