Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rustdoc: introduce the #[doc(keyword="")] attribute for documenting keywords #51140

Merged
merged 8 commits into from
Jun 5, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 13 additions & 9 deletions src/etc/htmldocck.py
Original file line number Diff line number Diff line change
Expand Up @@ -346,15 +346,19 @@ def check_tree_attr(tree, path, attr, pat, regexp):
def check_tree_text(tree, path, pat, regexp):
path = normalize_xpath(path)
ret = False
for e in tree.findall(path):
try:
value = flatten(e)
except KeyError:
continue
else:
ret = check_string(value, pat, regexp)
if ret:
break
try:
for e in tree.findall(path):
try:
value = flatten(e)
except KeyError:
continue
else:
ret = check_string(value, pat, regexp)
if ret:
break
except Exception as e:
print('Failed to get path "{}"'.format(path))
raise e
return ret


Expand Down
64 changes: 62 additions & 2 deletions src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use syntax::attr;
use syntax::codemap::{dummy_spanned, Spanned};
use syntax::feature_gate::UnstableFeatures;
use syntax::ptr::P;
use syntax::symbol::keywords;
use syntax::symbol::keywords::{self, Keyword};
use syntax::symbol::{Symbol, InternedString};
use syntax_pos::{self, DUMMY_SP, Pos, FileName};

Expand Down Expand Up @@ -54,6 +54,7 @@ use std::{mem, slice, vec};
use std::iter::{FromIterator, once};
use rustc_data_structures::sync::Lrc;
use std::rc::Rc;
use std::str::FromStr;
use std::cell::RefCell;
use std::sync::Arc;
use std::u32;
Expand Down Expand Up @@ -177,7 +178,7 @@ impl<'a, 'tcx, 'rcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx, 'rcx>
_ => unreachable!(),
}

let ExternalCrate { name, src, primitives, .. } = LOCAL_CRATE.clean(cx);
let ExternalCrate { name, src, primitives, keywords, .. } = LOCAL_CRATE.clean(cx);
{
let m = match module.inner {
ModuleItem(ref mut m) => m,
Expand All @@ -195,6 +196,18 @@ impl<'a, 'tcx, 'rcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx, 'rcx>
inner: PrimitiveItem(prim),
}
}));
m.items.extend(keywords.into_iter().map(|(def_id, kw, attrs)| {
Item {
source: Span::empty(),
name: Some(kw.clone()),
attrs: attrs,
visibility: Some(Public),
stability: get_stability(cx, def_id),
deprecation: get_deprecation(cx, def_id),
def_id,
inner: KeywordItem(kw),
}
}));
}

let mut access_levels = cx.access_levels.borrow_mut();
Expand All @@ -220,6 +233,7 @@ pub struct ExternalCrate {
pub src: FileName,
pub attrs: Attributes,
pub primitives: Vec<(DefId, PrimitiveType, Attributes)>,
pub keywords: Vec<(DefId, String, Attributes)>,
}

