Skip to content

Commit b450d0d

Browse files
committed
Remove suggestions for macro expansions, only use first line of span
1 parent 89a2a3b commit b450d0d

File tree

3 files changed

+110
-104
lines changed

3 files changed

+110
-104
lines changed

clippy_lints/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,7 @@ mod transmute;
362362
mod transmuting_null;
363363
mod try_err;
364364
mod types;
365+
mod undocumented_unsafe_blocks;
365366
mod undropped_manually_drops;
366367
mod unicode;
367368
mod unit_return_expecting_ord;
Lines changed: 103 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1-
use clippy_utils::diagnostics::span_lint_and_sugg;
2-
use clippy_utils::source::{snippet, indent_of, reindent_multiline};
1+
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
2+
use clippy_utils::source::{indent_of, reindent_multiline, snippet};
3+
use clippy_utils::{in_macro, is_lint_allowed};
34
use rustc_errors::Applicability;
5+
use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
46
use rustc_hir::{Block, BlockCheckMode, Expr, ExprKind, HirId, Local, UnsafeSource};
57
use rustc_lexer::TokenKind;
6-
use rustc_middle::hir::map::Map;
78
use rustc_lint::{LateContext, LateLintPass};
9+
use rustc_middle::hir::map::Map;
810
use rustc_middle::lint::in_external_macro;
911
use rustc_middle::ty::TyCtxt;
10-
use rustc_session::{impl_lint_pass, declare_tool_lint};
12+
use rustc_session::{declare_tool_lint, impl_lint_pass};
1113
use rustc_span::{BytePos, Span};
1214
use std::borrow::Cow;
13-
use clippy_utils::{is_lint_allowed, in_macro};
14-
use rustc_hir::intravisit::{NestedVisitorMap, Visitor, walk_expr};
1515

1616
declare_clippy_lint! {
1717
/// ### What it does
@@ -53,6 +53,10 @@ pub struct UndocumentedUnsafeBlocks {
5353
// The local was already checked for an overall safety comment
5454
// There is no need to continue checking the blocks in the local
5555
pub local_checked: bool,
56+
// Since we can only check the blocks from expanded macros
57+
// We have to omit the suggestion due to the actual definition
58+
// Not being available to us
59+
pub macro_expansion: bool,
5660
}
5761

5862
impl LateLintPass<'_> for UndocumentedUnsafeBlocks {
@@ -63,22 +67,22 @@ impl LateLintPass<'_> for UndocumentedUnsafeBlocks {
6367
if !in_external_macro(cx.tcx.sess, block.span);
6468
if let BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) = block.rules;
6569
if let Some(enclosing_scope_hir_id) = cx.tcx.hir().get_enclosing_scope(block.hir_id);
66-
if block_has_safety_comment(cx.tcx, enclosing_scope_hir_id, block.span) == Some(false);
70+
if self.block_has_safety_comment(cx.tcx, enclosing_scope_hir_id, block.span) == Some(false);
6771
then {
6872
let mut span = block.span;
6973

7074
if let Some(local_span) = self.local_span {
7175
span = local_span;
7276

73-
let result = block_has_safety_comment(cx.tcx, enclosing_scope_hir_id, span);
77+
let result = self.block_has_safety_comment(cx.tcx, enclosing_scope_hir_id, span);
7478

7579
if result.unwrap_or(true) {
7680
self.local_checked = true;
7781
return;
7882
}
7983
}
8084

81-
lint(cx, span);
85+
self.lint(cx, span);
8286
}
8387
}
8488
}
@@ -118,91 +122,104 @@ impl<'hir> Visitor<'hir> for UndocumentedUnsafeBlocks {
118122
fn visit_expr(&mut self, ex: &'v Expr<'v>) {
119123
match ex.kind {
120124
ExprKind::Block(_, _) => self.local_level = self.local_level.saturating_add(1),
121-
_ => walk_expr(self, ex)
125+
_ => walk_expr(self, ex),
122126
}
123127
}
124128
}
125129

