diff --git a/src/tools/clippy/clippy_lints/src/attrs/mixed_attributes_style.rs b/src/tools/clippy/clippy_lints/src/attrs/mixed_attributes_style.rs
index c2e21cfd33006..5d2ea36b366c1 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/mixed_attributes_style.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/mixed_attributes_style.rs
@@ -1,30 +1,85 @@
 use super::MIXED_ATTRIBUTES_STYLE;
 use clippy_utils::diagnostics::span_lint;
-use rustc_ast::AttrStyle;
-use rustc_lint::EarlyContext;
+use rustc_ast::{AttrKind, AttrStyle, Attribute};
+use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::sync::Lrc;
+use rustc_lint::{LateContext, LintContext};
+use rustc_span::source_map::SourceMap;
+use rustc_span::{SourceFile, Span, Symbol};
 
-pub(super) fn check(cx: &EarlyContext<'_>, item: &rustc_ast::Item) {
-    let mut has_outer = false;
-    let mut has_inner = false;
+#[derive(Hash, PartialEq, Eq)]
+enum SimpleAttrKind {
+    Doc,
+    /// A normal attribute, with its name symbols.
+    Normal(Vec<Symbol>),
+}
+
+impl From<&AttrKind> for SimpleAttrKind {
+    fn from(value: &AttrKind) -> Self {
+        match value {
+            AttrKind::Normal(attr) => {
+                let path_symbols = attr
+                    .item
+                    .path
+                    .segments
+                    .iter()
+                    .map(|seg| seg.ident.name)
+                    .collect::<Vec<_>>();
+                Self::Normal(path_symbols)
+            },
+            AttrKind::DocComment(..) => Self::Doc,
+        }
+    }
+}
+
+pub(super) fn check(cx: &LateContext<'_>, item_span: Span, attrs: &[Attribute]) {
+    let mut inner_attr_kind: FxHashSet<SimpleAttrKind> = FxHashSet::default();
+    let mut outer_attr_kind: FxHashSet<SimpleAttrKind> = FxHashSet::default();
+
+    let source_map = cx.sess().source_map();
+    let item_src = source_map.lookup_source_file(item_span.lo());
 
-    for attr in &item.attrs {
-        if attr.span.from_expansion() {
+    for attr in attrs {
+        if attr.span.from_expansion() || !attr_in_same_src_as_item(source_map, &item_src, attr.span) {
             continue;
         }
+
+        let kind: SimpleAttrKind = (&attr.kind).into();
         match attr.style {
-            AttrStyle::Inner => has_inner = true,
-            AttrStyle::Outer => has_outer = true,
-        }
+            AttrStyle::Inner => {
+                if outer_attr_kind.contains(&kind) {
+                    lint_mixed_attrs(cx, attrs);
+                    return;
+                }
+                inner_attr_kind.insert(kind);
+            },
+            AttrStyle::Outer => {
+                if inner_attr_kind.contains(&kind) {
+                    lint_mixed_attrs(cx, attrs);
+                    return;
+                }
+                outer_attr_kind.insert(kind);
+            },
+        };
     }
-    if !has_outer || !has_inner {
+}
+
+fn lint_mixed_attrs(cx: &LateContext<'_>, attrs: &[Attribute]) {
+    let mut attrs_iter = attrs.iter().filter(|attr| !attr.span.from_expansion());
+    let span = if let (Some(first), Some(last)) = (attrs_iter.next(), attrs_iter.last()) {
+        first.span.with_hi(last.span.hi())
+    } else {
         return;
-    }
-    let mut attrs_iter = item.attrs.iter().filter(|attr| !attr.span.from_expansion());
-    let span = attrs_iter.next().unwrap().span;
+    };
     span_lint(
         cx,
         MIXED_ATTRIBUTES_STYLE,
-        span.with_hi(attrs_iter.last().unwrap().span.hi()),
+        span,
         "item has both inner and outer attributes",
     );
 }
+
+fn attr_in_same_src_as_item(source_map: &SourceMap, item_src: &Lrc<SourceFile>, attr_span: Span) -> bool {
+    let attr_src = source_map.lookup_source_file(attr_span.lo());
+    Lrc::ptr_eq(item_src, &attr_src)
+}
diff --git a/src/tools/clippy/clippy_lints/src/attrs/mod.rs b/src/tools/clippy/clippy_lints/src/attrs/mod.rs
index c4c65d3248a7d..551a236c16ed3 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/mod.rs
@@ -464,10 +464,20 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks that an item has only one kind of attributes.
+    /// Checks for items that have the same kind of attributes with mixed styles (inner/outer).
     ///
     /// ### Why is this bad?
-    /// Having both kinds of attributes makes it more complicated to read code.
+    /// Having both style of said attributes makes it more complicated to read code.
+    ///
+    /// ### Known problems
+    /// This lint currently has false-negatives when mixing same attributes
+    /// but they have different path symbols, for example:
+    /// ```ignore
+    /// #[custom_attribute]
+    /// pub fn foo() {
+    ///     #![my_crate::custom_attribute]
+    /// }
+    /// ```
     ///
     /// ### Example
     /// ```no_run
@@ -485,7 +495,7 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "1.78.0"]
     pub MIXED_ATTRIBUTES_STYLE,
-    suspicious,
+    style,
     "item has both inner and outer attributes"
 }
 
