Basic framework for structured logging
This commit is contained in:
parent
ac698826d7
commit
0e8e8cfc9b
@ -20,3 +20,7 @@ compiletest_rs = "*"
|
||||
regex = "*"
|
||||
regex_macros = "*"
|
||||
lazy_static = "*"
|
||||
|
||||
[features]
|
||||
|
||||
structured_logging = []
|
@ -7,6 +7,7 @@ use syntax::ast_util::{is_comparison_binop, binop_to_string};
|
||||
use syntax::ptr::P;
|
||||
use syntax::codemap::Span;
|
||||
use std::f64::consts as f64;
|
||||
use utils::span_lint;
|
||||
|
||||
declare_lint! {
|
||||
pub APPROX_CONSTANT,
|
||||
@ -51,7 +52,7 @@ fn check_known_consts(cx: &Context, span: Span, str: &str, module: &str) {
|
||||
if let Ok(value) = str.parse::<f64>() {
|
||||
for &(constant, name) in KNOWN_CONSTS {
|
||||
if within_epsilon(constant, value) {
|
||||
cx.span_lint(APPROX_CONSTANT, span, &format!(
|
||||
span_lint(cx, APPROX_CONSTANT, span, &format!(
|
||||
"Approximate value of {}::{} found, consider using it directly.", module, &name));
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ use syntax::ast::*;
|
||||
use syntax::ptr::P;
|
||||
use syntax::codemap::{Span, ExpnInfo};
|
||||
use syntax::parse::token::InternedString;
|
||||
use utils::{in_macro, match_path};
|
||||
use utils::{in_macro, match_path, span_lint};
|
||||
|
||||
declare_lint! { pub INLINE_ALWAYS, Warn,
|
||||
"#[inline(always)] is usually a bad idea."}
|
||||
@ -100,7 +100,7 @@ fn check_attrs(cx: &Context, info: Option<&ExpnInfo>, ident: &Ident,
|
||||
if values.len() != 1 || inline != &"inline" { continue; }
|
||||
if let MetaWord(ref always) = values[0].node {
|
||||
if always != &"always" { continue; }
|
||||
cx.span_lint(INLINE_ALWAYS, attr.span, &format!(
|
||||
span_lint(cx, INLINE_ALWAYS, attr.span, &format!(
|
||||
"You have declared #[inline(always)] on {}. This \
|
||||
is usually a bad idea. Are you sure?",
|
||||
ident.as_str()));
|
||||
|
@ -6,6 +6,7 @@ use syntax::ast::*;
|
||||
use syntax::ast_util::{is_comparison_binop, binop_to_string};
|
||||
use syntax::ptr::P;
|
||||
use syntax::codemap::Span;
|
||||
use utils::span_lint;
|
||||
|
||||
declare_lint! {
|
||||
pub BAD_BIT_MASK,
|
||||
@ -95,18 +96,18 @@ fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_,
|
||||
BiEq | BiNe => match bit_op {
|
||||
BiBitAnd => if mask_value & cmp_value != mask_value {
|
||||
if cmp_value != 0 {
|
||||
cx.span_lint(BAD_BIT_MASK, *span, &format!(
|
||||
span_lint(cx, BAD_BIT_MASK, *span, &format!(
|
||||
"incompatible bit mask: _ & {} can never be equal to {}",
|
||||
mask_value, cmp_value));
|
||||
}
|
||||
} else {
|
||||
if mask_value == 0 {
|
||||
cx.span_lint(BAD_BIT_MASK, *span,
|
||||
span_lint(cx, BAD_BIT_MASK, *span,
|
||||
&format!("&-masking with zero"));
|
||||
}
|
||||
},
|
||||
BiBitOr => if mask_value | cmp_value != cmp_value {
|
||||
cx.span_lint(BAD_BIT_MASK, *span, &format!(
|
||||
span_lint(cx, BAD_BIT_MASK, *span, &format!(
|
||||
"incompatible bit mask: _ | {} can never be equal to {}",
|
||||
mask_value, cmp_value));
|
||||
},
|
||||
@ -114,22 +115,22 @@ fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_,
|
||||
},
|
||||
BiLt | BiGe => match bit_op {
|
||||
BiBitAnd => if mask_value < cmp_value {
|
||||
cx.span_lint(BAD_BIT_MASK, *span, &format!(
|
||||
span_lint(cx, BAD_BIT_MASK, *span, &format!(
|
||||
"incompatible bit mask: _ & {} will always be lower than {}",
|
||||
mask_value, cmp_value));
|
||||
} else {
|
||||
if mask_value == 0 {
|
||||
cx.span_lint(BAD_BIT_MASK, *span,
|
||||
span_lint(cx, BAD_BIT_MASK, *span,
|
||||
&format!("&-masking with zero"));
|
||||
}
|
||||
},
|
||||
BiBitOr => if mask_value >= cmp_value {
|
||||
cx.span_lint(BAD_BIT_MASK, *span, &format!(
|
||||
span_lint(cx, BAD_BIT_MASK, *span, &format!(
|
||||
"incompatible bit mask: _ | {} will never be lower than {}",
|
||||
mask_value, cmp_value));
|
||||
} else {
|
||||
if mask_value < cmp_value {
|
||||
cx.span_lint(INEFFECTIVE_BIT_MASK, *span, &format!(
|
||||
span_lint(cx, INEFFECTIVE_BIT_MASK, *span, &format!(
|
||||
"ineffective bit mask: x | {} compared to {} is the same as x compared directly",
|
||||
mask_value, cmp_value));
|
||||
}
|
||||
@ -138,22 +139,22 @@ fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_,
|
||||
},
|
||||
BiLe | BiGt => match bit_op {
|
||||
BiBitAnd => if mask_value <= cmp_value {
|
||||
cx.span_lint(BAD_BIT_MASK, *span, &format!(
|
||||
span_lint(cx, BAD_BIT_MASK, *span, &format!(
|
||||
"incompatible bit mask: _ & {} will never be higher than {}",
|
||||
mask_value, cmp_value));
|
||||
} else {
|
||||
if mask_value == 0 {
|
||||
cx.span_lint(BAD_BIT_MASK, *span,
|
||||
span_lint(cx, BAD_BIT_MASK, *span,
|
||||
&format!("&-masking with zero"));
|
||||
}
|
||||
},
|
||||
BiBitOr => if mask_value > cmp_value {
|
||||
cx.span_lint(BAD_BIT_MASK, *span, &format!(
|
||||
span_lint(cx, BAD_BIT_MASK, *span, &format!(
|
||||
"incompatible bit mask: _ | {} will always be higher than {}",
|
||||
mask_value, cmp_value));
|
||||
} else {
|
||||
if mask_value < cmp_value {
|
||||
cx.span_lint(INEFFECTIVE_BIT_MASK, *span, &format!(
|
||||
span_lint(cx, INEFFECTIVE_BIT_MASK, *span, &format!(
|
||||
"ineffective bit mask: x | {} compared to {} is the same as x compared directly",
|
||||
mask_value, cmp_value));
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ use syntax::ast::*;
|
||||
use syntax::ptr::P;
|
||||
use syntax::codemap::{Span, Spanned, ExpnInfo};
|
||||
use syntax::print::pprust::expr_to_string;
|
||||
use utils::in_macro;
|
||||
use utils::{in_macro, span_lint};
|
||||
|
||||
declare_lint! {
|
||||
pub COLLAPSIBLE_IF,
|
||||
@ -47,7 +47,7 @@ fn check_expr_expd(cx: &Context, e: &Expr, info: Option<&ExpnInfo>) {
|
||||
if let ExprIf(ref check, ref then, None) = e.node {
|
||||
if let Some(&Expr{ node: ExprIf(ref check_inner, _, None), ..}) =
|
||||
single_stmt_of_block(then) {
|
||||
cx.span_lint(COLLAPSIBLE_IF, e.span, &format!(
|
||||
span_lint(cx, COLLAPSIBLE_IF, e.span, &format!(
|
||||
"This if statement can be collapsed. Try: if {} && {}\n{:?}",
|
||||
check_to_string(check), check_to_string(check_inner), e));
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ use syntax::ast::*;
|
||||
use syntax::ast_util as ast_util;
|
||||
use syntax::ptr::P;
|
||||
use syntax::codemap as code;
|
||||
use utils::span_lint;
|
||||
|
||||
declare_lint! {
|
||||
pub EQ_OP,
|
||||
@ -21,7 +22,7 @@ impl LintPass for EqOp {
|
||||
fn check_expr(&mut self, cx: &Context, e: &Expr) {
|
||||
if let ExprBinary(ref op, ref left, ref right) = e.node {
|
||||
if is_cmp_or_bit(op) && is_exp_equal(left, right) {
|
||||
cx.span_lint(EQ_OP, e.span, &format!(
|
||||
span_lint(cx, EQ_OP, e.span, &format!(
|
||||
"equal expressions as operands to {}",
|
||||
ast_util::binop_to_string(op.node)));
|
||||
}
|
||||
|
@ -3,6 +3,8 @@ use rustc::lint::{Context, LintPass, LintArray, Lint, Level};
|
||||
use syntax::codemap::{Span, Spanned};
|
||||
use syntax::print::pprust::expr_to_string;
|
||||
|
||||
use utils::span_lint;
|
||||
|
||||
|
||||
#[allow(missing_copy_implementations)]
|
||||
pub struct EtaPass;
|
||||
@ -48,7 +50,7 @@ impl LintPass for EtaPass {
|
||||
return
|
||||
}
|
||||
}
|
||||
cx.span_lint(REDUNDANT_CLOSURE, expr.span,
|
||||
span_lint(cx, REDUNDANT_CLOSURE, expr.span,
|
||||
&format!("Redundant closure found, consider using `{}` in its place",
|
||||
expr_to_string(caller))[..])
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ use syntax::ast_util::{is_comparison_binop, binop_to_string};
|
||||
use syntax::ptr::P;
|
||||
use syntax::codemap::Span;
|
||||
|
||||
use utils::snippet;
|
||||
use utils::{span_lint, snippet};
|
||||
|
||||
declare_lint! { pub IDENTITY_OP, Warn,
|
||||
"Warn on identity operations, e.g. '_ + 0'"}
|
||||
@ -48,7 +48,7 @@ impl LintPass for IdentityOp {
|
||||
|
||||
fn check(cx: &Context, e: &Expr, m: i8, span: Span, arg: Span) {
|
||||
if have_lit(cx, e, m) {
|
||||
cx.span_lint(IDENTITY_OP, span, &format!(
|
||||
span_lint(cx, IDENTITY_OP, span, &format!(
|
||||
"The operation is ineffective. Consider reducing it to '{}'",
|
||||
snippet(cx, arg, "..")));
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ use rustc::middle::def::{DefTy, DefStruct, DefTrait};
|
||||
use syntax::codemap::{Span, Spanned};
|
||||
use syntax::ast::*;
|
||||
use misc::walk_ty;
|
||||
use utils::span_lint;
|
||||
|
||||
declare_lint!(pub LEN_ZERO, Warn,
|
||||
"Warn when .is_empty() could be used instead of checking .len()");
|
||||
@ -54,10 +55,10 @@ fn check_trait_items(cx: &Context, item: &Item, trait_items: &[P<TraitItem>]) {
|
||||
}
|
||||
|
||||
if !trait_items.iter().any(|i| is_named_self(i, "is_empty")) {
|
||||
//cx.span_lint(LEN_WITHOUT_IS_EMPTY, item.span, &format!("trait {}", item.ident.as_str()));
|
||||
//span_lint(cx, LEN_WITHOUT_IS_EMPTY, item.span, &format!("trait {}", item.ident.as_str()));
|
||||
for i in trait_items {
|
||||
if is_named_self(i, "len") {
|
||||
cx.span_lint(LEN_WITHOUT_IS_EMPTY, i.span,
|
||||
span_lint(cx, LEN_WITHOUT_IS_EMPTY, i.span,
|
||||
&format!("Trait '{}' has a '.len(_: &Self)' method, but no \
|
||||
'.is_empty(_: &Self)' method. Consider adding one.",
|
||||
item.ident.as_str()));
|
||||
@ -76,7 +77,7 @@ fn check_impl_items(cx: &Context, item: &Item, impl_items: &[P<ImplItem>]) {
|
||||
for i in impl_items {
|
||||
if is_named_self(i, "len") {
|
||||
let s = i.span;
|
||||
cx.span_lint(LEN_WITHOUT_IS_EMPTY,
|
||||
span_lint(cx, LEN_WITHOUT_IS_EMPTY,
|
||||
Span{ lo: s.lo, hi: s.lo, expn_id: s.expn_id },
|
||||
&format!("Item '{}' has a '.len(_: &Self)' method, but no \
|
||||
'.is_empty(_: &Self)' method. Consider adding one.",
|
||||
@ -107,7 +108,7 @@ fn check_len_zero(cx: &Context, span: Span, method: &SpannedIdent,
|
||||
if let &Spanned{node: LitInt(0, _), ..} = lit {
|
||||
if method.node.as_str() == "len" && args.len() == 1 &&
|
||||
has_is_empty(cx, &*args[0]) {
|
||||
cx.span_lint(LEN_ZERO, span, &format!(
|
||||
span_lint(cx, LEN_ZERO, span, &format!(
|
||||
"Consider replacing the len comparison with '{}_.is_empty()'",
|
||||
empty))
|
||||
}
|
||||
|
16
src/misc.rs
16
src/misc.rs
@ -8,7 +8,7 @@ use rustc::middle::ty;
|
||||
use syntax::codemap::{Span, Spanned};
|
||||
|
||||
use types::span_note_and_lint;
|
||||
use utils::{match_path, snippet};
|
||||
use utils::{match_path, snippet, span_lint};
|
||||
|
||||
pub fn walk_ty<'t>(ty: ty::Ty<'t>) -> ty::Ty<'t> {
|
||||
match ty.sty {
|
||||
@ -72,7 +72,7 @@ impl LintPass for StrToStringPass {
|
||||
ast::ExprMethodCall(ref method, _, ref args)
|
||||
if method.node.as_str() == "to_string"
|
||||
&& is_str(cx, &*args[0]) => {
|
||||
cx.span_lint(STR_TO_STRING, expr.span, "str.to_owned() is faster");
|
||||
span_lint(cx, STR_TO_STRING, expr.span, "str.to_owned() is faster");
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
@ -100,7 +100,7 @@ impl LintPass for TopLevelRefPass {
|
||||
fn check_fn(&mut self, cx: &Context, _: FnKind, decl: &FnDecl, _: &Block, _: Span, _: NodeId) {
|
||||
for ref arg in decl.inputs.iter() {
|
||||
if let PatIdent(BindByRef(_), _, _) = arg.pat.node {
|
||||
cx.span_lint(
|
||||
span_lint(cx,
|
||||
TOPLEVEL_REF_ARG,
|
||||
arg.pat.span,
|
||||
"`ref` directly on a function argument is ignored. Have you considered using a reference type instead?"
|
||||
@ -136,7 +136,7 @@ impl LintPass for CmpNan {
|
||||
|
||||
fn check_nan(cx: &Context, path: &Path, span: Span) {
|
||||
path.segments.last().map(|seg| if seg.identifier.as_str() == "NAN" {
|
||||
cx.span_lint(CMP_NAN, span, "Doomed comparison with NAN, use std::{f32,f64}::is_nan instead");
|
||||
span_lint(cx, CMP_NAN, span, "Doomed comparison with NAN, use std::{f32,f64}::is_nan instead");
|
||||
});
|
||||
}
|
||||
|
||||
@ -155,7 +155,7 @@ impl LintPass for FloatCmp {
|
||||
if let ExprBinary(ref cmp, ref left, ref right) = expr.node {
|
||||
let op = cmp.node;
|
||||
if (op == BiEq || op == BiNe) && (is_float(cx, left) || is_float(cx, right)) {
|
||||
cx.span_lint(FLOAT_CMP, expr.span, &format!(
|
||||
span_lint(cx, FLOAT_CMP, expr.span, &format!(
|
||||
"{}-Comparison of f32 or f64 detected. You may want to change this to 'abs({} - {}) < epsilon' for some suitable value of epsilon",
|
||||
binop_to_string(op), snippet(cx, left.span, ".."),
|
||||
snippet(cx, right.span, "..")));
|
||||
@ -186,7 +186,7 @@ impl LintPass for Precedence {
|
||||
fn check_expr(&mut self, cx: &Context, expr: &Expr) {
|
||||
if let ExprBinary(Spanned { node: op, ..}, ref left, ref right) = expr.node {
|
||||
if is_bit_op(op) && (is_arith_expr(left) || is_arith_expr(right)) {
|
||||
cx.span_lint(PRECEDENCE, expr.span,
|
||||
span_lint(cx, PRECEDENCE, expr.span,
|
||||
"Operator precedence can trip the unwary. Consider adding parenthesis to the subexpression.");
|
||||
}
|
||||
}
|
||||
@ -241,7 +241,7 @@ fn check_to_owned(cx: &Context, expr: &Expr, other_span: Span) {
|
||||
let name = ident.as_str();
|
||||
if name == "to_string" ||
|
||||
name == "to_owned" && is_str_arg(cx, args) {
|
||||
cx.span_lint(CMP_OWNED, expr.span, &format!(
|
||||
span_lint(cx, CMP_OWNED, expr.span, &format!(
|
||||
"this creates an owned instance just for comparison. \
|
||||
Consider using {}.as_slice() to compare without allocation",
|
||||
snippet(cx, other_span, "..")))
|
||||
@ -251,7 +251,7 @@ fn check_to_owned(cx: &Context, expr: &Expr, other_span: Span) {
|
||||
if let &ExprPath(None, ref path) = &path.node {
|
||||
if match_path(path, &["String", "from_str"]) ||
|
||||
match_path(path, &["String", "from"]) {
|
||||
cx.span_lint(CMP_OWNED, expr.span, &format!(
|
||||
span_lint(cx, CMP_OWNED, expr.span, &format!(
|
||||
"this creates an owned instance just for comparison. \
|
||||
Consider using {}.as_slice() to compare without allocation",
|
||||
snippet(cx, other_span, "..")))
|
||||
|
@ -3,7 +3,7 @@ use syntax::ast::*;
|
||||
use rustc::lint::{Context, LintPass, LintArray, Lint};
|
||||
use rustc::middle::ty::{TypeVariants, TypeAndMut, TyRef};
|
||||
use syntax::codemap::{BytePos, ExpnInfo, Span};
|
||||
use utils::in_macro;
|
||||
use utils::{in_macro, span_lint};
|
||||
|
||||
declare_lint!(pub MUT_MUT, Warn,
|
||||
"Warn on usage of double-mut refs, e.g. '&mut &mut ...'");
|
||||
@ -22,7 +22,7 @@ impl LintPass for MutMut {
|
||||
}
|
||||
|
||||
fn check_ty(&mut self, cx: &Context, ty: &Ty) {
|
||||
unwrap_mut(ty).and_then(unwrap_mut).map_or((), |_| cx.span_lint(MUT_MUT,
|
||||
unwrap_mut(ty).and_then(unwrap_mut).map_or((), |_| span_lint(cx, MUT_MUT,
|
||||
ty.span, "Generally you want to avoid &mut &mut _ if possible."))
|
||||
}
|
||||
}
|
||||
@ -39,12 +39,12 @@ fn check_expr_expd(cx: &Context, expr: &Expr, info: Option<&ExpnInfo>) {
|
||||
|
||||
unwrap_addr(expr).map_or((), |e| {
|
||||
unwrap_addr(e).map(|_| {
|
||||
cx.span_lint(MUT_MUT, expr.span,
|
||||
span_lint(cx, MUT_MUT, expr.span,
|
||||
"Generally you want to avoid &mut &mut _ if possible.")
|
||||
}).unwrap_or_else(|| {
|
||||
if let TyRef(_, TypeAndMut{ty: _, mutbl: MutMutable}) =
|
||||
cx.tcx.expr_ty(e).sty {
|
||||
cx.span_lint(MUT_MUT, expr.span,
|
||||
span_lint(cx, MUT_MUT, expr.span,
|
||||
"This expression mutably borrows a mutable reference. \
|
||||
Consider reborrowing")
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ use syntax::ast::*;
|
||||
use syntax::ast_util::{is_comparison_binop, binop_to_string};
|
||||
use syntax::ptr::P;
|
||||
use syntax::codemap::Span;
|
||||
use utils::de_p;
|
||||
use utils::{de_p, span_lint};
|
||||
|
||||
declare_lint! {
|
||||
pub NEEDLESS_BOOL,
|
||||
@ -30,16 +30,16 @@ impl LintPass for NeedlessBool {
|
||||
if let ExprIf(_, ref then_block, Option::Some(ref else_expr)) = e.node {
|
||||
match (fetch_bool_block(then_block), fetch_bool_expr(else_expr)) {
|
||||
(Option::Some(true), Option::Some(true)) => {
|
||||
cx.span_lint(NEEDLESS_BOOL, e.span,
|
||||
span_lint(cx, NEEDLESS_BOOL, e.span,
|
||||
"your if-then-else expression will always return true"); },
|
||||
(Option::Some(true), Option::Some(false)) => {
|
||||
cx.span_lint(NEEDLESS_BOOL, e.span,
|
||||
span_lint(cx, NEEDLESS_BOOL, e.span,
|
||||
"you can reduce your if-statement to its predicate"); },
|
||||
(Option::Some(false), Option::Some(true)) => {
|
||||
cx.span_lint(NEEDLESS_BOOL, e.span,
|
||||
span_lint(cx, NEEDLESS_BOOL, e.span,
|
||||
"you can reduce your if-statement to '!' + your predicate"); },
|
||||
(Option::Some(false), Option::Some(false)) => {
|
||||
cx.span_lint(NEEDLESS_BOOL, e.span,
|
||||
span_lint(cx, NEEDLESS_BOOL, e.span,
|
||||
"your if-then-else expression will always return false"); },
|
||||
_ => ()
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ use syntax::ast_util::{is_comparison_binop, binop_to_string};
|
||||
use syntax::ptr::P;
|
||||
use syntax::codemap::Span;
|
||||
use types::match_ty_unwrap;
|
||||
use utils::span_lint;
|
||||
|
||||
declare_lint! {
|
||||
pub PTR_ARG,
|
||||
@ -58,10 +59,10 @@ fn check_fn(cx: &Context, decl: &FnDecl) {
|
||||
fn check_ptr_subtype(cx: &Context, span: Span, ty: &Ty) {
|
||||
match_ty_unwrap(ty, &["Vec"]).map_or_else(|| match_ty_unwrap(ty,
|
||||
&["String"]).map_or((), |_| {
|
||||
cx.span_lint(PTR_ARG, span,
|
||||
span_lint(cx, PTR_ARG, span,
|
||||
"Writing '&String' instead of '&str' involves a new Object \
|
||||
where a slices will do. Consider changing the type to &str")
|
||||
}), |_| cx.span_lint(PTR_ARG, span, "Writing '&Vec<_>' instead of \
|
||||
}), |_| span_lint(cx, PTR_ARG, span, "Writing '&Vec<_>' instead of \
|
||||
'&[_]' involves one more reference and cannot be used with \
|
||||
non-vec-based slices. Consider changing the type to &[...]")
|
||||
)
|
||||
|
@ -6,6 +6,8 @@ use syntax::ast::*;
|
||||
use rustc::lint::{Context, LintPass, LintArray, Lint, Level};
|
||||
use syntax::codemap::Span;
|
||||
|
||||
use utils::span_lint;
|
||||
|
||||
/// Handles all the linting of funky types
|
||||
#[allow(missing_copy_implementations)]
|
||||
pub struct TypePass;
|
||||
@ -40,7 +42,7 @@ pub fn match_ty_unwrap<'a>(ty: &'a Ty, segments: &[&str]) -> Option<&'a [P<Ty>]>
|
||||
|
||||
/// Lets me span a note only if the lint is shown
|
||||
pub fn span_note_and_lint(cx: &Context, lint: &'static Lint, span: Span, msg: &str, note: &str) {
|
||||
cx.span_lint(lint, span, msg);
|
||||
span_lint(cx, lint, span, msg);
|
||||
if cx.current_level(lint) != Level::Allow {
|
||||
cx.sess().span_note(span, note);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
use rustc::lint::*;
|
||||
use syntax::ast::*;
|
||||
use syntax::codemap::{BytePos, Span};
|
||||
use utils::span_lint;
|
||||
|
||||
declare_lint!{ pub ZERO_WIDTH_SPACE, Deny, "Zero-width space is confusing" }
|
||||
|
||||
@ -36,7 +37,7 @@ fn check_str(cx: &Context, string: &str, span: Span) {
|
||||
|
||||
fn lint_zero_width(cx: &Context, span: Span, start: Option<usize>) {
|
||||
start.map(|index| {
|
||||
cx.span_lint(ZERO_WIDTH_SPACE, Span {
|
||||
span_lint(cx, ZERO_WIDTH_SPACE, Span {
|
||||
lo: span.lo + BytePos(index as u32),
|
||||
hi: span.lo + BytePos(index as u32),
|
||||
expn_id: span.expn_id,
|
||||
|
15
src/utils.rs
15
src/utils.rs
@ -1,4 +1,4 @@
|
||||
use rustc::lint::Context;
|
||||
use rustc::lint::{Context, Lint};
|
||||
use syntax::ast::{DefId, Name, Path};
|
||||
use syntax::codemap::{ExpnInfo, Span};
|
||||
use syntax::ptr::P;
|
||||
@ -52,3 +52,16 @@ pub fn snippet<'a>(cx: &Context, span: Span, default: &'a str) -> Cow<'a, str> {
|
||||
|
||||
/// dereference a P<T> and return a ref on the result
|
||||
pub fn de_p<T>(p: &P<T>) -> &T { &*p }
|
||||
|
||||
#[cfg(not(feature="structured_logging"))]
|
||||
pub fn span_lint(cx: &Context, lint: &'static Lint, sp: Span, msg: &str) {
|
||||
cx.span_lint(lint, sp, msg);
|
||||
}
|
||||
|
||||
#[cfg(feature="structured_logging")]
|
||||
pub fn span_lint(cx: &Context, lint: &'static Lint, sp: Span, msg: &str) {
|
||||
// lint.name / lint.desc is can give details of the lint
|
||||
// cx.sess().codemap() has all these nice functions for line/column/snippet details
|
||||
// http://doc.rust-lang.org/syntax/codemap/struct.CodeMap.html#method.span_to_string
|
||||
cx.span_lint(lint, sp, msg);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user