impl Clean<ExternalCrate> for CrateNum {
Expand Down Expand Up @@ -286,11 +300,53 @@ impl Clean<ExternalCrate> for CrateNum {
.filter_map(as_primitive).collect()
};

let as_keyword = |def: Def| {
if let Def::Mod(def_id) = def {
let attrs = cx.tcx.get_attrs(def_id).clean(cx);
let mut keyword = None;
for attr in attrs.lists("doc") {
if let Some(v) = attr.value_str() {
if attr.check_name("keyword") {
keyword = Keyword::from_str(&v.as_str()).ok()
.map(|x| x.name().to_string());
if keyword.is_some() {
break
}
// FIXME: should warn on unknown keywords?
}
}
}
return keyword.map(|p| (def_id, p, attrs));
}
None
};
let keywords = if root.is_local() {
cx.tcx.hir.krate().module.item_ids.iter().filter_map(|&id| {
let item = cx.tcx.hir.expect_item(id.id);
match item.node {
hir::ItemMod(_) => {
as_keyword(Def::Mod(cx.tcx.hir.local_def_id(id.id)))
}
hir::ItemUse(ref path, hir::UseKind::Single)
if item.vis == hir::Visibility::Public => {
as_keyword(path.def).map(|(_, prim, attrs)| {
(cx.tcx.hir.local_def_id(id.id), prim, attrs)
})
}
_ => None
}
}).collect()
} else {
cx.tcx.item_children(root).iter().map(|item| item.def)
.filter_map(as_keyword).collect()
};

ExternalCrate {
name: cx.tcx.crate_name(*self).to_string(),
src: krate_src,
attrs: cx.tcx.get_attrs(root).clean(cx),
primitives,
keywords,
}
}
}
Expand Down Expand Up @@ -397,6 +453,9 @@ impl Item {
pub fn is_extern_crate(&self) -> bool {
self.type_() == ItemType::ExternCrate
}
pub fn is_keyword(&self) -> bool {
self.type_() == ItemType::Keyword
}

pub fn is_stripped(&self) -> bool {
match self.inner { StrippedItem(..) => true, _ => false }
Expand Down Expand Up @@ -475,6 +534,7 @@ pub enum ItemEnum {
AssociatedTypeItem(Vec<TyParamBound>, Option<Type>),
/// An item that has been stripped by a rustdoc pass
StrippedItem(Box<ItemEnum>),
KeywordItem(String),
}

impl ItemEnum {
Expand Down
8 changes: 8 additions & 0 deletions src/librustdoc/html/item_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ pub enum ItemType {
AssociatedConst = 18,
Union = 19,
ForeignType = 20,
Keyword = 21,
}


Expand All @@ -50,6 +51,7 @@ pub enum NameSpace {
Type,
Value,
Macro,
Keyword,
}

impl<'a> From<&'a clean::Item> for ItemType {
Expand Down Expand Up @@ -83,6 +85,7 @@ impl<'a> From<&'a clean::Item> for ItemType {
clean::AssociatedConstItem(..) => ItemType::AssociatedConst,
clean::AssociatedTypeItem(..) => ItemType::AssociatedType,
clean::ForeignTypeItem => ItemType::ForeignType,
clean::KeywordItem(..) => ItemType::Keyword,
clean::StrippedItem(..) => unreachable!(),
}
}
Expand Down Expand Up @@ -131,6 +134,7 @@ impl ItemType {
ItemType::Constant => "constant",
ItemType::AssociatedConst => "associatedconstant",
ItemType::ForeignType => "foreigntype",
ItemType::Keyword => "keyword",
}
}

Expand Down Expand Up @@ -159,6 +163,8 @@ impl ItemType {
ItemType::AssociatedConst => NameSpace::Value,

ItemType::Macro => NameSpace::Macro,

ItemType::Keyword => NameSpace::Keyword,
}
}
}
Expand All @@ -172,13 +178,15 @@ impl fmt::Display for ItemType {
pub const NAMESPACE_TYPE: &'static str = "t";
pub const NAMESPACE_VALUE: &'static str = "v";
pub const NAMESPACE_MACRO: &'static str = "m";
pub const NAMESPACE_KEYWORD: &'static str = "k";

impl NameSpace {
pub fn to_static_str(&self) -> &'static str {
match *self {
NameSpace::Type => NAMESPACE_TYPE,
NameSpace::Value => NAMESPACE_VALUE,
NameSpace::Macro => NAMESPACE_MACRO,
NameSpace::Keyword => NAMESPACE_KEYWORD,
}
}
}
Expand Down
87 changes: 40 additions & 47 deletions src/librustdoc/html/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1541,6 +1541,7 @@ struct AllTypes {
typedefs: HashSet<ItemEntry>,
statics: HashSet<ItemEntry>,
constants: HashSet<ItemEntry>,
keywords: HashSet<ItemEntry>,
}

impl AllTypes {
Expand All @@ -1556,6 +1557,7 @@ impl AllTypes {
typedefs: HashSet::with_capacity(100),
statics: HashSet::with_capacity(100),
constants: HashSet::with_capacity(100),
keywords: HashSet::with_capacity(100),
}
}

