use clippy_utils::source::snippet;
use rustc_ast::{Item, Path, PathSegment, UseTree, UseTreeKind, VisibilityKind};
use rustc_lint::LateContext;
use rustc_span::{Ident, Symbol, kw};
pub(super) fn real_segments(path: &Path) -> &[PathSegment] {
match path.segments.as_slice() {
[first, rest @ ..] if first.ident.name == kw::PathRoot => rest,
all => all,
}
}
pub(super) fn has_path_root(path: &Path) -> bool {
matches!(path.segments.first(), Some(first) if first.ident.name == kw::PathRoot)
}
pub(super) fn segment_names(path: &Path) -> Vec<Symbol> {
real_segments(path)
.iter()
.map(|segment| segment.ident.name)
.collect()
}
pub(super) fn render_segments(segments: &[PathSegment]) -> String {
segments
.iter()
.map(|segment| segment.ident.to_string())
.collect::<Vec<_>>()
.join("::")
}
pub(super) fn render_rooted(path: &Path, segments: &[PathSegment]) -> String {
let body = render_segments(segments);
if has_path_root(path) {
format!("::{body}")
} else {
body
}
}
pub(super) fn render_prefix(path: &Path) -> String {
render_rooted(path, real_segments(path))
}
pub(super) fn with_rename(path: String, rename: Option<Ident>) -> String {
match rename {
Some(rename) => format!("{path} as {rename}"),
None => path,
}
}
pub(super) fn render_use_tree(tree: &UseTree) -> String {
let path = render_prefix(&tree.prefix);
match &tree.kind {
UseTreeKind::Simple(rename) => with_rename(path, *rename),
UseTreeKind::Glob(_) => {
if path.is_empty() {
"*".to_owned()
} else {
format!("{path}::*")
}
}
UseTreeKind::Nested { items, .. } => {
let inner = items
.iter()
.map(|(item, _)| render_use_tree(item))
.collect::<Vec<_>>()
.join(", ");
if path.is_empty() {
format!("{{{inner}}}")
} else {
format!("{path}::{{{inner}}}")
}
}
}
}
pub(super) fn is_self_leaf(tree: &UseTree) -> bool {
matches!(tree.kind, UseTreeKind::Simple(_))
&& matches!(segment_names(&tree.prefix).as_slice(), [name] if *name == kw::SelfLower)
}
pub(super) fn simple_self_module(tree: &UseTree) -> Option<Vec<Symbol>> {
if !matches!(tree.kind, UseTreeKind::Simple(_)) {
return None;
}
let names = segment_names(&tree.prefix);
match names.split_last() {
Some((last, rest)) if *last == kw::SelfLower => Some(rest.to_vec()),
_ => None,
}
}
pub(super) fn render_visibility(cx: &LateContext<'_>, item: &Item) -> String {
match item.vis.kind {
VisibilityKind::Inherited => String::new(),
_ => format!("{} ", snippet(cx, item.vis.span, "").trim()),
}
}
pub(super) fn attr_snippets(cx: &LateContext<'_>, item: &Item) -> Vec<String> {
item.attrs
.iter()
.map(|attr| snippet(cx, attr.span, "").trim().to_string())
.collect()
}