Daniel García
2 months ago
10 changed files with 1862 additions and 0 deletions
@ -0,0 +1,2 @@ |
|||||
|
[workspace.metadata.dylint] |
||||
|
libraries = [{ path = "dylints/*" }] |
@ -0,0 +1,7 @@ |
|||||
|
# How to run Lints |
||||
|
|
||||
|
```sh |
||||
|
cargo install cargo-dylint dylint-link |
||||
|
|
||||
|
RUSTFLAGS="-Aunreachable_patterns" cargo dylint --all -- --features sqlite |
||||
|
``` |
@ -0,0 +1,2 @@ |
|||||
|
[target.'cfg(all())'] |
||||
|
linker = "dylint-link" |
@ -0,0 +1 @@ |
|||||
|
/target |
File diff suppressed because it is too large
@ -0,0 +1,20 @@ |
|||||
|
[package] |
||||
|
name = "non_authenticated_routes" |
||||
|
version = "0.1.0" |
||||
|
authors = ["authors go here"] |
||||
|
description = "description goes here" |
||||
|
edition = "2021" |
||||
|
publish = false |
||||
|
|
||||
|
[lib] |
||||
|
crate-type = ["cdylib"] |
||||
|
|
||||
|
[dependencies] |
||||
|
clippy_utils = { git = "https://github.com/rust-lang/rust-clippy", rev = "4f0e46b74dbc8441daf084b6f141a7fe414672a2" } |
||||
|
dylint_linting = "3.2.1" |
||||
|
|
||||
|
[dev-dependencies] |
||||
|
dylint_testing = "3.2.1" |
||||
|
|
||||
|
[package.metadata.rust-analyzer] |
||||
|
rustc_private = true |
@ -0,0 +1,3 @@ |
|||||
|
[toolchain] |
||||
|
channel = "nightly-2024-11-09" |
||||
|
components = ["llvm-tools-preview", "rustc-dev"] |
@ -0,0 +1,167 @@ |
|||||
|
#![feature(rustc_private)] |
||||
|
#![feature(let_chains)] |
||||
|
|
||||
|
extern crate rustc_arena; |
||||
|
extern crate rustc_ast; |
||||
|
extern crate rustc_ast_pretty; |
||||
|
extern crate rustc_attr; |
||||
|
extern crate rustc_data_structures; |
||||
|
extern crate rustc_errors; |
||||
|
extern crate rustc_hir; |
||||
|
extern crate rustc_hir_pretty; |
||||
|
extern crate rustc_index; |
||||
|
extern crate rustc_infer; |
||||
|
extern crate rustc_lexer; |
||||
|
extern crate rustc_middle; |
||||
|
extern crate rustc_mir_dataflow; |
||||
|
extern crate rustc_parse; |
||||
|
extern crate rustc_span; |
||||
|
extern crate rustc_target; |
||||
|
extern crate rustc_trait_selection; |
||||
|
|
||||
|
use clippy_utils::diagnostics::span_lint; |
||||
|
use rustc_hir::{def_id::DefId, Item, ItemKind, QPath, TyKind}; |
||||
|
use rustc_lint::{LateContext, LateLintPass}; |
||||
|
use rustc_span::{symbol::Ident, Span, Symbol}; |
||||
|
|
||||
|
dylint_linting::impl_late_lint! { |
||||
|
/// ### What it does
|
||||
|
///
|
||||
|
/// ### Why is this bad?
|
||||
|
///
|
||||
|
/// ### Known problems
|
||||
|
/// Remove if none.
|
||||
|
///
|
||||
|
/// ### Example
|
||||
|
/// ```rust
|
||||
|
/// // example code where a warning is issued
|
||||
|
/// ```
|
||||
|
/// Use instead:
|
||||
|
/// ```rust
|
||||
|
/// // example code that does not raise a warning
|
||||
|
/// ```
|
||||
|
pub NON_AUTHENTICATED_ROUTES, |
||||
|
Warn, |
||||
|
"description goes here", |
||||
|
NonAuthenticatedRoutes::default() |
||||
|
} |
||||
|
|
||||
|
#[derive(Default)] |
||||
|
pub struct NonAuthenticatedRoutes { |
||||
|
last_function_item: Option<(Ident, Span, bool)>, |
||||
|
} |
||||
|
|
||||
|
// Collect all the attribute macros that are applied to the given span
|
||||
|
fn attr_def_ids(mut span: rustc_span::Span) -> Vec<(DefId, Symbol, Option<DefId>)> { |
||||
|
use rustc_span::hygiene::{walk_chain, ExpnKind, MacroKind}; |
||||
|
use rustc_span::{ExpnData, SyntaxContext}; |
||||
|
|
||||
|
let mut def_ids = Vec::new(); |
||||
|
while span.ctxt() != SyntaxContext::root() { |
||||
|
if let ExpnData { |
||||
|
kind: ExpnKind::Macro(MacroKind::Attr, macro_symbol), |
||||
|
macro_def_id: Some(def_id), |
||||
|
parent_module, |
||||
|
.. |
||||
|
} = span.ctxt().outer_expn_data() |
||||
|
{ |
||||
|
def_ids.push((def_id, macro_symbol, parent_module)); |
||||
|
} |
||||
|
span = walk_chain(span, SyntaxContext::root()); |
||||
|
} |
||||
|
def_ids |
||||
|
} |
||||
|
|
||||
|
const ROCKET_MACRO_EXCEPTIONS: [(&str, &str); 1] = [("rocket::catch", "catch")]; |
||||
|
|
||||
|
const VALID_AUTH_HEADERS: [&str; 6] = [ |
||||
|
"auth::Headers", |
||||
|
"auth::OrgHeaders", |
||||
|
"auth::AdminHeaders", |
||||
|
"auth::ManagerHeaders", |
||||
|
"auth::ManagerHeadersLoose", |
||||
|
"auth::OwnerHeaders", |
||||
|
]; |
||||
|
|
||||
|
impl<'tcx> LateLintPass<'tcx> for NonAuthenticatedRoutes { |
||||
|
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item) { |
||||
|
if let ItemKind::Fn(sig, ..) = item.kind { |
||||
|
let mut has_auth_headers = false; |
||||
|
|
||||
|
for input in sig.decl.inputs { |
||||
|
let TyKind::Path(QPath::Resolved(_, path)) = input.kind else { |
||||
|
continue; |
||||
|
}; |
||||
|
|
||||
|
for seg in path.segments { |
||||
|
if let Some(def_id) = seg.res.opt_def_id() { |
||||
|
let def = cx.tcx.def_path_str(def_id); |
||||
|
if VALID_AUTH_HEADERS.contains(&def.as_str()) { |
||||
|
has_auth_headers = true; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
self.last_function_item = Some((item.ident, sig.span, has_auth_headers)); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
let ItemKind::Struct(_data, _generics) = item.kind else { |
||||
|
return; |
||||
|
}; |
||||
|
|
||||
|
let def_ids = attr_def_ids(item.span); |
||||
|
|
||||
|
let mut is_rocket_route = false; |
||||
|
|
||||
|
for (def_id, sym, parent) in &def_ids { |
||||
|
let def_id = cx.tcx.def_path_str(*def_id); |
||||
|
let sym = sym.as_str(); |
||||
|
let parent = parent.map(|parent| cx.tcx.def_path_str(parent)); |
||||
|
|
||||
|
if ROCKET_MACRO_EXCEPTIONS.contains(&(&def_id, sym)) { |
||||
|
is_rocket_route = false; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
if def_id.starts_with("rocket::") || parent.as_deref() == Some("rocket_codegen") { |
||||
|
is_rocket_route = true; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if !is_rocket_route { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
let Some((func_ident, func_span, has_auth_headers)) = self.last_function_item.take() else { |
||||
|
span_lint(cx, NON_AUTHENTICATED_ROUTES, item.span, "No function found before the expanded route"); |
||||
|
return; |
||||
|
}; |
||||
|
|
||||
|
if func_ident != item.ident { |
||||
|
span_lint( |
||||
|
cx, |
||||
|
NON_AUTHENTICATED_ROUTES, |
||||
|
item.span, |
||||
|
"The function before the expanded route does not match the route", |
||||
|
); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
if !has_auth_headers { |
||||
|
span_lint( |
||||
|
cx, |
||||
|
NON_AUTHENTICATED_ROUTES, |
||||
|
func_span, |
||||
|
"This Rocket route does not have any authentication headers", |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#[test] |
||||
|
fn ui() { |
||||
|
dylint_testing::ui_test(env!("CARGO_PKG_NAME"), "ui"); |
||||
|
} |
@ -0,0 +1 @@ |
|||||
|
fn main() {} |
Loading…
Reference in new issue