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 216a575f2fb..5edbe9b5a08 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -227,3 +227,7 @@ pub struct LinkMeta { 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 0adc8e915c6..b1b366ec030 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -29,6 +29,8 @@ 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 094e83d2a47..3cd8c55b066 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -34,6 +34,7 @@ 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 7997af1ee5e..2a7697f0a52 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 @@ struct Stats { 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 8f60fe340e4..0f5af4421a5 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 a238c207696..531dced550a 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 2f7d766c28f..3c942d0791e 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 953b736f38b..417a5521a12 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1320,16 +1320,26 @@ fn clean(&self) -> Item { 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), -- 2.44.0