new lint: `implied_bounds_in_impls`
Closes#10849
A new lint that looks for explicitly specified bounds that are already implied by other bounds in `impl Trait` return position types.
One example, as shown in the linked example, would be
```rs
fn foo<T>(x: T) -> impl Deref<Target = T> + DerefMut<Target = T> {
Box::new(x)
}
```
`DerefMut<Target = T>` requires `Deref<Target = T>` to be wellformed, so specifying `Deref` there is unnecessary.
This currently "ignores" (i.e., does not lint at all) transitive supertrait bounds (e.g. `trait A {} trait B: A {} trait C: B {}`, then having an `impl A + C` type), because that seems a bit more difficult and I think this isn't technically a blocker. It leads to FNs, but shouldn't bring any FPs
changelog: new lint [`implied_bounds_in_impls`]
Added new lint: `reserve_after_initialization`
Closes https://github.com/rust-lang/rust-clippy/issues/11330.
A new lint that informs the user about a more concise way to create a vector with a known capacity.
Example:
```rust
let mut v: Vec<usize> = vec![];
v.reserve(10);
```
Produces the following help:
```rust
|
2 | / let mut v: Vec<usize> = vec![];
3 | | v.reserve(10);
| |__________________^ help: consider using `Vec::with_capacity(space_hint)`: `let v: Vec<usize> = Vec::with_capacity(10);`
|
```
And can be rewritten as:
```rust
let v: Vec<usize> = Vec::with_capacity(10);
```
changelog: new lint [`reserve_after_initialization`]
Fix tuple_array_conversions lint on nightly
```
changelog: ICE: [`tuple_array_conversions`]: Don't expect array length to always be usize
```
tl;dr: changed [`Const::eval_target_usize`](https://github.com/rust-lang/rust/blob/master/compiler/rustc_middle/src/ty/consts.rs#L359) to [`Consts::try_eval_target_usize`](https://github.com/rust-lang/rust/blob/master/compiler/rustc_middle/src/ty/consts.rs#L327) to get rid of ICE.
I have encountered a problem with clippy: it caught ICE when working with a codebase that uses a lot of nightly features.
Here's a (stripped) ICE info:
```
error: internal compiler error: /rustc/5c6a7e71cd66705c31c9af94077901a220f0870c/compiler/rustc_middle/src/ty/consts.rs:361:32: expected usize, got Const { ty: usize, kind: N/#1 }
thread 'rustc' panicked at /rustc/5c6a7e71cd66705c31c9af94077901a220f0870c/compiler/rustc_errors/src/lib.rs:1635:9:
Box<dyn Any>
stack backtrace:
...
16: 0x110b9c590 - rustc_middle[449edf845976488d]::util:🐛:bug_fmt
17: 0x102f76ae0 - clippy_lints[71754038dd04c2d2]::tuple_array_conversions::all_bindings_are_for_conv
...
```
I don't really know what's going on low-level-wise, but seems like this lin assumed that the length of the array can always be treated as `usize`, and *I assume* this doesn't play well with `feat(generic_const_exprs)`.
I wasn't able to build a minimal reproducible example, but locally this fix does resolve the issue.
Add error annotations in UI tests
As discussed on [zulip](https://rust-lang.zulipchat.com/#narrow/stream/257328-clippy/topic/Improve.20UI.20error.20checks), this PR adds missing error annotations in UI tests.
I used this script to generate them:
<details>
```python
import os
def handle_err(line, stderr, elems, kind, i):
msg = line.split("{}: ".format(kind), 1)[1]
i += 1
try:
line_nb = int(stderr[i].split(":")[1])
except Exception:
return i
in_macro = False
note_found = False
help_found = False
elem = {"kind": kind, "msg": msg, "line": line_nb, "notes": [], "helps": []}
while i < len(stderr):
if len(stderr[i]) == 0:
break
elif stderr[i].startswith("note:"):
note_found = True # error checker doesn't like multi-note apparently.
elif stderr[i].startswith(" = note:"):
if not note_found and not help_found and "this error originates in the macro" not in stderr[i]:
elem["notes"].append(stderr[i].split(" = note:", 1)[1].strip())
note_found = True # error checker doesn't like multi-note apparently.
elif stderr[i].startswith(" = help:") or stderr[i].startswith("help:"):
help_found = True
# elif stderr[i].startswith("help:"):
# if not help_found:
# elem["helps"].append(stderr[i].split("help:", 1)[1].strip())
# help_found = True # error checker doesn't like multi-help apparently.
elif "in this macro invocation" in stderr[i]:
in_macro = True
i += 1
if not in_macro:
elems.append(elem)
return i
def show_kind(kind):
if kind == "error":
return "ERROR"
elif kind == "warning":
return "WARNING"
elif kind == "note":
return "NOTE"
return "HELP"
def generate_code_err(indent, elem, up):
content = "{}//~{} {}: {}".format(indent, up, show_kind(elem["kind"]), elem["msg"])
if up == "^":
up = "|"
for note in elem["notes"]:
content += "\n{}//~{} {}: {}".format(indent, up, show_kind("note"), note)
for help_msg in elem["helps"]:
content += "\n{}//~{} {}: {}".format(indent, up, show_kind("help"), help_msg)
return content, up
def update_content(p, content):
TO_IGNORE = [
"needless_bool/simple.rs", # https://github.com/rust-lang/rust-clippy/issues/11248
"crashes/ice-7868.rs", # Has errors but in another file.
"trivially_copy_pass_by_ref.rs", # the `N` in the stderr needs to be replaced by the number
"tests/ui/large_types_passed_by_value.rs", # the `N` in the stderr needs to be replaced by the number
]
for to_ignore in TO_IGNORE:
if p.endswith(to_ignore):
return
try:
with open(p.replace(".rs", ".stderr"), "r", encoding="utf8") as f:
stderr = f.read().split('\n')
except Exception:
return
print("Updating `{}`".format(p))
i = 0
elems = []
while i < len(stderr):
line = stderr[i]
if line.startswith("error: ") and not line.startswith("error: aborting due to"):
i = handle_err(line, stderr, elems, "error", i)
elif line.startswith("warning: ") and not line.endswith("warning emitted") and line.endswith("warnings emitted"):
i = handle_err(line, stderr, elems, "warning", i)
i += 1
elems.sort(key=lambda e: e["line"], reverse=True)
i = 0
while i < len(elems):
elem = elems[i]
indent = ""
c = 0
line = content[elem["line"] - 1]
while c < len(line) and line[c] == ' ':
indent += " "
c += 1
new_content, up = generate_code_err(indent, elem, "^")
i += 1
while i < len(elems) and elems[i]["line"] == elem["line"]:
elem = elems[i]
ret = generate_code_err(indent, elem, up)
new_content += "\n" + ret[0]
up = ret[1]
i += 1
content.insert(elem["line"], new_content)
with open(p, "w", encoding="utf8") as f:
f.write("\n".join(content))
def check_if_contains_ui_test(p):
if not p.endswith(".rs"):
return
with open(p, "r", encoding="utf8") as f:
x = f.read()
if "//~" not in x and "`@run-rustfix"` not in x and "`@aux-build"` not in x:
update_content(p, x.split("\n"))
for path, subdirs, files in os.walk("tests/ui"):
for name in files:
check_if_contains_ui_test(os.path.join(path, name))
```
</details>
Then ran `cargo uibless`.
changelog: none
[iter_overeager_cloned]: detect .cloned().map() and .cloned().for_each()
changelog: [`iter_overeager_cloned`]
key idea:
for `f` in `.map(f)` and `.for_each(f)`:
1. `f` must be closure
2. don't lint if mutable paramter in clsure `f`: `|mut x| ...`
3. don't lint if parameter is moved
4. maybe incorrect
key idea:
for `f` in `.map(f)` and `.for_each(f)`:
1. `f` must be a closure with one parameter
2. don't lint if mutable paramter in clsure `f`: `|mut x| ...`
3. don't lint if parameter is moved
[new_without_default]: include `where` clause in suggestions, make applicable
changelog: [`new_without_default`]: include `where` clause in suggestions
Correctly handle async blocks for NEEDLESS_PASS_BY_REF_MUT
Fixes https://github.com/rust-lang/rust-clippy/issues/11299.
The problem was that the `async block`s are popping a closure which we didn't go into, making it miss the mutable access to the variables.
cc `@Centri3`
changelog: none
[`useless_conversion`]: only lint on paths to fn items and fix FP in macro
Fixes#11065 (which is actually two issues: an ICE and a false positive)
It now makes sure that the function call path points to a function-like item (and not e.g. a `const` like in the linked issue), so that calling `TyCtxt::fn_sig` later in the lint does not ICE (fixes https://github.com/rust-lang/rust-clippy/issues/11065#issuecomment-1616836099).
It *also* makes sure that the expression is not part of a macro call (fixes https://github.com/rust-lang/rust-clippy/issues/11065#issuecomment-1616919639). ~~I'm not sure if there's a better way to check this other than to walk the parent expr chain and see if any of them are expansions.~~ (edit: it doesn't do this anymore)
changelog: [`useless_conversion`]: fix ICE when call receiver is a non-fn item
changelog: [`useless_conversion`]: don't lint if argument is a macro argument (fixes a FP)
r? `@llogiq` (reviewed #10814, which introduced these issues)