-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
undocumented_unsafe_blocks
does not trigger on unsafe trait impls
#8761
Conversation
r? @giraffate (rust-highfive has picked a reviewer for you, use r? to override) |
Sorry, I can't take much time this week, but next week I can take time for a review. @Jarcho Could you do a review on this? |
item_and_spans.push((item, item.span)); | ||
} | ||
// Sort items by start position | ||
item_and_spans.sort_by_key(|e| e.1.lo()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Item's are already in declarations order, so there's no need to sort.
@@ -86,6 +87,65 @@ impl LateLintPass<'_> for UndocumentedUnsafeBlocks { | |||
); | |||
} | |||
} | |||
|
|||
fn check_mod(&mut self, cx: &LateContext<'_>, module: &'_ hir::Mod<'_>, mod_span: Span, hir_id: hir::HirId) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be using check_item
rather than check_mod
. Items can appear within functions as well as modules. A combination of clippy_utils::get_parent_node
and scanning for the id of the contained item can be used to get the span to use for the search bounds.
} else { | ||
// unsafe impl S {} /* comment */ unsafe impl T {} | ||
// ^-------------^ | ||
item_and_spans[idx - 1].1.between(*item_span) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will break if the previous item is from a macro expansion. You'll need to use rustc_span::hygiene::walk_chain(item_and_spans[idx - 1].1, SyntaxContext::root())
for (idx, (item, item_span)) in item_and_spans.iter().enumerate() { | ||
if let hir::ItemKind::Impl(imple) = &item.kind | ||
&& imple.unsafety == hir::Unsafety::Unsafe | ||
&& !item_span.from_expansion() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Optional extension here to handle macro expansion from the same crate. See block_has_safety_comment
for how that's done for unsafe blocks.
A call to is_unsafe_from_proc_macro
is needed. You can change the function to take a Span
rather than a Block
.
|
||
if let Ok(start) = source_map.lookup_line(span_before_impl.lo()) | ||
&& let Ok(end) = source_map.lookup_line(span_before_impl.hi()) | ||
&& let Some(src) = start.sf.src.as_deref() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You'll need to add a check here that the file is the same for both line lookups. This is more a sanity check then anything. Two spans from the same SyntaxContext
in the same module should be in the same file, but I can't say for certain that's the case.
&& !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, hir_id) | ||
{ | ||
// Checks if the lines immediately preceding the impl contain a safety comment. | ||
let impl_has_safety_comment = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor nit here. This block isn't needed. The first statement can be moved out, then the if assigned directly.
☔ The latest upstream changes (presumably #8788) made this pull request unmergeable. Please resolve the merge conflicts. |
Thanks for your review @Jarcho |
|
||
/// Checks if the lines immediately preceding the item contain a safety comment. | ||
fn item_has_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>) -> bool { | ||
if span_from_macro_expansion_has_safety_comment(cx, item.span) || span_in_body_has_safety_comment(cx, item.span) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be returning false if the item is within a function, but doesn't have a safety comment. e.g.
unsafe trait Foo {}
fn f() {
Struct S;
// no comment
unsafe impl Foo for S {}
}
Not a particularly big deal on it's own, but it contributes to the ICE later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's still duplicate work here. Easiest fix would be to remove the call to span_in_body_has_safety_comment
as it's handled afterwards when matching on Node::Stmt(_)
.
let mut hi = false; | ||
if let Node::Item(parent_item) = parent_node { | ||
if let ItemKind::Mod(parent_mod) = &parent_item.kind { | ||
for (idx, item_id) in parent_mod.item_ids.iter().enumerate() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be better to use Iterator::find_map
here. the extraction of either Span::lo
or Span::hi
could be done here as well.
This should get rid of the need to have span_before_item
and hi
as mutable.
} | ||
} | ||
} | ||
let span_before_item = span_before_item.unwrap(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can fail when the impl is inside a function and I think the crate root.
let span_before_item = span_before_item.unwrap(); | ||
|
||
let source_map = cx.sess().source_map(); | ||
if let Some(item_span) = walk_span_to_context(item.span, SyntaxContext::root()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
walk_span_to_context
isn't needed here. item.span
is already at the root context.
Thanks for your review @Jarcho |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just two more small things. I think it's good otherwise, but I'll take one more look at it later. Thanks for keeping up with the review.
|
||
/// Checks if the lines immediately preceding the item contain a safety comment. | ||
fn item_has_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>) -> bool { | ||
if span_from_macro_expansion_has_safety_comment(cx, item.span) || span_in_body_has_safety_comment(cx, item.span) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's still duplicate work here. Easiest fix would be to remove the call to span_in_body_has_safety_comment
as it's handled afterwards when matching on Node::Stmt(_)
.
if item.span.ctxt() == SyntaxContext::root() { | ||
if let Some(parent_node) = get_parent_node(cx.tcx, item.hir_id()) { | ||
let comment_start; | ||
match parent_node { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Small nit. This could be let comment_start = match parent_node {
The delayed initialization makes it seem like something complicated is coming up.
Thanks! I removed the call to |
The only way an item can appear in a function is through |
Everything looks good now. Good job. |
Thank you so much! @Jarcho |
@bors r=Jarcho @tamaroning @Jarcho It looks good, thanks! |
📌 Commit 9e66f2d has been approved by |
`undocumented_unsafe_blocks` does not trigger on unsafe trait impls Closes #8505 changelog: ~~`unsafe impl`s from macro invocations don't trigger the lint for now.~~ ~~This lint checks unsafe impls from/not from macro expansions~~ This lint checks unsafe impls NOT from macro expansions and checks ones in macro declarations.
💔 Test failed - checks-action_test |
You'll need to add |
@bors retry |
☀️ Test successful - checks-action_dev_test, checks-action_remark_test, checks-action_test |
Closes #8505
changelog: This lint checks unsafe impls NOT from macro expansions and checks ones in macro declarations.
unsafe impl
s from macro invocations don't trigger the lint for now.This lint checks unsafe impls from/not from macro expansions