Auto merge of #51611 - QuietMisdreavus:slippery-macros, r=ollie27
rustdoc: import cross-crate macros alongside everything else The thrilling conclusion of the cross-crate macro saga in rustdoc! After https://github.com/rust-lang/rust/pull/51425 made sure we saw all the namespaces of an import (and prevented us from losing the `vec!` macro in std's documentation), here is the PR to handle cross-crate macro re-exports at the same time as everything else. This way, attributes like `#[doc(hidden)]` and `#[doc(no_inline)]` can be used to control how the documentation for these macros is seen, rather than rustdoc inlining every macro every time. Fixes https://github.com/rust-lang/rust/issues/50647
This commit is contained in:
commit
4af9132a02
@ -13,16 +13,19 @@
|
||||
use std::iter::once;
|
||||
|
||||
use syntax::ast;
|
||||
use rustc::hir;
|
||||
use syntax::ext::base::MacroKind;
|
||||
use syntax_pos::Span;
|
||||
|
||||
use rustc::hir;
|
||||
use rustc::hir::def::{Def, CtorKind};
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::middle::cstore::LoadedMacro;
|
||||
use rustc::ty;
|
||||
use rustc::util::nodemap::FxHashSet;
|
||||
|
||||
use core::{DocContext, DocAccessLevels};
|
||||
use doctree;
|
||||
use clean::{self, GetDefId, get_auto_traits_with_def_id};
|
||||
use clean::{self, GetDefId, ToSource, get_auto_traits_with_def_id};
|
||||
|
||||
use super::Clean;
|
||||
|
||||
@ -97,9 +100,12 @@ pub fn try_inline(cx: &DocContext, def: Def, name: ast::Name, visited: &mut FxHa
|
||||
record_extern_fqn(cx, did, clean::TypeKind::Const);
|
||||
clean::ConstantItem(build_const(cx, did))
|
||||
}
|
||||
// Macros are eagerly inlined back in visit_ast, don't show their export statements
|
||||
// FIXME(50647): the eager inline does not take doc(hidden)/doc(no_inline) into account
|
||||
Def::Macro(..) => return Some(Vec::new()),
|
||||
// FIXME(misdreavus): if attributes/derives come down here we should probably document them
|
||||
// separately
|
||||
Def::Macro(did, MacroKind::Bang) => {
|
||||
record_extern_fqn(cx, did, clean::TypeKind::Macro);
|
||||
clean::MacroItem(build_macro(cx, did, name))
|
||||
}
|
||||
_ => return None,
|
||||
};
|
||||
cx.renderinfo.borrow_mut().inlined.insert(did);
|
||||
@ -460,6 +466,33 @@ fn build_static(cx: &DocContext, did: DefId, mutable: bool) -> clean::Static {
|
||||
}
|
||||
}
|
||||
|
||||
fn build_macro(cx: &DocContext, did: DefId, name: ast::Name) -> clean::Macro {
|
||||
let imported_from = cx.tcx.original_crate_name(did.krate);
|
||||
let def = match cx.cstore.load_macro_untracked(did, cx.sess()) {
|
||||
LoadedMacro::MacroDef(macro_def) => macro_def,
|
||||
// FIXME(jseyfried): document proc macro re-exports
|
||||
LoadedMacro::ProcMacro(..) => panic!("attempting to document proc-macro re-export"),
|
||||
};
|
||||
|
||||
let matchers: hir::HirVec<Span> = if let ast::ItemKind::MacroDef(ref def) = def.node {
|
||||
let tts: Vec<_> = def.stream().into_trees().collect();
|
||||
tts.chunks(4).map(|arm| arm[0].span()).collect()
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
let source = format!("macro_rules! {} {{\n{}}}",
|
||||
name.clean(cx),
|
||||
matchers.iter().map(|span| {
|
||||
format!(" {} => {{ ... }};\n", span.to_src(cx))
|
||||
}).collect::<String>());
|
||||
|
||||
clean::Macro {
|
||||
source,
|
||||
imported_from: Some(imported_from).clean(cx),
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait's generics clause actually contains all of the predicates for all of
|
||||
/// its associated types as well. We specifically move these clauses to the
|
||||
/// associated types instead when displaying, so when we're generating the
|
||||
|
@ -21,9 +21,8 @@ use syntax_pos::{self, Span};
|
||||
use rustc::hir::map as hir_map;
|
||||
use rustc::hir::def::Def;
|
||||
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
|
||||
use rustc::middle::cstore::{LoadedMacro, CrateStore};
|
||||
use rustc::middle::cstore::CrateStore;
|
||||
use rustc::middle::privacy::AccessLevel;
|
||||
use rustc::ty::Visibility;
|
||||
use rustc::util::nodemap::{FxHashSet, FxHashMap};
|
||||
|
||||
use rustc::hir;
|
||||
@ -212,44 +211,6 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> {
|
||||
self.visit_item(item, None, &mut om);
|
||||
}
|
||||
self.inside_public_path = orig_inside_public_path;
|
||||
let def_id = self.cx.tcx.hir.local_def_id(id);
|
||||
if let Some(exports) = self.cx.tcx.module_exports(def_id) {
|
||||
for export in exports.iter().filter(|e| e.vis == Visibility::Public) {
|
||||
if let Def::Macro(def_id, ..) = export.def {
|
||||
// FIXME(50647): this eager macro inlining does not take
|
||||
// doc(hidden)/doc(no_inline) into account
|
||||
if def_id.krate == LOCAL_CRATE {
|
||||
continue // These are `krate.exported_macros`, handled in `self.visit()`.
|
||||
}
|
||||
|
||||
let imported_from = self.cx.tcx.original_crate_name(def_id.krate);
|
||||
let def = match self.cstore.load_macro_untracked(def_id, self.cx.sess()) {
|
||||
LoadedMacro::MacroDef(macro_def) => macro_def,
|
||||
// FIXME(jseyfried): document proc macro re-exports
|
||||
LoadedMacro::ProcMacro(..) => continue,
|
||||
};
|
||||
|
||||
let matchers = if let ast::ItemKind::MacroDef(ref def) = def.node {
|
||||
let tts: Vec<_> = def.stream().into_trees().collect();
|
||||
tts.chunks(4).map(|arm| arm[0].span()).collect()
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
debug!("inlining macro {}", def.ident.name);
|
||||
om.macros.push(Macro {
|
||||
def_id,
|
||||
attrs: def.attrs.clone().into(),
|
||||
name: def.ident.name,
|
||||
whence: self.cx.tcx.def_span(def_id),
|
||||
matchers,
|
||||
stab: self.cx.tcx.lookup_stability(def_id).cloned(),
|
||||
depr: self.cx.tcx.lookup_deprecation(def_id),
|
||||
imported_from: Some(imported_from),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
om
|
||||
}
|
||||
|
||||
|
@ -66,6 +66,6 @@ pub use all_item_types::FOO_STATIC;
|
||||
#[doc(no_inline)]
|
||||
pub use all_item_types::FOO_CONSTANT;
|
||||
|
||||
// @has 'foo/index.html' '//a[@href="../foo/macro.foo_macro.html"]' 'foo_macro'
|
||||
// @has 'foo/index.html' '//a[@href="../all_item_types/macro.foo_macro.html"]' 'foo_macro'
|
||||
#[doc(no_inline)]
|
||||
pub use all_item_types::foo_macro;
|
||||
|
35
src/test/rustdoc/inline_cross/auxiliary/macro-vis.rs
Normal file
35
src/test/rustdoc/inline_cross/auxiliary/macro-vis.rs
Normal file
@ -0,0 +1,35 @@
|
||||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![crate_name = "qwop"]
|
||||
|
||||
/// (writen on a spider's web) Some Macro
|
||||
#[macro_export]
|
||||
macro_rules! some_macro {
|
||||
() => {
|
||||
println!("this is some macro, for sure");
|
||||
};
|
||||
}
|
||||
|
||||
/// Some other macro, to fill space.
|
||||
#[macro_export]
|
||||
macro_rules! other_macro {
|
||||
() => {
|
||||
println!("this is some other macro, whatev");
|
||||
};
|
||||
}
|
||||
|
||||
/// This macro is so cool, it's Super.
|
||||
#[macro_export]
|
||||
macro_rules! super_macro {
|
||||
() => {
|
||||
println!("is it a bird? a plane? no, it's Super Macro!");
|
||||
};
|
||||
}
|
48
src/test/rustdoc/inline_cross/macro-vis.rs
Normal file
48
src/test/rustdoc/inline_cross/macro-vis.rs
Normal file
@ -0,0 +1,48 @@
|
||||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// aux-build:macro-vis.rs
|
||||
// build-aux-docs
|
||||
// ignore-cross-compile
|
||||
|
||||
#![feature(use_extern_macros)]
|
||||
|
||||
#[macro_use] extern crate qwop;
|
||||
|
||||
// @has macro_vis/macro.some_macro.html
|
||||
// @has macro_vis/index.html '//a/@href' 'macro.some_macro.html'
|
||||
pub use qwop::some_macro;
|
||||
|
||||
// @has macro_vis/macro.renamed_macro.html
|
||||
// @!has - '//pre' 'some_macro'
|
||||
// @has macro_vis/index.html '//a/@href' 'macro.renamed_macro.html'
|
||||
#[doc(inline)]
|
||||
pub use qwop::some_macro as renamed_macro;
|
||||
|
||||
// @!has macro_vis/macro.other_macro.html
|
||||
// @!has macro_vis/index.html '//a/@href' 'macro.other_macro.html'
|
||||
// @!has - '//code' 'pub use qwop::other_macro;'
|
||||
#[doc(hidden)]
|
||||
pub use qwop::other_macro;
|
||||
|
||||
// @has macro_vis/index.html '//code' 'pub use qwop::super_macro;'
|
||||
// @!has macro_vis/macro.super_macro.html
|
||||
#[doc(no_inline)]
|
||||
pub use qwop::super_macro;
|
||||
|
||||
// @has macro_vis/macro.this_is_dope.html
|
||||
// @has macro_vis/index.html '//a/@href' 'macro.this_is_dope.html'
|
||||
/// What it says on the tin.
|
||||
#[macro_export]
|
||||
macro_rules! this_is_dope {
|
||||
() => {
|
||||
println!("yo check this out");
|
||||
};
|
||||
}
|
@ -23,7 +23,7 @@ pub use macros::bar;
|
||||
#[doc(inline)]
|
||||
pub use macros::baz;
|
||||
|
||||
// @has pub_use_extern_macros/macro.quux.html
|
||||
// @!has pub_use_extern_macros/macro.quux.html
|
||||
// @!has pub_use_extern_macros/index.html '//code' 'pub use macros::quux;'
|
||||
#[doc(hidden)]
|
||||
pub use macros::quux;
|
||||
|
Loading…
Reference in New Issue
Block a user