@@ -496,6 +506,7 @@ declare_lint_pass!(Attributes => [
     USELESS_ATTRIBUTE,
     BLANKET_CLIPPY_RESTRICTION_LINTS,
     SHOULD_PANIC_WITHOUT_EXPECT,
+    MIXED_ATTRIBUTES_STYLE,
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for Attributes {
@@ -539,6 +550,7 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
             ItemKind::ExternCrate(..) | ItemKind::Use(..) => useless_attribute::check(cx, item, attrs),
             _ => {},
         }
+        mixed_attributes_style::check(cx, item.span, attrs);
     }
 
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
@@ -567,13 +579,11 @@ impl_lint_pass!(EarlyAttributes => [
     MAYBE_MISUSED_CFG,
     DEPRECATED_CLIPPY_CFG_ATTR,
     UNNECESSARY_CLIPPY_CFG,
-    MIXED_ATTRIBUTES_STYLE,
 ]);
 
 impl EarlyLintPass for EarlyAttributes {
     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &rustc_ast::Item) {
         empty_line_after::check(cx, item);
-        mixed_attributes_style::check(cx, item);
     }
 
     fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) {
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
index 8fd95d9654cf0..907861755621a 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
@@ -118,7 +118,7 @@ enum Sign {
     Uncertain,
 }
 
-fn expr_sign<'cx>(cx: &LateContext<'cx>, expr: &Expr<'_>, ty: impl Into<Option<Ty<'cx>>>) -> Sign {
+fn expr_sign<'cx, 'tcx>(cx: &LateContext<'cx>, mut expr: &'tcx Expr<'tcx>, ty: impl Into<Option<Ty<'cx>>>) -> Sign {
     // Try evaluate this expr first to see if it's positive
     if let Some(val) = get_const_signed_int_eval(cx, expr, ty) {
         return if val >= 0 { Sign::ZeroOrPositive } else { Sign::Negative };
@@ -134,11 +134,12 @@ fn expr_sign<'cx>(cx: &LateContext<'cx>, expr: &Expr<'_>, ty: impl Into<Option<T
         // Peel unwrap(), expect(), etc.
         while let Some(&found_name) = METHODS_UNWRAP.iter().find(|&name| &method_name == name)
             && let Some(arglist) = method_chain_args(expr, &[found_name])
-            && let ExprKind::MethodCall(inner_path, ..) = &arglist[0].0.kind
+            && let ExprKind::MethodCall(inner_path, recv, ..) = &arglist[0].0.kind
         {
             // The original type has changed, but we can't use `ty` here anyway, because it has been
             // moved.
             method_name = inner_path.ident.name.as_str();
+            expr = recv;
         }
 
         if METHODS_POW.iter().any(|&name| method_name == name)
diff --git a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
index 35e36e9ef3f5f..16de93136854d 100644
--- a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
@@ -62,8 +62,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) {
         // we omit following `cast`:
         let omit_cast = if let ExprKind::Call(func, []) = cast_expr.kind
             && let ExprKind::Path(ref qpath @ QPath::Resolved(None, path)) = func.kind
+            && let Some(method_defid) = path.res.opt_def_id()
         {
-            let method_defid = path.res.def_id();
             if cx.tcx.is_diagnostic_item(sym::ptr_null, method_defid) {
                 OmitFollowedCastReason::Null(qpath)
             } else if cx.tcx.is_diagnostic_item(sym::ptr_null_mut, method_defid) {
diff --git a/src/tools/clippy/tests/ui/cast.rs b/src/tools/clippy/tests/ui/cast.rs
index a7331ddc7d0e7..ce76ad3d3ad12 100644
--- a/src/tools/clippy/tests/ui/cast.rs
+++ b/src/tools/clippy/tests/ui/cast.rs
@@ -9,7 +9,12 @@
     clippy::cast_sign_loss,
     clippy::cast_possible_wrap
 )]
-#![allow(clippy::cast_abs_to_unsigned, clippy::no_effect, clippy::unnecessary_operation)]
+#![allow(
+    clippy::cast_abs_to_unsigned,
+    clippy::no_effect,
+    clippy::unnecessary_operation,
+    clippy::unnecessary_literal_unwrap
+)]
 
 fn main() {
     // Test clippy::cast_precision_loss
@@ -457,3 +462,8 @@ fn issue11642() {
         //~^ ERROR: casting `i32` to `u32` may lose the sign of the value
     }
 }
+
+fn issue12506() -> usize {
+    let bar: Result<Option<i64>, u32> = Ok(Some(10));
+    bar.unwrap().unwrap() as usize
+}
diff --git a/src/tools/clippy/tests/ui/cast.stderr b/src/tools/clippy/tests/ui/cast.stderr
index dd5d339b81b2a..3736e8aee0af1 100644
--- a/src/tools/clippy/tests/ui/cast.stderr
+++ b/src/tools/clippy/tests/ui/cast.stderr
@@ -1,5 +1,5 @@
 error: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide)
