Convert librustdoc to use the new parsed representation
This commit is contained in:
parent
5590fc034c
commit
4429814412
4 changed files with 11 additions and 273 deletions
|
|
@ -7,7 +7,6 @@ use std::sync::Arc;
|
|||
use std::{fmt, mem, ops};
|
||||
|
||||
use itertools::Either;
|
||||
use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::thin_vec::{ThinVec, thin_vec};
|
||||
use rustc_hir as hir;
|
||||
|
|
@ -29,12 +28,6 @@ mod tests;
|
|||
#[cfg_attr(test, derive(PartialEq))]
|
||||
pub(crate) struct Cfg(CfgEntry);
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub(crate) struct InvalidCfgError {
|
||||
pub(crate) msg: &'static str,
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
/// Whether the configuration consists of just `Cfg` or `Not`.
|
||||
fn is_simple_cfg(cfg: &CfgEntry) -> bool {
|
||||
match cfg {
|
||||
|
|
@ -105,106 +98,6 @@ fn should_capitalize_first_letter(cfg: &CfgEntry) -> bool {
|
|||
}
|
||||
|
||||
impl Cfg {
|
||||
/// Parses a `MetaItemInner` into a `Cfg`.
|
||||
fn parse_nested(
|
||||
nested_cfg: &MetaItemInner,
|
||||
exclude: &FxHashSet<NameValueCfg>,
|
||||
) -> Result<Option<Cfg>, InvalidCfgError> {
|
||||
match nested_cfg {
|
||||
MetaItemInner::MetaItem(cfg) => Cfg::parse_without(cfg, exclude),
|
||||
MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => {
|
||||
Ok(Some(Cfg(CfgEntry::Bool(*b, DUMMY_SP))))
|
||||
}
|
||||
MetaItemInner::Lit(lit) => {
|
||||
Err(InvalidCfgError { msg: "unexpected literal", span: lit.span })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_without(
|
||||
cfg: &MetaItem,
|
||||
exclude: &FxHashSet<NameValueCfg>,
|
||||
) -> Result<Option<Cfg>, InvalidCfgError> {
|
||||
let name = match cfg.ident() {
|
||||
Some(ident) => ident.name,
|
||||
None => {
|
||||
return Err(InvalidCfgError {
|
||||
msg: "expected a single identifier",
|
||||
span: cfg.span,
|
||||
});
|
||||
}
|
||||
};
|
||||
match cfg.kind {
|
||||
MetaItemKind::Word => {
|
||||
if exclude.contains(&NameValueCfg::new(name)) {
|
||||
Ok(None)
|
||||
} else {
|
||||
Ok(Some(Cfg(CfgEntry::NameValue { name, value: None, span: DUMMY_SP })))
|
||||
}
|
||||
}
|
||||
MetaItemKind::NameValue(ref lit) => match lit.kind {
|
||||
LitKind::Str(value, _) => {
|
||||
if exclude.contains(&NameValueCfg::new_value(name, value)) {
|
||||
Ok(None)
|
||||
} else {
|
||||
Ok(Some(Cfg(CfgEntry::NameValue {
|
||||
name,
|
||||
value: Some(value),
|
||||
span: DUMMY_SP,
|
||||
})))
|
||||
}
|
||||
}
|
||||
_ => Err(InvalidCfgError {
|
||||
// FIXME: if the main #[cfg] syntax decided to support non-string literals,
|
||||
// this should be changed as well.
|
||||
msg: "value of cfg option should be a string literal",
|
||||
span: lit.span,
|
||||
}),
|
||||
},
|
||||
MetaItemKind::List(ref items) => {
|
||||
let orig_len = items.len();
|
||||
let mut sub_cfgs =
|
||||
items.iter().filter_map(|i| Cfg::parse_nested(i, exclude).transpose());
|
||||
let ret = match name {
|
||||
sym::all => {
|
||||
sub_cfgs.try_fold(Cfg(CfgEntry::Bool(true, DUMMY_SP)), |x, y| Ok(x & y?))
|
||||
}
|
||||
sym::any => {
|
||||
sub_cfgs.try_fold(Cfg(CfgEntry::Bool(false, DUMMY_SP)), |x, y| Ok(x | y?))
|
||||
}
|
||||
sym::not => {
|
||||
if orig_len == 1 {
|
||||
let mut sub_cfgs = sub_cfgs.collect::<Vec<_>>();
|
||||
if sub_cfgs.len() == 1 {
|
||||
Ok(!sub_cfgs.pop().unwrap()?)
|
||||
} else {
|
||||
return Ok(None);
|
||||
}
|
||||
} else {
|
||||
Err(InvalidCfgError { msg: "expected 1 cfg-pattern", span: cfg.span })
|
||||
}
|
||||
}
|
||||
_ => Err(InvalidCfgError { msg: "invalid predicate", span: cfg.span }),
|
||||
};
|
||||
match ret {
|
||||
Ok(c) => Ok(Some(c)),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Parses a `MetaItem` into a `Cfg`.
|
||||
///
|
||||
/// The `MetaItem` should be the content of the `#[cfg(...)]`, e.g., `unix` or
|
||||
/// `target_os = "redox"`.
|
||||
///
|
||||
/// If the content is not properly formatted, it will return an error indicating what and where
|
||||
/// the error is.
|
||||
pub(crate) fn parse(cfg: &MetaItemInner) -> Result<Cfg, InvalidCfgError> {
|
||||
Self::parse_nested(cfg, &FxHashSet::default()).map(|ret| ret.unwrap())
|
||||
}
|
||||
|
||||
/// Renders the configuration for human display, as a short HTML description.
|
||||
pub(crate) fn render_short_html(&self) -> String {
|
||||
let mut msg = Display(&self.0, Format::ShortHtml).to_string();
|
||||
|
|
@ -644,10 +537,6 @@ impl NameValueCfg {
|
|||
fn new(name: Symbol) -> Self {
|
||||
Self { name, value: None }
|
||||
}
|
||||
|
||||
fn new_value(name: Symbol, value: Symbol) -> Self {
|
||||
Self { name, value: Some(value) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a CfgEntry> for NameValueCfg {
|
||||
|
|
@ -751,15 +640,6 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator<Item = &'a hir::Attribute>
|
|||
tcx: TyCtxt<'_>,
|
||||
cfg_info: &mut CfgInfo,
|
||||
) -> Option<Arc<Cfg>> {
|
||||
fn single<T: IntoIterator>(it: T) -> Option<T::Item> {
|
||||
let mut iter = it.into_iter();
|
||||
let item = iter.next()?;
|
||||
if iter.next().is_some() {
|
||||
return None;
|
||||
}
|
||||
Some(item)
|
||||
}
|
||||
|
||||
fn check_changed_auto_active_status(
|
||||
changed_auto_active_status: &mut Option<rustc_span::Span>,
|
||||
attr_span: Span,
|
||||
|
|
@ -859,12 +739,11 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator<Item = &'a hir::Attribute>
|
|||
}
|
||||
continue;
|
||||
} else if !cfg_info.parent_is_doc_cfg
|
||||
&& let Some(name) = attr.name()
|
||||
&& matches!(name, sym::cfg | sym::cfg_trace)
|
||||
&& let Some(attr) = single(attr.meta_item_list()?)
|
||||
&& let Ok(new_cfg) = Cfg::parse(&attr)
|
||||
&& let hir::Attribute::Parsed(AttributeKind::CfgTrace(cfgs)) = attr
|
||||
{
|
||||
cfg_info.current_cfg &= new_cfg;
|
||||
for (new_cfg, _) in cfgs {
|
||||
cfg_info.current_cfg &= Cfg(new_cfg.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
use rustc_ast::ast::LitIntType;
|
||||
use rustc_ast::{MetaItemInner, MetaItemLit, Path, Safety, StrStyle};
|
||||
use rustc_data_structures::thin_vec::thin_vec;
|
||||
use rustc_hir::attrs::CfgEntry;
|
||||
use rustc_span::symbol::{Ident, kw};
|
||||
use rustc_span::{DUMMY_SP, create_default_session_globals_then};
|
||||
|
||||
use super::*;
|
||||
|
|
@ -28,10 +25,6 @@ fn name_value_cfg_e(name: &str, value: &str) -> CfgEntry {
|
|||
}
|
||||
}
|
||||
|
||||
fn dummy_lit(symbol: Symbol, kind: LitKind) -> MetaItemInner {
|
||||
MetaItemInner::Lit(MetaItemLit { symbol, suffix: None, kind, span: DUMMY_SP })
|
||||
}
|
||||
|
||||
fn cfg_all(v: ThinVec<CfgEntry>) -> Cfg {
|
||||
Cfg(cfg_all_e(v))
|
||||
}
|
||||
|
|
@ -52,51 +45,6 @@ fn cfg_not(v: CfgEntry) -> Cfg {
|
|||
Cfg(CfgEntry::Not(Box::new(v), DUMMY_SP))
|
||||
}
|
||||
|
||||
fn dummy_meta_item_word(name: &str) -> MetaItemInner {
|
||||
MetaItemInner::MetaItem(MetaItem {
|
||||
unsafety: Safety::Default,
|
||||
path: Path::from_ident(Ident::from_str(name)),
|
||||
kind: MetaItemKind::Word,
|
||||
span: DUMMY_SP,
|
||||
})
|
||||
}
|
||||
|
||||
fn dummy_meta_item_name_value(name: &str, symbol: Symbol, kind: LitKind) -> MetaItemInner {
|
||||
let lit = MetaItemLit { symbol, suffix: None, kind, span: DUMMY_SP };
|
||||
MetaItemInner::MetaItem(MetaItem {
|
||||
unsafety: Safety::Default,
|
||||
path: Path::from_ident(Ident::from_str(name)),
|
||||
kind: MetaItemKind::NameValue(lit),
|
||||
span: DUMMY_SP,
|
||||
})
|
||||
}
|
||||
|
||||
macro_rules! dummy_meta_item_list {
|
||||
($name:ident, [$($list:ident),* $(,)?]) => {
|
||||
MetaItemInner::MetaItem(MetaItem {
|
||||
unsafety: Safety::Default,
|
||||
path: Path::from_ident(Ident::from_str(stringify!($name))),
|
||||
kind: MetaItemKind::List(thin_vec![
|
||||
$(
|
||||
dummy_meta_item_word(stringify!($list)),
|
||||
)*
|
||||
]),
|
||||
span: DUMMY_SP,
|
||||
})
|
||||
};
|
||||
|
||||
($name:ident, [$($list:expr),* $(,)?]) => {
|
||||
MetaItemInner::MetaItem(MetaItem {
|
||||
unsafety: Safety::Default,
|
||||
path: Path::from_ident(Ident::from_str(stringify!($name))),
|
||||
kind: MetaItemKind::List(thin_vec![
|
||||
$($list,)*
|
||||
]),
|
||||
span: DUMMY_SP,
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
fn cfg_true() -> Cfg {
|
||||
Cfg(CfgEntry::Bool(true, DUMMY_SP))
|
||||
}
|
||||
|
|
@ -303,87 +251,6 @@ fn test_cfg_or() {
|
|||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_ok() {
|
||||
create_default_session_globals_then(|| {
|
||||
let r#true = Symbol::intern("true");
|
||||
let mi = dummy_lit(r#true, LitKind::Bool(true));
|
||||
assert_eq!(Cfg::parse(&mi), Ok(cfg_true()));
|
||||
|
||||
let r#false = Symbol::intern("false");
|
||||
let mi = dummy_lit(r#false, LitKind::Bool(false));
|
||||
assert_eq!(Cfg::parse(&mi), Ok(cfg_false()));
|
||||
|
||||
let mi = dummy_meta_item_word("all");
|
||||
assert_eq!(Cfg::parse(&mi), Ok(word_cfg("all")));
|
||||
|
||||
let done = Symbol::intern("done");
|
||||
let mi = dummy_meta_item_name_value("all", done, LitKind::Str(done, StrStyle::Cooked));
|
||||
assert_eq!(Cfg::parse(&mi), Ok(name_value_cfg("all", "done")));
|
||||
|
||||
let mi = dummy_meta_item_list!(all, [a, b]);
|
||||
assert_eq!(Cfg::parse(&mi), Ok(word_cfg("a") & word_cfg("b")));
|
||||
|
||||
let mi = dummy_meta_item_list!(any, [a, b]);
|
||||
assert_eq!(Cfg::parse(&mi), Ok(word_cfg("a") | word_cfg("b")));
|
||||
|
||||
let mi = dummy_meta_item_list!(not, [a]);
|
||||
assert_eq!(Cfg::parse(&mi), Ok(!word_cfg("a")));
|
||||
|
||||
let mi = dummy_meta_item_list!(
|
||||
not,
|
||||
[dummy_meta_item_list!(
|
||||
any,
|
||||
[dummy_meta_item_word("a"), dummy_meta_item_list!(all, [b, c]),]
|
||||
),]
|
||||
);
|
||||
assert_eq!(Cfg::parse(&mi), Ok(!(word_cfg("a") | (word_cfg("b") & word_cfg("c")))));
|
||||
|
||||
let mi = dummy_meta_item_list!(all, [a, b, c]);
|
||||
assert_eq!(Cfg::parse(&mi), Ok(word_cfg("a") & word_cfg("b") & word_cfg("c")));
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_err() {
|
||||
create_default_session_globals_then(|| {
|
||||
let mi = dummy_meta_item_name_value("foo", kw::False, LitKind::Bool(false));
|
||||
assert!(Cfg::parse(&mi).is_err());
|
||||
|
||||
let mi = dummy_meta_item_list!(not, [a, b]);
|
||||
assert!(Cfg::parse(&mi).is_err());
|
||||
|
||||
let mi = dummy_meta_item_list!(not, []);
|
||||
assert!(Cfg::parse(&mi).is_err());
|
||||
|
||||
let mi = dummy_meta_item_list!(foo, []);
|
||||
assert!(Cfg::parse(&mi).is_err());
|
||||
|
||||
let mi = dummy_meta_item_list!(
|
||||
all,
|
||||
[dummy_meta_item_list!(foo, []), dummy_meta_item_word("b"),]
|
||||
);
|
||||
assert!(Cfg::parse(&mi).is_err());
|
||||
|
||||
let mi = dummy_meta_item_list!(
|
||||
any,
|
||||
[dummy_meta_item_word("a"), dummy_meta_item_list!(foo, []),]
|
||||
);
|
||||
assert!(Cfg::parse(&mi).is_err());
|
||||
|
||||
let mi = dummy_meta_item_list!(not, [dummy_meta_item_list!(foo, []),]);
|
||||
assert!(Cfg::parse(&mi).is_err());
|
||||
|
||||
let c = Symbol::intern("e");
|
||||
let mi = dummy_lit(c, LitKind::Char('e'));
|
||||
assert!(Cfg::parse(&mi).is_err());
|
||||
|
||||
let five = Symbol::intern("5");
|
||||
let mi = dummy_lit(five, LitKind::Int(5.into(), LitIntType::Unsuffixed));
|
||||
assert!(Cfg::parse(&mi).is_err());
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_render_short_html() {
|
||||
create_default_session_globals_then(|| {
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ use rustc_middle::ty::{self, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeVisitableE
|
|||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_span::ExpnKind;
|
||||
use rustc_span::hygiene::{AstPass, MacroKind};
|
||||
use rustc_span::symbol::{Ident, Symbol, kw, sym};
|
||||
use rustc_span::symbol::{Ident, Symbol, kw};
|
||||
use rustc_trait_selection::traits::wf::object_region_bounds;
|
||||
use tracing::{debug, instrument};
|
||||
use utils::*;
|
||||
|
|
@ -2682,17 +2682,13 @@ fn add_without_unwanted_attributes<'hir>(
|
|||
import_parent,
|
||||
));
|
||||
}
|
||||
hir::Attribute::Unparsed(normal) if let [name] = &*normal.path.segments => {
|
||||
if is_inline || *name != sym::cfg_trace {
|
||||
// If it's not a `cfg()` attribute, we keep it.
|
||||
attrs.push((Cow::Borrowed(attr), import_parent));
|
||||
}
|
||||
}
|
||||
// FIXME: make sure to exclude `#[cfg_trace]` here when it is ported to the new parsers
|
||||
hir::Attribute::Parsed(..) => {
|
||||
|
||||
// We discard `#[cfg(...)]` attributes unless we're inlining
|
||||
hir::Attribute::Parsed(AttributeKind::CfgTrace(..)) if !is_inline => {}
|
||||
// We keep all other attributes
|
||||
_ => {
|
||||
attrs.push((Cow::Borrowed(attr), import_parent));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
use rustc_hir::Attribute;
|
||||
use rustc_hir::attrs::{AttributeKind, DocAttribute};
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
use crate::clean::inline::{load_attrs, merge_attrs};
|
||||
use crate::clean::{CfgInfo, Crate, Item, ItemKind};
|
||||
|
|
@ -39,10 +38,7 @@ fn add_only_cfg_attributes(attrs: &mut Vec<Attribute>, new_attrs: &[Attribute])
|
|||
let mut new_attr = DocAttribute::default();
|
||||
new_attr.cfg = d.cfg.clone();
|
||||
attrs.push(Attribute::Parsed(AttributeKind::Doc(Box::new(new_attr))));
|
||||
} else if let Attribute::Unparsed(normal) = attr
|
||||
&& let [name] = &*normal.path.segments
|
||||
&& *name == sym::cfg_trace
|
||||
{
|
||||
} else if let Attribute::Parsed(AttributeKind::CfgTrace(..)) = attr {
|
||||
// If it's a `cfg()` attribute, we keep it.
|
||||
attrs.push(attr.clone());
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue