From 531a3c680d31b52fab99b50fe9a52c55505b9ac9 Mon Sep 17 00:00:00 2001 From: Corey Richardson Date: Sat, 26 Jul 2014 13:21:36 -0700 Subject: [PATCH] rustdoc: show struct field docs when inlined Some minor changes to the compiler to expose this information. Very inconvenient since struct fields aren't an item. Adds (yet another) table to metadata. Closes #15739 --- src/librustc/metadata/common.rs | 4 ++++ src/librustc/metadata/csearch.rs | 8 +++++++ src/librustc/metadata/decoder.rs | 14 ++++++++++++ src/librustc/metadata/encoder.rs | 25 ++++++++++++++++++++++ src/librustc/middle/ty.rs | 4 ++-- src/librustc/middle/typeck/check/_match.rs | 2 +- src/librustdoc/clean/inline.rs | 2 +- src/librustdoc/clean/mod.rs | 14 ++++++++++-- 8 files changed, 67 insertions(+), 6 deletions(-) diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index 216a575f2fb2b..5edbe9b5a082c 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -227,3 +227,7 @@ 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; 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..3cd8c55b066b0 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, diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 7997af1ee5e11..2a7697f0a52a5 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -1644,6 +1644,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 +1951,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..417a5521a12c4 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -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),