diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs
index b99052e66..7ef80b1a5 100644
--- a/clippy_lints/src/missing_doc.rs
+++ b/clippy_lints/src/missing_doc.rs
@@ -7,6 +7,7 @@
 
 use clippy_utils::attrs::is_doc_hidden;
 use clippy_utils::diagnostics::span_lint;
+use clippy_utils::is_from_proc_macro;
 use if_chain::if_chain;
 use rustc_ast::ast::{self, MetaItem, MetaItemKind};
 use rustc_hir as hir;
@@ -158,14 +159,18 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
         let (article, desc) = cx.tcx.article_and_description(it.def_id.to_def_id());
 
         let attrs = cx.tcx.hir().attrs(it.hir_id());
-        self.check_missing_docs_attrs(cx, attrs, it.span, article, desc);
+        if !is_from_proc_macro(cx, it) {
+            self.check_missing_docs_attrs(cx, attrs, it.span, article, desc);
+        }
     }
 
     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx hir::TraitItem<'_>) {
         let (article, desc) = cx.tcx.article_and_description(trait_item.def_id.to_def_id());
 
         let attrs = cx.tcx.hir().attrs(trait_item.hir_id());
-        self.check_missing_docs_attrs(cx, attrs, trait_item.span, article, desc);
+        if !is_from_proc_macro(cx, trait_item) {
+            self.check_missing_docs_attrs(cx, attrs, trait_item.span, article, desc);
+        }
     }
 
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) {
@@ -181,18 +186,24 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
 
         let (article, desc) = cx.tcx.article_and_description(impl_item.def_id.to_def_id());
         let attrs = cx.tcx.hir().attrs(impl_item.hir_id());
-        self.check_missing_docs_attrs(cx, attrs, impl_item.span, article, desc);
+        if !is_from_proc_macro(cx, impl_item) {
+            self.check_missing_docs_attrs(cx, attrs, impl_item.span, article, desc);
+        }
     }
 
     fn check_field_def(&mut self, cx: &LateContext<'tcx>, sf: &'tcx hir::FieldDef<'_>) {
         if !sf.is_positional() {
             let attrs = cx.tcx.hir().attrs(sf.hir_id);
-            self.check_missing_docs_attrs(cx, attrs, sf.span, "a", "struct field");
+            if !is_from_proc_macro(cx, sf) {
+                self.check_missing_docs_attrs(cx, attrs, sf.span, "a", "struct field");
+            }
         }
     }
 
     fn check_variant(&mut self, cx: &LateContext<'tcx>, v: &'tcx hir::Variant<'_>) {
         let attrs = cx.tcx.hir().attrs(v.id);
-        self.check_missing_docs_attrs(cx, attrs, v.span, "a", "variant");
+        if !is_from_proc_macro(cx, v) {
+            self.check_missing_docs_attrs(cx, attrs, v.span, "a", "variant");
+        }
     }
 }
diff --git a/clippy_lints/src/unit_types/mod.rs b/clippy_lints/src/unit_types/mod.rs
index 6aa86a57c..546242ebd 100644
--- a/clippy_lints/src/unit_types/mod.rs
+++ b/clippy_lints/src/unit_types/mod.rs
@@ -103,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for UnitTypes {
         let_unit_value::check(cx, local);
     }
 
-    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         unit_cmp::check(cx, expr);
         unit_arg::check(cx, expr);
     }
diff --git a/clippy_lints/src/unit_types/unit_arg.rs b/clippy_lints/src/unit_types/unit_arg.rs
index cd38720f7..16da2f11b 100644
--- a/clippy_lints/src/unit_types/unit_arg.rs
+++ b/clippy_lints/src/unit_types/unit_arg.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::is_expr_from_proc_macro;
+use clippy_utils::is_from_proc_macro;
 use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
@@ -8,7 +8,7 @@ use rustc_lint::LateContext;
 
 use super::{utils, UNIT_ARG};
 
-pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
     if expr.span.from_expansion() {
         return;
     }
@@ -45,7 +45,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
                     }
                 })
                 .collect::<Vec<_>>();
-            if !args_to_recover.is_empty() && !is_expr_from_proc_macro(cx, expr) {
+            if !args_to_recover.is_empty() && !is_from_proc_macro(cx, expr) {
                 lint_unit_args(cx, expr, &args_to_recover);
             }
         },
diff --git a/clippy_utils/src/check_proc_macro.rs b/clippy_utils/src/check_proc_macro.rs
index 51cd70f5e..4dd0ec6b6 100644
--- a/clippy_utils/src/check_proc_macro.rs
+++ b/clippy_utils/src/check_proc_macro.rs
@@ -14,17 +14,20 @@
 
 use rustc_ast::ast::{IntTy, LitIntType, LitKind, StrStyle, UintTy};
 use rustc_hir::{
-    Block, BlockCheckMode, Closure, Destination, Expr, ExprKind, LoopSource, MatchSource, QPath, UnOp, UnsafeSource,
-    YieldSource,
+    Block, BlockCheckMode, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, Impl, ImplItem, ImplItemKind,
+    IsAuto, Item, ItemKind, LoopSource, MatchSource, QPath, TraitItem, TraitItemKind, UnOp, UnsafeSource, Unsafety,
+    Variant, VariantData, VisibilityKind, YieldSource,
 };
 use rustc_lint::{LateContext, LintContext};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
 use rustc_span::{Span, Symbol};
+use rustc_target::spec::abi::Abi;
 
 #[derive(Clone, Copy)]
-enum Pat {
+pub enum Pat {
     Str(&'static str),
+    MultiStr(&'static [&'static str]),
     Sym(Symbol),
     Num,
 }
@@ -43,10 +46,12 @@ fn span_matches_pat(sess: &Session, span: Span, start_pat: Pat, end_pat: Pat) ->
         let end_str = s.trim_end_matches(|c: char| c.is_whitespace() || c == ')' || c == ',');
         (match start_pat {
             Pat::Str(text) => start_str.starts_with(text),
+            Pat::MultiStr(texts) => texts.iter().any(|s| start_str.starts_with(s)),
             Pat::Sym(sym) => start_str.starts_with(sym.as_str()),
             Pat::Num => start_str.as_bytes().first().map_or(false, u8::is_ascii_digit),
         } && match end_pat {
             Pat::Str(text) => end_str.ends_with(text),
+            Pat::MultiStr(texts) => texts.iter().any(|s| start_str.ends_with(s)),
             Pat::Sym(sym) => end_str.ends_with(sym.as_str()),
             Pat::Num => end_str.as_bytes().last().map_or(false, u8::is_ascii_hexdigit),
         })
@@ -155,10 +160,121 @@ fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) {
     }
 }
 
-/// Checks if the expression likely came from a proc-macro
-pub fn is_expr_from_proc_macro(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
-    let (start_pat, end_pat) = expr_search_pat(cx.tcx, e);
-    !span_matches_pat(cx.sess(), e.span, start_pat, end_pat)
+fn fn_header_search_pat(header: FnHeader) -> Pat {
+    if header.is_async() {
+        Pat::Str("async")
+    } else if header.is_const() {
+        Pat::Str("const")
+    } else if header.is_unsafe() {
+        Pat::Str("unsafe")
+    } else if header.abi != Abi::Rust {
+        Pat::Str("extern")
+    } else {
+        Pat::MultiStr(&["fn", "extern"])
+    }
+}
+
+fn item_search_pat(item: &Item<'_>) -> (Pat, Pat) {
+    let (start_pat, end_pat) = match &item.kind {
+        ItemKind::ExternCrate(_) => (Pat::Str("extern"), Pat::Str(";")),
+        ItemKind::Static(..) => (Pat::Str("static"), Pat::Str(";")),
+        ItemKind::Const(..) => (Pat::Str("const"), Pat::Str(";")),
+        ItemKind::Fn(sig, ..) => (fn_header_search_pat(sig.header), Pat::Str("")),
+        ItemKind::ForeignMod { .. } => (Pat::Str("extern"), Pat::Str("}")),
+        ItemKind::TyAlias(..) | ItemKind::OpaqueTy(_) => (Pat::Str("type"), Pat::Str(";")),
+        ItemKind::Enum(..) => (Pat::Str("enum"), Pat::Str("}")),
+        ItemKind::Struct(VariantData::Struct(..), _) => (Pat::Str("struct"), Pat::Str("}")),
+        ItemKind::Struct(..) => (Pat::Str("struct"), Pat::Str(";")),
+        ItemKind::Union(..) => (Pat::Str("union"), Pat::Str("}")),
+        ItemKind::Trait(_, Unsafety::Unsafe, ..)
+        | ItemKind::Impl(Impl {
+            unsafety: Unsafety::Unsafe,
+            ..
+        }) => (Pat::Str("unsafe"), Pat::Str("}")),
+        ItemKind::Trait(IsAuto::Yes, ..) => (Pat::Str("auto"), Pat::Str("}")),
+        ItemKind::Trait(..) => (Pat::Str("trait"), Pat::Str("}")),
+        ItemKind::Impl(_) => (Pat::Str("impl"), Pat::Str("}")),
+        _ => return (Pat::Str(""), Pat::Str("")),
+    };
+    if matches!(item.vis.node, VisibilityKind::Inherited) {
+        (start_pat, end_pat)
+    } else {
+        (Pat::Str("pub"), end_pat)
+    }
+}
+
+fn trait_item_search_pat(item: &TraitItem<'_>) -> (Pat, Pat) {
+    match &item.kind {
+        TraitItemKind::Const(..) => (Pat::Str("const"), Pat::Str(";")),
+        TraitItemKind::Type(..) => (Pat::Str("type"), Pat::Str(";")),
+        TraitItemKind::Fn(sig, ..) => (fn_header_search_pat(sig.header), Pat::Str("")),
+    }
+}
+
+fn impl_item_search_pat(item: &ImplItem<'_>) -> (Pat, Pat) {
+    let (start_pat, end_pat) = match &item.kind {
+        ImplItemKind::Const(..) => (Pat::Str("const"), Pat::Str(";")),
+        ImplItemKind::TyAlias(..) => (Pat::Str("type"), Pat::Str(";")),
+        ImplItemKind::Fn(sig, ..) => (fn_header_search_pat(sig.header), Pat::Str("")),
+    };
+    if matches!(item.vis.node, VisibilityKind::Inherited) {
+        (start_pat, end_pat)
+    } else {
+        (Pat::Str("pub"), end_pat)
+    }
+}
+
+fn field_def_search_pat(def: &FieldDef<'_>) -> (Pat, Pat) {
+    if matches!(def.vis.node, VisibilityKind::Inherited) {
+        if def.is_positional() {
+            (Pat::Str(""), Pat::Str(""))
+        } else {
+            (Pat::Sym(def.ident.name), Pat::Str(""))
+        }
+    } else {
+        (Pat::Str("pub"), Pat::Str(""))
+    }
+}
+
+fn variant_search_pat(v: &Variant<'_>) -> (Pat, Pat) {
+    match v.data {
+        VariantData::Struct(..) => (Pat::Sym(v.ident.name), Pat::Str("}")),
+        VariantData::Tuple(..) => (Pat::Sym(v.ident.name), Pat::Str("")),
+        VariantData::Unit(..) => (Pat::Sym(v.ident.name), Pat::Sym(v.ident.name)),
+    }
+}
+
+pub trait WithSearchPat {
+    type Context: LintContext;
+    fn search_pat(&self, cx: &Self::Context) -> (Pat, Pat);
+    fn span(&self) -> Span;
+}
+macro_rules! impl_with_search_pat {
+    ($cx:ident: $ty:ident with $fn:ident $(($tcx:ident))?) => {
+        impl<'cx> WithSearchPat for $ty<'cx> {
+            type Context = $cx<'cx>;
+            #[allow(unused_variables)]
+            fn search_pat(&self, cx: &Self::Context) -> (Pat, Pat) {
+                $(let $tcx = cx.tcx;)?
+                $fn($($tcx,)? self)
+            }
+            fn span(&self) -> Span {
+                self.span
+            }
+        }
+    };
+}
+impl_with_search_pat!(LateContext: Expr with expr_search_pat(tcx));
+impl_with_search_pat!(LateContext: Item with item_search_pat);
+impl_with_search_pat!(LateContext: TraitItem with trait_item_search_pat);
+impl_with_search_pat!(LateContext: ImplItem with impl_item_search_pat);
+impl_with_search_pat!(LateContext: FieldDef with field_def_search_pat);
+impl_with_search_pat!(LateContext: Variant with variant_search_pat);
+
+/// Checks if the item likely came from a proc-macro
+pub fn is_from_proc_macro<T: WithSearchPat>(cx: &T::Context, item: &T) -> bool {
+    let (start_pat, end_pat) = item.search_pat(cx);
+    !span_matches_pat(cx.sess(), item.span(), start_pat, end_pat)
 }
 
 /// Checks if the span actually refers to a match expression
diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs
index 086e6d6e3..dcfc03475 100644
--- a/clippy_utils/src/lib.rs
+++ b/clippy_utils/src/lib.rs
@@ -59,7 +59,7 @@ pub mod usage;
 pub mod visitors;
 
 pub use self::attrs::*;
-pub use self::check_proc_macro::{is_expr_from_proc_macro, is_span_if, is_span_match};
+pub use self::check_proc_macro::{is_from_proc_macro, is_span_if, is_span_match};
 pub use self::hir_utils::{
     both, count_eq, eq_expr_value, hash_expr, hash_stmt, over, HirEqInterExpr, SpanlessEq, SpanlessHash,
 };
diff --git a/tests/ui/missing-doc.rs b/tests/ui/missing_doc.rs
similarity index 82%
rename from tests/ui/missing-doc.rs
rename to tests/ui/missing_doc.rs
index 6e2e710e2..29cc026a8 100644
--- a/tests/ui/missing-doc.rs
+++ b/tests/ui/missing_doc.rs
@@ -1,3 +1,5 @@
+// aux-build: proc_macro_with_span.rs
+
 #![warn(clippy::missing_docs_in_private_items)]
 // When denying at the crate level, be sure to not get random warnings from the
 // injected intrinsics by the compiler.
@@ -5,6 +7,9 @@
 //! Some garbage docs for the crate here
 #![doc = "More garbage"]
 
+extern crate proc_macro_with_span;
+
+use proc_macro_with_span::with_span;
 use std::arch::global_asm;
 
 type Typedef = String;
@@ -100,3 +105,11 @@ fn main() {}
 
 // Ensure global asm doesn't require documentation.
 global_asm! { "" }
+
+// Don't lint proc macro output with an unexpected span.
+with_span!(span pub struct FooPm { pub field: u32});
+with_span!(span pub struct FooPm2;);
+with_span!(span pub enum FooPm3 { A, B(u32), C { field: u32 }});
+with_span!(span pub fn foo_pm() {});
+with_span!(span pub static FOO_PM: u32 = 0;);
+with_span!(span pub const FOO2_PM: u32 = 0;);
diff --git a/tests/ui/missing-doc.stderr b/tests/ui/missing_doc.stderr
similarity index 79%
rename from tests/ui/missing-doc.stderr
rename to tests/ui/missing_doc.stderr
index a876dc078..6c8e66f46 100644
--- a/tests/ui/missing-doc.stderr
+++ b/tests/ui/missing_doc.stderr
@@ -1,5 +1,5 @@
 error: missing documentation for a type alias
-  --> $DIR/missing-doc.rs:10:1
+  --> $DIR/missing_doc.rs:15:1
    |
 LL | type Typedef = String;
    | ^^^^^^^^^^^^^^^^^^^^^^
@@ -7,37 +7,37 @@ LL | type Typedef = String;
    = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings`
 
 error: missing documentation for a type alias
-  --> $DIR/missing-doc.rs:11:1
+  --> $DIR/missing_doc.rs:16:1
    |
 LL | pub type PubTypedef = String;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a module
-  --> $DIR/missing-doc.rs:13:1
+  --> $DIR/missing_doc.rs:18:1
    |
 LL | mod module_no_dox {}
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a module
-  --> $DIR/missing-doc.rs:14:1
+  --> $DIR/missing_doc.rs:19:1
    |
 LL | pub mod pub_module_no_dox {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-  --> $DIR/missing-doc.rs:18:1
+  --> $DIR/missing_doc.rs:23:1
    |
 LL | pub fn foo2() {}
    | ^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-  --> $DIR/missing-doc.rs:19:1
+  --> $DIR/missing_doc.rs:24:1
    |
 LL | fn foo3() {}
    | ^^^^^^^^^^^^
 
 error: missing documentation for an enum
-  --> $DIR/missing-doc.rs:33:1
+  --> $DIR/missing_doc.rs:38:1
    |
 LL | / enum Baz {
 LL | |     BazA { a: isize, b: isize },
@@ -46,31 +46,31 @@ LL | | }
    | |_^
 
 error: missing documentation for a variant
-  --> $DIR/missing-doc.rs:34:5
+  --> $DIR/missing_doc.rs:39:5
    |
 LL |     BazA { a: isize, b: isize },
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a struct field
-  --> $DIR/missing-doc.rs:34:12
+  --> $DIR/missing_doc.rs:39:12
    |
 LL |     BazA { a: isize, b: isize },
    |            ^^^^^^^^
 
 error: missing documentation for a struct field
-  --> $DIR/missing-doc.rs:34:22
+  --> $DIR/missing_doc.rs:39:22
    |
 LL |     BazA { a: isize, b: isize },
    |                      ^^^^^^^^
 
 error: missing documentation for a variant
-  --> $DIR/missing-doc.rs:35:5
+  --> $DIR/missing_doc.rs:40:5
    |
 LL |     BarB,
    |     ^^^^
 
 error: missing documentation for an enum
-  --> $DIR/missing-doc.rs:38:1
+  --> $DIR/missing_doc.rs:43:1
    |
 LL | / pub enum PubBaz {
 LL | |     PubBazA { a: isize },
@@ -78,43 +78,43 @@ LL | | }
    | |_^
 
 error: missing documentation for a variant
-  --> $DIR/missing-doc.rs:39:5
+  --> $DIR/missing_doc.rs:44:5
    |
 LL |     PubBazA { a: isize },
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a struct field
-  --> $DIR/missing-doc.rs:39:15
+  --> $DIR/missing_doc.rs:44:15
    |
 LL |     PubBazA { a: isize },
    |               ^^^^^^^^
 
 error: missing documentation for a constant
-  --> $DIR/missing-doc.rs:59:1
+  --> $DIR/missing_doc.rs:64:1
    |
 LL | const FOO: u32 = 0;
    | ^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a constant
-  --> $DIR/missing-doc.rs:66:1
+  --> $DIR/missing_doc.rs:71:1
    |
 LL | pub const FOO4: u32 = 0;
    | ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a static
-  --> $DIR/missing-doc.rs:68:1
+  --> $DIR/missing_doc.rs:73:1
    |
 LL | static BAR: u32 = 0;
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a static
-  --> $DIR/missing-doc.rs:75:1
+  --> $DIR/missing_doc.rs:80:1
    |
 LL | pub static BAR4: u32 = 0;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a module
-  --> $DIR/missing-doc.rs:77:1
+  --> $DIR/missing_doc.rs:82:1
    |
 LL | / mod internal_impl {
 LL | |     /// dox
@@ -126,31 +126,31 @@ LL | | }
    | |_^
 
 error: missing documentation for a function
-  --> $DIR/missing-doc.rs:80:5
+  --> $DIR/missing_doc.rs:85:5
    |
 LL |     pub fn undocumented1() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-  --> $DIR/missing-doc.rs:81:5
+  --> $DIR/missing_doc.rs:86:5
    |
 LL |     pub fn undocumented2() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-  --> $DIR/missing-doc.rs:82:5
+  --> $DIR/missing_doc.rs:87:5
    |
 LL |     fn undocumented3() {}
    |     ^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-  --> $DIR/missing-doc.rs:87:9
+  --> $DIR/missing_doc.rs:92:9
    |
 LL |         pub fn also_undocumented1() {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-  --> $DIR/missing-doc.rs:88:9
+  --> $DIR/missing_doc.rs:93:9
    |
 LL |         fn also_undocumented2() {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/missing-doc-crate.rs b/tests/ui/missing_doc_crate.rs
similarity index 100%
rename from tests/ui/missing-doc-crate.rs
rename to tests/ui/missing_doc_crate.rs
diff --git a/tests/ui/missing-doc-crate-missing.rs b/tests/ui/missing_doc_crate_missing.rs
similarity index 100%
rename from tests/ui/missing-doc-crate-missing.rs
rename to tests/ui/missing_doc_crate_missing.rs
diff --git a/tests/ui/missing-doc-crate-missing.stderr b/tests/ui/missing_doc_crate_missing.stderr
similarity index 86%
rename from tests/ui/missing-doc-crate-missing.stderr
rename to tests/ui/missing_doc_crate_missing.stderr
index d56c5cc4c..19516bf5f 100644
--- a/tests/ui/missing-doc-crate-missing.stderr
+++ b/tests/ui/missing_doc_crate_missing.stderr
@@ -1,5 +1,5 @@
 error: missing documentation for the crate
-  --> $DIR/missing-doc-crate-missing.rs:1:1
+  --> $DIR/missing_doc_crate_missing.rs:1:1
    |
 LL | / #![warn(clippy::missing_docs_in_private_items)]
 LL | |
diff --git a/tests/ui/missing-doc-impl.rs b/tests/ui/missing_doc_impl.rs
similarity index 83%
rename from tests/ui/missing-doc-impl.rs
rename to tests/ui/missing_doc_impl.rs
index d5724bf66..0396d1193 100644
--- a/tests/ui/missing-doc-impl.rs
+++ b/tests/ui/missing_doc_impl.rs
@@ -1,3 +1,5 @@
+// aux-build: proc_macro_with_span.rs
+
 #![warn(clippy::missing_docs_in_private_items)]
 #![allow(dead_code)]
 #![feature(associated_type_defaults)]
@@ -5,6 +7,9 @@
 //! Some garbage docs for the crate here
 #![doc = "More garbage"]
 
+extern crate proc_macro_with_span;
+use proc_macro_with_span::with_span;
+
 struct Foo {
     a: isize,
     b: isize,
@@ -90,3 +95,13 @@ impl F for Foo {
 }
 
 fn main() {}
+
+// don't lint proc macro output
+with_span!(span
+    pub struct FooPm;
+    impl FooPm {
+        pub fn foo() {}
+        pub const fn bar() {}
+        pub const X: u32 = 0;
+    }
+);
diff --git a/tests/ui/missing-doc-impl.stderr b/tests/ui/missing_doc_impl.stderr
similarity index 78%
rename from tests/ui/missing-doc-impl.stderr
rename to tests/ui/missing_doc_impl.stderr
index bda63d66a..f22fa19db 100644
--- a/tests/ui/missing-doc-impl.stderr
+++ b/tests/ui/missing_doc_impl.stderr
@@ -1,5 +1,5 @@
 error: missing documentation for a struct
-  --> $DIR/missing-doc-impl.rs:8:1
+  --> $DIR/missing_doc_impl.rs:13:1
    |
 LL | / struct Foo {
 LL | |     a: isize,
@@ -10,19 +10,19 @@ LL | | }
    = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings`
 
 error: missing documentation for a struct field
-  --> $DIR/missing-doc-impl.rs:9:5
+  --> $DIR/missing_doc_impl.rs:14:5
    |
 LL |     a: isize,
    |     ^^^^^^^^
 
 error: missing documentation for a struct field
-  --> $DIR/missing-doc-impl.rs:10:5
+  --> $DIR/missing_doc_impl.rs:15:5
    |
 LL |     b: isize,
    |     ^^^^^^^^
 
 error: missing documentation for a struct
-  --> $DIR/missing-doc-impl.rs:13:1
+  --> $DIR/missing_doc_impl.rs:18:1
    |
 LL | / pub struct PubFoo {
 LL | |     pub a: isize,
@@ -31,19 +31,19 @@ LL | | }
    | |_^
 
 error: missing documentation for a struct field
-  --> $DIR/missing-doc-impl.rs:14:5
+  --> $DIR/missing_doc_impl.rs:19:5
    |
 LL |     pub a: isize,
    |     ^^^^^^^^^^^^
 
 error: missing documentation for a struct field
-  --> $DIR/missing-doc-impl.rs:15:5
+  --> $DIR/missing_doc_impl.rs:20:5
    |
 LL |     b: isize,
    |     ^^^^^^^^
 
 error: missing documentation for a trait
-  --> $DIR/missing-doc-impl.rs:38:1
+  --> $DIR/missing_doc_impl.rs:43:1
    |
 LL | / pub trait C {
 LL | |     fn foo(&self);
@@ -52,31 +52,31 @@ LL | | }
    | |_^
 
 error: missing documentation for an associated function
-  --> $DIR/missing-doc-impl.rs:39:5
+  --> $DIR/missing_doc_impl.rs:44:5
    |
 LL |     fn foo(&self);
    |     ^^^^^^^^^^^^^^
 
 error: missing documentation for an associated function
-  --> $DIR/missing-doc-impl.rs:40:5
+  --> $DIR/missing_doc_impl.rs:45:5
    |
 LL |     fn foo_with_impl(&self) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for an associated type
-  --> $DIR/missing-doc-impl.rs:50:5
+  --> $DIR/missing_doc_impl.rs:55:5
    |
 LL |     type AssociatedType;
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for an associated type
-  --> $DIR/missing-doc-impl.rs:51:5
+  --> $DIR/missing_doc_impl.rs:56:5
    |
 LL |     type AssociatedTypeDef = Self;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for an associated function
-  --> $DIR/missing-doc-impl.rs:62:5
+  --> $DIR/missing_doc_impl.rs:67:5
    |
 LL | /     pub fn new() -> Self {
 LL | |         Foo { a: 0, b: 0 }
@@ -84,19 +84,19 @@ LL | |     }
    | |_____^
 
 error: missing documentation for an associated function
-  --> $DIR/missing-doc-impl.rs:65:5
+  --> $DIR/missing_doc_impl.rs:70:5
    |
 LL |     fn bar() {}
    |     ^^^^^^^^^^^
 
 error: missing documentation for an associated function
-  --> $DIR/missing-doc-impl.rs:69:5
+  --> $DIR/missing_doc_impl.rs:74:5
    |
 LL |     pub fn foo() {}
    |     ^^^^^^^^^^^^^^^
 
 error: missing documentation for an associated function
-  --> $DIR/missing-doc-impl.rs:73:5
+  --> $DIR/missing_doc_impl.rs:78:5
    |
 LL | /     fn foo2() -> u32 {
 LL | |         1