new regex syntax lint, fixes #597

This commit is contained in:
llogiq 2016-02-05 00:36:06 +01:00
parent b90288eced
commit 3d85cc24e7
7 changed files with 81 additions and 4 deletions

View file

@ -28,6 +28,9 @@ extern crate unicode_normalization;
// for semver check in attrs.rs
extern crate semver;
// for regex checking
extern crate regex_syntax;
extern crate rustc_plugin;
use rustc_plugin::Registry;
@ -82,6 +85,7 @@ pub mod derive;
pub mod print;
pub mod vec;
pub mod drop_ref;
pub mod regex;
mod reexport {
pub use syntax::ast::{Name, NodeId};
@ -150,7 +154,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
reg.register_late_lint_pass(box vec::UselessVec);
reg.register_late_lint_pass(box drop_ref::DropRefPass);
reg.register_late_lint_pass(box types::AbsurdUnsignedComparisons);
reg.register_late_lint_pass(box regex::RegexPass);
reg.register_lint_group("clippy_pedantic", vec![
matches::SINGLE_MATCH_ELSE,
@ -163,7 +167,6 @@ pub fn plugin_registrar(reg: &mut Registry) {
shadow::SHADOW_REUSE,
shadow::SHADOW_SAME,
shadow::SHADOW_UNRELATED,
strings::STRING_ADD,
strings::STRING_ADD_ASSIGN,
types::CAST_POSSIBLE_TRUNCATION,
types::CAST_POSSIBLE_WRAP,
@ -250,6 +253,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
ptr_arg::PTR_ARG,
ranges::RANGE_STEP_BY_ZERO,
ranges::RANGE_ZIP_WITH_LEN,
regex::INVALID_REGEX,
returns::LET_AND_RETURN,
returns::NEEDLESS_RETURN,
strings::STRING_LIT_AS_BYTES,

53
src/regex.rs Normal file
View file

@ -0,0 +1,53 @@
use regex_syntax;
use std::error::Error;
use syntax::codemap::{Span, BytePos, Pos};
use rustc_front::hir::*;
use rustc::middle::const_eval::{eval_const_expr_partial, ConstVal};
use rustc::middle::const_eval::EvalHint::ExprTypeChecked;
use rustc::lint::*;
use utils::{match_path, REGEX_NEW_PATH, span_lint};
/// **What it does:** This lint checks `Regex::new(_)` invocations for correct regex syntax. It is `deny` by default.
///
/// **Why is this bad?** This will lead to a runtime panic.
///
/// **Known problems:** None.
///
/// **Example:** `Regex::new("|")`
declare_lint! {
pub INVALID_REGEX,
Deny,
"finds invalid regular expressions in `Regex::new(_)` invocations"
}
#[derive(Copy,Clone)]
pub struct RegexPass;
impl LintPass for RegexPass {
fn get_lints(&self) -> LintArray {
lint_array!(INVALID_REGEX)
}
}
impl LateLintPass for RegexPass {
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
if_let_chain!{[
let ExprCall(ref fun, ref args) = expr.node,
let ExprPath(_, ref path) = fun.node,
match_path(path, &REGEX_NEW_PATH) && args.len() == 1,
let Ok(ConstVal::Str(r)) = eval_const_expr_partial(cx.tcx,
&*args[0],
ExprTypeChecked,
None),
let Err(e) = regex_syntax::Expr::parse(&r)
], {
let lo = args[0].span.lo + BytePos::from_usize(e.position());
let span = Span{ lo: lo, hi: lo, expn_id: args[0].span.expn_id };
span_lint(cx,
INVALID_REGEX,
span,
&format!("Regex syntax error: {}", e.description()));
}}
}
}

View file

@ -36,6 +36,7 @@ pub const LL_PATH: [&'static str; 3] = ["collections", "linked_list", "LinkedLis
pub const MUTEX_PATH: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"];
pub const OPEN_OPTIONS_PATH: [&'static str; 3] = ["std", "fs", "OpenOptions"];
pub const OPTION_PATH: [&'static str; 3] = ["core", "option", "Option"];
pub const REGEX_NEW_PATH: [&'static str; 3] = ["regex", "Regex", "new"];
pub const RESULT_PATH: [&'static str; 3] = ["core", "result", "Result"];
pub const STRING_PATH: [&'static str; 3] = ["collections", "string", "String"];
pub const VEC_FROM_ELEM_PATH: [&'static str; 3] = ["std", "vec", "from_elem"];