-  --> tests/ui/cast.rs:17:5
+  --> tests/ui/cast.rs:22:5
    |
 LL |     x0 as f32;
    |     ^^^^^^^^^
@@ -8,37 +8,37 @@ LL |     x0 as f32;
    = help: to override `-D warnings` add `#[allow(clippy::cast_precision_loss)]`
 
 error: casting `i64` to `f32` causes a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide)
-  --> tests/ui/cast.rs:21:5
+  --> tests/ui/cast.rs:26:5
    |
 LL |     x1 as f32;
    |     ^^^^^^^^^
 
 error: casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
-  --> tests/ui/cast.rs:23:5
+  --> tests/ui/cast.rs:28:5
    |
 LL |     x1 as f64;
    |     ^^^^^^^^^
 
 error: casting `u32` to `f32` causes a loss of precision (`u32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide)
-  --> tests/ui/cast.rs:26:5
+  --> tests/ui/cast.rs:31:5
    |
 LL |     x2 as f32;
    |     ^^^^^^^^^
 
 error: casting `u64` to `f32` causes a loss of precision (`u64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide)
-  --> tests/ui/cast.rs:29:5
+  --> tests/ui/cast.rs:34:5
    |
 LL |     x3 as f32;
    |     ^^^^^^^^^
 
 error: casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
-  --> tests/ui/cast.rs:31:5
+  --> tests/ui/cast.rs:36:5
    |
 LL |     x3 as f64;
    |     ^^^^^^^^^
 
 error: casting `f32` to `i32` may truncate the value
-  --> tests/ui/cast.rs:34:5
+  --> tests/ui/cast.rs:39:5
    |
 LL |     1f32 as i32;
    |     ^^^^^^^^^^^
@@ -48,7 +48,7 @@ LL |     1f32 as i32;
    = help: to override `-D warnings` add `#[allow(clippy::cast_possible_truncation)]`
 
 error: casting `f32` to `u32` may truncate the value
-  --> tests/ui/cast.rs:36:5
+  --> tests/ui/cast.rs:41:5
    |
 LL |     1f32 as u32;
    |     ^^^^^^^^^^^
@@ -56,7 +56,7 @@ LL |     1f32 as u32;
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:36:5
+  --> tests/ui/cast.rs:41:5
    |
 LL |     1f32 as u32;
    |     ^^^^^^^^^^^
@@ -65,7 +65,7 @@ LL |     1f32 as u32;
    = help: to override `-D warnings` add `#[allow(clippy::cast_sign_loss)]`
 
 error: casting `f64` to `f32` may truncate the value
-  --> tests/ui/cast.rs:40:5
+  --> tests/ui/cast.rs:45:5
    |
 LL |     1f64 as f32;
    |     ^^^^^^^^^^^
@@ -73,7 +73,7 @@ LL |     1f64 as f32;
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `i32` to `i8` may truncate the value
-  --> tests/ui/cast.rs:42:5
+  --> tests/ui/cast.rs:47:5
    |
 LL |     1i32 as i8;
    |     ^^^^^^^^^^
@@ -85,7 +85,7 @@ LL |     i8::try_from(1i32);
    |     ~~~~~~~~~~~~~~~~~~
 
 error: casting `i32` to `u8` may truncate the value
-  --> tests/ui/cast.rs:44:5
+  --> tests/ui/cast.rs:49:5
    |
 LL |     1i32 as u8;
    |     ^^^^^^^^^^
@@ -97,7 +97,7 @@ LL |     u8::try_from(1i32);
    |     ~~~~~~~~~~~~~~~~~~
 
 error: casting `f64` to `isize` may truncate the value
-  --> tests/ui/cast.rs:46:5
+  --> tests/ui/cast.rs:51:5
    |
 LL |     1f64 as isize;
    |     ^^^^^^^^^^^^^
@@ -105,7 +105,7 @@ LL |     1f64 as isize;
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f64` to `usize` may truncate the value
-  --> tests/ui/cast.rs:48:5
+  --> tests/ui/cast.rs:53:5
    |
 LL |     1f64 as usize;
    |     ^^^^^^^^^^^^^
@@ -113,13 +113,13 @@ LL |     1f64 as usize;
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f64` to `usize` may lose the sign of the value
-  --> tests/ui/cast.rs:48:5
+  --> tests/ui/cast.rs:53:5
    |
 LL |     1f64 as usize;
    |     ^^^^^^^^^^^^^
 
 error: casting `u32` to `u16` may truncate the value
-  --> tests/ui/cast.rs:51:5
+  --> tests/ui/cast.rs:56:5
    |
 LL |     1f32 as u32 as u16;
    |     ^^^^^^^^^^^^^^^^^^
@@ -131,7 +131,7 @@ LL |     u16::try_from(1f32 as u32);
    |     ~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `f32` to `u32` may truncate the value
-  --> tests/ui/cast.rs:51:5
+  --> tests/ui/cast.rs:56:5
    |
 LL |     1f32 as u32 as u16;
    |     ^^^^^^^^^^^
@@ -139,13 +139,13 @@ LL |     1f32 as u32 as u16;
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:51:5
+  --> tests/ui/cast.rs:56:5
    |
 LL |     1f32 as u32 as u16;
    |     ^^^^^^^^^^^
 
 error: casting `i32` to `i8` may truncate the value
-  --> tests/ui/cast.rs:56:22
+  --> tests/ui/cast.rs:61:22
    |
 LL |         let _x: i8 = 1i32 as _;
    |                      ^^^^^^^^^
@@ -157,7 +157,7 @@ LL |         let _x: i8 = 1i32.try_into();
    |                      ~~~~~~~~~~~~~~~
 
 error: casting `f32` to `i32` may truncate the value
-  --> tests/ui/cast.rs:58:9
+  --> tests/ui/cast.rs:63:9
    |
 LL |         1f32 as i32;
    |         ^^^^^^^^^^^
@@ -165,7 +165,7 @@ LL |         1f32 as i32;
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f64` to `i32` may truncate the value
-  --> tests/ui/cast.rs:60:9
+  --> tests/ui/cast.rs:65:9
    |
 LL |         1f64 as i32;
    |         ^^^^^^^^^^^
@@ -173,7 +173,7 @@ LL |         1f64 as i32;
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f32` to `u8` may truncate the value
-  --> tests/ui/cast.rs:62:9
+  --> tests/ui/cast.rs:67:9
    |
 LL |         1f32 as u8;
    |         ^^^^^^^^^^
@@ -181,13 +181,13 @@ LL |         1f32 as u8;
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f32` to `u8` may lose the sign of the value
-  --> tests/ui/cast.rs:62:9
+  --> tests/ui/cast.rs:67:9
    |
 LL |         1f32 as u8;
    |         ^^^^^^^^^^
 
 error: casting `u8` to `i8` may wrap around the value
-  --> tests/ui/cast.rs:67:5
+  --> tests/ui/cast.rs:72:5
    |
 LL |     1u8 as i8;
    |     ^^^^^^^^^
@@ -196,31 +196,31 @@ LL |     1u8 as i8;
    = help: to override `-D warnings` add `#[allow(clippy::cast_possible_wrap)]`
 
 error: casting `u16` to `i16` may wrap around the value
-  --> tests/ui/cast.rs:70:5
+  --> tests/ui/cast.rs:75:5
    |
 LL |     1u16 as i16;
    |     ^^^^^^^^^^^
 
 error: casting `u32` to `i32` may wrap around the value
-  --> tests/ui/cast.rs:72:5
+  --> tests/ui/cast.rs:77:5
    |
 LL |     1u32 as i32;
    |     ^^^^^^^^^^^
 
 error: casting `u64` to `i64` may wrap around the value
-  --> tests/ui/cast.rs:74:5
+  --> tests/ui/cast.rs:79:5
    |
 LL |     1u64 as i64;
    |     ^^^^^^^^^^^
 
 error: casting `usize` to `isize` may wrap around the value
-  --> tests/ui/cast.rs:76:5
+  --> tests/ui/cast.rs:81:5
    |
 LL |     1usize as isize;
    |     ^^^^^^^^^^^^^^^
 
 error: casting `usize` to `i8` may truncate the value
-  --> tests/ui/cast.rs:79:5
+  --> tests/ui/cast.rs:84:5
    |
 LL |     1usize as i8;
    |     ^^^^^^^^^^^^
@@ -232,7 +232,7 @@ LL |     i8::try_from(1usize);
    |     ~~~~~~~~~~~~~~~~~~~~
 
 error: casting `usize` to `i16` may truncate the value
-  --> tests/ui/cast.rs:82:5
+  --> tests/ui/cast.rs:87:5
    |
 LL |     1usize as i16;
    |     ^^^^^^^^^^^^^
@@ -244,7 +244,7 @@ LL |     i16::try_from(1usize);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `usize` to `i16` may wrap around the value on targets with 16-bit wide pointers
-  --> tests/ui/cast.rs:82:5
+  --> tests/ui/cast.rs:87:5
    |
 LL |     1usize as i16;
    |     ^^^^^^^^^^^^^
@@ -253,7 +253,7 @@ LL |     1usize as i16;
    = note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types
 
 error: casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers
-  --> tests/ui/cast.rs:87:5
+  --> tests/ui/cast.rs:92:5
    |
 LL |     1usize as i32;
    |     ^^^^^^^^^^^^^
@@ -265,19 +265,19 @@ LL |     i32::try_from(1usize);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `usize` to `i32` may wrap around the value on targets with 32-bit wide pointers
-  --> tests/ui/cast.rs:87:5
+  --> tests/ui/cast.rs:92:5
    |
 LL |     1usize as i32;
    |     ^^^^^^^^^^^^^
 
 error: casting `usize` to `i64` may wrap around the value on targets with 64-bit wide pointers
-  --> tests/ui/cast.rs:91:5
+  --> tests/ui/cast.rs:96:5
    |
 LL |     1usize as i64;
    |     ^^^^^^^^^^^^^
 
 error: casting `u16` to `isize` may wrap around the value on targets with 16-bit wide pointers
-  --> tests/ui/cast.rs:96:5
+  --> tests/ui/cast.rs:101:5
    |
 LL |     1u16 as isize;
    |     ^^^^^^^^^^^^^
@@ -286,13 +286,13 @@ LL |     1u16 as isize;
    = note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types
 
 error: casting `u32` to `isize` may wrap around the value on targets with 32-bit wide pointers
-  --> tests/ui/cast.rs:100:5
+  --> tests/ui/cast.rs:105:5
    |
 LL |     1u32 as isize;
    |     ^^^^^^^^^^^^^
 
 error: casting `u64` to `isize` may truncate the value on targets with 32-bit wide pointers
-  --> tests/ui/cast.rs:103:5
+  --> tests/ui/cast.rs:108:5
    |
 LL |     1u64 as isize;
    |     ^^^^^^^^^^^^^
@@ -304,55 +304,55 @@ LL |     isize::try_from(1u64);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `u64` to `isize` may wrap around the value on targets with 64-bit wide pointers
-  --> tests/ui/cast.rs:103:5
+  --> tests/ui/cast.rs:108:5
    |
 LL |     1u64 as isize;
    |     ^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:108:5
+  --> tests/ui/cast.rs:113:5
    |
 LL |     -1i32 as u32;
    |     ^^^^^^^^^^^^
 
 error: casting `isize` to `usize` may lose the sign of the value
-  --> tests/ui/cast.rs:111:5
+  --> tests/ui/cast.rs:116:5
    |
 LL |     -1isize as usize;
    |     ^^^^^^^^^^^^^^^^
 
 error: casting `i8` to `u8` may lose the sign of the value
-  --> tests/ui/cast.rs:122:5
+  --> tests/ui/cast.rs:127:5
    |
 LL |     (i8::MIN).abs() as u8;
    |     ^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i64` to `u64` may lose the sign of the value
-  --> tests/ui/cast.rs:126:5
+  --> tests/ui/cast.rs:131:5
    |
 LL |     (-1i64).abs() as u64;
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: casting `isize` to `usize` may lose the sign of the value
-  --> tests/ui/cast.rs:127:5
+  --> tests/ui/cast.rs:132:5
    |
 LL |     (-1isize).abs() as usize;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i64` to `u64` may lose the sign of the value
-  --> tests/ui/cast.rs:134:5
+  --> tests/ui/cast.rs:139:5
    |
 LL |     (unsafe { (-1i64).checked_abs().unwrap_unchecked() }) as u64;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i64` to `u64` may lose the sign of the value
-  --> tests/ui/cast.rs:149:5
+  --> tests/ui/cast.rs:154:5
    |
 LL |     (unsafe { (-1i64).checked_isqrt().unwrap_unchecked() }) as u64;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i64` to `i8` may truncate the value
-  --> tests/ui/cast.rs:200:5
+  --> tests/ui/cast.rs:205:5
    |
 LL |     (-99999999999i64).min(1) as i8;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -364,7 +364,7 @@ LL |     i8::try_from((-99999999999i64).min(1));
    |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `u64` to `u8` may truncate the value
-  --> tests/ui/cast.rs:214:5
+  --> tests/ui/cast.rs:219:5
    |
 LL |     999999u64.clamp(0, 256) as u8;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -376,7 +376,7 @@ LL |     u8::try_from(999999u64.clamp(0, 256));
    |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `main::E2` to `u8` may truncate the value
-  --> tests/ui/cast.rs:237:21
+  --> tests/ui/cast.rs:242:21
    |
 LL |             let _ = self as u8;
    |                     ^^^^^^^^^^
@@ -388,7 +388,7 @@ LL |             let _ = u8::try_from(self);
    |                     ~~~~~~~~~~~~~~~~~~
 
 error: casting `main::E2::B` to `u8` will truncate the value
-  --> tests/ui/cast.rs:239:21
+  --> tests/ui/cast.rs:244:21
    |
 LL |             let _ = Self::B as u8;
    |                     ^^^^^^^^^^^^^
@@ -397,7 +397,7 @@ LL |             let _ = Self::B as u8;
    = help: to override `-D warnings` add `#[allow(clippy::cast_enum_truncation)]`
 
 error: casting `main::E5` to `i8` may truncate the value
-  --> tests/ui/cast.rs:281:21
+  --> tests/ui/cast.rs:286:21
    |
 LL |             let _ = self as i8;
    |                     ^^^^^^^^^^
@@ -409,13 +409,13 @@ LL |             let _ = i8::try_from(self);
    |                     ~~~~~~~~~~~~~~~~~~
 
 error: casting `main::E5::A` to `i8` will truncate the value
-  --> tests/ui/cast.rs:283:21
+  --> tests/ui/cast.rs:288:21
    |
 LL |             let _ = Self::A as i8;
    |                     ^^^^^^^^^^^^^
 
 error: casting `main::E6` to `i16` may truncate the value
-  --> tests/ui/cast.rs:300:21
+  --> tests/ui/cast.rs:305:21
    |
 LL |             let _ = self as i16;
    |                     ^^^^^^^^^^^
