generated from rust-marker/lint-crate-template
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add
clippy::almost_complete_range
written in Marker
- Loading branch information
Showing
7 changed files
with
177 additions
and
52 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
//! This is the parent module for lints, which are inspired by Clippy lints. | ||
//! See [Clippy's lint list] for a full list. | ||
//! | ||
//! It can happen that some lints from Clippy are simply not reproducible as Clippy | ||
//! has access to more compiler internals than Marker might ever expose via its public API. | ||
//! | ||
//! [Clippy's lint list]: <https://rust-lang.github.io/rust-clippy/master/index.html> | ||
|
||
use marker_api::{lint::Lint, prelude::*}; | ||
|
||
mod almost_complete_range; | ||
|
||
pub fn lints() -> Vec<&'static Lint> { | ||
vec![almost_complete_range::ALMOST_COMPLETE_RANGE] | ||
} | ||
|
||
pub(crate) fn check_expr<'ast>(cx: &'ast AstContext<'ast>, expr: ExprKind<'ast>) { | ||
almost_complete_range::check(cx, expr) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
use marker_api::{ast::expr::LitExprKind, diagnostic::Applicability, prelude::*}; | ||
|
||
marker_api::declare_lint! { | ||
/// # What it does | ||
/// Checks for ranges that almost check an entire ascii range. The linted | ||
/// ranges are: | ||
/// * `'a'..'z'` | ||
/// * `'A'..'Z'` | ||
/// * `'0'..'9'` | ||
/// | ||
/// These ranges should probably be inclusive. | ||
/// | ||
/// # Example | ||
/// ``` | ||
/// # let x = 0; | ||
/// ('a'..'z').contains(&c); | ||
/// ``` | ||
/// | ||
/// Use instead | ||
/// ``` | ||
/// # let x = 0; | ||
/// ('a'..='z').contains(&c); | ||
/// ``` | ||
/// | ||
/// # Note | ||
/// This lint was inspired by the [clippy::almost_complete_range] lint. | ||
/// | ||
/// [clippy::almost_complete_range]: <https://rust-lang.github.io/rust-clippy/master/index.html#/almost_complete_range> | ||
ALMOST_COMPLETE_RANGE, | ||
Warn, | ||
} | ||
|
||
pub(crate) fn check<'ast>(cx: &AstContext<'ast>, expr: ExprKind<'ast>) { | ||
if let ExprKind::Range(range) = expr | ||
&& !range.is_inclusive() | ||
&& let Some(start) = range.start() | ||
&& let Some(end) = range.end() | ||
&& is_almost_complete(start, end) | ||
{ | ||
cx.emit_lint(ALMOST_COMPLETE_RANGE, expr.id(), "almost complete ascii range", expr.span(), |diag| { | ||
let mut app = Applicability::MachineApplicable; | ||
let a = start.span().snippet_with_applicability("<start>", &mut app); | ||
let b = start.span().snippet_with_applicability("<end>", &mut app); | ||
diag.span_suggestion("try", expr.span(), format!("{a}..={b}"), app) | ||
}) | ||
} | ||
} | ||
|
||
fn is_almost_complete(start: ExprKind<'_>, end: ExprKind<'_>) -> bool { | ||
if let (Ok(start), Ok(end)) = ( | ||
TryInto::<LitExprKind>::try_into(start), | ||
TryInto::<LitExprKind>::try_into(end), | ||
) { | ||
match (start, end) { | ||
(LitExprKind::Int(start), LitExprKind::Int(end)) => { | ||
if start.value() < u8::MAX.into() || end.value() < u8::MAX.into() { | ||
match (start.value() as u8, end.value() as u8) { | ||
(b'a', b'z') => true, | ||
(b'A', b'Z') => true, | ||
(b'0', b'9') => true, | ||
_ => false, | ||
} | ||
} else { | ||
false | ||
} | ||
} | ||
(LitExprKind::Char(start), LitExprKind::Char(end)) => { | ||
match (start.value(), end.value()) { | ||
('a', 'z') => true, | ||
('A', 'Z') => true, | ||
('0', '9') => true, | ||
_ => false, | ||
} | ||
} | ||
_ => false, | ||
} | ||
} else { | ||
false | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,48 +1,22 @@ | ||
#![feature(let_chains)] | ||
#![warn(clippy::pedantic)] | ||
|
||
use marker_api::ast::expr::ExprKind; | ||
use marker_api::prelude::*; | ||
use marker_api::{LintPass, LintPassInfo, LintPassInfoBuilder}; | ||
|
||
mod clippy; | ||
|
||
#[derive(Default)] | ||
struct MyLintPass {} | ||
marker_api::export_lint_pass!(MyLintPass); | ||
|
||
marker_api::declare_lint! { | ||
/// # What it does | ||
/// Here you can explain what your lint does. The description supports normal | ||
/// markdown. | ||
/// | ||
/// # Example | ||
/// ```rs | ||
/// // Bad example | ||
/// ``` | ||
/// | ||
/// Use instead: | ||
/// ```rs | ||
/// // Good example | ||
/// ``` | ||
MY_LINT, | ||
Warn, | ||
} | ||
|
||
impl LintPass for MyLintPass { | ||
fn info(&self) -> LintPassInfo { | ||
LintPassInfoBuilder::new(Box::new([MY_LINT])).build() | ||
LintPassInfoBuilder::new(clippy::lints().into_boxed_slice()).build() | ||
} | ||
|
||
fn check_item<'ast>(&mut self, cx: &'ast AstContext<'ast>, item: ItemKind<'ast>) { | ||
if let ItemKind::Fn(func) = item { | ||
if let Some(ident) = func.ident() { | ||
if ident.name() == "main" { | ||
cx.emit_lint( | ||
MY_LINT, | ||
item.id(), | ||
"hello, main (From Marker)", | ||
item.span(), | ||
|_| {}, | ||
); | ||
} | ||
} | ||
} | ||
fn check_expr<'ast>(&mut self, cx: &'ast AstContext<'ast>, expr: ExprKind<'ast>) { | ||
clippy::check_expr(cx, expr); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
#[allow(clippy::manual_is_ascii_check)] | ||
|
||
fn main() { | ||
let x = 0; | ||
let c = 'x'; | ||
|
||
// Lint | ||
let _ = (b'a'..b'z').contains(&x); | ||
let _ = (b'A'..b'Z').contains(&x); | ||
let _ = (b'0'..b'9').contains(&x); | ||
let _ = ('a'..'z').contains(&c); | ||
let _ = ('A'..'Z').contains(&c); | ||
let _ = ('0'..'9').contains(&c); | ||
|
||
// Don't lint (inclusive) | ||
let _ = (b'a'..=b'z').contains(&x); | ||
let _ = (b'A'..=b'Z').contains(&x); | ||
let _ = (b'0'..=b'9').contains(&x); | ||
let _ = ('a'..='z').contains(&c); | ||
let _ = ('A'..='Z').contains(&c); | ||
let _ = ('0'..='9').contains(&c); | ||
|
||
let b: i32 = 32; | ||
|
||
// Don't lint (something else) | ||
let _ = (b'a'..).contains(&x); | ||
let _ = (..=b'Z').contains(&x); | ||
let _ = (256..7272).contains(&b); | ||
let _ = (0..1).contains(&x); | ||
let _ = (0..9).contains(&x); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
warning: almost complete ascii range | ||
--> $DIR/almost_complete_range.rs:8:13 | ||
| | ||
8 | let _ = (b'a'..b'z').contains(&x); | ||
| ^^^^^^^^^^^^ help: try: `b'a'..=b'a'` | ||
| | ||
= note: `#[warn(marker::almost_complete_range)]` on by default | ||
|
||
warning: almost complete ascii range | ||
--> $DIR/almost_complete_range.rs:9:13 | ||
| | ||
9 | let _ = (b'A'..b'Z').contains(&x); | ||
| ^^^^^^^^^^^^ help: try: `b'A'..=b'A'` | ||
|
||
warning: almost complete ascii range | ||
--> $DIR/almost_complete_range.rs:10:13 | ||
| | ||
10 | let _ = (b'0'..b'9').contains(&x); | ||
| ^^^^^^^^^^^^ help: try: `b'0'..=b'0'` | ||
|
||
warning: almost complete ascii range | ||
--> $DIR/almost_complete_range.rs:11:13 | ||
| | ||
11 | let _ = ('a'..'z').contains(&c); | ||
| ^^^^^^^^^^ help: try: `'a'..='a'` | ||
|
||
warning: almost complete ascii range | ||
--> $DIR/almost_complete_range.rs:12:13 | ||
| | ||
12 | let _ = ('A'..'Z').contains(&c); | ||
| ^^^^^^^^^^ help: try: `'A'..='A'` | ||
|
||
warning: almost complete ascii range | ||
--> $DIR/almost_complete_range.rs:13:13 | ||
| | ||
13 | let _ = ('0'..'9').contains(&c); | ||
| ^^^^^^^^^^ help: try: `'0'..='0'` | ||
|
||
warning: 6 warnings emitted | ||
|
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.