|
| 1 | +mod proper_safety_comment; |
| 2 | + |
| 3 | +use rustc_lint::{EarlyContext, EarlyLintPass}; |
| 4 | +use rustc_session::impl_lint_pass; |
| 5 | + |
| 6 | +declare_clippy_lint! { |
| 7 | + /// ### What it does |
| 8 | + /// |
| 9 | + /// It requires proper safety comments at the barrier of [Unsafety](https://doc.rust-lang.org/reference/unsafety.html). |
| 10 | + /// This includes any part of the [code that needs to satisfy extra safety conditions](https://doc.rust-lang.org/reference/unsafe-keyword.html): |
| 11 | + /// |
| 12 | + /// - unsafe blocks (`unsafe {}`) |
| 13 | + /// - unsafe trait implementations (`unsafe impl`) |
| 14 | + /// - unsafe external blocks (`unsafe extern`) |
| 15 | + /// - unsafe attributes (`#[unsafe(attr)]`) |
| 16 | + /// |
| 17 | + /// Safety comments are [non-doc line comments](https://doc.rust-lang.org/reference/comments.html) starting with `SAFETY:`: |
| 18 | + /// |
| 19 | + /// ```no_run |
| 20 | + /// // SAFETY: A safety comment |
| 21 | + /// // that can cover |
| 22 | + /// // multiple lines. |
| 23 | + /// ``` |
| 24 | + /// |
| 25 | + /// Furthermore, it detects unnecessary safety comments for non-critical blocks, trait implementations and attributes. However, there can be false negatives. |
| 26 | + /// |
| 27 | + /// [Code that defines extra safety conditions](https://doc.rust-lang.org/reference/unsafe-keyword.html) is covered by [`clippy::missing_safety_doc`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_safety_doc) and [`clippy::unnecessary_safety_doc`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_safety_doc) |
| 28 | + /// |
| 29 | + /// ### Why restrict this? |
| 30 | + /// |
| 31 | + /// Breaking the safety barrier should not be done carelessly. |
| 32 | + /// Proper documentation should be provided as to why each unsafe operation does not introduce [undefined behavior](https://doc.rust-lang.org/reference/behavior-considered-undefined.html). |
| 33 | + /// Thinking about these safety requirements and writing them down can prevent incorrect implementations. |
| 34 | + /// On the other hand, unnecessary safety comments are confusing and should not exist. |
| 35 | + /// |
| 36 | + /// ### Example |
| 37 | + /// |
| 38 | + /// ```no_run |
| 39 | + /// unsafe fn f1() {} |
| 40 | + /// fn f2() { |
| 41 | + /// unsafe { f1() } |
| 42 | + /// } |
| 43 | + /// |
| 44 | + /// unsafe trait A {} |
| 45 | + /// unsafe impl A for () {} |
| 46 | + /// |
| 47 | + /// unsafe extern { |
| 48 | + /// pub fn g1(); |
| 49 | + /// pub unsafe fn g2(); |
| 50 | + /// pub safe fn g3(); |
| 51 | + /// } |
| 52 | + /// |
| 53 | + /// #[unsafe(no_mangle)] |
| 54 | + /// fn h() {} |
| 55 | + /// ``` |
| 56 | + /// |
| 57 | + /// Use instead: |
| 58 | + /// |
| 59 | + /// ```no_run |
| 60 | + /// unsafe fn f1() {} |
| 61 | + /// fn f2() { |
| 62 | + /// unsafe { |
| 63 | + /// // SAFETY: ... |
| 64 | + /// f1() |
| 65 | + /// } |
| 66 | + /// } |
| 67 | + /// |
| 68 | + /// unsafe trait A {} |
| 69 | + /// // SAFETY: ... |
| 70 | + /// unsafe impl A for () {} |
| 71 | + /// |
| 72 | + /// // SAFETY: ... |
| 73 | + /// unsafe extern { |
| 74 | + /// // SAFETY: ... |
| 75 | + /// pub fn g1(); |
| 76 | + /// // SAFETY: ... |
| 77 | + /// pub unsafe fn g2(); |
| 78 | + /// // SAFETY: ... |
| 79 | + /// pub safe fn g3(); |
| 80 | + /// } |
| 81 | + /// |
| 82 | + /// // SAFETY: ... |
| 83 | + /// #[unsafe(no_mangle)] |
| 84 | + /// fn h() {} |
| 85 | + /// ``` |
| 86 | + #[clippy::version = "1.85.0"] |
| 87 | + pub PROPER_SAFETY_COMMENT, |
| 88 | + restriction, |
| 89 | + "requires proper safety comments at the barrier of unsafety" |
| 90 | +} |
| 91 | + |
| 92 | +pub struct Safety; |
| 93 | + |
| 94 | +impl_lint_pass!(Safety => [ |
| 95 | + PROPER_SAFETY_COMMENT, |
| 96 | +]); |
| 97 | + |
| 98 | +impl EarlyLintPass for Safety { |
| 99 | + fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &rustc_ast::Attribute) { |
| 100 | + proper_safety_comment::check_attribute(cx, attr); |
| 101 | + } |
| 102 | + |
| 103 | + fn check_block(&mut self, cx: &EarlyContext<'_>, block: &rustc_ast::Block) { |
| 104 | + proper_safety_comment::check_block(cx, block); |
| 105 | + } |
| 106 | + |
| 107 | + fn check_item(&mut self, cx: &EarlyContext<'_>, item: &rustc_ast::Item) { |
| 108 | + proper_safety_comment::check_item(cx, item); |
| 109 | + } |
| 110 | +} |
0 commit comments