Expand Down Expand Up @@ -2063,12 +2065,13 @@ impl<'a> fmt::Display for Item<'a> {
clean::StaticItem(..) | clean::ForeignStaticItem(..) => write!(fmt, "Static ")?,
clean::ConstantItem(..) => write!(fmt, "Constant ")?,
clean::ForeignTypeItem => write!(fmt, "Foreign Type ")?,
clean::KeywordItem(..) => write!(fmt, "Keyword ")?,
_ => {
// We don't generate pages for any other type.
unreachable!();
}
}
if !self.item.is_primitive() {
if !self.item.is_primitive() && !self.item.is_keyword() {
let cur = &self.cx.current;
let amt = if self.item.is_mod() { cur.len() - 1 } else { cur.len() };
for (i, component) in cur.iter().enumerate().take(amt) {
Expand Down Expand Up @@ -2126,6 +2129,7 @@ impl<'a> fmt::Display for Item<'a> {
item_static(fmt, self.cx, self.item, i),
clean::ConstantItem(ref c) => item_constant(fmt, self.cx, self.item, c),
clean::ForeignTypeItem => item_foreign_type(fmt, self.cx, self.item),
clean::KeywordItem(ref k) => item_keyword(fmt, self.cx, self.item, k),
_ => {
// We don't generate pages for any other type.
unreachable!();
Expand Down Expand Up @@ -2353,29 +2357,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context,
write!(w, "</table>")?;
}
curty = myty;
let (short, name) = match myty.unwrap() {
ItemType::ExternCrate |
ItemType::Import => ("reexports", "Re-exports"),
ItemType::Module => ("modules", "Modules"),
ItemType::Struct => ("structs", "Structs"),
ItemType::Union => ("unions", "Unions"),
ItemType::Enum => ("enums", "Enums"),
ItemType::Function => ("functions", "Functions"),
ItemType::Typedef => ("types", "Type Definitions"),
ItemType::Static => ("statics", "Statics"),
ItemType::Constant => ("constants", "Constants"),
ItemType::Trait => ("traits", "Traits"),
ItemType::Impl => ("impls", "Implementations"),
ItemType::TyMethod => ("tymethods", "Type Methods"),
ItemType::Method => ("methods", "Methods"),
ItemType::StructField => ("fields", "Struct Fields"),
ItemType::Variant => ("variants", "Variants"),
ItemType::Macro => ("macros", "Macros"),
ItemType::Primitive => ("primitives", "Primitive Types"),
ItemType::AssociatedType => ("associated-types", "Associated Types"),
ItemType::AssociatedConst => ("associated-consts", "Associated Constants"),
ItemType::ForeignType => ("foreign-types", "Foreign Types"),
};
let (short, name) = item_ty_to_strs(&myty.unwrap());
write!(w, "<h2 id='{id}' class='section-header'>\
<a href=\"#{id}\">{name}</a></h2>\n<table>",
id = derive_id(short.to_owned()), name = name)?;
Expand Down Expand Up @@ -4360,6 +4342,33 @@ fn sidebar_enum(fmt: &mut fmt::Formatter, it: &clean::Item,
Ok(())
}

fn item_ty_to_strs(ty: &ItemType) -> (&'static str, &'static str) {
match *ty {
ItemType::ExternCrate |
ItemType::Import => ("reexports", "Re-exports"),
ItemType::Module => ("modules", "Modules"),
ItemType::Struct => ("structs", "Structs"),
ItemType::Union => ("unions", "Unions"),
ItemType::Enum => ("enums", "Enums"),
ItemType::Function => ("functions", "Functions"),
ItemType::Typedef => ("types", "Type Definitions"),
ItemType::Static => ("statics", "Statics"),
ItemType::Constant => ("constants", "Constants"),
ItemType::Trait => ("traits", "Traits"),
ItemType::Impl => ("impls", "Implementations"),
ItemType::TyMethod => ("tymethods", "Type Methods"),
ItemType::Method => ("methods", "Methods"),
ItemType::StructField => ("fields", "Struct Fields"),
ItemType::Variant => ("variants", "Variants"),
ItemType::Macro => ("macros", "Macros"),
ItemType::Primitive => ("primitives", "Primitive Types"),
ItemType::AssociatedType => ("associated-types", "Associated Types"),
ItemType::AssociatedConst => ("associated-consts", "Associated Constants"),
ItemType::ForeignType => ("foreign-types", "Foreign Types"),
ItemType::Keyword => ("keywords", "Keywords"),
}
}

fn sidebar_module(fmt: &mut fmt::Formatter, _it: &clean::Item,
items: &[clean::Item]) -> fmt::Result {
let mut sidebar = String::new();
Expand All @@ -4379,29 +4388,7 @@ fn sidebar_module(fmt: &mut fmt::Formatter, _it: &clean::Item,
ItemType::TyMethod, ItemType::Method, ItemType::StructField, ItemType::Variant,
ItemType::AssociatedType, ItemType::AssociatedConst, ItemType::ForeignType] {
if items.iter().any(|it| !it.is_stripped() && it.type_() == myty) {
let (short, name) = match myty {
ItemType::ExternCrate |
ItemType::Import => ("reexports", "Re-exports"),
ItemType::Module => ("modules", "Modules"),
ItemType::Struct => ("structs", "Structs"),
ItemType::Union => ("unions", "Unions"),
ItemType::Enum => ("enums", "Enums"),
ItemType::Function => ("functions", "Functions"),
ItemType::Typedef => ("types", "Type Definitions"),
ItemType::Static => ("statics", "Statics"),
ItemType::Constant => ("constants", "Constants"),
ItemType::Trait => ("traits", "Traits"),
ItemType::Impl => ("impls", "Implementations"),
ItemType::TyMethod => ("tymethods", "Type Methods"),
ItemType::Method => ("methods", "Methods"),
ItemType::StructField => ("fields", "Struct Fields"),
ItemType::Variant => ("variants", "Variants"),
ItemType::Macro => ("macros", "Macros"),
ItemType::Primitive => ("primitives", "Primitive Types"),
ItemType::AssociatedType => ("associated-types", "Associated Types"),
ItemType::AssociatedConst => ("associated-consts", "Associated Constants"),
ItemType::ForeignType => ("foreign-types", "Foreign Types"),
};
let (short, name) = item_ty_to_strs(&myty);
sidebar.push_str(&format!("<li><a href=\"#{id}\">{name}</a></li>",
id = short,
name = name));
Expand Down Expand Up @@ -4462,6 +4449,12 @@ fn item_primitive(w: &mut fmt::Formatter, cx: &Context,
render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
}

fn item_keyword(w: &mut fmt::Formatter, cx: &Context,
it: &clean::Item,
_p: &str) -> fmt::Result {
document(w, cx, it)
}

const BASIC_KEYWORDS: &'static str = "rust, rustlang, rust-lang";

fn make_item_keywords(it: &clean::Item) -> String {
Expand Down
Loading