Skip to content

Commit d99bf09

Browse files
committed
Add #[clippy::print_hir] attribute for debugging
1 parent b6645d0 commit d99bf09

File tree

6 files changed

+68
-1
lines changed

6 files changed

+68
-1
lines changed

clippy_lints/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
514514
}
515515

516516
store.register_late_pass(|| Box::new(utils::author::Author));
517+
store.register_late_pass(|| Box::new(utils::print_hir::PrintHir));
517518
store.register_late_pass(|| Box::new(await_holding_invalid::AwaitHolding));
518519
store.register_late_pass(|| Box::new(serde_api::SerdeApi));
519520
let vec_box_size_threshold = conf.vec_box_size_threshold;

clippy_lints/src/utils/internal_lints/metadata_collector.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,12 @@ use std::path::Path;
3333
/// This is the output file of the lint collector.
3434
const OUTPUT_FILE: &str = "../util/gh-pages/lints.json";
3535
/// These lints are excluded from the export.
36-
const BLACK_LISTED_LINTS: [&str; 3] = ["lint_author", "deep_code_inspection", "internal_metadata_collector"];
36+
const BLACK_LISTED_LINTS: &[&str] = &[
37+
"lint_author",
38+
"deep_code_inspection",
39+
"internal_metadata_collector",
40+
"print_ast",
41+
];
3742
/// These groups will be ignored by the lint group matcher. This is useful for collections like
3843
/// `clippy::all`
3944
const IGNORED_LINT_GROUPS: [&str; 1] = ["clippy::all"];

clippy_lints/src/utils/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ pub mod conf;
33
pub mod inspector;
44
#[cfg(feature = "internal")]
55
pub mod internal_lints;
6+
pub mod print_hir;
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
use clippy_utils::get_attr;
2+
use rustc_hir as hir;
3+
use rustc_lint::{LateContext, LateLintPass, LintContext};
4+
use rustc_session::{declare_lint_pass, declare_tool_lint};
5+
6+
declare_clippy_lint! {
7+
/// ### What it does
8+
/// It formats the attached node with `{:#?}` and writes the result to the
9+
/// standard output. This is intended for debugging.
10+
///
11+
pub PRINT_HIR,
12+
internal_warn,
13+
"helper for writing lints"
14+
}
15+
16+
declare_lint_pass!(PrintHir => [PRINT_HIR]);
17+
18+
impl<'tcx> LateLintPass<'tcx> for PrintHir {
19+
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
20+
if has_attr(cx, item.hir_id()) {
21+
println!("{item:#?}");
22+
}
23+
}
24+
25+
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
26+
if has_attr(cx, expr.hir_id) {
27+
println!("{expr:#?}");
28+
}
29+
}
30+
31+
fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx hir::Stmt<'_>) {
32+
match stmt.kind {
33+
hir::StmtKind::Expr(e) | hir::StmtKind::Semi(e) if has_attr(cx, e.hir_id) => return,
34+
_ => {},
35+
}
36+
if has_attr(cx, stmt.hir_id) {
37+
println!("{stmt:#?}");
38+
}
39+
}
40+
}
41+
42+
fn has_attr(cx: &LateContext<'_>, hir_id: hir::HirId) -> bool {
43+
let attrs = cx.tcx.hir().attrs(hir_id);
44+
get_attr(cx.sess(), attrs, "print_hir").count() > 0
45+
}

clippy_utils/src/attrs.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ pub enum DeprecationStatus {
1717
#[rustfmt::skip]
1818
pub const BUILTIN_ATTRIBUTES: &[(&str, DeprecationStatus)] = &[
1919
("author", DeprecationStatus::None),
20+
("print_hir", DeprecationStatus::None),
2021
("version", DeprecationStatus::None),
2122
("cognitive_complexity", DeprecationStatus::None),
2223
("cyclomatic_complexity", DeprecationStatus::Replaced("cognitive_complexity")),

doc/adding_lints.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ because that's clearly a non-descriptive name.
2222
- [Adding the lint logic](#adding-the-lint-logic)
2323
- [Specifying the lint's minimum supported Rust version (MSRV)](#specifying-the-lints-minimum-supported-rust-version-msrv)
2424
- [Author lint](#author-lint)
25+
- [Print HIR lint](#print-hir-lint)
2526
- [Documentation](#documentation)
2627
- [Running rustfmt](#running-rustfmt)
2728
- [Debugging](#debugging)
@@ -484,6 +485,19 @@ you are implementing your lint.
484485

485486
[author_example]: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=9a12cb60e5c6ad4e3003ac6d5e63cf55
486487

488+
## Print HIR lint
489+
490+
To implement a lint, it's helpful to first understand the internal representation
491+
that rustc uses. Clippy has the `#[clippy::print_hir]` attribute that prints the
492+
[`High-Level Intermediate Representation (HIR)`] of the item, statement, or
493+
expression that the attribute is attached to. To attach the attribute to expressions
494+
you often need to enable `#![feature(stmt_expr_attributes)]`.
495+
496+
[Here][print_hir_example] you can find an example, just select _Tools_ and run _Clippy_.
497+
498+
[`High-Level Intermediate Representation (HIR)`]: https://rustc-dev-guide.rust-lang.org/hir.html
499+
[print_hir_example]: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=54d0f768e0ad9f333872f01c2c701bd5
500+
487501
## Documentation
488502

489503
The final thing before submitting our PR is to add some documentation to our

0 commit comments

Comments
 (0)