Skip to content

Commit d9cf7a1

Browse files
authored
Rollup merge of #73183 - Manishearth:intra-doc-macro, r=GuillaumeGomez
Support proc macros in intra doc link resolution The feature was written pre-proc macro resolution, so it only supported the wacky MBE resolution rules. This adds support for proc macros as well. cc @GuillaumeGomez Fixes #73173
2 parents 6cc757e + 34c6b38 commit d9cf7a1

File tree

3 files changed

+134
-28
lines changed

3 files changed

+134
-28
lines changed

src/librustdoc/passes/collect_intra_doc_links.rs

+72-28
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use rustc_hir::def_id::{DefId, LocalDefId};
1212
use rustc_middle::ty;
1313
use rustc_resolve::ParentScope;
1414
use rustc_session::lint;
15+
use rustc_span::hygiene::MacroKind;
1516
use rustc_span::symbol::Ident;
1617
use rustc_span::symbol::Symbol;
1718
use rustc_span::DUMMY_SP;
@@ -122,6 +123,42 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
122123
}
123124
}
124125

126+
/// Resolves a string as a macro.
127+
fn macro_resolve(&self, path_str: &str, parent_id: Option<hir::HirId>) -> Option<Res> {
128+
let cx = self.cx;
129+
let path = ast::Path::from_ident(Ident::from_str(path_str));
130+
cx.enter_resolver(|resolver| {
131+
if let Ok((Some(ext), res)) = resolver.resolve_macro_path(
132+
&path,
133+
None,
134+
&ParentScope::module(resolver.graph_root()),
135+
false,
136+
false,
137+
) {
138+
if let SyntaxExtensionKind::LegacyBang { .. } = ext.kind {
139+
return Some(res.map_id(|_| panic!("unexpected id")));
140+
}
141+
}
142+
if let Some(res) = resolver.all_macros().get(&Symbol::intern(path_str)) {
143+
return Some(res.map_id(|_| panic!("unexpected id")));
144+
}
145+
if let Some(module_id) = parent_id.or(self.mod_ids.last().cloned()) {
146+
let module_id = cx.tcx.hir().local_def_id(module_id);
147+
if let Ok((_, res)) =
148+
resolver.resolve_str_path_error(DUMMY_SP, path_str, MacroNS, module_id)
149+
{
150+
// don't resolve builtins like `#[derive]`
151+
if let Res::Def(..) = res {
152+
let res = res.map_id(|_| panic!("unexpected node_id"));
153+
return Some(res);
154+
}
155+
}
156+
} else {
157+
debug!("attempting to resolve item without parent module: {}", path_str);
158+
}
159+
None
160+
})
161+
}
125162
/// Resolves a string as a path within a particular namespace. Also returns an optional
126163
/// URL fragment in the case of variants and methods.
127164
fn resolve(
@@ -371,6 +408,22 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
371408
}
372409
}
373410

