From 27dcb4aab534741f747354c6a72ff29d0ccce329 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Wed, 10 Jun 2020 00:33:10 -0700 Subject: [PATCH] Avoid collisions between traits and their derive macros --- .../passes/collect_intra_doc_links.rs | 29 +++++++++++++++++-- .../auxiliary/intra-link-proc-macro-macro.rs | 5 ++++ src/test/rustdoc/intra-link-proc-macro.rs | 6 +++- 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 4514a616bd8..ab4dbb87425 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -12,6 +12,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::ty; use rustc_resolve::ParentScope; use rustc_session::lint; +use rustc_span::hygiene::MacroKind; use rustc_span::symbol::Ident; use rustc_span::symbol::Symbol; use rustc_span::DUMMY_SP; @@ -407,6 +408,22 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { } } +/// Check for resolve collisions between a trait and its derive +/// +/// These are common and we should just resolve to the trait in that case +fn is_derive_trait_collision(ns: &PerNS>) -> bool { + if let PerNS { + type_ns: Some((Res::Def(DefKind::Trait, _), _)), + macro_ns: Some((Res::Def(DefKind::Macro(MacroKind::Derive), _), _)), + .. + } = *ns + { + true + } else { + false + } +} + impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { fn fold_item(&mut self, mut item: Item) -> Option { let item_hir_id = if item.is_mod() { @@ -650,7 +667,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } None => { // Try everything! - let candidates = PerNS { + let mut candidates = PerNS { macro_ns: self .macro_resolve(path_str, base_node) .map(|res| (res, extra_fragment.clone())), @@ -705,10 +722,16 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { continue; } - let is_unambiguous = candidates.clone().present_items().count() == 1; - if is_unambiguous { + let len = candidates.clone().present_items().count(); + + if len == 1 { candidates.present_items().next().unwrap() + } else if len == 2 && is_derive_trait_collision(&candidates) { + candidates.type_ns.unwrap() } else { + if is_derive_trait_collision(&candidates) { + candidates.macro_ns = None; + } ambiguity_error( cx, &item, diff --git a/src/test/rustdoc/auxiliary/intra-link-proc-macro-macro.rs b/src/test/rustdoc/auxiliary/intra-link-proc-macro-macro.rs index fee92ff2e0d..04a431d9902 100644 --- a/src/test/rustdoc/auxiliary/intra-link-proc-macro-macro.rs +++ b/src/test/rustdoc/auxiliary/intra-link-proc-macro-macro.rs @@ -19,6 +19,11 @@ pub fn b_derive(input: TokenStream) -> TokenStream { input } +#[proc_macro_derive(DeriveTrait)] +pub fn trait_derive(input: TokenStream) -> TokenStream { + input +} + #[proc_macro_attribute] pub fn attr_a(input: TokenStream, _args: TokenStream) -> TokenStream { input diff --git a/src/test/rustdoc/intra-link-proc-macro.rs b/src/test/rustdoc/intra-link-proc-macro.rs index 78ef91ab682..405e08d4c07 100644 --- a/src/test/rustdoc/intra-link-proc-macro.rs +++ b/src/test/rustdoc/intra-link-proc-macro.rs @@ -11,7 +11,11 @@ use intra_link_proc_macro_macro::{DeriveB, attr_b}; // @has - '//a/@href' '../intra_link_proc_macro/derive.DeriveA.html' // @has - '//a/@href' '../intra_link_proc_macro/attr.attr_a.html' +// @has - '//a/@href' '../intra_link_proc_macro/trait.DeriveTrait.html' // @has - '//a/@href' '../intra_link_proc_macro_macro/derive.DeriveB.html' // @has - '//a/@href' '../intra_link_proc_macro_macro/attr.attr_b.html' -/// Link to [DeriveA], [attr_a], [DeriveB], [attr_b] +/// Link to [DeriveA], [attr_a], [DeriveB], [attr_b], [DeriveTrait] pub struct Foo; + +// this should not cause ambiguity errors +pub trait DeriveTrait {}