126-
fn lint(cx: &LateContext<'_>, span: Span) {
127-
let block_indent = indent_of(cx, span);
128-
let suggestion = format!("// Safety: ...\n{}", snippet(cx, span, ".."));
129-
130-
span_lint_and_sugg(
131-
cx,
132-
UNDOCUMENTED_UNSAFE_BLOCKS,
133-
span,
134-
"unsafe block missing a safety comment",
135-
"consider adding a safety comment",
136-
reindent_multiline(Cow::Borrowed(&suggestion), true, block_indent).to_string(),
137-
Applicability::HasPlaceholders,
138-
);
139-
}
140-
141-
fn block_has_safety_comment(
142-
tcx: TyCtxt<'_>,
143-
enclosing_hir_id: HirId,
144-
block_span: Span,
145-
) -> Option<bool> {
146-
let map = tcx.hir();
147-
let source_map = tcx.sess.source_map();
148-
149-
let enclosing_scope_span = map.opt_span(enclosing_hir_id)?;
150-
151-
let between_span = if in_macro(block_span) {
152-
enclosing_scope_span.with_hi(block_span.hi())
153-
} else {
154-
enclosing_scope_span.to(block_span)
155-
};
156-
157-
let file_name = source_map.span_to_filename(between_span);
158-
let source_file = source_map.get_source_file(&file_name)?;
159-
160-
let lex_start = (between_span.lo().0 + 1) as usize;
161-
let src_str = source_file.src.as_ref()?[lex_start..between_span.hi().0 as usize].to_string();
162-
163-
let mut pos = 0;
164-
let mut comment = false;
165-
166-
for token in rustc_lexer::tokenize(&src_str) {
167-
match token.kind {
168-
TokenKind::LineComment { doc_style: None }
169-
| TokenKind::BlockComment {
170-
doc_style: None,
171-
terminated: true,
172-
} => {
173-
let comment_str = src_str[pos + 2..pos + token.len].to_ascii_uppercase();
174-
175-
if comment_str.contains("SAFETY:") {
176-
comment = true;
177-
}
178-
}
179-
// We need to add all whitespace to `pos` before checking the comment's line number
180-
TokenKind::Whitespace => {}
181-
_ => {
182-
if comment {
183-
// Get the line number of the "comment" (really wherever the trailing whitespace ended)
184-
let comment_line_num = source_file
185-
.lookup_file_pos_with_col_display(BytePos(
186-
(lex_start + pos).try_into().unwrap(),
187-
))
188-
.0;
189-
// Find the block/local's line number
190-
let block_line_num =
191-
tcx.sess.source_map().lookup_char_pos(block_span.lo()).line;
192-
193-
// Check the comment is immediately followed by the block/local
194-
if block_line_num == comment_line_num + 1 || block_line_num == comment_line_num
195-
{
196-
return Some(true);
130+
impl UndocumentedUnsafeBlocks {
131+
fn block_has_safety_comment(&mut self, tcx: TyCtxt<'_>, enclosing_hir_id: HirId, block_span: Span) -> Option<bool> {
132+
let map = tcx.hir();
133+
let source_map = tcx.sess.source_map();
134+
135+
let enclosing_scope_span = map.opt_span(enclosing_hir_id)?;
136+
137+
let between_span = if in_macro(block_span) {
138+
self.macro_expansion = true;
139+
enclosing_scope_span.with_hi(block_span.hi())
140+
} else {
141+
self.macro_expansion = false;
142+
enclosing_scope_span.to(block_span)
143+
};
144+
145+
let file_name = source_map.span_to_filename(between_span);
146+
let source_file = source_map.get_source_file(&file_name)?;
147+
148+
let lex_start = (between_span.lo().0 + 1) as usize;
149+
let src_str = source_file.src.as_ref()?[lex_start..between_span.hi().0 as usize].to_string();
150+
151+
let mut pos = 0;
152+
let mut comment = false;
153+
154+
for token in rustc_lexer::tokenize(&src_str) {
155+
match token.kind {
156+
TokenKind::LineComment { doc_style: None }
157+
| TokenKind::BlockComment {
158+
doc_style: None,
159+
terminated: true,
160+
} => {
161+
let comment_str = src_str[pos + 2..pos + token.len].to_ascii_uppercase();
162+
163+
if comment_str.contains("SAFETY:") {
164+
comment = true;
197165
}
198-
199-
comment = false;
200-
}
166+
},
167+
// We need to add all whitespace to `pos` before checking the comment's line number
168+
TokenKind::Whitespace => {},
169+
_ => {
170+
if comment {
171+
// Get the line number of the "comment" (really wherever the trailing whitespace ended)
172+
let comment_line_num = source_file
173+
.lookup_file_pos_with_col_display(BytePos((lex_start + pos).try_into().unwrap()))
174+
.0;
175+
// Find the block/local's line number
176+
let block_line_num = tcx.sess.source_map().lookup_char_pos(block_span.lo()).line;
177+
178+
// Check the comment is immediately followed by the block/local
179+
if block_line_num == comment_line_num + 1 || block_line_num == comment_line_num {
180+
return Some(true);
181+
}
182+
183+
comment = false;
184+
}
185+
},
201186
}
187+
188+
pos += token.len;
202189
}
203190

204-
pos += token.len;
191+
Some(false)
205192
}
206193

207-
Some(false)
194+
fn lint(&self, cx: &LateContext<'_>, mut span: Span) {
195+
let source_map = cx.tcx.sess.source_map();
196+
197+
if source_map.is_multiline(span) {
198+
span = source_map.span_until_char(span, '\n');
199+
}
200+
201+
if self.macro_expansion {
202+
span_lint_and_help(
203+
cx,
204+
UNDOCUMENTED_UNSAFE_BLOCKS,
205+
span,
206+
"unsafe block in macro expansion missing a safety comment",
207+
None,
208+
"consider adding a safety comment in the macro definition",
209+
);
210+
} else {
211+
let block_indent = indent_of(cx, span);
212+
let suggestion = format!("// Safety: ...\n{}", snippet(cx, span, ".."));
213+
214+
span_lint_and_sugg(
215+
cx,
216+
UNDOCUMENTED_UNSAFE_BLOCKS,
217+
span,
218+
"unsafe block missing a safety comment",
219+
"consider adding a safety comment",
220+
reindent_multiline(Cow::Borrowed(&suggestion), true, block_indent).to_string(),
221+
Applicability::HasPlaceholders,
222+
);
223+
}
224+
}
208225
}

tests/ui/undocumented_unsafe_blocks.stderr

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -50,17 +50,13 @@ LL + let _ = *unsafe { &42 };
5050
error: unsafe block missing a safety comment
5151
--> $DIR/undocumented_unsafe_blocks.rs:232:5
5252
|
53-
LL | / let _ = match unsafe {} {
54-
LL | | _ => {},
55-
LL | | };
56-
| |______^
53+
LL | let _ = match unsafe {} {
54+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
5755
|
5856
help: consider adding a safety comment
5957
|
6058
LL ~ // Safety: ...
6159
LL + let _ = match unsafe {} {
62-
LL + _ => {},
63-
LL + };
6460
|
6561

6662
error: unsafe block missing a safety comment
@@ -111,7 +107,7 @@ LL ~ t!(// Safety: ...
111107
LL ~ unsafe {});
112108
|
113109

114-
error: unsafe block missing a safety comment
110+
error: unsafe block in macro expansion missing a safety comment
115111
--> $DIR/undocumented_unsafe_blocks.rs:262:13
116112
|
117113
LL | unsafe {}
@@ -120,12 +116,8 @@ LL | unsafe {}
120116
LL | t!();
121117
| ----- in this macro invocation
122118
|
119+
= help: consider adding a safety comment in the macro definition
123120
= note: this error originates in the macro `t` (in Nightly builds, run with -Z macro-backtrace for more info)
124-
help: consider adding a safety comment
125-
|
126-
LL ~ // Safety: ...
127-
LL + unsafe {}
128-
|
129121

130122
error: unsafe block missing a safety comment
131123
--> $DIR/undocumented_unsafe_blocks.rs:270:5
@@ -142,17 +134,13 @@ LL ~ unsafe {} // Safety:
142134
error: unsafe block missing a safety comment
143135
--> $DIR/undocumented_unsafe_blocks.rs:274:5
144136
|
145-
LL | / unsafe {
146-
LL | | // Safety:
147-
LL | | }
148-
| |_____^
137+
LL | unsafe {
138+
| ^^^^^^^^
149139
|
150140
help: consider adding a safety comment
151141
|
152142
LL ~ // Safety: ...
153143
LL + unsafe {
154-
LL + // Safety:
155-
LL + }
156144
|
157145

158146
error: unsafe block missing a safety comment

0 commit comments

Comments
 (0)