411+
/// Check for resolve collisions between a trait and its derive
412+
///
413+
/// These are common and we should just resolve to the trait in that case
414+
fn is_derive_trait_collision<T>(ns: &PerNS<Option<(Res, T)>>) -> bool {
415+
if let PerNS {
416+
type_ns: Some((Res::Def(DefKind::Trait, _), _)),
417+
macro_ns: Some((Res::Def(DefKind::Macro(MacroKind::Derive), _), _)),
418+
..
419+
} = *ns
420+
{
421+
true
422+
} else {
423+
false
424+
}
425+
}
426+
374427
impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
375428
fn fold_item(&mut self, mut item: Item) -> Option<Item> {
376429
let item_hir_id = if item.is_mod() {
@@ -532,6 +585,9 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
532585
} else if link.starts_with("macro@") {
533586
kind = Some(MacroNS);
534587
link.trim_start_matches("macro@")
588+
} else if link.starts_with("derive@") {
589+
kind = Some(MacroNS);
590+
link.trim_start_matches("derive@")
535591
} else if link.ends_with('!') {
536592
kind = Some(MacroNS);
537593
link.trim_end_matches('!')
@@ -614,8 +670,9 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
614670
}
615671
None => {
616672
// Try everything!
617-
let candidates = PerNS {
618-
macro_ns: macro_resolve(cx, path_str)
673+
let mut candidates = PerNS {
674+
macro_ns: self
675+
.macro_resolve(path_str, base_node)
619676
.map(|res| (res, extra_fragment.clone())),
620677
type_ns: match self.resolve(
621678
path_str,
@@ -668,10 +725,16 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
668725
continue;
669726
}
670727

671-
let is_unambiguous = candidates.clone().present_items().count() == 1;
672-
if is_unambiguous {
728+
let len = candidates.clone().present_items().count();
729+
730+
if len == 1 {
673731
candidates.present_items().next().unwrap()
732+
} else if len == 2 && is_derive_trait_collision(&candidates) {
733+
candidates.type_ns.unwrap()
674734
} else {
735+
if is_derive_trait_collision(&candidates) {
736+
candidates.macro_ns = None;
737+
}
675738
ambiguity_error(
676739
cx,
677740
&item,
@@ -684,7 +747,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
684747
}
685748
}
686749
Some(MacroNS) => {
687-
if let Some(res) = macro_resolve(cx, path_str) {
750+
if let Some(res) = self.macro_resolve(path_str, base_node) {
688751
(res, extra_fragment)
689752
} else {
690753
resolution_failure(cx, &item, path_str, &dox, link_range);
@@ -727,28 +790,6 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
727790
}
728791
}
729792

730-
/// Resolves a string as a macro.
731-
fn macro_resolve(cx: &DocContext<'_>, path_str: &str) -> Option<Res> {
732-
let path = ast::Path::from_ident(Ident::from_str(path_str));
733-
cx.enter_resolver(|resolver| {
734-
if let Ok((Some(ext), res)) = resolver.resolve_macro_path(
735-
&path,
736-
None,
737-
&ParentScope::module(resolver.graph_root()),
738-
false,
739-
false,
740-
) {
741-
if let SyntaxExtensionKind::LegacyBang { .. } = ext.kind {
742-
return Some(res.map_id(|_| panic!("unexpected id")));
743-
}
744-
}
745-
if let Some(res) = resolver.all_macros().get(&Symbol::intern(path_str)) {
746-
return Some(res.map_id(|_| panic!("unexpected id")));
747-
}
748-
None
749-
})
750-
}
751-
752793
fn build_diagnostic(
753794
cx: &DocContext<'_>,
754795
item: &Item,
@@ -916,7 +957,7 @@ fn ambiguity_error(
916957
Res::Def(DefKind::AssocFn | DefKind::Fn, _) => {
917958
("add parentheses", format!("{}()", path_str))
918959
}
919-
Res::Def(DefKind::Macro(..), _) => {
960+
Res::Def(DefKind::Macro(MacroKind::Bang), _) => {
920961
("add an exclamation mark", format!("{}!", path_str))
921962
}
922963
_ => {
@@ -930,6 +971,9 @@ fn ambiguity_error(
930971
(Res::Def(DefKind::Mod, _), _) => "module",
931972
(_, TypeNS) => "type",
932973
(_, ValueNS) => "value",
974+
(Res::Def(DefKind::Macro(MacroKind::Derive), _), MacroNS) => {
975+
"derive"
976+
}
933977
(_, MacroNS) => "macro",
934978
};
935979

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// force-host
2+
// no-prefer-dynamic
3+
// compile-flags: --crate-type proc-macro
4+
5+
#![crate_type="proc-macro"]
6+
#![crate_name="intra_link_proc_macro_macro"]
7+
8+
extern crate proc_macro;
9+
10+
use proc_macro::TokenStream;
11+
12+
#[proc_macro_derive(DeriveA)]
13+
pub fn a_derive(input: TokenStream) -> TokenStream {
14+
input
15+
}
16+
17+
#[proc_macro_derive(DeriveB)]
18+
pub fn b_derive(input: TokenStream) -> TokenStream {
19+
input
20+
}
21+
22+
#[proc_macro_derive(DeriveTrait)]
23+
pub fn trait_derive(input: TokenStream) -> TokenStream {
24+
input
25+
}
26+
27+
#[proc_macro_attribute]
28+
pub fn attr_a(input: TokenStream, _args: TokenStream) -> TokenStream {
29+
input
30+
}
31+
32+
#[proc_macro_attribute]
33+
pub fn attr_b(input: TokenStream, _args: TokenStream) -> TokenStream {
34+
input
35+
}
+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// aux-build:intra-link-proc-macro-macro.rs
2+
// build-aux-docs
3+
#![deny(intra_doc_link_resolution_failure)]
4+
5+
extern crate intra_link_proc_macro_macro;
6+
7+
8+
pub use intra_link_proc_macro_macro::{DeriveA, attr_a};
9+
use intra_link_proc_macro_macro::{DeriveB, attr_b};
10+
11+
// @has intra_link_proc_macro/struct.Foo.html
12+
// @has - '//a/@href' '../intra_link_proc_macro/derive.DeriveA.html'
13+
// @has - '//a/@href' '../intra_link_proc_macro/attr.attr_a.html'
14+
// @has - '//a/@href' '../intra_link_proc_macro/trait.DeriveTrait.html'
15+
// @has - '//a/@href' '../intra_link_proc_macro_macro/derive.DeriveB.html'
16+
// @has - '//a/@href' '../intra_link_proc_macro_macro/attr.attr_b.html'
17+
/// Link to [DeriveA], [attr_a], [DeriveB], [attr_b], [DeriveTrait]
18+
pub struct Foo;
19+
20+
// @has intra_link_proc_macro/struct.Bar.html
21+
// @has - '//a/@href' '../intra_link_proc_macro/derive.DeriveA.html'
22+
// @has - '//a/@href' '../intra_link_proc_macro/attr.attr_a.html'
23+
/// Link to [deriveA](derive@DeriveA) [attr](macro@attr_a)
24+
pub struct Bar;
25+
26+
// this should not cause ambiguity errors
27+
pub trait DeriveTrait {}

0 commit comments

Comments
 (0)