Auto merge of #11696 - y21:iter_without_into_iter_suggestion, r=xFrednet
[`iter_without_into_iter`]: fix papercuts in suggestion and restrict linting to exported types See #11692 for more context. tldr: the lint `iter_without_into_iter` has suggestions that don't compile, which imo isn't that problematic because it does have the appropriate `Applicability` that tells external tools that it shouldn't be auto-applied. However there were some obvious "errors" in the suggestion that really should've been included in my initial PR adding the lint, which is fixed by this PR: - `IntoIterator::into_iter` needs a `self` argument. - `IntoIterator::Iter` associated type doesn't exist. This should've just been `Item`. This still doesn't make it machine applicable, and the remaining things are imho quite non-trivial to implement, as I've explained in https://github.com/rust-lang/rust-clippy/issues/11692#issuecomment-1773886111. I personally think it's fine to leave it there and let the user change the remaining errors when copy-pasting the suggestion (e.g. errors caused by lifetimes that were permitted in fn return-position but are not in associated types). This is how many of our other lint suggestions already work. Also, we now restrict linting to only exported types. This required moving basically all of the tests around since they were previously in the `main` function. Same for `into_iter_without_iter`. The git diff is a bit useless here... changelog: [`iter_without_into_iter`]: fix papercuts in suggestion and restrict linting to exported types (cc `@lopopolo,` figured I should mention you since you created the issue)
This commit is contained in:
commit
f8409ef85f
5 changed files with 370 additions and 355 deletions
|
|
@ -19,6 +19,11 @@ declare_clippy_lint! {
|
|||
/// It's not bad, but having them is idiomatic and allows the type to be used in for loops directly
|
||||
/// (`for val in &iter {}`), without having to first call `iter()` or `iter_mut()`.
|
||||
///
|
||||
/// ### Limitations
|
||||
/// This lint focuses on providing an idiomatic API. Therefore, it will only
|
||||
/// lint on types which are accessible outside of the crate. For internal types,
|
||||
/// the `IntoIterator` trait can be implemented on demand if it is actually needed.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```no_run
|
||||
/// struct MySlice<'a>(&'a [u8]);
|
||||
|
|
@ -61,6 +66,14 @@ declare_clippy_lint! {
|
|||
/// by just calling `.iter()`, instead of the more awkward `<&Type>::into_iter` or `(&val).into_iter()` syntax
|
||||
/// in case of ambiguity with another `IntoIterator` impl.
|
||||
///
|
||||
/// ### Limitations
|
||||
/// This lint focuses on providing an idiomatic API. Therefore, it will only
|
||||
/// lint on types which are accessible outside of the crate. For internal types,
|
||||
/// these methods can be added on demand if they are actually needed. Otherwise,
|
||||
/// it would trigger the [`dead_code`] lint for the unused method.
|
||||
///
|
||||
/// [`dead_code`]: https://doc.rust-lang.org/rustc/lints/listing/warn-by-default.html#dead-code
|
||||
///
|
||||
/// ### Example
|
||||
/// ```no_run
|
||||
/// struct MySlice<'a>(&'a [u8]);
|
||||
|
|
@ -104,6 +117,12 @@ fn is_nameable_in_impl_trait(ty: &rustc_hir::Ty<'_>) -> bool {
|
|||
!matches!(ty.kind, TyKind::OpaqueDef(..))
|
||||
}
|
||||
|
||||
fn is_ty_exported(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
|
||||
ty.ty_adt_def()
|
||||
.and_then(|adt| adt.did().as_local())
|
||||
.is_some_and(|did| cx.effective_visibilities.is_exported(did))
|
||||
}
|
||||
|
||||
/// Returns the deref chain of a type, starting with the type itself.
|
||||
fn deref_chain<'cx, 'tcx>(cx: &'cx LateContext<'tcx>, ty: Ty<'tcx>) -> impl Iterator<Item = Ty<'tcx>> + 'cx {
|
||||
iter::successors(Some(ty), |&ty| {
|
||||
|
|
@ -154,6 +173,7 @@ impl LateLintPass<'_> for IterWithoutIntoIter {
|
|||
None
|
||||
}
|
||||
})
|
||||
&& is_ty_exported(cx, ty)
|
||||
{
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
|
|
@ -226,6 +246,7 @@ impl {self_ty_without_ref} {{
|
|||
)
|
||||
// Only lint if the `IntoIterator` impl doesn't actually exist
|
||||
&& !implements_trait(cx, ref_ty, into_iter_did, &[])
|
||||
&& is_ty_exported(cx, ref_ty.peel_refs())
|
||||
{
|
||||
let self_ty_snippet = format!("{borrow_prefix}{}", snippet(cx, imp.self_ty.span, ".."));
|
||||
|
||||
|
|
@ -247,8 +268,8 @@ impl {self_ty_without_ref} {{
|
|||
"
|
||||
impl IntoIterator for {self_ty_snippet} {{
|
||||
type IntoIter = {ret_ty};
|
||||
type Iter = {iter_ty};
|
||||
fn into_iter() -> Self::IntoIter {{
|
||||
type Item = {iter_ty};
|
||||
fn into_iter(self) -> Self::IntoIter {{
|
||||
self.iter()
|
||||
}}
|
||||
}}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue