diff options
| author | QuietMisdreavus <grey@quietmisdreavus.net> | 2017-09-21 22:37:00 -0500 |
|---|---|---|
| committer | QuietMisdreavus <grey@quietmisdreavus.net> | 2017-11-21 15:46:49 -0600 |
| commit | f9f3611f5c2d8b88361cd67d06528ff1ae7876e9 (patch) | |
| tree | fc3739e05f0d3669da28533415e134b7a42a5138 /src/libsyntax/ext | |
| parent | f28df200260c89b2a0bdf942510e0f888c29a70d (diff) | |
| download | rust-f9f3611f5c2d8b88361cd67d06528ff1ae7876e9.tar.gz rust-f9f3611f5c2d8b88361cd67d06528ff1ae7876e9.zip | |
allow loading external files in documentation
Partial implementation of https://github.com/rust-lang/rfcs/pull/1990 (needs error reporting work) cc #44732
Diffstat (limited to 'src/libsyntax/ext')
| -rw-r--r-- | src/libsyntax/ext/base.rs | 2 | ||||
| -rw-r--r-- | src/libsyntax/ext/expand.rs | 88 |
2 files changed, 89 insertions, 1 deletions
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 0e05cce35e2..6c96692f719 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -665,6 +665,7 @@ pub struct ExtCtxt<'a> { pub parse_sess: &'a parse::ParseSess, pub ecfg: expand::ExpansionConfig<'a>, pub crate_root: Option<&'static str>, + pub root_path: PathBuf, pub resolver: &'a mut Resolver, pub resolve_err_count: usize, pub current_expansion: ExpansionData, @@ -680,6 +681,7 @@ impl<'a> ExtCtxt<'a> { parse_sess, ecfg, crate_root: None, + root_path: PathBuf::new(), resolver, resolve_err_count: 0, current_expansion: ExpansionData { diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 491dbed01f1..0d1b1c65a29 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -11,7 +11,7 @@ use ast::{self, Block, Ident, NodeId, PatKind, Path}; use ast::{MacStmtStyle, StmtKind, ItemKind}; use attr::{self, HasAttrs}; -use codemap::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute}; +use codemap::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute, dummy_spanned}; use config::{is_test_or_bench, StripUnconfigured}; use errors::FatalError; use ext::base::*; @@ -35,6 +35,8 @@ use util::small_vector::SmallVector; use visit::Visitor; use std::collections::HashMap; +use std::fs::File; +use std::io::Read; use std::mem; use std::rc::Rc; @@ -223,6 +225,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { directory: self.cx.codemap().span_to_unmapped_path(krate.span), }; module.directory.pop(); + self.cx.root_path = module.directory.clone(); self.cx.current_expansion.module = Rc::new(module); let orig_mod_span = krate.module.inner; @@ -843,6 +846,11 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { feature_gate::check_attribute(attr, self.cx.parse_sess, features); } } + + fn check_attribute(&mut self, at: &ast::Attribute) { + let features = self.cx.ecfg.features.unwrap(); + feature_gate::check_attribute(at, self.cx.parse_sess, features); + } } pub fn find_attr_invoc(attrs: &mut Vec<ast::Attribute>) -> Option<ast::Attribute> { @@ -1063,6 +1071,84 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { } } + fn fold_attribute(&mut self, at: ast::Attribute) -> Option<ast::Attribute> { + // turn `#[doc(include="filename")]` attributes into `#[doc(include(file="filename", + // contents="file contents")]` attributes + if !at.check_name("doc") { + return noop_fold_attribute(at, self); + } + + if let Some(list) = at.meta_item_list() { + if !list.iter().any(|it| it.check_name("include")) { + return noop_fold_attribute(at, self); + } + + let mut items = vec![]; + + for it in list { + if !it.check_name("include") { + items.push(noop_fold_meta_list_item(it, self)); + continue; + } + + if let Some(file) = it.value_str() { + let err_count = self.cx.parse_sess.span_diagnostic.err_count(); + self.check_attribute(&at); + if self.cx.parse_sess.span_diagnostic.err_count() > err_count { + // avoid loading the file if they haven't enabled the feature + return noop_fold_attribute(at, self); + } + + let mut buf = vec![]; + let filename = self.cx.root_path.join(file.to_string()); + + match File::open(&filename).and_then(|mut f| f.read_to_end(&mut buf)) { + Ok(..) => {} + Err(e) => { + self.cx.span_warn(at.span, + &format!("couldn't read {}: {}", + filename.display(), + e)); + } + } + + match String::from_utf8(buf) { + Ok(src) => { + let include_info = vec![ + dummy_spanned(ast::NestedMetaItemKind::MetaItem( + attr::mk_name_value_item_str("file".into(), + file))), + dummy_spanned(ast::NestedMetaItemKind::MetaItem( + attr::mk_name_value_item_str("contents".into(), + (&*src).into()))), + ]; + + items.push(dummy_spanned(ast::NestedMetaItemKind::MetaItem( + attr::mk_list_item("include".into(), include_info)))); + } + Err(_) => { + self.cx.span_warn(at.span, + &format!("{} wasn't a utf-8 file", + filename.display())); + } + } + } else { + items.push(noop_fold_meta_list_item(it, self)); + } + } + + let meta = attr::mk_list_item("doc".into(), items); + match at.style { + ast::AttrStyle::Inner => + Some(attr::mk_spanned_attr_inner(at.span, at.id, meta)), + ast::AttrStyle::Outer => + Some(attr::mk_spanned_attr_outer(at.span, at.id, meta)), + } + } else { + noop_fold_attribute(at, self) + } + } + fn new_id(&mut self, id: ast::NodeId) -> ast::NodeId { if self.monotonic { assert_eq!(id, ast::DUMMY_NODE_ID); |
