-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Introduce #[suppress]: suppress Rocket lints.
Adding `#[suppress(lint)]` for a known `lint` suppresses the corresponding warning generated by Rocket's codegen. The lints are: * `unknown_format` * `dubious_payload` * `segment_chars` * `arbitrary_main` * `sync_spawn` For example, the following works as expected to suppress the warning generated by the unknown media type "application/foo": ```rust fn post_foo() -> &'static str { "post_foo" } ``` Resolves #1188.
- Loading branch information
1 parent
35a1cf1
commit bd26ca4
Showing
12 changed files
with
201 additions
and
19 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
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
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
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 |
---|---|---|
|
@@ -3,3 +3,4 @@ pub mod catch; | |
pub mod route; | ||
pub mod param; | ||
pub mod async_bound; | ||
pub mod suppress; |
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
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
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
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,115 @@ | ||
use std::cell::RefCell; | ||
use std::collections::{HashMap, HashSet}; | ||
use std::ops::Range; | ||
|
||
use devise::ext::PathExt; | ||
use proc_macro2::{Span, TokenStream}; | ||
use syn::{parse::Parser, punctuated::Punctuated}; | ||
|
||
macro_rules! declare_lints { | ||
($($name:ident ( $string:literal) ),* $(,)?) => ( | ||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] | ||
pub enum Lint { | ||
$($name),* | ||
} | ||
|
||
impl Lint { | ||
fn from_str(string: &str) -> Option<Self> { | ||
$(if string.eq_ignore_ascii_case($string) { | ||
return Some(Lint::$name); | ||
})* | ||
|
||
None | ||
} | ||
|
||
fn as_str(&self) -> &'static str { | ||
match self { | ||
$(Lint::$name => $string),* | ||
} | ||
} | ||
|
||
fn lints() -> &'static str { | ||
concat!("[" $(,$string,)", "* "]") | ||
} | ||
} | ||
) | ||
} | ||
|
||
declare_lints! { | ||
UnknownFormat("unknown_format"), | ||
DubiousPayload("dubious_payload"), | ||
SegmentChars("segment_chars"), | ||
ArbitraryMain("arbitrary_main"), | ||
SyncSpawn("sync_spawn"), | ||
} | ||
|
||
thread_local! { | ||
static SUPPRESSIONS: RefCell<HashMap<Lint, HashSet<Range<usize>>>> = RefCell::default(); | ||
} | ||
|
||
fn span_to_range(span: Span) -> Option<Range<usize>> { | ||
let string = format!("{span:?}"); | ||
let i = string.find('(')?; | ||
let j = string[i..].find(')')?; | ||
let (start, end) = string[(i + 1)..(i + j)].split_once("..")?; | ||
Some(Range { start: start.parse().ok()?, end: end.parse().ok()? }) | ||
} | ||
|
||
impl Lint { | ||
pub fn suppress_attrs(attrs: &[syn::Attribute], ctxt: Span) { | ||
let _ = attrs.iter().try_for_each(|attr| Lint::suppress_attr(attr, ctxt)); | ||
} | ||
|
||
pub fn suppress_attr(attr: &syn::Attribute, ctxt: Span) -> Result<(), syn::Error> { | ||
let syn::Meta::List(list) = &attr.meta else { | ||
return Ok(()); | ||
}; | ||
|
||
if !list.path.last_ident().map_or(false, |i| i == "suppress") { | ||
return Ok(()); | ||
} | ||
|
||
Self::suppress_tokens(list.tokens.clone(), ctxt) | ||
} | ||
|
||
pub fn suppress_tokens(attr_tokens: TokenStream, ctxt: Span) -> Result<(), syn::Error> { | ||
let lints = Punctuated::<Lint, syn::Token![,]>::parse_terminated.parse2(attr_tokens)?; | ||
lints.iter().for_each(|lint| lint.suppress(ctxt)); | ||
Ok(()) | ||
} | ||
|
||
pub fn suppress(self, ctxt: Span) { | ||
SUPPRESSIONS.with_borrow_mut(|s| { | ||
let range = span_to_range(ctxt).unwrap_or_default(); | ||
s.entry(self).or_default().insert(range); | ||
}) | ||
} | ||
|
||
pub fn is_suppressed(self, ctxt: Span) -> bool { | ||
SUPPRESSIONS.with_borrow(|s| { | ||
let this = span_to_range(ctxt).unwrap_or_default(); | ||
s.get(&self).map_or(false, |set| { | ||
set.iter().any(|r| this.start >= r.start && this.end <= r.end) | ||
}) | ||
}) | ||
} | ||
|
||
pub fn enabled(self, ctxt: Span) -> bool { | ||
!self.is_suppressed(ctxt) | ||
} | ||
|
||
pub fn how_to_suppress(self) -> String { | ||
format!("apply `#[suppress({})]` before the item to suppress this lint", self.as_str()) | ||
} | ||
} | ||
|
||
impl syn::parse::Parse for Lint { | ||
fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> { | ||
let ident: syn::Ident = input.parse()?; | ||
let name = ident.to_string(); | ||
Lint::from_str(&name).ok_or_else(|| { | ||
let msg = format!("invalid lint `{name}` (known lints: {})", Lint::lints()); | ||
syn::Error::new(ident.span(), msg) | ||
}) | ||
} | ||
} |
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,20 @@ | ||
use proc_macro2::TokenStream; | ||
use devise::Spanned; | ||
|
||
mod lint; | ||
|
||
pub use lint::Lint; | ||
|
||
pub fn suppress_attribute( | ||
args: proc_macro::TokenStream, | ||
input: proc_macro::TokenStream | ||
) -> TokenStream { | ||
let input: TokenStream = input.into(); | ||
match Lint::suppress_tokens(args.into(), input.span()) { | ||
Ok(_) => input, | ||
Err(e) => { | ||
let error: TokenStream = e.to_compile_error().into(); | ||
quote!(#error #input) | ||
} | ||
} | ||
} |
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
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
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