Rewrite std_instead_of_core - #17364
Conversation
|
Lintcheck changes for f26808e
This comment will be updated if you push new changes |
eca13eb to
226f1c7
Compare
std_instead_of_core
std_instead_of_corestd_instead_of_core
|
r? @llogiq rustbot has assigned @llogiq. Use Why was this reviewer chosen?The reviewer was selected based on:
|
|
r? Jarcho Please feel free to reverse this! I'm assigning it to you since this is an alternative to #17252 and based on your feedback to me, so I feel you'd be most appropriate to review. Again, thanks for all your help so far! |
This comment has been minimized.
This comment has been minimized.
226f1c7 to
a834ba8
Compare
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
a834ba8 to
9ee6d98
Compare
This comment has been minimized.
This comment has been minimized.
9ee6d98 to
bad1275
Compare
bad1275 to
de99588
Compare
This comment has been minimized.
This comment has been minimized.
de99588 to
b37f793
Compare
|
You beat me to finishing my first review by a few hours (I had it mostly typed up yesterday). You ended up doing one of the major things I was pointing out so that's cool. |
There was a problem hiding this comment.
You might find it nicer to handle list stems specially and turn lint points into a flattened tree. This will get you something like:
newtype_index! {
pub struct NodeId {}
}
enum RootCrate {
Std,
Alloc,
}
enum NodeKind {
Stem {
did: DefId,
/// Span of the final segment
sp: Span,
/// Index of the final path segment
idx: u32,
},
Item(PerNs<Option<DefId>>),
Glob,
}
struct Node {
parent: NodeId,
sp: Span,
kind: NodeKind
}
struct Pass {
root: Option<(RootCrate, Span)>,
nodes: IndexVec<NodeId, Node>,
skip_paths: u32,
}
fn get_parent_for(nodes: &IndexSlice<NodeId, Node>, p: &[PathSegment<'_>]) -> NodeId {
let mut i = NodeId::from_usize(nodes.len() - 1);
while i != NodeId::ZERO {
let node = &nodes[i];
if let Node::Stem { sp, idx } = node.kind
&& let Some(seg) = p.get(idx as usize)
&& seg.ident.span == s.span
{
return i;
}
i = node.parent;
}
i
}
fn check_item(...) {
if let ItemKind::Use(path, kind) = item.kind
&& let (krate_seg, rest) = match path.segments {
[root, krate, rest @ ..] if root.ident.name == kw::PathRoot => (krate, rest),
[krate, rest @ ..] => (krate, rest),
_ => return,
}
&& let Some(krate) = RootCrate::from_name(krate_seg.ident.name)
{
// skip each path with a res only if there's a second path segment.
self.skip_paths = path.res.map(|x| u32::from(x.is_some())).iter().sum::<u32>()
& u32::from(rest.is_empty()).wrapping_sub(1);
if self.root == Some((krate, krate_seg.ident.span)) {
let last = path.segments.last().unwrap();
self.nodes.push(Node {
parent = get_parent_for(self.nodes, path.segments),
sp: path.span,
kind: match kind {
UseKind::ListStem => NodeKind::Seg {
did: last.res.def_id(),
sp: last.ident.span,
idx: path.segments.len() as u32 - 1
},
UseKind::Item(_) => NodeKind::Item(path.res.map(|x| x.and_then(|r| r.opt_def_id()))),
UseKind::Glob => NodeKind::Glob,
},
});
return;
}
self.try_emit_use_tree();
if let [.., last] = rest {
match kind {
UseKind::ListStem {
self.root = Some((krate, krate_seg.ident.span));
self.nodes.push(Node {
parent: NodeId::ZERO,
sp: path.span,
kind: NodeKind::ListStem {
did: last.res.def_id(),
sp: last.ident.span,
idx: path.segments.len() as u32 - 1,
},
});
},
UseKind::Item(_) | UseKind::Glob => {
// Lint like a single path, but with three potential namespaces
},
}
}
} else {
self.try_emit_use_tree();
}
}
fn check_path(...) {
let (krate, last) = match path.segments {
[root, krate, _, last] if root.ident.name == kw::PathRoot => (krate, last),
[krate, _, last] => (krate, last),
_ => return,
};
if let Some(krate) = RootCrate::from_name(krate_seg.ident.name) {
if let Some(n) = self.skip_paths.checked_sub(1) {
self.skip_paths = n;
return;
}
// Lint a path
}
}|
Reminder, once the PR becomes ready for a review, use |
I'm so sorry for that! I figured this was a better version of my PR anyway, but I won't do q big change like this again without a comment and a ping first to check in. |
This comment has been minimized.
This comment has been minimized.
b37f793 to
5726ad0
Compare
|
This PR was rebased onto a different master commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
89fe311 to
f670b91
Compare
f670b91 to
f26808e
Compare
|
@rustbot ready |
View all comments
Objective
std_instead_of_coredoes not detect uses of non-fully qualified items #11159std_instead_of_corecreates an invalid fix on stacked imports #12468std_instead_of_core/etc. miss macros #17260Solution
This PR is a major rewrite of
std_instead_of_corewhich reduces allocations and hardens against possible changes to path segment resolution information, such as what is proposed in rust-lang/rust#159760. Instead of relying exclusively oncheck_pathto collect possible lint points, we primarily rely oncheck_itemforusestatements.check_pathis still used to catch instances such asstd::boxed::Box::new(123), but such cases will contain resolution information for the full path, as the path is not shared across multiple items.Lintcheck Interpretation
alloc_instead_of_corefmt::Resultwhen a crate doesuse std::fmt;. This is intended.std_instead_of_allocsync::{Arc, Mutex}and catching crate renames (extern crate std as alloc, etc.)std_instead_of_corehash::Hash.extern crate core as std, etc.)std::fmt::{self, Debug}(whileDebugis defined incore,std::fmt::selfisalloc::fmt, so this cannot be a merged suggestion.Please write a short comment explaining your change (or "none" for internal only changes)
changelog: [
std_instead_of_core], [std_instead_of_alloc], [alloc_instead_of_core]: fix false positive suggestions for multi-importschangelog: [
std_instead_of_core], [std_instead_of_alloc], [alloc_instead_of_core]: consider crate renameschangelog: [
std_instead_of_core], [std_instead_of_alloc], [alloc_instead_of_core]: include relative pathschangelog: [
std_instead_of_core], [std_instead_of_alloc], [alloc_instead_of_core]: include macros