Improve path segment joining.

There are many places that join path segments with `::` to produce a
string. A lot of these use `join("::")`. Many in rustdoc use
`join_with_double_colon`, and a few use `.joined("..")`. One in Clippy
uses `itertools::join`. A couple of them look for `kw::PathRoot` in the
first segment, which can be important.

This commit introduces `rustc_ast::join_path_{syms,ident}` to do the
joining for everyone. `rustc_ast` is as good a location for these as
any, being the earliest-running of the several crates with a `Path`
type. Two functions are needed because `Ident` printing is more complex
than simple `Symbol` printing.

The commit also removes `join_with_double_colon`, and
`estimate_item_path_byte_length` with it.

There are still a handful of places that join strings with "::" that are
unchanged. They are not that important: some of them are in tests, and
some of them first split a path around "::" and then rejoin with "::".

This fixes one test case where `{{root}}` shows up in an error message.
This commit is contained in:
Nicholas Nethercote 2025-05-27 15:51:47 +10:00
parent f4b827abeb
commit b7caf7593e
2 changed files with 11 additions and 9 deletions

View file

@ -4,6 +4,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::implements_trait;
use clippy_utils::{is_path_diagnostic_item, sugg};
use rustc_ast::join_path_idents;
use rustc_errors::Applicability;
use rustc_hir::def::Res;
use rustc_hir::{self as hir, Expr, ExprKind, GenericArg, QPath, TyKind};
@ -47,7 +48,7 @@ fn build_full_type(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, app: &mut Applica
&& let QPath::Resolved(None, ty_path) = &ty_qpath
&& let Res::Def(_, ty_did) = ty_path.res
{
let mut ty_str = itertools::join(ty_path.segments.iter().map(|s| s.ident), "::");
let mut ty_str = join_path_idents(ty_path.segments.iter().map(|seg| seg.ident));
let mut first = true;
let mut append = |arg: &str| {
write!(&mut ty_str, "{}{arg}", [", ", "<"][usize::from(first)]).unwrap();

View file

@ -89,6 +89,7 @@ use std::sync::{Mutex, MutexGuard, OnceLock};
use itertools::Itertools;
use rustc_abi::Integer;
use rustc_ast::join_path_syms;
use rustc_ast::ast::{self, LitKind, RangeLimits};
use rustc_attr_data_structures::{AttributeKind, find_attr};
use rustc_data_structures::fx::FxHashMap;
@ -3245,8 +3246,8 @@ fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> St
// a::b::c ::d::sym refers to
// e::f::sym:: ::
// result should be super::super::super::super::e::f
if let DefPathData::TypeNs(s) = l {
path.push(s.to_string());
if let DefPathData::TypeNs(sym) = l {
path.push(sym);
}
if let DefPathData::TypeNs(_) = r {
go_up_by += 1;
@ -3256,7 +3257,7 @@ fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> St
// a::b::sym:: :: refers to
// c::d::e ::f::sym
// when looking at `f`
Left(DefPathData::TypeNs(sym)) => path.push(sym.to_string()),
Left(DefPathData::TypeNs(sym)) => path.push(sym),
// consider:
// a::b::c ::d::sym refers to
// e::f::sym:: ::
@ -3268,17 +3269,17 @@ fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> St
if go_up_by > max_super {
// `super` chain would be too long, just use the absolute path instead
once(String::from("crate"))
.chain(to.data.iter().filter_map(|el| {
join_path_syms(
once(kw::Crate).chain(to.data.iter().filter_map(|el| {
if let DefPathData::TypeNs(sym) = el.data {
Some(sym.to_string())
Some(sym)
} else {
None
}
}))
.join("::")
)
} else {
repeat_n(String::from("super"), go_up_by).chain(path).join("::")
join_path_syms(repeat_n(kw::Super, go_up_by).chain(path))
}
}