Rust å ¬å¼ linter ã® clippy ã«æ°ããã«ã¼ã«ãå®è£ ãã
Rust å ¬å¼ã® linterï¼clippy ã«æ°ããã«ã¼ã«ã足ããã«ãªã¯ãåºãã¦ãã¼ã¸ãããæã®ã¡ã¢ã§ãï¼
dbg!
ãã¯ã
Rust 1.32 㧠dbg!
ã¨ãããã¯ãã追å ããã¾ããï¼
ããã¯å¤ã1ã¤å¼æ°ã«ã¨ã£ã¦ãã®å¤ãè¿ããã¯ãã§ï¼åãåã£ãå¤ã¨ã½ã¼ã¹ã³ã¼ãä¸ã§ã®ä½ç½®ã print ãã¾ãï¼
fn factorial(n: u32) -> u32 { if dbg!(n <= 1) { dbg!(1) } else { dbg!(n * factorial(n - 1)) } } dbg!(factorial(4));
ååã®éãï¼ãããã print debug ç¨éã®ãã¯ããªã®ã§ï¼ãããã°ãçµãã£ã¦ãªãã¸ããªã« commit ããåã«ã¯ã³ã¼ããã dbg!
ãã¯ããåé¤ãã¦ããã®ããã¹ããã©ã¯ãã£ã¹ã§ãï¼
å
¬å¼ããã¥ã¡ã³ãã«ã
Note that the macro is intended as a debugging tool and therefore you should avoid having uses of it in version control for longer periods.
ã¨æ¸ãã¦ããã¾ãï¼
ã¡ãã£ã¨ãããããã°ã«é常ã«ä¾¿å©ãªã®ã§ããï¼å¤ã move ã§åãåã£ã¦ãã®å¤ãè¿ãã ããªã®ã§ãã£ããæ¶ãå¿ããã¨ãã¹ããå£ããã¨ããªãæ°ä»ããªãã±ã¼ã¹ããããã¨ã«æ°ä»ãã¾ããï¼
dbg_macro
ã«ã¼ã«
ããã§ï¼ã³ã¼ãå
ã® dbg!
ãã¯ããæ¤åºã§ãã dbg_macro
ã«ã¼ã«ãã¤ããã¾ããï¼
#![deny(clippy::dbg_macro)] fn main() { dbg!(42); }
ã®ãããªã³ã¼ãã«å¯¾ãã¦ï¼
cargo clippy -- -W clippy::dbg_macro
ã®ããã«å®è¡ããã¨
error: `dbg!` macro is intended as a debugging tool --> foo.rs:4:5 | 4 | dbg!(42); | ^^^^^^^^ | help: ensure to avoid having uses of it in version control | 4 | 42; | ^^
ã®ããã«è¦åãåºãã¾ãï¼
ããã©ã«ãã§æå¹ã«ãªã£ã¦ããã¨ãããã°ä¸ã«ã¨ãã£ã¿ãè¦åãã¾ãã£ã¦ããããã®ã§ï¼restriction
ã«ãã´ãªã§ããã©ã«ãã¯ç¡å¹ã«ãªã£ã¦ãã¾ãï¼
restriction
ã«ãã´ãªã¯ README ã«ã¯è¼ã£ã¦ãã¾ãããï¼ãunimplemented!
ã使ããªãããä»åã®ã«ã¼ã«ã®ãããªç¹å®ã®å ´é¢ï¼production åã®ãã§ãã¯ãªã©ï¼ã§æå¹ãªã«ã¼ã«ãï¼ãmem::forget
ã Drop
ãå®è£
ããåã§ä½¿ããªããã¨ãã£ãä¸äººåãã§ã¯ãªããããã®ã«ã¼ã«ãç»é²ããã¦ãã¾ãï¼
clippy ã®ãªãã¸ããªã restriction ã§æ¤ç´¢ããã¨ãã£ã¨è¦æ¸¡ããã¨ãã§ãã¾ãï¼
æ°ããã«ã¼ã«ã®ææ¡ã¨è¿½å
ã¾ã㯠issue ã§ãããããã«ã¼ã«ããã¨è¯ãã¨æããã¨ææ¡ãï¼ç¹ã«å対ããªãã¡ã¤ã³éçºè ã® upvote ãä»ãã¾ããï¼'good first issue'ï¼åã㦠contribute ãã人ãåãçµãã¨è¯ãæãã issueï¼ã®ã©ãã«ãã¤ããã®ã§ï¼èªåã§å®è£ ãã¦ã¿ã¦ï¼ãã«ãªã¯ãåºãã¾ããï¼ãã¨ã¯ä¸è¬çãªãã«ãªã¯ã¨åãã§ä½åº¦ãã¬ãã¥ã¼ãã¦ããã£ã¦ OK ãåºã¦ãã¼ã¸ã¨ããæµãã§ããï¼
clippy ã®å®è£
åºæ¬çã«ã¯ã¾ã CONTRIBUTING.md ãèªãã°å¤§ä½åããããã«ãªã£ã¦ããï¼å¿ èªã§ãï¼
ãã£ã¬ã¯ããªæ§æ
src/*
: clippy ã®ã³ãã³ãã©ã¤ã³é¨åã¨ãã©ã¤ãï¼å®è¡ã®å段é¨åï¼ã®å®è£ ã®ã¿clippy_lints/
: linter ã®åã«ã¼ã«ã®å®è£clippy_lints/lib.rs
: ã«ã¼ã«ãã¹ã¦ã import ãã¦ç»é²ãã¦ããã¨ããclippy_lints/*.rs
: ã«ã¼ã«ã®å®è£ ï¼lib.rs
以å¤ï¼clippy_lints/utils
: ã«ã¼ã«ã®å®è£ ã«ä½¿ããããã
clippy_dev/
: éçºæã«ä½¿ããã¼ã«ç¾¤ï¼ã«ã¼ã«ãªã¹ãã®æ´æ°ãªã©ï¼clippy_dummy/
: ãã¹ãåãtests/
: pass ãèµ°ãããé¨åã®ãã¹ããåã«ã¼ã«ãé©ç¨ãã¦æ£ããè¦åãåºããã©ããã®ãã¹ã
æ°ããã«ã¼ã«ã足ãã«ã¯åºæ¬çã« clippy_lints
crate ããã³ tests/
ã«è¿½å ã»ä¿®æ£ãå ãããã¨ã«ãªãã¾ãï¼
Early Pass 㨠Later Pass
clippy ã®ã«ã¼ã«ã¯æ§ææ¨ï¼syntax::ast
ï¼ããã㯠HIRï¼rustc::hir
ï¼ã«å¯¾ãã pass ã¨ãã¦å®è£
ãã¾ãï¼HIR ã¯ãã¼ã¹ããæ§ææ¨ã«ã³ã³ãã¤ã©åãã®æ
å ±ã足ãããã®ã§ï¼Rust RFC 1191ã«è©³ããæ¸ãã¦ããã¾ãï¼
èªåã® pass ãå®è£ ãã¦ç»é²ãã¦ããã¨ï¼clippy ãæ§ææ¨ã¾ã㯠HIR ããã©ãã¼ã¹ããã¨ãã«åãã¼ãã«ãã® pass ãé©ç¨ãã¦ï¼pass ã«å®è£ ããã³ã¼ã«ããã¯ã¡ã½ããããããããã¨é©å®å¼ã³åºããã¾ãï¼
æ§ææ¨ã«ãããããã pass ã early passï¼HIR ã«ãããããã pass ã later pass ã¨ããï¼ä¸è¨ã®ãããªé åºã§é©ç¨ããã¾ãï¼
- parse ãã¦æ§ææ¨ãå¾ã
- æ§ææ¨ããã©ãã¼ã¹ã㦠early pass ãé©ç¨
- HIR ã¸ã®å¤æã¨åãã§ãã¯
- HIR ããã©ãã¼ã¹ã㦠later pass ãé©ç¨
early pass ã¯æ§ææ¨ã®ã¿ï¼later pass 㯠HIRï¼åæ
å ±ï¼ã³ã³ãã¤ã©ã³ã³ãã£ã°ï¼cfg!
ï¼ãªã©ã«ã¢ã¯ã»ã¹ã§ãã¾ãï¼
æ§ææ¨ããã¼ã¹ããã pass ãé©ç¨ãããªã©ã®å¦ç㯠rustc ã³ã³ãã¤ã©æ¬ä½ã« linter åãã®æ±ç¨ç㪠API ãããï¼rust/src/librustc/lint
ï¼ï¼rustc ã³ã³ãã¤ã©èªä½ã® unused è¦åãªã©ããããå©ç¨ãã¦ãã¾ãï¼rust/src/librustc_lint
ï¼ï¼rust-clippy ãªãã¸ããªã§ã¯ãããå©ç¨ãã¦ã«ã¼ã«éã¨ã³ãã³ãã©ã¤ã³é¨åã®ã¿ãå®è£
ãã¦ãã¾ãï¼ãªã®ã§ï¼clippy ã®å®è£
æã«ã¯ rustc
ï¼rustc_*
ã syntax
ã¨ãã£ã rustc ã³ã³ãã¤ã© API ãç¥ãå¿
è¦ãããã¾ãï¼
å
·ä½çã« early pass 㨠later pass ã§ã©ã®ãã¹ãéãã¦ããã㯠rust/src/librustc/lint/mod.rs
ã«å®è£
ãããã¾ãï¼
https://github.com/rust-lang/rust/blob/master/src/librustc/lint/mod.rs
æ°ãã Early Pass ã追å ãã
ã¾ã clippy_lints/src
å
ã«ã«ã¼ã«åãã®ã½ã¼ã¹ãã¡ã¤ã«ãä½æãã¾ãï¼ããã§ã¯ clippy_lints/src/my_rule.rs
ã¨ããã¨ãã¾ãï¼
declare_clippy_lint! { pub MY_RULE, style, "my rule for clippy" }
第1å¼æ°ã linter ã¤ã³ã¹ã¿ã³ã¹ï¼2å¼æ°ç®ã perf, correctness, complexity, style ãªã©ã®ã«ãã´ãªã§ãï¼
declare_clippy_lint
㯠rustc::lint
ãæä¾ãã declare_tool_lint!
ãã¯ãã®èã wrapper ã«ãªã£ã¦ãã¦ï¼ã«ãã´ãªãè¦ã¦ããã©ã«ãã®è¦åã¬ãã«ãã»ãããããªã©ã®è¨å®ãè¡ã£ã¦ãã¾ãï¼
次㫠pass ãªãã¸ã§ã¯ããå®ç¾©ãã¾ãï¼
#[derive(Copy, Clone, Debug)] pub struct MyRule; impl LintPass for MyRule { fn get_lints(&self) -> LintArray { lint_array!(MY_RULE) } fn name(&self) -> &'static str { "MyRule" } } impl EarlyLintPass for MyRule { fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &syntax::Expr) { // ããã«ãã§ãã¯å¦çãå®è£ } }
rustc::lint::LintPass
ã®å®è£
ã§ã¯ãã® pass ã®å
±éæ
å ±ãè¨è¿°ãã¾ãï¼1ã¤ã® pass ã§è¤æ°ã®ã«ã¼ã«ããã§ãã¯ãããã¨ãã§ãï¼rustc::lint::lint_array!
ãã¯ãã§æå®ãã¾ãï¼
early pass ã®å®è£
æ¬ä½ã¯ rustc::lint::EarlyLintPass
ãå®è£
ãããã¨ã§å®è£
ãã¾ãï¼ãã¨ã㨠EarlyLintPass
ã«ãã check_*
ã¡ã½ããããªã¼ãã¼ã©ã¤ãããã¨ï¼ãã®ã¡ã½ããã対å¿ããæ§ææ¨ãã¼ãã visit ããã¨ãã«é©ç¨ããã¾ãï¼rustc::lint::EarlyContext
ãéã㦠lint ã®ã³ã³ããã¹ãæ
å ±ãåãåããã¨ãã§ãã¾ãï¼
ä¸è¨ã§ã¯å¼ã«å¯¾ããå¦ç check_expr
ããªã¼ãã¼ã©ã¤ããã¦ãã¾ããï¼ä¸è¦§ã¯rustc ã®ã½ã¼ã¹å
ã§ç¢ºèªã§ãã¾ãï¼
æ§ææ¨ã®ãã¿ã¼ã³ããã§ãã¯ããããã¿ã¼ã³ã«ããããã¦ãããããã§ãã¯ãå¿
è¦ãªæ
å ±ãæãåºãã«ã¯ match
ã if let
ãªã©ã®ãã¿ã¼ã³ãããããã¹ãããã¾ãããã¨ã«ãªãã®ã§ï¼if_chain::if_chain!
ãã¯ãã便å©ã§ãï¼
ä¾ãã° let x = EXPR; x
ãåãåºãå¦çã¯ãããªæãã«æ¸ãã¾ãï¼
if_chain! { if let Some(retexpr) = it.next_back(); if let ast::StmtKind::Expr(ref retexpr) = retexpr.node; if let Some(stmt) = it.next_back(); if let ast::StmtKind::Local(ref local) = stmt.node; if let Some(ref initexpr) = local.init; if let ast::PatKind::Ident(_, ident, _) = local.pat.node; if let ast::ExprKind::Path(_, ref path) = retexpr.node; if !in_external_macro(cx.sess(), initexpr.span); then { // ããã§ãããããã¨ãã®å¦ç } }
è¦åãã¹ãã³ã¼ãããã¿ã¼ã³ãããã§è¦ã¤ãããè¦åãåºãå¦çãæ¸ãã¾ãï¼è¦åãåºãæ¹æ³ã¯ clippy_lints/src/utils
ã«ä¾¿å©é¢æ°ç¾¤ãããï¼
- è¦åã¡ãã»ã¼ã¸ã®ã¿:
span_lint()
,span_lint_node()
- è¦åã¡ãã»ã¼ã¸ã¨ãã«ã:
span_help_and_lint()
- è¦åã¡ãã»ã¼ã¸ã¨ãã¼ã:
span_note_and_lint()
- è¦åã¡ãã»ã¼ã¸ã¨ãã«ãã¨ä¿®æ£ææ¡:
span_lint_and_sugg()
ãªã©ã使ãã¾ãï¼span ã¨ã¯ã½ã¼ã¹ã³ã¼ãçã®ãã¨ã§ï¼éå§ä½ç½®ã»çµäºä½ç½®ã»ã³ã³ããã¹ãæ
å ±ãã¨ã³ã³ã¼ãããã u32
ã®å¤ã§ï¼ã½ã¼ã¹ã³ã¼ãã®ãã¡è¦åãåºãé¨åãæå®ããã®ã«ä½¿ãã¾ãï¼åæ§ææ¨ãã¼ã㯠syntax::Spanned
㧠wrap ãã㦠check_*
ã¡ã½ããã«æ¸¡ãããã®ã§ï¼ãã¼ãã«å¯¾å¿ãã span ã¯ç°¡åã«åå¾ã§ãã¾ãï¼
span_lint_and_sugg()
ã§ã¯ã½ã¼ã¹ã³ã¼ãã®ä¿®æ£ææ¡ã String
ã§æ¸¡ãã¾ãï¼rustc_errors::Applicability::MachineApplicable
ãæå®ãããã¨ã§ï¼èªåä¿®æ£æ©è½ï¼ãããã rustfixï¼ï¼ã§èªåä¿®æ£ã§ãã¾ãï¼æ¸¡ããæåå㧠span ã§æå®ããç¯å²ãç½®ãæãã¾ãï¼span 㯠utils::snippet()
ã使ã£ã¦ã³ã¼ãçï¼ã¹ããããï¼ã¨ãã¦æåååãããã¨ãã§ãï¼ä¿®æ£ææ¡ã®ããã®æååã楽ã«ã¤ãããã±ã¼ã¹ãããã¾ãï¼
æå¾ã«ä½æããã«ã¼ã«ã clippy ã«ç»é²ãã¾ãï¼clippy_lints/src/lib.rs
å
ã§ä¸è¨ã®ããã«å¯¾å¿ããã«ãã´ãªã« linter æ
å ±ã追å ãã¾ãï¼
// ... pub mod my_rule; // ... reg.register_lint_group("clippy::style", Some("clippy_style"), vec![ // ... my_rule::MY_RULE // ... ]); // ...
æå¾ã«ã¤ãã£ã pass ãç»é²ããã®ã§ãããearly pass ã®å ´åã¯ããã§æ³¨æãå¿ è¦ã§ãã
// ãã¯ãå±éå¾ã§ OK 㪠pass ã¯æ®éã« early pass ã¨ãã¦ç»é² pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { // ... reg.register_early_lint_pass(box reference::Pass); // ... } // ãã¯ãã«å¯¾ãã lint ãªã©ï¼ãã¯ãã®å±éåã§ãªãã¨åããªã pass ã¯ãã£ã¡ã«ç»é² pub fn register_pre_expansion_lints(...) { // ... store.register_pre_expansion_pass(Some(session), true, false, box dbg_macro::Pass); }
ãã¯ãã®æ§ææ¨ãã¼ãã«ãããããã check_mac()
ãªã©ã使ãå ´åã¯å¾è
ã® register_pre_expansion_pass
å´ã« pass ãç»é²ããå¿
è¦ãããã¾ãï¼
early pass ã®é©ç¨é åºã¯
pre_expansion_pass
- ãã¯ãã®å±éå¦ç
early_lint_pass
ã¨ãªã£ã¦ãã¾ãã
æ°ãã Later Pass ã追å ãã
early pass ã¨åºæ¬çã«ã¯åãã§ï¼rustc::lint::EarlyLintPass<'a>
ã®ä»£ããã« rustc::lint::LateLintPass<'a, 'tcx>
ãå®è£
ãã¾ãï¼tcx
ã¯åæ
å ±ã®ã³ã³ããã¹ãã®å¯¿å½ã表ãã¦ããããã§ãï¼
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MyRule { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx rustc::hir::Expr) { // ã«ã¼ã«ã®å®è£ } }
ãªã¼ãã¼ã©ã¤ãã§ããã¡ã½ããã¯rustc ã®ã½ã¼ã¹å ã§ç¢ºèªã§ãã¾ãï¼
early pass ã¨éãï¼check_expr
ãªã©ã®ã¡ã½ããã« rustc::hir::*
ã渡ããï¼åæ
å ±ã®ã³ã³ããã¹ãã®å¯¿å½ tcx
ãå¶ç´ã¨ãã¦ä»ãã¾ãï¼
åæ
å ±ã«ã¯ LateContext
ã® tcx
ãã£ã¼ã«ãããã¢ã¯ã»ã¹ã§ãã¾ãï¼ï¼e.g. cx.tcx.fn_sig
ï¼ã³ã³ãã¤ã©ã³ã³ãã£ã°ï¼cfg
ï¼ã¯ cx.tcx.sess.parse_sess.config
ã«ãã rustc::session::config::Config
ãªå¤ã«ã¢ã¯ã»ã¹ãããã¨ã§ãã§ãã¯ã§ããããã§ãï¼æ§é ä½ã®ãµã¤ãºãªã©ã¿ã¼ã²ããä¾åã§å¤ãããã®ããã§ãã¯ããéã«ä½¿ããã¾ãï¼
ã¾ãï¼later pass ã§ã¯ call flow graph ã rustc::cfg::CFG
ã使ã£ã¦åå¾ã§ãã¾ãï¼
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MyRule { fn check_fn( &mut self, cx: &LateContext<'a, 'tcx>, kind: intravisit::FnKind<'tcx>, decl: &'tcx FnDecl, body: &'tcx Body, span: Span, node_id: NodeId, ) { // call flow graph ãçæ let cfg = CFG::new(cx.tcx, body); // ... } }
ä¾ãã° cyclomatic complexity ãè¨ç®ããéã«ä½¿ããã¦ããããã§ãï¼
pass ã®ç»é²ã«ã¤ãã¦ï¼later pass ã®å ´åã¯ãã¯ãã«å¯¾ãããã¹ããã©ãã㧠pass ã®ç»é²å
ãåããå¿
è¦ã¯ããã¾ããï¼ãã HIR ãã¼ãããã¯ãå±éçµæçæããããã®ãã¯ï¼ãã®ãã¼ãã® span ã使ã£ã¦ clippy_lints/src/utils
ã® utils::is_expn_of
ã§åããã¾ãï¼
ãã¹ãã®å®è£
ãã¹ã㯠UI ãã¹ãï¼åé¡ãããã³ã¼ãã«å®è£ ããã«ã¼ã«ãé©ç¨ãã¦ï¼çµæã¨ãã¦æå¾ ããè¦åã®åºåãã³ãã³ãã©ã¤ã³åºåã¨ãã¦å¾ããããã©ããï¼ã®ã¿ã§è¡ãã¾ãï¼
CONTRIBUTING.md ã«ããã¨ï¼å®è£
åã«ã¾ãã¯è¦åãåºãã¦ã»ããã³ã¼ãã tests/ui/my_rule.rs
ã«æ¸ãï¼TESTNAME=ui/my_rule cargo test --test compile-test
ã¨å®è¡ããã¨ï¼ãã®ã³ã¼ãã®æ§ææ¨ã«ããããã linter å®è£
ã³ã¼ãã®éå½¢ãã¤ãã£ã¦ããããããã®ã§ããï¼åã®å ´å㯠dbg!
ãå±éãããå¾ã®æ§ææ¨ã«ããããããããªã³ã¼ããåããã¦ãã¾ã£ããã使ãã¾ããã§ããï¼
linter ã®å®è£
ãçµãã£ãã CLIPPY_TESTS=true cargo run --bin clippy-driver -- -L ./target/debug tests/ui/my_rule.rs
ã§è¦åãæå³éãåºåããã¦ãããã¨ã確èªãï¼ãã®çµæãå¤å°æ´å½¢ã㦠tests/ui/my_rule.stderr
ã¨ãã¦ä¿åãã¾ãï¼æå¾ã« TESTNAME=ui/my_rule cargo test --test compile-test
㧠my_rule
åãã®ãã¹ããå®è¡ãã¦çµæã確èªã§ãã¾ãï¼
dbg_macro
ã«ã¼ã«ã®å®è£
ä»åå®è£
ããã«ã¼ã«ã¯ dbg!(expr)
ãã¯ãã®ä½¿ç¨ç®æãæ¤ç¥ãã¦è¦åã¨ãã¦è¡¨ç¤ºãï¼dbg!(expr)
ã®ä»£ããã« expr
ãä¿®æ£ææ¡ã¨ãã¦è¡¨ç¤ºããå°ããªãã®ã§ãï¼
rustc::lint::EarlyLintPass
ã¨ãã¦å®è£
ãï¼pre-expansion pass ã¨ãã¦ç»é²ãã¾ãï¼ãã¯ãå¼åºãã«ããããã EarlyLintPass::check_mac
ã¡ã½ããããªã¼ãã¼ã©ã¤ããã¦å®è£
ãï¼æ¸¡ããã ast::Mac
ã®ãã¹ã "dbg"
ãã©ãããã§ãã¯ããã ãã§ãï¼
impl EarlyLintPass for Pass { fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &ast::Mac) { if mac.node.path == "dbg" { // è¦åã表示 } } }
ast::Mac
㯠syntax::Spaned
㧠wrap ãããåãªã®ã§ mac.span
ã§ãã¯ãå¼åºãã®ã½ã¼ã¹ã³ã¼ãä¸ã§ã®ç¯å²ï¼spanï¼ã¯ç°¡åã«åå¾ã§ãã¾ãï¼
ãã¨ã¯ä¿®æ£ææ¡ç¨ã®æååãçæã§ããã°çµããã§ãï¼
ãã¯ãã¯å¼æ°ã«ãã¼ã¯ã³åãåãã®ã§ï¼å±éåã¯å¼æ°ã®ãã¼ã¯ã³åã®ã¿ãæ§ææ¨ãã¼ãã«æ ¼ç´ããã¦ãã¾ãï¼mac.node.tts
ï¼ï¼
dbg!(expr)
ãã¯ãã®ä¸èº« expr
ã® span ãåå¾ã§ããã°ï¼ãã®ç¯å²ã utils::snippet
ã§ã³ã¼ãçåã§ãã¾ãï¼
å¼æ°ã® span ãåãæ¹æ³ã¯
- ãã¼ã¯ã³åã®æåã®ãã¼ã¯ã³ã® span ã®å§ã¾ãä½ç½®ã¨ãã¼ã¯ã³åã®æå¾ã®ãã¼ã¯ã³ã® span ã®çµããä½ç½®ãããã¼ã¯ã³åå ¨ä½ã®ç¯å²ã表ã span ãçæãã
dbg!()
ã¯ä»æ§ã¨ãã¦1ã¤ã®å¤ãåãã®ã§ï¼ãã¼ã¯ã³åãsyntax::ast::Expr
ã«ãã¼ã¹ããçµæã®ãã¼ããã span ãåãåºã- early pass ãããï¼later pass ã«ãã¦
dbg!()
ã®å¼æ°é¨åããå±éããã HIR ãã¼ããç¹å®ã㦠span ãåãåºã
ã®ãã£ãã3éããèãããã¾ãï¼3. ã¯å¤§å¤ããã ã 2. ã¯å¼ã¨ãã¦ãã¼ã¹ã§ããªãã£ãå ´åã®ã¨ã©ã¼ãã³ããªã³ã°ããã¼ã¹ã®ã³ã¹ããããã®ã§ï¼1. ãä¸çªè¯ãããã§ãï¼
Rust ã®ãã¼ã¯ã³å㯠syntax::tokenstream::TokenStream
ã¨ããåã§è¡¨ããï¼syntax::tokenstream::TokenTree
ã®åã§è¡¨ç¾ããã¦ãã¾ãï¼ã©ãããããã㯠proc macro ã®å®è£
ãªã©ã§ä½¿ã proc_macro::TokenStream
ã proc_macro::TokenTree
ã¨ã¯å¥ç©ã®ããã§ãï¼
TokenStream
㯠.trees()
ã§ï¼clone ããï¼TokenTree
ã®ã¤ãã¬ã¼ã¿ãè¿ããã®ã§ï¼ããããæåã®ãã¼ã¯ã³ããªã¼ã¨æå¾ã®ãã¼ã¯ã³ããªã¼ãåå¾ãï¼Span::to
ã使ã£ã¦æåã®ãã¼ã¯ã³ããªã¼ã® span ããæå¾ã®ãã¼ã¯ã³ããªã¼ã® span ã¾ã§ã®ç¯å²ã表ã span ãæ°ãã«çæãã¾ãï¼
let mut cursor = mac.node.tts.trees(); let first = cursor.next().unwrap(); let last = cursor.last().unwrap_or(first); let entire_span = first.span().to(last.span());
æå¾ã«ã¹ããããæååã span ããçæããã°ä¿®æ£ææ¡ã«ä½¿ãæååãçæã§ãã¾ãï¼
let snip = utils::snippet_opt(cx, entire_span).unwrap().to_string();
æå¾ã« clippy_dev
㨠cargo fmt
ãå®è¡ãã¦ããã¾ãï¼clippy_dev
㯠clippy_lints/src/lib.rs
ã§ç»é²ããã¦ãã pass ããã§ãã¯ãããï¼CHANGELOG.md 㨠README.md ãæ´æ°ããããã¦ããã¾ãï¼
cd clippy_dev/ cargo run -- update_lints cargo +nightly fmt --all
ã¾ã¨ã
dbg_macro
ã«ã¼ã«ã Rust å
¬å¼ linter ã® clippy ã«è¿½å ãã¾ããï¼æ¬¡ã® clippy ã®ãªãªã¼ã¹æã«å
¥ãã¨æãã®ã§ï¼è¯ããã° CI ã Git ã® pre-commit ããã㯠pre-push ããã¯ãªã©ã§
cargo clippy -- -W clippy::dbg_macro
ã¨å®è¡ãã¦ä½¿ã£ã¦ã¿ã¦ãã ããï¼
ã¾ã clippy ã«æ°ããã«ã¼ã«ã追å ããæ¹æ³ã«ã¤ãã¦ãç°¡åã«ç´¹ä»ãã¾ããï¼rustc
ï¼rustc_*
ï¼syntax
ãããã® nightly ã§ãã使ããªã rustc ã³ã³ãã¤ã© API ã使ã£ããèªãã ãããå¿
è¦ã¯ãªããªãç¡ãã®ã§ï¼å®é使ã£ãã®ã¯ããä¸é¨ã§ããè¯ãæ©ä¼ã ã£ãã¨æãã¾ãï¼ã¡ãªã¿ã«ãããã® crate 㯠rustc ã³ã³ãã¤ã©ã®å
é¨å®è£
ã§é »ç¹ã«å¤æ´ãããã®ã§ï¼ä¸è¨ã®ç´¹ä»ããå
容ããããæ£ãããªããªãå¯è½æ§ãé«ãã§ãï¼