@@ -427,7 +427,7 @@ LL |             let _ = i16::try_from(self);
    |                     ~~~~~~~~~~~~~~~~~~~
 
 error: casting `main::E7` to `usize` may truncate the value on targets with 32-bit wide pointers
-  --> tests/ui/cast.rs:319:21
+  --> tests/ui/cast.rs:324:21
    |
 LL |             let _ = self as usize;
    |                     ^^^^^^^^^^^^^
@@ -439,7 +439,7 @@ LL |             let _ = usize::try_from(self);
    |                     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `main::E10` to `u16` may truncate the value
-  --> tests/ui/cast.rs:366:21
+  --> tests/ui/cast.rs:371:21
    |
 LL |             let _ = self as u16;
    |                     ^^^^^^^^^^^
@@ -451,7 +451,7 @@ LL |             let _ = u16::try_from(self);
    |                     ~~~~~~~~~~~~~~~~~~~
 
 error: casting `u32` to `u8` may truncate the value
-  --> tests/ui/cast.rs:377:13
+  --> tests/ui/cast.rs:382:13
    |
 LL |     let c = (q >> 16) as u8;
    |             ^^^^^^^^^^^^^^^
@@ -463,7 +463,7 @@ LL |     let c = u8::try_from(q >> 16);
    |             ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `u32` to `u8` may truncate the value
-  --> tests/ui/cast.rs:381:13
+  --> tests/ui/cast.rs:386:13
    |
 LL |     let c = (q / 1000) as u8;
    |             ^^^^^^^^^^^^^^^^
@@ -475,85 +475,85 @@ LL |     let c = u8::try_from(q / 1000);
    |             ~~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:393:9
+  --> tests/ui/cast.rs:398:9
    |
 LL |         (x * x) as u32;
    |         ^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:398:32
+  --> tests/ui/cast.rs:403:32
    |
 LL |     let _a = |x: i32| -> u32 { (x * x * x * x) as u32 };
    |                                ^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:400:5
+  --> tests/ui/cast.rs:405:5
    |
 LL |     (2_i32).checked_pow(3).unwrap() as u32;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:401:5
+  --> tests/ui/cast.rs:406:5
    |
 LL |     (-2_i32).pow(3) as u32;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:406:5
+  --> tests/ui/cast.rs:411:5
    |
 LL |     (-5_i32 % 2) as u32;
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:408:5
+  --> tests/ui/cast.rs:413:5
    |
 LL |     (-5_i32 % -2) as u32;
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:411:5
+  --> tests/ui/cast.rs:416:5
    |
 LL |     (-2_i32 >> 1) as u32;
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:415:5
+  --> tests/ui/cast.rs:420:5
    |
 LL |     (x * x) as u32;
    |     ^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:416:5
+  --> tests/ui/cast.rs:421:5
    |
 LL |     (x * x * x) as u32;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:420:5
+  --> tests/ui/cast.rs:425:5
    |
 LL |     (y * y * y * y * -2) as u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:422:5
+  --> tests/ui/cast.rs:427:5
    |
 LL |     (y * y * y / y * 2) as u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:423:5
+  --> tests/ui/cast.rs:428:5
    |
 LL |     (y * y / y * 2) as u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:425:5
+  --> tests/ui/cast.rs:430:5
    |
 LL |     (y / y * y * -2) as u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: equal expressions as operands to `/`
-  --> tests/ui/cast.rs:425:6
+  --> tests/ui/cast.rs:430:6
    |
 LL |     (y / y * y * -2) as u16;
    |      ^^^^^
@@ -561,94 +561,112 @@ LL |     (y / y * y * -2) as u16;
    = note: `#[deny(clippy::eq_op)]` on by default
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:428:5
+  --> tests/ui/cast.rs:433:5
    |
 LL |     (y + y + y + -2) as u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:430:5
+  --> tests/ui/cast.rs:435:5
    |
 LL |     (y + y + y + 2) as u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:434:5
+  --> tests/ui/cast.rs:439:5
    |
 LL |     (z + -2) as u16;
    |     ^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:436:5
+  --> tests/ui/cast.rs:441:5
    |
 LL |     (z + z + 2) as u16;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:439:9
+  --> tests/ui/cast.rs:444:9
    |
 LL |         (a * a * b * b * c * c) as u32;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:440:9
+  --> tests/ui/cast.rs:445:9
    |
 LL |         (a * b * c) as u32;
    |         ^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:442:9
+  --> tests/ui/cast.rs:447:9
    |
 LL |         (a * -b * c) as u32;
    |         ^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:444:9
+  --> tests/ui/cast.rs:449:9
    |
 LL |         (a * b * c * c) as u32;
    |         ^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:445:9
+  --> tests/ui/cast.rs:450:9
    |
 LL |         (a * -2) as u32;
    |         ^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:447:9
+  --> tests/ui/cast.rs:452:9
    |
 LL |         (a * b * c * -2) as u32;
    |         ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:449:9
+  --> tests/ui/cast.rs:454:9
    |
 LL |         (a / b) as u32;
    |         ^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:450:9
