Repository: rust-lang/rust-clippy (Rust)

Issue:
False positive of `just_underscores_and_digits` when missing R_ANGLE when ending type prameters
### Summary

As it's said in the title, something like `Type<T` will trigger this bug.

### Lint Name

clippy::just_underscores_and_digits

### Reproducer

```rust
pub struct Aa<T>(PhantomData<T>);

fn aa(a: Aa<String) {

}
```

I saw this happen:

```
warning: consider choosing a more descriptive name
   --> rizlium_editor/src/extensions/editing/world_view/cam_response.rs:130:13
    |
130 | fn aa(a: Aa<String) {
    |             ^^^^^^
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#just_underscores_and_digits
    = note: `#[warn(clippy::just_underscores_and_digits)]` on by default
```

also, regular "Syntax error" did worked.


### Version

```text
rustc 1.75.0 (82e1608df 2023-12-21)
binary: rustc
commit-hash: 82e1608dfa6e0b5569232559e3d385fea5a93112
commit-date: 2023-12-21
host: x86_64-unknown-linux-gnu
release: 1.75.0
LLVM version: 17.0.6
```


### Additional Labels

_No response_


Discussion:
My best guess is that the parser tries to recover while giving the type parameters dummy values (probably using `DummyAstNode`). I don't really know if it's worth it to fix this



Patch:
diff --git a/clippy_dev/src/fmt.rs b/clippy_dev/src/fmt.rs
index 790dafa811f9..bdddf46a2cb1 100644
--- a/clippy_dev/src/fmt.rs
+++ b/clippy_dev/src/fmt.rs
@@ -290,8 +290,13 @@ fn run_rustfmt(context: &FmtContext) -> Result<(), Error> {
         .filter_map(|entry| {
             let entry = entry.expect("failed to find tests");
             let path = entry.path();
-
-            if path.extension() != Some("rs".as_ref()) || entry.file_name() == "ice-3891.rs" {
+            if path.extension() != Some("rs".as_ref())
+                || path
+                    .components()
+                    .nth_back(1)
+                    .is_some_and(|c| c.as_os_str() == "syntax-error-recovery")
+                || entry.file_name() == "ice-3891.rs"
+            {
                 None
             } else {
                 Some(entry.into_path().into_os_string())
diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs
index 1a3b43cbb10a..c5873589b26f 100644
--- a/clippy_lints/src/non_expressive_names.rs
+++ b/clippy_lints/src/non_expressive_names.rs
@@ -208,7 +208,8 @@ impl SimilarNamesNameVisitor<'_, '_, '_> {
 
     fn check_ident(&mut self, ident: Ident) {
         let interned_name = ident.name.as_str();
-        if interned_name.chars().any(char::is_uppercase) {
+        // name can be empty if it comes from recovery
+        if interned_name.chars().any(char::is_uppercase) || interned_name.is_empty() {
             return;
         }
         if interned_name.chars().all(|c| c.is_ascii_digit() || c == '_') {


Test patch:
diff --git a/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.fixed b/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.fixed
new file mode 100644
index 000000000000..5e5821a140de
--- /dev/null
+++ b/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.fixed
@@ -0,0 +1,8 @@
+// https://github.com/rust-lang/rust-clippy/issues/12302
+use std::marker::PhantomData;
+
+pub struct Aa<T>(PhantomData<T>);
+
+fn aa(a: Aa<String>) {
+
+}
diff --git a/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.rs b/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.rs
new file mode 100644
index 000000000000..d6e1da0e0898
--- /dev/null
+++ b/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.rs
@@ -0,0 +1,8 @@
+// https://github.com/rust-lang/rust-clippy/issues/12302
+use std::marker::PhantomData;
+
+pub struct Aa<T>(PhantomData<T>);
+
+fn aa(a: Aa<String) {
+
+}
diff --git a/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.stderr b/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.stderr
new file mode 100644
index 000000000000..e334ca5241eb
--- /dev/null
+++ b/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.stderr
@@ -0,0 +1,13 @@
+error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `)`
+  --> tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.rs:6:19
+   |
+LL | fn aa(a: Aa<String) {
+   |                   ^ expected one of 7 possible tokens
+   |
+help: you might have meant to end the type parameters here
+   |
+LL | fn aa(a: Aa<String>) {
+   |                   +
+
+error: aborting due to 1 previous error
+