From dee21a67b802ba9d8a0fac11369cbcd53552a216 Mon Sep 17 00:00:00 2001 From: Kang Seonghoon Date: Sun, 27 Apr 2014 05:05:45 +0900 Subject: [PATCH 1/2] syntax: `Mod` records the span for inner contents. this is useful when the module item and module contents are defined from different files (like rustdoc). in most cases the original span for the module item would be used; in other cases, the span for module contents is available separately at the `inner` field. --- src/librustc/front/config.rs | 1 + src/librustc/front/test.rs | 2 ++ src/libsyntax/ast.rs | 18 +++++++++++++++--- src/libsyntax/ext/build.rs | 5 +++-- src/libsyntax/fold.rs | 1 + src/libsyntax/parse/parser.rs | 17 ++++++++++++----- 6 files changed, 34 insertions(+), 10 deletions(-) diff --git a/src/librustc/front/config.rs b/src/librustc/front/config.rs index 8dcc97c936cbb..4fc33c2ad9b14 100644 --- a/src/librustc/front/config.rs +++ b/src/librustc/front/config.rs @@ -70,6 +70,7 @@ fn fold_mod(cx: &mut Context, m: &ast::Mod) -> ast::Mod { filter_view_item(cx, a).map(|x| cx.fold_view_item(x)) }).collect(); ast::Mod { + inner: m.inner, view_items: filtered_view_items, items: flattened_items } diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs index 72b63ebc80d54..685714cd74a5a 100644 --- a/src/librustc/front/test.rs +++ b/src/librustc/front/test.rs @@ -143,6 +143,7 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> { } let mod_nomain = ast::Mod { + inner: m.inner, view_items: m.view_items.clone(), items: m.items.iter().map(|i| nomain(&self.cx, *i)).collect(), }; @@ -335,6 +336,7 @@ fn mk_test_module(cx: &TestCtxt) -> @ast::Item { )).unwrap(); let testmod = ast::Mod { + inner: DUMMY_SP, view_items: view_items, items: vec!(mainfn, tests), }; diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index ccb25239f6ce4..3afc4b0e118bc 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -921,8 +921,12 @@ pub struct Method { #[deriving(Clone, Eq, TotalEq, Encodable, Decodable, Hash)] pub struct Mod { - pub view_items: Vec , - pub items: Vec<@Item> , + /// A span from the first token past `{` to the last token until `}`. + /// For `mod foo;`, the inner span ranges from the first token + /// to the last token in the external file. + pub inner: Span, + pub view_items: Vec, + pub items: Vec<@Item>, } #[deriving(Clone, Eq, TotalEq, Encodable, Decodable, Hash)] @@ -1165,7 +1169,15 @@ mod test { fn check_asts_encodable() { use std::io; let e = Crate { - module: Mod {view_items: Vec::new(), items: Vec::new()}, + module: Mod { + inner: Span { + lo: BytePos(11), + hi: BytePos(19), + expn_info: None, + }, + view_items: Vec::new(), + items: Vec::new(), + }, attrs: Vec::new(), config: Vec::new(), span: Span { diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 1a160cb33aa76..7e084ac263de4 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -220,7 +220,7 @@ pub trait AstBuilder { generics: Generics) -> @ast::Item; fn item_struct(&self, span: Span, name: Ident, struct_def: ast::StructDef) -> @ast::Item; - fn item_mod(&self, span: Span, + fn item_mod(&self, span: Span, inner_span: Span, name: Ident, attrs: Vec , vi: Vec , items: Vec<@ast::Item> ) -> @ast::Item; @@ -898,7 +898,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { self.item(span, name, Vec::new(), ast::ItemStruct(@struct_def, generics)) } - fn item_mod(&self, span: Span, name: Ident, + fn item_mod(&self, span: Span, inner_span: Span, name: Ident, attrs: Vec , vi: Vec , items: Vec<@ast::Item> ) -> @ast::Item { @@ -907,6 +907,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { name, attrs, ast::ItemMod(ast::Mod { + inner: inner_span, view_items: vi, items: items, }) diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index ae82a07601baf..1e21c0d09869c 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -654,6 +654,7 @@ pub fn noop_fold_type_method(m: &TypeMethod, fld: &mut T) -> TypeMeth pub fn noop_fold_mod(m: &Mod, folder: &mut T) -> Mod { ast::Mod { + inner: folder.new_span(m.inner), view_items: m.view_items .iter() .map(|x| folder.fold_view_item(x)).collect(), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 974077956d1c7..68dd38604d847 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4036,7 +4036,8 @@ impl<'a> Parser<'a> { // attributes (of length 0 or 1), parse all of the items in a module fn parse_mod_items(&mut self, term: token::Token, - first_item_attrs: Vec ) + first_item_attrs: Vec, + inner_lo: BytePos) -> Mod { // parse all of the items up to closing or an attribute. // view items are legal here. @@ -4081,7 +4082,11 @@ impl<'a> Parser<'a> { self.span_err(self.last_span, "expected item after attributes"); } - ast::Mod { view_items: view_items, items: items } + ast::Mod { + inner: mk_sp(inner_lo, self.span.lo), + view_items: view_items, + items: items + } } fn parse_item_const(&mut self) -> ItemInfo { @@ -4107,8 +4112,9 @@ impl<'a> Parser<'a> { } else { self.push_mod_path(id, outer_attrs); self.expect(&token::LBRACE); + let mod_inner_lo = self.span.lo; let (inner, next) = self.parse_inner_attrs_and_next(); - let m = self.parse_mod_items(token::RBRACE, next); + let m = self.parse_mod_items(token::RBRACE, next, mod_inner_lo); self.expect(&token::RBRACE); self.pop_mod_path(); (id, ItemMod(m), Some(inner)) @@ -4197,10 +4203,11 @@ impl<'a> Parser<'a> { self.cfg.clone(), &path, id_sp); + let mod_inner_lo = p0.span.lo; let (inner, next) = p0.parse_inner_attrs_and_next(); let mod_attrs = outer_attrs.append(inner.as_slice()); let first_item_outer_attrs = next; - let m0 = p0.parse_mod_items(token::EOF, first_item_outer_attrs); + let m0 = p0.parse_mod_items(token::EOF, first_item_outer_attrs, mod_inner_lo); self.sess.included_mod_stack.borrow_mut().pop(); return (ast::ItemMod(m0), mod_attrs); } @@ -5061,7 +5068,7 @@ impl<'a> Parser<'a> { let (inner, next) = self.parse_inner_attrs_and_next(); let first_item_outer_attrs = next; // parse the items inside the crate: - let m = self.parse_mod_items(token::EOF, first_item_outer_attrs); + let m = self.parse_mod_items(token::EOF, first_item_outer_attrs, lo); ast::Crate { module: m, From c8a29c4c595e76b71372a2e40d359ac1ddd8aec8 Mon Sep 17 00:00:00 2001 From: Kang Seonghoon Date: Sun, 27 Apr 2014 05:08:36 +0900 Subject: [PATCH 2/2] rustdoc: External module item links to the module contents. Fixes #12926. the basic strategy is to distinguish `mod foo;` from `mod foo {...}` by checking if the span for the module item and module contents is in different files. if it's the case, we prefer module contents. it is technically possible to fix #12926 without changing the AST, probably by checking the individual items' span. this is not without a problem though, since it is possible that some items inside `mod foo {...}` may have originated from other file (e.g. `include!`). therefore it is better to record both spans explicitly. --- src/librustdoc/clean.rs | 19 ++++++++++++++++++- src/librustdoc/doctree.rs | 6 ++++-- src/librustdoc/visit_ast.rs | 3 ++- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/clean.rs b/src/librustdoc/clean.rs index be05ccdfcb412..7007c31c67b29 100644 --- a/src/librustdoc/clean.rs +++ b/src/librustdoc/clean.rs @@ -223,10 +223,27 @@ impl Clean for doctree::Module { self.view_items.clean().move_iter().collect(), self.macros.clean().move_iter().collect() ); + + // determine if we should display the inner contents or + // the outer `mod` item for the source code. + let where = { + let ctxt = local_data::get(super::ctxtkey, |x| *x.unwrap()); + let cm = ctxt.sess().codemap(); + let outer = cm.lookup_char_pos(self.where_outer.lo); + let inner = cm.lookup_char_pos(self.where_inner.lo); + if outer.file.start_pos == inner.file.start_pos { + // mod foo { ... } + self.where_outer + } else { + // mod foo; (and a separate FileMap for the contents) + self.where_inner + } + }; + Item { name: Some(name), attrs: self.attrs.clean(), - source: self.where.clean(), + source: where.clean(), visibility: self.vis.clean(), id: self.id, inner: ModuleItem(Module { diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 1de53ecc68f3a..ac846482f9f26 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -19,7 +19,8 @@ use syntax::ast::{Ident, NodeId}; pub struct Module { pub name: Option, pub attrs: Vec, - pub where: Span, + pub where_outer: Span, + pub where_inner: Span, pub structs: Vec, pub enums: Vec, pub fns: Vec, @@ -42,7 +43,8 @@ impl Module { name : name, id: 0, vis: ast::Inherited, - where: syntax::codemap::DUMMY_SP, + where_outer: syntax::codemap::DUMMY_SP, + where_inner: syntax::codemap::DUMMY_SP, attrs : Vec::new(), structs : Vec::new(), enums : Vec::new(), diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 3fc65dd9647cd..f78fb4658c120 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -118,7 +118,8 @@ impl<'a> RustdocVisitor<'a> { for item in m.view_items.iter() { self.visit_view_item(item, &mut om); } - om.where = span; + om.where_outer = span; + om.where_inner = m.inner; om.attrs = attrs; om.vis = vis; om.id = id;