diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index 216a575f2fb2b..a42880b2d36c7 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -227,3 +227,9 @@ pub static tag_region_param_def_index: uint = 0x94; pub static tag_unboxed_closures: uint = 0x95; pub static tag_unboxed_closure: uint = 0x96; pub static tag_unboxed_closure_type: uint = 0x97; + +pub static tag_struct_fields: uint = 0x98; +pub static tag_struct_field: uint = 0x99; +pub static tag_struct_field_id: uint = 0x9a; + +pub static tag_attribute_is_sugared_doc: uint = 0x9b; diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index 0adc8e915c679..b1b366ec03090 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -29,6 +29,8 @@ use syntax::attr; use syntax::diagnostic::expect; use syntax::parse::token; +use std::collections::hashmap::HashMap; + pub struct StaticMethodInfo { pub ident: ast::Ident, pub def_id: ast::DefId, @@ -192,6 +194,12 @@ pub fn get_struct_fields(cstore: &cstore::CStore, decoder::get_struct_fields(cstore.intr.clone(), &*cdata, def.node) } +pub fn get_struct_field_attrs(cstore: &cstore::CStore, def: ast::DefId) -> HashMap> { + let cdata = cstore.get_crate_data(def.krate); + decoder::get_struct_field_attrs(&*cdata) +} + pub fn get_type(tcx: &ty::ctxt, def: ast::DefId) -> ty::Polytype { diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 094e83d2a4770..f7576ffb4818b 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -34,6 +34,7 @@ use std::hash::Hash; use std::hash; use std::io::extensions::u64_from_be_bytes; use std::io; +use std::collections::hashmap::HashMap; use std::rc::Rc; use std::u64; use serialize::ebml::reader; @@ -963,6 +964,19 @@ pub fn get_item_attrs(cdata: Cmd, f(get_attributes(item)); } +pub fn get_struct_field_attrs(cdata: Cmd) -> HashMap> { + let data = ebml::Doc::new(cdata.data()); + let fields = reader::get_doc(data, tag_struct_fields); + let mut map = HashMap::new(); + reader::tagged_docs(fields, tag_struct_field, |field| { + let id = reader::doc_as_u32(reader::get_doc(field, tag_struct_field_id)); + let attrs = get_attributes(field); + map.insert(id, attrs); + true + }); + map +} + fn struct_field_family_to_visibility(family: Family) -> ast::Visibility { match family { PublicField => ast::Public, @@ -1042,6 +1056,9 @@ fn get_attributes(md: ebml::Doc) -> Vec { match reader::maybe_get_doc(md, tag_attributes) { Some(attrs_d) => { reader::tagged_docs(attrs_d, tag_attribute, |attr_doc| { + let is_sugared_doc = reader::doc_as_u8( + reader::get_doc(attr_doc, tag_attribute_is_sugared_doc) + ) == 1; let meta_items = get_meta_items(attr_doc); // Currently it's only possible to have a single meta item on // an attribute @@ -1053,7 +1070,7 @@ fn get_attributes(md: ebml::Doc) -> Vec { id: attr::mk_attr_id(), style: ast::AttrOuter, value: meta_item, - is_sugared_doc: false, + is_sugared_doc: is_sugared_doc, }, span: codemap::DUMMY_SP }); diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 7997af1ee5e11..6665e913e192f 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -1490,6 +1490,7 @@ fn encode_attributes(ebml_w: &mut Encoder, attrs: &[Attribute]) { ebml_w.start_tag(tag_attributes); for attr in attrs.iter() { ebml_w.start_tag(tag_attribute); + ebml_w.wr_tagged_u8(tag_attribute_is_sugared_doc, attr.node.is_sugared_doc as u8); encode_meta_item(ebml_w, attr.node.value); ebml_w.end_tag(); } @@ -1644,6 +1645,29 @@ fn encode_unboxed_closures<'a>( ebml_w.end_tag(); } +fn encode_struct_field_attrs(ebml_w: &mut Encoder, krate: &Crate) { + struct StructFieldVisitor<'a, 'b> { + ebml_w: &'a mut Encoder<'b>, + } + + impl<'a, 'b> Visitor<()> for StructFieldVisitor<'a, 'b> { + fn visit_struct_field(&mut self, field: &ast::StructField, _: ()) { + self.ebml_w.start_tag(tag_struct_field); + self.ebml_w.wr_tagged_u32(tag_struct_field_id, field.node.id); + encode_attributes(self.ebml_w, field.node.attrs.as_slice()); + self.ebml_w.end_tag(); + } + } + + ebml_w.start_tag(tag_struct_fields); + visit::walk_crate(&mut StructFieldVisitor { + ebml_w: ebml_w + }, krate, ()); + ebml_w.end_tag(); +} + + + struct ImplVisitor<'a,'b,'c> { ecx: &'a EncodeContext<'b>, ebml_w: &'a mut Encoder<'c>, @@ -1928,6 +1952,8 @@ fn encode_metadata_inner(wr: &mut MemWriter, parms: EncodeParams, krate: &Crate) stats.index_bytes = ebml_w.writer.tell().unwrap() - i; ebml_w.end_tag(); + encode_struct_field_attrs(&mut ebml_w, krate); + stats.total_bytes = ebml_w.writer.tell().unwrap(); if tcx.sess.meta_stats() { diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 8f60fe340e4d6..0f5af4421a5e8 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -4071,7 +4071,7 @@ pub fn lookup_struct_fields(cx: &ctxt, did: ast::DefId) -> Vec { let len = results.as_slice().iter().map(|x| x.len()).sum(); let mut result: Vec = Vec::with_capacity(len); - result.extend(results.as_slice().iter().flat_map(|rs| rs.iter().map(|&f| f))); + result.extend(results.as_slice().iter().flat_map(|rs| rs.iter().map(|f| f.clone()))); assert!(result.len() == len); result } else { @@ -4085,7 +4085,7 @@ pub fn lookup_struct_field(cx: &ctxt, -> field_ty { let r = lookup_struct_fields(cx, parent); match r.iter().find(|f| f.id.node == field_id.node) { - Some(t) => *t, + Some(t) => t.clone(), None => cx.sess.bug("struct ID not found in parent's fields") } } diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs index a238c207696a1..531dced550a82 100644 --- a/src/librustc/middle/typeck/check/_match.rs +++ b/src/librustc/middle/typeck/check/_match.rs @@ -322,7 +322,7 @@ pub fn check_struct_pat_fields(pcx: &pat_ctxt, } Some(&(index, ref mut used)) => { *used = true; - let class_field = *class_fields.get(index); + let class_field = class_fields.get(index).clone(); let field_type = ty::lookup_field_type(tcx, class_id, class_field.id, diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 2f7d766c28fa8..3c942d0791e77 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -209,7 +209,7 @@ fn build_struct(tcx: &ty::ctxt, did: ast::DefId) -> clean::Struct { _ => doctree::Plain, }, generics: (&t.generics, subst::TypeSpace).clean(), - fields: fields.iter().map(|f| f.clean()).collect(), + fields: fields.clean(), fields_stripped: false, } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 953b736f38b43..002f887834747 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -347,18 +347,18 @@ impl Clean for doctree::Module { } } let items: Vec > = vec!( - self.structs.clean().move_iter().collect(), - self.enums.clean().move_iter().collect(), - self.fns.clean().move_iter().collect(), + self.structs.clean(), + self.enums.clean(), + self.fns.clean(), foreigns, - self.mods.clean().move_iter().collect(), - self.typedefs.clean().move_iter().collect(), - self.statics.clean().move_iter().collect(), - self.traits.clean().move_iter().collect(), - self.impls.clean().move_iter().collect(), + self.mods.clean(), + self.typedefs.clean(), + self.statics.clean(), + self.traits.clean(), + self.impls.clean(), self.view_items.clean().move_iter() .flat_map(|s| s.move_iter()).collect(), - self.macros.clean().move_iter().collect() + self.macros.clean(), ); // determine if we should display the inner contents or @@ -406,7 +406,7 @@ impl Clean for ast::MetaItem { match self.node { ast::MetaWord(ref s) => Word(s.get().to_string()), ast::MetaList(ref s, ref l) => { - List(s.get().to_string(), l.clean().move_iter().collect()) + List(s.get().to_string(), l.clean()) } ast::MetaNameValue(ref s, ref v) => { NameValue(s.get().to_string(), lit_to_string(v)) @@ -460,7 +460,7 @@ impl Clean for ast::TyParam { TyParam { name: self.ident.clean(), did: ast::DefId { krate: ast::LOCAL_CRATE, node: self.id }, - bounds: self.bounds.clean().move_iter().collect(), + bounds: self.bounds.clean(), default: self.default.clean() } } @@ -688,7 +688,7 @@ impl Clean for ast::Method { }; Item { name: Some(self.pe_ident().clean()), - attrs: self.attrs.clean().move_iter().collect(), + attrs: self.attrs.clean(), source: self.span.clean(), def_id: ast_util::local_def(self.id), visibility: self.pe_vis().clean(), @@ -727,7 +727,7 @@ impl Clean for ast::TypeMethod { }; Item { name: Some(self.ident.clean()), - attrs: self.attrs.clean().move_iter().collect(), + attrs: self.attrs.clean(), source: self.span.clean(), def_id: ast_util::local_def(self.id), visibility: None, @@ -805,7 +805,7 @@ impl Clean for ast::ClosureTy { onceness: self.onceness, fn_style: self.fn_style, bounds: match self.bounds { - Some(ref x) => x.clean().move_iter().collect(), + Some(ref x) => x.clean(), None => Vec::new() }, } @@ -1178,7 +1178,7 @@ impl Clean for ast::Ty { TyTup(ref tys) => Tuple(tys.iter().map(|x| x.clean()).collect()), TyPath(ref p, ref tpbs, id) => { resolve_type(p.clean(), - tpbs.clean().map(|x| x.move_iter().collect()), + tpbs.clean().map(|x| x), id) } TyClosure(ref c, region) => Closure(box c.clean(), region.clean()), @@ -1307,7 +1307,7 @@ impl Clean for ast::StructField { }; Item { name: name.clean(), - attrs: self.node.attrs.clean().move_iter().collect(), + attrs: self.node.attrs.clean(), source: self.span.clean(), visibility: Some(vis), stability: get_stability(ast_util::local_def(self.node.id)), @@ -1320,16 +1320,26 @@ impl Clean for ast::StructField { impl Clean for ty::field_ty { fn clean(&self) -> Item { use syntax::parse::token::special_idents::unnamed_field; + use rustc::metadata::csearch; + + let cx = get_cx(); + let attrs; + + let attr_map = csearch::get_struct_field_attrs(&cx.tcx().sess.cstore, self.id); + let name = if self.name == unnamed_field.name { + attrs = None; None } else { + attrs = Some(attr_map.find(&self.id.node).unwrap()); Some(self.name) }; - let cx = get_cx(); + let ty = ty::lookup_item_type(cx.tcx(), self.id); + Item { name: name.clean(), - attrs: inline::load_attrs(cx.tcx(), self.id), + attrs: attrs.unwrap_or(&Vec::new()).clean(), source: Span::empty(), visibility: Some(self.vis), stability: get_stability(self.id), @@ -1388,7 +1398,7 @@ impl Clean for syntax::ast::StructDef { fn clean(&self) -> VariantStruct { VariantStruct { struct_type: doctree::struct_type_from_def(self), - fields: self.fields.clean().move_iter().collect(), + fields: self.fields.clean(), fields_stripped: false, } } @@ -1556,7 +1566,7 @@ impl Clean for ast::Path { fn clean(&self) -> Path { Path { global: self.global, - segments: self.segments.clean().move_iter().collect(), + segments: self.segments.clean(), } } } @@ -1572,8 +1582,8 @@ impl Clean for ast::PathSegment { fn clean(&self) -> PathSegment { PathSegment { name: self.identifier.clean(), - lifetimes: self.lifetimes.clean().move_iter().collect(), - types: self.types.clean().move_iter().collect() + lifetimes: self.lifetimes.clean(), + types: self.types.clean(), } } } @@ -1640,7 +1650,7 @@ impl Clean for ast::BareFnTy { BareFunctionDecl { fn_style: self.fn_style, generics: Generics { - lifetimes: self.lifetimes.clean().move_iter().collect(), + lifetimes: self.lifetimes.clean(), type_params: Vec::new(), }, decl: self.decl.clean(), @@ -1745,7 +1755,7 @@ impl Clean> for ast::ViewItem { let convert = |node: &ast::ViewItem_| { Item { name: None, - attrs: self.attrs.clean().move_iter().collect(), + attrs: self.attrs.clean(), source: self.span.clean(), def_id: ast_util::local_def(0), visibility: self.vis.clean(), @@ -1840,7 +1850,7 @@ impl Clean for ast::ViewPath { GlobImport(resolve_use_source(p.clean(), id)), ast::ViewPathList(ref p, ref pl, id) => { ImportList(resolve_use_source(p.clean(), id), - pl.clean().move_iter().collect()) + pl.clean()) } } } @@ -1893,7 +1903,7 @@ impl Clean for ast::ForeignItem { }; Item { name: Some(self.ident.clean()), - attrs: self.attrs.clean().move_iter().collect(), + attrs: self.attrs.clean(), source: self.span.clean(), def_id: ast_util::local_def(self.id), visibility: self.vis.clean(),