+  --> tests/ui/cast.rs:455:9
    |
 LL |         (a / b * c) as u32;
    |         ^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:452:9
+  --> tests/ui/cast.rs:457:9
    |
 LL |         (a / b + b * c) as u32;
    |         ^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:454:9
+  --> tests/ui/cast.rs:459:9
    |
 LL |         a.saturating_pow(3) as u32;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:456:9
+  --> tests/ui/cast.rs:461:9
    |
 LL |         (a.abs() * b.pow(2) / c.abs()) as u32
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 85 previous errors
+error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers
+  --> tests/ui/cast.rs:468:5
+   |
+LL |     bar.unwrap().unwrap() as usize
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
+help: ... or use `try_from` and handle the error accordingly
+   |
+LL |     usize::try_from(bar.unwrap().unwrap())
+   |
+
+error: casting `i64` to `usize` may lose the sign of the value
+  --> tests/ui/cast.rs:468:5
+   |
+LL |     bar.unwrap().unwrap() as usize
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 87 previous errors
 
diff --git a/src/tools/clippy/tests/ui/crashes/ice-12616.fixed b/src/tools/clippy/tests/ui/crashes/ice-12616.fixed
new file mode 100644
index 0000000000000..a5a5b3d1e78ed
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-12616.fixed
@@ -0,0 +1,7 @@
+#![warn(clippy::ptr_as_ptr)]
+#![allow(clippy::unnecessary_operation, clippy::unnecessary_cast)]
+
+fn main() {
+    let s = std::ptr::null::<()>;
+    s().cast::<()>();
+}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-12616.rs b/src/tools/clippy/tests/ui/crashes/ice-12616.rs
new file mode 100644
index 0000000000000..6ee9a5ec08fe9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-12616.rs
@@ -0,0 +1,7 @@
+#![warn(clippy::ptr_as_ptr)]
+#![allow(clippy::unnecessary_operation, clippy::unnecessary_cast)]
+
+fn main() {
+    let s = std::ptr::null::<()>;
+    s() as *const ();
+}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-12616.stderr b/src/tools/clippy/tests/ui/crashes/ice-12616.stderr
new file mode 100644
index 0000000000000..ef573f55cf36f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-12616.stderr
@@ -0,0 +1,19 @@
+error: `as` casting between raw pointers without changing its mutability
+  --> tests/ui/crashes/ice-12616.rs:6:5
+   |
+LL |     s() as *const ();
+   |     ^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `s().cast::<()>()`
+   |
+   = note: `-D clippy::ptr-as-ptr` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::ptr_as_ptr)]`
+
+error: `as` casting between raw pointers without changing its mutability
+  --> tests/ui/crashes/ice-12616.rs:6:5
+   |
+LL |     s() as *const ();
+   |     ^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `s().cast::<()>()`
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/mixed_attributes_style.rs b/src/tools/clippy/tests/ui/mixed_attributes_style.rs
index ad93e3019fa65..a31aed32fd4f0 100644
--- a/src/tools/clippy/tests/ui/mixed_attributes_style.rs
+++ b/src/tools/clippy/tests/ui/mixed_attributes_style.rs
@@ -1,5 +1,11 @@
+//@aux-build:proc_macro_attr.rs
+//@compile-flags: --test --cfg dummy_cfg
+#![feature(custom_inner_attributes)]
 #![warn(clippy::mixed_attributes_style)]
 
+#[macro_use]
+extern crate proc_macro_attr;
+
 #[allow(unused)] //~ ERROR: item has both inner and outer attributes
 fn foo1() {
     #![allow(unused)]
@@ -37,3 +43,57 @@ mod bar {
 fn main() {
     // test code goes here
 }
+
+// issue #12435
+#[cfg(test)]
+mod tests {
+    //! Module doc, don't lint
+}
+#[allow(unused)]
+mod baz {
+    //! Module doc, don't lint
+    const FOO: u8 = 0;
+}
+/// Module doc, don't lint
+mod quz {
+    #![allow(unused)]
+}
+
+mod issue_12530 {
+    // don't lint different attributes entirely
+    #[cfg(test)]
+    mod tests {
+        #![allow(clippy::unreadable_literal)]
+
+        #[allow(dead_code)] //~ ERROR: item has both inner and outer attributes
+        mod inner_mod {
+            #![allow(dead_code)]
+        }
+    }
+    #[cfg(dummy_cfg)]
+    mod another_mod {
+        #![allow(clippy::question_mark)]
+    }
+    /// Nested mod
+    mod nested_mod {
+        #[allow(dead_code)] //~ ERROR: item has both inner and outer attributes
+        mod inner_mod {
+            #![allow(dead_code)]
+        }
+    }
+    /// Nested mod //~ ERROR: item has both inner and outer attributes
+    #[allow(unused)]
+    mod nest_mod_2 {
+        #![allow(unused)]
+
+        #[allow(dead_code)] //~ ERROR: item has both inner and outer attributes
+        mod inner_mod {
+            #![allow(dead_code)]
+        }
+    }
+    // Different path symbols - Known FN
+    #[dummy]
+    fn use_dummy() {
+        #![proc_macro_attr::dummy]
+    }
+}
diff --git a/src/tools/clippy/tests/ui/mixed_attributes_style.stderr b/src/tools/clippy/tests/ui/mixed_attributes_style.stderr
index d1d5cd3f47f31..f3cce4fe4822f 100644
--- a/src/tools/clippy/tests/ui/mixed_attributes_style.stderr
+++ b/src/tools/clippy/tests/ui/mixed_attributes_style.stderr
@@ -1,5 +1,5 @@
 error: item has both inner and outer attributes
-  --> tests/ui/mixed_attributes_style.rs:3:1
+  --> tests/ui/mixed_attributes_style.rs:9:1
    |
 LL | / #[allow(unused)]
 LL | | fn foo1() {
@@ -10,7 +10,7 @@ LL | |     #![allow(unused)]
    = help: to override `-D warnings` add `#[allow(clippy::mixed_attributes_style)]`
 
 error: item has both inner and outer attributes
