Skip to content

Commit c931d07

Browse files
committed
Rename lint, use rust lexer, allow whitespace
1 parent de83414 commit c931d07

File tree

7 files changed

+93
-136
lines changed

7 files changed

+93
-136
lines changed

clippy_lints/src/lib.mods.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ mod transmute;
202202
mod transmuting_null;
203203
mod try_err;
204204
mod types;
205-
mod undocumented_unsafe_block_safety;
205+
mod undocumented_unsafe_blocks;
206206
mod undropped_manually_drops;
207207
mod unicode;
208208
mod unit_return_expecting_ord;

clippy_lints/src/lib.register_lints.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -462,7 +462,7 @@ store.register_lints(&[
462462
types::REDUNDANT_ALLOCATION,
463463
types::TYPE_COMPLEXITY,
464464
types::VEC_BOX,
465-
undocumented_unsafe_block_safety::UNDOCUMENTED_UNSAFE_BLOCK_SAFETY,
465+
undocumented_unsafe_blocks::UNDOCUMENTED_UNSAFE_BLOCKS,
466466
undropped_manually_drops::UNDROPPED_MANUALLY_DROPS,
467467
unicode::INVISIBLE_CHARACTERS,
468468
unicode::NON_ASCII_LITERAL,

clippy_lints/src/lib.register_restriction.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve
5656
LintId::of(strings::STR_TO_STRING),
5757
LintId::of(types::RC_BUFFER),
5858
LintId::of(types::RC_MUTEX),
59-
LintId::of(undocumented_unsafe_block_safety::UNDOCUMENTED_UNSAFE_BLOCK_SAFETY),
59+
LintId::of(undocumented_unsafe_blocks::UNDOCUMENTED_UNSAFE_BLOCKS),
6060
LintId::of(unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS),
6161
LintId::of(unwrap_in_result::UNWRAP_IN_RESULT),
6262
LintId::of(verbose_file_reads::VERBOSE_FILE_READS),

clippy_lints/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -535,7 +535,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
535535
store.register_late_pass(move || Box::new(feature_name::FeatureName));
536536
store.register_late_pass(move || Box::new(iter_not_returning_iterator::IterNotReturningIterator));
537537
store.register_late_pass(move || Box::new(if_then_panic::IfThenPanic));
538-
store.register_late_pass(move || Box::new(undocumented_unsafe_block_safety::UndocumentedUnsafeBlockSafety::default()));
538+
store.register_late_pass(move || Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks::default()));
539539
}
540540

541541
#[rustfmt::skip]

clippy_lints/src/undocumented_unsafe_block_safety.rs renamed to clippy_lints/src/undocumented_unsafe_blocks.rs

Lines changed: 34 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -8,64 +8,56 @@ use rustc_middle::lint::in_external_macro;
88
use rustc_middle::ty::TyCtxt;
99
use rustc_session::{impl_lint_pass, declare_tool_lint};
1010
use rustc_span::Span;
11-
use core::str::Lines;
12-
use core::iter::Rev;
1311
use std::borrow::Cow;
1412
use clippy_utils::is_lint_allowed;
1513

1614
declare_clippy_lint! {
1715
/// ### What it does
1816
/// Checks for `unsafe` blocks without a `// Safety: ` comment
1917
/// explaining why the unsafe operations performed inside
20-
/// the block are (or are not) safe.
18+
/// the block are safe.
2119
///
2220
/// ### Why is this bad?
23-
/// Unsafe blocks without a safety comment can be difficult to
24-
/// understand for those that are unfamiliar with the block's code
25-
/// and/or unsafe in general.
21+
/// Undocumented unsafe blocks can make it difficult to
22+
/// read and maintain code, as well as uncover unsoundness
23+
/// and bugs.
2624
///
2725
/// ### Example
2826
/// ```rust
29-
/// unsafe {};
27+
/// use std::ptr::NonNull;
28+
/// let a = &mut 42;
3029
///
31-
/// let _ = unsafe {};
30+
/// let ptr = unsafe { NonNull::new_unchecked(a) };
3231
/// ```
3332
/// Use instead:
3433
/// ```rust
35-
/// // Safety: ...
36-
/// unsafe {}
34+
/// use std::ptr::NonNull;
35+
/// let a = &mut 42;
3736
///
38-
/// // Safety: ...
39-
/// let _ = unsafe {};
37+
/// // Safety: references are guaranteed to be non-null.
38+
/// let ptr = unsafe { NonNull::new_unchecked(a) };
4039
/// ```
41-
pub UNDOCUMENTED_UNSAFE_BLOCK_SAFETY,
40+
pub UNDOCUMENTED_UNSAFE_BLOCKS,
4241
restriction,
43-
"creating an unsafe block without explaining why it is or is not safe"
42+
"creating an unsafe block without explaining why it is safe"
4443
}
4544

