-
Notifications
You must be signed in to change notification settings - Fork 13.7k
Add new doc(attribute = "...")
attribute
#142472
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
Changes from all commits
ab0ee84
75cbd05
38e8963
10bd61d
f3c0234
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -145,6 +145,10 @@ passes_doc_alias_start_end = | |
passes_doc_attr_not_crate_level = | ||
`#![doc({$attr_name} = "...")]` isn't allowed as a crate-level attribute | ||
|
||
passes_doc_attribute_not_attribute = | ||
nonexistent builtin attribute `{$attribute}` used in `#[doc(attribute = "...")]` | ||
.help = only existing builtin attributes are allowed in core/std | ||
Comment on lines
+149
to
+150
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (minor) I'm not so keen on hard-coding There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I took the same format as the existing |
||
|
||
passes_doc_cfg_hide_takes_list = | ||
`#[doc(cfg_hide(...))]` takes a list of attributes | ||
|
||
|
@@ -173,16 +177,16 @@ passes_doc_inline_only_use = | |
passes_doc_invalid = | ||
invalid `doc` attribute | ||
|
||
passes_doc_keyword_empty_mod = | ||
`#[doc(keyword = "...")]` should be used on empty modules | ||
passes_doc_keyword_attribute_empty_mod = | ||
`#[doc({$attr_name} = "...")]` should be used on empty modules | ||
|
||
passes_doc_keyword_attribute_not_mod = | ||
`#[doc({$attr_name} = "...")]` should be used on modules | ||
|
||
passes_doc_keyword_not_keyword = | ||
nonexistent keyword `{$keyword}` used in `#[doc(keyword = "...")]` | ||
.help = only existing keywords are allowed in core/std | ||
|
||
passes_doc_keyword_not_mod = | ||
`#[doc(keyword = "...")]` should be used on modules | ||
|
||
passes_doc_keyword_only_impl = | ||
`#[doc(keyword = "...")]` should be used on impl blocks | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -99,6 +99,21 @@ impl IntoDiagArg for ProcMacroKind { | |
} | ||
} | ||
|
||
#[derive(Clone, Copy)] | ||
enum DocFakeItemKind { | ||
Attribute, | ||
Keyword, | ||
} | ||
|
||
impl DocFakeItemKind { | ||
fn name(self) -> &'static str { | ||
match self { | ||
Self::Attribute => "attribute", | ||
Self::Keyword => "keyword", | ||
} | ||
} | ||
} | ||
|
||
struct CheckAttrVisitor<'tcx> { | ||
tcx: TyCtxt<'tcx>, | ||
|
||
|
@@ -851,17 +866,27 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | |
} | ||
} | ||
|
||
fn check_doc_keyword(&self, meta: &MetaItemInner, hir_id: HirId) { | ||
fn check_doc_keyword_and_attribute( | ||
&self, | ||
meta: &MetaItemInner, | ||
hir_id: HirId, | ||
attr_kind: DocFakeItemKind, | ||
) { | ||
fn is_doc_keyword(s: Symbol) -> bool { | ||
// FIXME: Once rustdoc can handle URL conflicts on case insensitive file systems, we | ||
// can remove the `SelfTy` case here, remove `sym::SelfTy`, and update the | ||
// `#[doc(keyword = "SelfTy")` attribute in `library/std/src/keyword_docs.rs`. | ||
s.is_reserved(|| edition::LATEST_STABLE_EDITION) || s.is_weak() || s == sym::SelfTy | ||
} | ||
|
||
let doc_keyword = match meta.value_str() { | ||
// FIXME: This should support attributes with namespace like `diagnostic::do_not_recommend`. | ||
fn is_builtin_attr(s: Symbol) -> bool { | ||
rustc_feature::BUILTIN_ATTRIBUTE_MAP.contains_key(&s) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How does this interact with "attribute namespaces" (I'm not referring to attribute tools) like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unless I missed something, it's only supposed to be used on attributes provided "by default". Are there attributes with namespaces in this case? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, It doesn't matter to me if your PR doesn't support them, we can always do that in a follow-up, I'm just curious to know what happens if you put those inside There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Curious as well. Gonna add a test for it so we actually know. :) If not supported, gonna do that in a follow-up then. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not supported, added a |
||
} | ||
|
||
let value = match meta.value_str() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sigh, I'll put the doc attribute high up on my todo list to get a proper parser... (this is fine for now) |
||
Some(value) if value != sym::empty => value, | ||
_ => return self.doc_attr_str_error(meta, "keyword"), | ||
_ => return self.doc_attr_str_error(meta, attr_kind.name()), | ||
}; | ||
|
||
let item_kind = match self.tcx.hir_node(hir_id) { | ||
|
@@ -871,20 +896,38 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | |
match item_kind { | ||
Some(ItemKind::Mod(_, module)) => { | ||
if !module.item_ids.is_empty() { | ||
self.dcx().emit_err(errors::DocKeywordEmptyMod { span: meta.span() }); | ||
self.dcx().emit_err(errors::DocKeywordAttributeEmptyMod { | ||
span: meta.span(), | ||
attr_name: attr_kind.name(), | ||
}); | ||
return; | ||
} | ||
} | ||
_ => { | ||
self.dcx().emit_err(errors::DocKeywordNotMod { span: meta.span() }); | ||
self.dcx().emit_err(errors::DocKeywordAttributeNotMod { | ||
span: meta.span(), | ||
attr_name: attr_kind.name(), | ||
}); | ||
return; | ||
} | ||
} | ||
if !is_doc_keyword(doc_keyword) { | ||
self.dcx().emit_err(errors::DocKeywordNotKeyword { | ||
span: meta.name_value_literal_span().unwrap_or_else(|| meta.span()), | ||
keyword: doc_keyword, | ||
}); | ||
match attr_kind { | ||
DocFakeItemKind::Keyword => { | ||
if !is_doc_keyword(value) { | ||
self.dcx().emit_err(errors::DocKeywordNotKeyword { | ||
span: meta.name_value_literal_span().unwrap_or_else(|| meta.span()), | ||
keyword: value, | ||
}); | ||
} | ||
} | ||
DocFakeItemKind::Attribute => { | ||
if !is_builtin_attr(value) { | ||
self.dcx().emit_err(errors::DocAttributeNotAttribute { | ||
span: meta.name_value_literal_span().unwrap_or_else(|| meta.span()), | ||
attribute: value, | ||
}); | ||
} | ||
} | ||
} | ||
} | ||
|
||
|
@@ -1144,7 +1187,21 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | |
|
||
Some(sym::keyword) => { | ||
if self.check_attr_not_crate_level(meta, hir_id, "keyword") { | ||
self.check_doc_keyword(meta, hir_id); | ||
self.check_doc_keyword_and_attribute( | ||
meta, | ||
hir_id, | ||
DocFakeItemKind::Keyword, | ||
); | ||
} | ||
} | ||
|
||
Some(sym::attribute) => { | ||
if self.check_attr_not_crate_level(meta, hir_id, "attribute") { | ||
self.check_doc_keyword_and_attribute( | ||
meta, | ||
hir_id, | ||
DocFakeItemKind::Attribute, | ||
); | ||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -196,7 +196,7 @@ to enable. | |
|
||
### Document keywords | ||
|
||
This is for Rust compiler internal use only. | ||
This is for internal use in the std library. | ||
|
||
Rust keywords are documented in the standard library (look for `match` for example). | ||
|
||
|
@@ -211,6 +211,23 @@ To do so, the `#[doc(keyword = "...")]` attribute is used. Example: | |
mod empty_mod {} | ||
``` | ||
|
||
### Document builtin attributes | ||
|
||
This is for internal use in the std library. | ||
|
||
Rust builtin attributes are documented in the standard library (look for `repr` for example). | ||
|
||
To do so, the `#[doc(attribute = "...")]` attribute is used. Example: | ||
|
||
```rust | ||
#![feature(rustdoc_internals)] | ||
#![allow(internal_features)] | ||
|
||
/// Some documentation about the attribute. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How do we make sure this stays in sync with the compiler's view of attributes? Is the plan to keep this manual, or could we somehow generate this from for example rustc_attr_data_structures There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just like keywords: we can only check that the attribute is used on an existing one. If new ones are added, there is no check for that. We could add a tidy check for it though. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. that'd be nice |
||
#[doc(attribute = "repr")] | ||
mod empty_mod {} | ||
``` | ||
|
||
### Use the Rust logo as the crate logo | ||
|
||
This is for official Rust project use only. | ||
|