-  --> tests/ui/mixed_attributes_style.rs:17:1
+  --> tests/ui/mixed_attributes_style.rs:23:1
    |
 LL | / /// linux
 LL | |
@@ -19,12 +19,45 @@ LL | |     //! windows
    | |_______________^
 
 error: item has both inner and outer attributes
-  --> tests/ui/mixed_attributes_style.rs:32:1
+  --> tests/ui/mixed_attributes_style.rs:38:1
    |
 LL | / #[allow(unused)]
 LL | | mod bar {
 LL | |     #![allow(unused)]
    | |_____________________^
 
-error: aborting due to 3 previous errors
+error: item has both inner and outer attributes
+  --> tests/ui/mixed_attributes_style.rs:68:9
+   |
+LL | /         #[allow(dead_code)]
+LL | |         mod inner_mod {
+LL | |             #![allow(dead_code)]
+   | |________________________________^
+
+error: item has both inner and outer attributes
+  --> tests/ui/mixed_attributes_style.rs:79:9
+   |
+LL | /         #[allow(dead_code)]
+LL | |         mod inner_mod {
+LL | |             #![allow(dead_code)]
+   | |________________________________^
+
+error: item has both inner and outer attributes
+  --> tests/ui/mixed_attributes_style.rs:84:5
+   |
+LL | /     /// Nested mod
+LL | |     #[allow(unused)]
+LL | |     mod nest_mod_2 {
+LL | |         #![allow(unused)]
+   | |_________________________^
+
+error: item has both inner and outer attributes
+  --> tests/ui/mixed_attributes_style.rs:89:9
+   |
+LL | /         #[allow(dead_code)]
+LL | |         mod inner_mod {
+LL | |             #![allow(dead_code)]
+   | |________________________________^
+
+error: aborting due to 7 previous errors
 
diff --git a/src/tools/clippy/tests/ui/mixed_attributes_style/auxiliary/submodule.rs b/src/tools/clippy/tests/ui/mixed_attributes_style/auxiliary/submodule.rs
new file mode 100644
index 0000000000000..df44b07a69414
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mixed_attributes_style/auxiliary/submodule.rs
@@ -0,0 +1,9 @@
+//! Module level doc
+
+#![allow(dead_code)]
+
+#[allow(unused)]
+//~^ ERROR: item has both inner and outer attributes
+mod foo {
+    #![allow(dead_code)]
+}
diff --git a/src/tools/clippy/tests/ui/mixed_attributes_style/global_allow.rs b/src/tools/clippy/tests/ui/mixed_attributes_style/global_allow.rs
new file mode 100644
index 0000000000000..153262e65570d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mixed_attributes_style/global_allow.rs
@@ -0,0 +1,7 @@
+// issue 12436
+#![allow(clippy::mixed_attributes_style)]
+
+#[path = "auxiliary/submodule.rs"]
+mod submodule;
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/mixed_attributes_style/mod_declaration.rs b/src/tools/clippy/tests/ui/mixed_attributes_style/mod_declaration.rs
new file mode 100644
index 0000000000000..b0f1f0bda9e60
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mixed_attributes_style/mod_declaration.rs
@@ -0,0 +1,3 @@
+#[path = "auxiliary/submodule.rs"] // don't lint.
+/// This doc comment should not lint, it could be used to add context to the original module doc
+mod submodule;
diff --git a/src/tools/clippy/tests/ui/mixed_attributes_style/mod_declaration.stderr b/src/tools/clippy/tests/ui/mixed_attributes_style/mod_declaration.stderr
new file mode 100644
index 0000000000000..968c537c7e44f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mixed_attributes_style/mod_declaration.stderr
@@ -0,0 +1,14 @@
+error: item has both inner and outer attributes
+  --> tests/ui/mixed_attributes_style/auxiliary/submodule.rs:5:1
+   |
+LL | / #[allow(unused)]
+LL | |
+LL | | mod foo {
+LL | |     #![allow(dead_code)]
+   | |________________________^
+   |
+   = note: `-D clippy::mixed-attributes-style` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::mixed_attributes_style)]`
+
+error: aborting due to 1 previous error
+