46-
impl_lint_pass!(UndocumentedUnsafeBlockSafety => [UNDOCUMENTED_UNSAFE_BLOCK_SAFETY]);
45+
impl_lint_pass!(UndocumentedUnsafeBlocks => [UNDOCUMENTED_UNSAFE_BLOCKS]);
4746

4847
#[derive(Default)]
49-
pub struct UndocumentedUnsafeBlockSafety {
48+
pub struct UndocumentedUnsafeBlocks {
5049
pub local: bool
5150
}
5251

53-
#[derive(PartialEq)]
54-
enum CommentType {
55-
Safety,
56-
Unrelated,
57-
None,
58-
}
59-
60-
impl LateLintPass<'_> for UndocumentedUnsafeBlockSafety {
52+
impl LateLintPass<'_> for UndocumentedUnsafeBlocks {
6153
fn check_block(&mut self, cx: &LateContext<'_>, block: &'_ Block<'_>) {
6254
if self.local {
6355
self.local = false;
6456
return
6557
}
6658

6759
if_chain! {
68-
if !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCK_SAFETY, block.hir_id);
60+
if !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, block.hir_id);
6961
if !in_external_macro(cx.tcx.sess, block.span);
7062
if let BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) = block.rules;
7163
if let Some(enclosing_scope_hir_id) = cx.tcx.hir().get_enclosing_scope(block.hir_id);
@@ -77,7 +69,7 @@ impl LateLintPass<'_> for UndocumentedUnsafeBlockSafety {
7769

7870
fn check_local(&mut self, cx: &LateContext<'_>, local: &'_ Local<'_>) {
7971
if_chain! {
80-
if !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCK_SAFETY, local.hir_id);
72+
if !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, local.hir_id);
8173
if !in_external_macro(cx.tcx.sess, local.span);
8274
if let Some(init) = local.init;
8375
if let ExprKind::Block(block, _) = init.kind;
@@ -101,7 +93,7 @@ fn find_candidate(cx: &LateContext<'_>, span: Span, enclosing_hir_id: HirId) {
10193

10294
span_lint_and_sugg(
10395
cx,
104-
UNDOCUMENTED_UNSAFE_BLOCK_SAFETY,
96+
UNDOCUMENTED_UNSAFE_BLOCKS,
10597
span,
10698
"unsafe block missing a safety comment",
10799
"consider adding a safety comment",
@@ -123,76 +115,28 @@ fn block_has_safety_comment(tcx: TyCtxt<'_>, enclosing_hir_id: HirId, block_span
123115
let lex_start = (between_span.lo().0 + 1) as usize;
124116
let mut src_str = source_file.src.as_ref()?[lex_start..between_span.hi().0 as usize].to_string();
125117

126-
// Remove all whitespace, but retain newlines to verify the block immediately follows the comment
127-
src_str.retain(|c| c == '\n' || !c.is_whitespace());
118+
src_str.retain(|c| !c.is_whitespace());
128119

129-
let mut src_str_split = src_str.lines().rev();
120+
let src_str_split = src_str.lines().rev().collect::<Vec<_>>();
121+
let src_str = src_str_split.join("");
130122

123+
let mut pos = 0;
131124
let mut found_safety_comment = false;
132125

133-
while let Some(line) = src_str_split.next() {
134-
match line {
135-
"*/" => return Some(check_multiline_block(&mut src_str_split, None)),
136-
line if (line.starts_with('*') && line.ends_with("*/")) => return Some(check_multiline_block(&mut src_str_split, Some(&line[1..]))),
137-
// Covers both line comments and single line block comments
138-
line => match contains_safety_comment(line, false) {
139-
CommentType::Safety => { found_safety_comment = true; break },
140-
CommentType::Unrelated => continue,
141-
CommentType::None => break,
142-
}
143-
}
144-
}
145-
146-
Some(found_safety_comment)
147-
}
148-
149-
fn check_multiline_block(lines: &mut Rev<Lines<'_>>, same_line_terminator: Option<&str>) -> bool {
150-
let mut found_safety = false;
151-
152-
if let Some(line) = same_line_terminator {
153-
found_safety = contains_safety_comment(line, true) == CommentType::Safety;
154-
}
155-
156-
for next_line in lines {
157-
if found_safety {
158-
break
159-
}
160-
161-
let text_start = if next_line.starts_with('*') {
162-
1
163-
} else if next_line.starts_with("/*") {
164-
2
165-
} else {
166-
return false
167-
};
168-
169-
found_safety = contains_safety_comment(&next_line[text_start..], true) == CommentType::Safety;
170-
}
171-
172-
found_safety
173-
}
174-
175-
fn contains_safety_comment(comment: &str, block: bool) -> CommentType {
176-
if block || is_comment(comment) {
177-
let comment_upper = comment.to_uppercase();
178-
if comment_upper.trim_start().starts_with("SAFETY:") || comment_upper.contains("SAFETY:") {
179-
return CommentType::Safety
180-
}
181-
182-
return CommentType::Unrelated
183-
}
184-
185-
CommentType::None
186-
}
187-
188-
fn is_comment(comment: &str) -> bool {
189-
if let Some(token) = rustc_lexer::tokenize(comment).next() {
126+
for token in rustc_lexer::tokenize(&src_str) {
190127
match token.kind {
191128
TokenKind::LineComment { doc_style: None }
192-
| TokenKind::BlockComment { doc_style: None, terminated: true } => return true,
193-
_ => {},
129+
| TokenKind::BlockComment { doc_style: None, terminated: true } => {
130+
if src_str[pos + 2.. pos + token.len].to_ascii_uppercase().contains("SAFETY:") {
131+
found_safety_comment = true;
132+
break
133+
}
134+
},
135+
_ => break
194136
}
137+
138+
pos += token.len;
195139
}
196140

197-
false
141+
Some(found_safety_comment)
198142
}

tests/ui/undocumented_unsafe_block_safety.rs renamed to tests/ui/undocumented_unsafe_blocks.rs

Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#![warn(clippy::undocumented_unsafe_block_safety)]
1+
#![warn(clippy::undocumented_unsafe_blocks)]
22

33
// Valid comments
44

@@ -7,22 +7,37 @@ fn line_comment() {
77
unsafe {}
88
}
99

10-
fn line_comment_with_extras() {
11-
// This is a description
10+
fn line_comment_newlines() {
1211
// Safety:
12+
1313
unsafe {}
1414
}
1515

16-
fn let_statement_line_comment() {
16+
fn line_comment_empty() {
1717
// Safety:
18-
let _ = unsafe {};
18+
//
19+
//
20+
//
21+
unsafe {}
22+
}
23+
24+
fn line_comment_with_extras() {
25+
// This is a description
26+
// Safety:
27+
unsafe {}
1928
}
2029

2130
fn block_comment() {
2231
/* Safety: */
2332
unsafe {}
2433
}
2534

35+
fn block_comment_newlines() {
36+
/* Safety: */
37+
38+
unsafe {}
39+
}
40+
2641
#[rustfmt::skip]
2742
fn inline_block_comment() {
2843
/* Safety: */unsafe {}
@@ -41,11 +56,6 @@ fn block_comment_terminator_same_line() {
4156
unsafe {}
4257
}
4358

44-
fn let_statement_block_comment() {
45-
/* Safety: */
46-
let _ = unsafe {};
47-
}
48-
4959
fn buried_safety() {
5060
// Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
5161
// incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
@@ -65,17 +75,36 @@ fn safety_with_prepended_text() {
6575
unsafe {}
6676
}
6777

78+
fn nested_local() {
79+
let _ = {
80+
let _ = {
81+
// Safety:
82+
let _ = unsafe {};
83+
};
84+
};
85+
}
86+
87+
fn local_line_comment() {
88+
// Safety:
89+
let _ = unsafe {};
90+
}
91+
92+
fn local_block_comment() {
93+
/* Safety: */
94+
let _ = unsafe {};
95+
}
96+
6897
// Invalid comments
6998

7099
fn no_comment() {
71100
unsafe {}
72101
}
73102

74-
fn let_statement_no_comment() {
103+
fn local_no_comment() {
75104
let _ = unsafe {};
76105
}
77106

78-
fn let_statement_commented_block() {
107+
fn local_commented_block() {
79108
let _ =
80109
// Safety:
81110
unsafe {};
@@ -91,16 +120,12 @@ fn internal_comment() {
91120
}
92121
}
93122

94-
fn line_comment_newlines() {
95-
// Safety:
96-
97-
unsafe {}
98-
}
123+
fn interference() {
124+
// Safety
99125

100-
fn block_comment_newlines() {
101-
/* Safety: */
126+
let _ = 42;
102127

103-
unsafe {}
128+
unsafe {};
104129
}
105130

106131
fn main() {}

0 commit comments

Comments
 (0)