Test dylint
This commit is contained in:
parent
2f20ad86f9
commit
f312e00dfa
|
@ -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
Load Diff
|
@ -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