diff --git a/src/librustc_trans/save/dump_csv.rs b/src/librustc_trans/save/dump_csv.rs index 36901ff096711..cbc40af4b524e 100644 --- a/src/librustc_trans/save/dump_csv.rs +++ b/src/librustc_trans/save/dump_csv.rs @@ -54,6 +54,15 @@ use super::recorder::{Recorder, FmtStrs}; use util::ppaux; +macro_rules! down_cast_data { + ($id:ident, $kind:ident, $this:ident, $sp:expr) => { + let $id = if let super::Data::$kind(data) = $id { + data + } else { + $this.sess.span_bug($sp, &format!("unexpected data kind: {:?}", $id)); + }; + }; +} pub struct DumpCsvVisitor<'l, 'tcx: 'l> { save_ctxt: SaveContext<'l, 'tcx>, @@ -249,7 +258,7 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { match def { def::DefMod(_) | def::DefForeignMod(_) => Some(recorder::ModRef), - def::DefStruct(_) => Some(recorder::StructRef), + def::DefStruct(_) => Some(recorder::TypeRef), def::DefTy(..) | def::DefAssociatedTy(..) | def::DefTrait(_) => Some(recorder::TypeRef), @@ -419,48 +428,31 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { id); } - fn process_trait_ref(&mut self, - trait_ref: &ast::TraitRef) { - match self.lookup_type_ref(trait_ref.ref_id) { - Some(id) => { - let sub_span = self.span.sub_span_for_type_name(trait_ref.path.span); - self.fmt.ref_str(recorder::TypeRef, - trait_ref.path.span, - sub_span, - id, - self.cur_scope); - visit::walk_path(self, &trait_ref.path); - }, - None => () + fn process_trait_ref(&mut self, trait_ref: &ast::TraitRef) { + let trait_ref_data = self.save_ctxt.get_trait_ref_data(trait_ref, self.cur_scope); + if let Some(trait_ref_data) = trait_ref_data { + self.fmt.ref_str(recorder::TypeRef, + trait_ref.path.span, + Some(trait_ref_data.span), + trait_ref_data.ref_id, + trait_ref_data.scope); + visit::walk_path(self, &trait_ref.path); } } fn process_struct_field_def(&mut self, field: &ast::StructField, - qualname: &str, - scope_id: NodeId) { - match field.node.kind { - ast::NamedField(ident, _) => { - let name = get_ident(ident); - let qualname = format!("{}::{}", qualname, name); - let typ = - ppaux::ty_to_string( - &self.analysis.ty_cx, - *self.analysis.ty_cx.node_types().get(&field.node.id).unwrap()); - match self.span.sub_span_before_token(field.span, token::Colon) { - Some(sub_span) => self.fmt.field_str(field.span, - Some(sub_span), - field.node.id, - &name, - &qualname, - &typ, - scope_id), - None => self.sess.span_bug(field.span, - &format!("Could not find sub-span for field {}", - qualname)), - } - }, - _ => (), + parent_id: NodeId) { + let field_data = self.save_ctxt.get_field_data(field, parent_id); + if let Some(field_data) = field_data { + down_cast_data!(field_data, VariableData, self, field.span); + self.fmt.field_str(field.span, + Some(field_data.span), + field_data.id, + &field_data.name, + &field_data.qualname, + &field_data.type_value, + field_data.scope); } } @@ -497,19 +489,16 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { ty_params: &ast::Generics, body: &ast::Block) { let fn_data = self.save_ctxt.get_item_data(item); - if let super::Data::FunctionData(fn_data) = fn_data { - self.fmt.fn_str(item.span, - Some(fn_data.span), - fn_data.id, - &fn_data.qualname, - fn_data.scope); + down_cast_data!(fn_data, FunctionData, self, item.span); + self.fmt.fn_str(item.span, + Some(fn_data.span), + fn_data.id, + &fn_data.qualname, + fn_data.scope); - self.process_formals(&decl.inputs, &fn_data.qualname); - self.process_generic_params(ty_params, item.span, &fn_data.qualname, item.id); - } else { - self.sess.span_bug(item.span, "expected FunctionData"); - } + self.process_formals(&decl.inputs, &fn_data.qualname); + self.process_generic_params(ty_params, item.span, &fn_data.qualname, item.id); for arg in &decl.inputs { self.visit_ty(&arg.ty); @@ -528,18 +517,15 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { expr: &ast::Expr) { let var_data = self.save_ctxt.get_item_data(item); - if let super::Data::VariableData(var_data) = var_data { - self.fmt.static_str(item.span, - Some(var_data.span), - var_data.id, - &var_data.name, - &var_data.qualname, - &var_data.value, - &var_data.type_value, - var_data.scope); - } else { - self.sess.span_bug(item.span, "expected VariableData"); - } + down_cast_data!(var_data, VariableData, self, item.span); + self.fmt.static_str(item.span, + Some(var_data.span), + var_data.id, + &var_data.name, + &var_data.qualname, + &var_data.value, + &var_data.type_value, + var_data.scope); self.visit_ty(&typ); self.visit_expr(expr); @@ -593,8 +579,8 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { // fields for field in &def.fields { - self.process_struct_field_def(field, &qualname, item.id); - self.visit_ty(&*field.node.ty); + self.process_struct_field_def(field, item.id); + self.visit_ty(&field.node.ty); } self.process_generic_params(ty_params, item.span, &qualname, item.id); @@ -605,59 +591,57 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { enum_definition: &ast::EnumDef, ty_params: &ast::Generics) { let enum_data = self.save_ctxt.get_item_data(item); - if let super::Data::EnumData(enum_data) = enum_data { - self.fmt.enum_str(item.span, - Some(enum_data.span), - enum_data.id, - &enum_data.qualname, - self.cur_scope, - &enum_data.value); - for variant in &enum_definition.variants { - let name = &get_ident(variant.node.name); - let mut qualname = enum_data.qualname.clone(); - qualname.push_str("::"); - qualname.push_str(name); - let val = self.span.snippet(variant.span); - match variant.node.kind { - ast::TupleVariantKind(ref args) => { - // first ident in span is the variant's name - self.fmt.tuple_variant_str(variant.span, - self.span.span_for_first_ident(variant.span), - variant.node.id, - name, - &qualname, - &enum_data.qualname, - &val, - item.id); - for arg in args { - self.visit_ty(&*arg.ty); - } + down_cast_data!(enum_data, EnumData, self, item.span); + self.fmt.enum_str(item.span, + Some(enum_data.span), + enum_data.id, + &enum_data.qualname, + enum_data.scope, + &enum_data.value); + + for variant in &enum_definition.variants { + let name = &get_ident(variant.node.name); + let mut qualname = enum_data.qualname.clone(); + qualname.push_str("::"); + qualname.push_str(name); + let val = self.span.snippet(variant.span); + match variant.node.kind { + ast::TupleVariantKind(ref args) => { + // first ident in span is the variant's name + self.fmt.tuple_variant_str(variant.span, + self.span.span_for_first_ident(variant.span), + variant.node.id, + name, + &qualname, + &enum_data.qualname, + &val, + enum_data.id); + for arg in args { + self.visit_ty(&*arg.ty); } - ast::StructVariantKind(ref struct_def) => { - let ctor_id = match struct_def.ctor_id { - Some(node_id) => node_id, - None => -1, - }; - self.fmt.struct_variant_str(variant.span, - self.span.span_for_first_ident(variant.span), - variant.node.id, - ctor_id, - &qualname, - &enum_data.qualname, - &val, - item.id); - - for field in &struct_def.fields { - self.process_struct_field_def(field, &qualname, variant.node.id); - self.visit_ty(&*field.node.ty); - } + } + ast::StructVariantKind(ref struct_def) => { + let ctor_id = match struct_def.ctor_id { + Some(node_id) => node_id, + None => -1, + }; + self.fmt.struct_variant_str(variant.span, + self.span.span_for_first_ident(variant.span), + variant.node.id, + ctor_id, + &qualname, + &enum_data.qualname, + &val, + enum_data.id); + + for field in &struct_def.fields { + self.process_struct_field_def(field, variant.node.id); + self.visit_ty(&*field.node.ty); } } } - self.process_generic_params(ty_params, item.span, &enum_data.qualname, item.id); - } else { - self.sess.span_bug(item.span, "expected EnumData"); } + self.process_generic_params(ty_params, item.span, &enum_data.qualname, enum_data.id); } fn process_impl(&mut self, @@ -666,45 +650,36 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { trait_ref: &Option, typ: &ast::Ty, impl_items: &[P]) { - let trait_id = trait_ref.as_ref().and_then(|tr| self.lookup_type_ref(tr.ref_id)); - match typ.node { - // Common case impl for a struct or something basic. - ast::TyPath(None, ref path) => { - let sub_span = self.span.sub_span_for_type_name(path.span); - let self_id = self.lookup_type_ref(typ.id).map(|id| { - self.fmt.ref_str(recorder::TypeRef, - path.span, - sub_span, - id, - self.cur_scope); - id - }); - self.fmt.impl_str(path.span, - sub_span, - item.id, - self_id, - trait_id, - self.cur_scope); - }, - _ => { - // Less useful case, impl for a compound type. - self.visit_ty(&*typ); - - let sub_span = self.span.sub_span_for_type_name(typ.span); - self.fmt.impl_str(typ.span, - sub_span, - item.id, - None, - trait_id, - self.cur_scope); + let impl_data = self.save_ctxt.get_item_data(item); + down_cast_data!(impl_data, ImplData, self, item.span); + match impl_data.self_ref { + Some(ref self_ref) => { + self.fmt.ref_str(recorder::TypeRef, + item.span, + Some(self_ref.span), + self_ref.ref_id, + self_ref.scope); + } + None => { + self.visit_ty(&typ); } } - - match *trait_ref { - Some(ref trait_ref) => self.process_trait_ref(trait_ref), - None => (), + if let Some(ref trait_ref_data) = impl_data.trait_ref { + self.fmt.ref_str(recorder::TypeRef, + item.span, + Some(trait_ref_data.span), + trait_ref_data.ref_id, + trait_ref_data.scope); + visit::walk_path(self, &trait_ref.as_ref().unwrap().path); } + self.fmt.impl_str(item.span, + Some(impl_data.span), + impl_data.id, + impl_data.self_ref.map(|data| data.ref_id), + impl_data.trait_ref.map(|data| data.ref_id), + impl_data.scope); + self.process_generic_params(type_parameters, item.span, "", item.id); for impl_item in impl_items { self.visit_impl_item(impl_item); @@ -765,16 +740,13 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { fn process_mod(&mut self, item: &ast::Item) { // The module in question, represented as an item. let mod_data = self.save_ctxt.get_item_data(item); - if let super::Data::ModData(mod_data) = mod_data { - self.fmt.mod_str(item.span, - Some(mod_data.span), - mod_data.id, - &mod_data.qualname, - mod_data.scope, - &mod_data.filename); - } else { - self.sess.span_bug(item.span, "expected ModData"); - } + down_cast_data!(mod_data, ModData, self, item.span); + self.fmt.mod_str(item.span, + Some(mod_data.span), + mod_data.id, + &mod_data.qualname, + mod_data.scope, + &mod_data.filename); } fn process_path(&mut self, @@ -804,7 +776,7 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { sub_span, def.def_id(), self.cur_scope), - def::DefStruct(def_id) => self.fmt.ref_str(recorder::StructRef, + def::DefStruct(def_id) => self.fmt.ref_str(recorder::TypeRef, span, sub_span, def_id, @@ -901,44 +873,33 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { self.write_sub_paths_truncated(path, false); - let ty = &ty::expr_ty_adjusted(&self.analysis.ty_cx, ex).sty; - let struct_def = match *ty { - ty::TyStruct(def_id, _) => { - let sub_span = self.span.span_for_last_ident(path.span); - self.fmt.ref_str(recorder::StructRef, - path.span, - sub_span, - def_id, - self.cur_scope); - Some(def_id) - } - _ => None - }; - - for field in fields { - match struct_def { - Some(struct_def) => { - let fields = ty::lookup_struct_fields(&self.analysis.ty_cx, struct_def); - for f in &fields { - if generated_code(field.ident.span) { - continue; - } - if f.name == field.ident.node.name { - // We don't really need a sub-span here, but no harm done - let sub_span = self.span.span_for_last_ident(field.ident.span); - self.fmt.ref_str(recorder::VarRef, - field.ident.span, - sub_span, - f.id, - self.cur_scope); - } - } + if let Some(struct_lit_data) = self.save_ctxt.get_expr_data(ex) { + down_cast_data!(struct_lit_data, TypeRefData, self, ex.span); + self.fmt.ref_str(recorder::TypeRef, + ex.span, + Some(struct_lit_data.span), + struct_lit_data.ref_id, + struct_lit_data.scope); + let struct_def = struct_lit_data.ref_id; + + for field in fields { + if generated_code(field.ident.span) { + continue; } - None => {} - } - self.visit_expr(&*field.expr) + let field_data = self.save_ctxt.get_field_ref_data(field, + struct_def, + self.cur_scope); + self.fmt.ref_str(recorder::VarRef, + field.ident.span, + Some(field_data.span), + field_data.ref_id, + field_data.scope); + + self.visit_expr(&field.expr) + } } + visit::walk_expr_opt(self, base) } @@ -1174,7 +1135,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { self.process_impl(item, ty_params, trait_ref, - &**typ, + &typ, impl_items) } ast::ItemTrait(_, ref generics, ref trait_refs, ref methods) => @@ -1296,15 +1257,13 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { self.visit_expr(&sub_ex); - let field_data = self.save_ctxt.get_expr_data(ex); - if let super::Data::VariableRefData(field_data) = field_data { + if let Some(field_data) = self.save_ctxt.get_expr_data(ex) { + down_cast_data!(field_data, VariableRefData, self, ex.span); self.fmt.ref_str(recorder::VarRef, ex.span, Some(field_data.span), field_data.ref_id, field_data.scope); - } else { - self.sess.span_bug(ex.span, "expected VariableRefData"); } }, ast::ExprTupField(ref sub_ex, idx) => { diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index 096ee7ad7b30d..380d6b0ee6578 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -10,6 +10,7 @@ use session::Session; use middle::ty; +use middle::def; use std::env; use std::fs::{self, File}; @@ -23,9 +24,11 @@ use syntax::parse::token::{self, get_ident, keywords}; use syntax::visit::{self, Visitor}; use syntax::print::pprust::ty_to_string; +use util::ppaux; use self::span_utils::SpanUtils; + mod span_utils; mod recorder; @@ -44,22 +47,28 @@ pub struct CrateData { /// Data for any entity in the Rust language. The actual data contained varied /// with the kind of entity being queried. See the nested structs for details. +#[derive(Debug)] pub enum Data { /// Data for all kinds of functions and methods. FunctionData(FunctionData), - /// Data for local and global variables (consts and statics). + /// Data for local and global variables (consts and statics), and fields. VariableData(VariableData), /// Data for modules. ModData(ModData), /// Data for Enums. EnumData(EnumData), + /// Data for impls. + ImplData(ImplData), /// Data for the use of some variable (e.g., the use of a local variable, which /// will refere to that variables declaration). VariableRefData(VariableRefData), + /// Data for a reference to a type or trait. + TypeRefData(TypeRefData), } /// Data for all kinds of functions and methods. +#[derive(Debug)] pub struct FunctionData { pub id: NodeId, pub name: String, @@ -70,6 +79,7 @@ pub struct FunctionData { } /// Data for local and global variables (consts and statics). +#[derive(Debug)] pub struct VariableData { pub id: NodeId, pub name: String, @@ -81,6 +91,7 @@ pub struct VariableData { } /// Data for modules. +#[derive(Debug)] pub struct ModData { pub id: NodeId, pub name: String, @@ -91,15 +102,30 @@ pub struct ModData { } /// Data for enum declarations. +#[derive(Debug)] pub struct EnumData { pub id: NodeId, pub value: String, pub qualname: String, pub span: Span, + pub scope: NodeId, +} + +#[derive(Debug)] +pub struct ImplData { + pub id: NodeId, + pub span: Span, + pub scope: NodeId, + // FIXME: I'm not really sure inline data is the best way to do this. Seems + // OK in this case, but generalising leads to returning chunks of AST, which + // feels wrong. + pub trait_ref: Option, + pub self_ref: Option, } /// Data for the use of some item (e.g., the use of a local variable, which /// will refere to that variables declaration (by ref_id)). +#[derive(Debug)] pub struct VariableRefData { pub name: String, pub span: Span, @@ -107,6 +133,14 @@ pub struct VariableRefData { pub ref_id: DefId, } +/// Data for a reference to a type or trait. +#[derive(Debug)] +pub struct TypeRefData { + pub span: Span, + pub scope: NodeId, + pub ref_id: DefId, +} + impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { pub fn new(sess: &'l Session, @@ -209,8 +243,42 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { value: val, span: sub_span.unwrap(), qualname: enum_name, + scope: self.analysis.ty_cx.map.get_parent(item.id), }) }, + ast::ItemImpl(_, _, _, ref trait_ref, ref typ, _) => { + let mut type_data = None; + let sub_span; + + let parent = self.analysis.ty_cx.map.get_parent(item.id); + + match typ.node { + // Common case impl for a struct or something basic. + ast::TyPath(None, ref path) => { + sub_span = self.span_utils.sub_span_for_type_name(path.span); + type_data = self.lookup_ref_id(typ.id).map(|id| TypeRefData { + span: sub_span.unwrap(), + scope: parent, + ref_id: id, + }); + }, + _ => { + // Less useful case, impl for a compound type. + sub_span = self.span_utils.sub_span_for_type_name(typ.span); + } + } + + let trait_data = + trait_ref.as_ref().and_then(|tr| self.get_trait_ref_data(tr, parent)); + + Data::ImplData(ImplData { + id: item.id, + span: sub_span.unwrap(), + scope: parent, + trait_ref: trait_data, + self_ref: type_data, + }) + } _ => { // FIXME unimplemented!(); @@ -218,7 +286,50 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } } - pub fn get_expr_data(&self, expr: &ast::Expr) -> Data { + // FIXME: we ought to be able to get the parent id ourselves, but we can't + // for now. + pub fn get_field_data(&self, field: &ast::StructField, parent: NodeId) -> Option { + match field.node.kind { + ast::NamedField(ident, _) => { + let name = get_ident(ident); + let qualname = format!("::{}::{}", + self.analysis.ty_cx.map.path_to_string(parent), + name); + let typ = ppaux::ty_to_string(&self.analysis.ty_cx, + *self.analysis.ty_cx.node_types() + .get(&field.node.id).unwrap()); + let sub_span = self.span_utils.sub_span_before_token(field.span, token::Colon); + Some(Data::VariableData(VariableData { + id: field.node.id, + name: get_ident(ident).to_string(), + qualname: qualname, + span: sub_span.unwrap(), + scope: parent, + value: "".to_owned(), + type_value: typ, + })) + }, + _ => None, + } + } + + // FIXME: we ought to be able to get the parent id ourselves, but we can't + // for now. + pub fn get_trait_ref_data(&self, + trait_ref: &ast::TraitRef, + parent: NodeId) + -> Option { + self.lookup_ref_id(trait_ref.ref_id).map(|def_id| { + let sub_span = self.span_utils.sub_span_for_type_name(trait_ref.path.span); + TypeRefData { + span: sub_span.unwrap(), + scope: parent, + ref_id: def_id, + } + }) + } + + pub fn get_expr_data(&self, expr: &ast::Expr) -> Option { match expr.node { ast::ExprField(ref sub_ex, ident) => { let ty = &ty::expr_ty_adjusted(&self.analysis.ty_cx, &sub_ex).sty; @@ -228,12 +339,12 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { for f in &fields { if f.name == ident.node.name { let sub_span = self.span_utils.span_for_last_ident(expr.span); - return Data::VariableRefData(VariableRefData { + return Some(Data::VariableRefData(VariableRefData { name: get_ident(ident.node).to_string(), span: sub_span.unwrap(), scope: self.analysis.ty_cx.map.get_parent(expr.id), ref_id: f.id, - }); + })); } } @@ -242,8 +353,29 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { &get_ident(ident.node), ty)) } - _ => self.sess.span_bug(expr.span, - &format!("Expected struct type, found {:?}", ty)), + _ => { + debug!("Expected struct type, found {:?}", ty); + None + } + } + } + ast::ExprStruct(ref path, _, _) => { + let ty = &ty::expr_ty_adjusted(&self.analysis.ty_cx, expr).sty; + match *ty { + ty::TyStruct(def_id, _) => { + let sub_span = self.span_utils.span_for_last_ident(path.span); + Some(Data::TypeRefData(TypeRefData { + span: sub_span.unwrap(), + scope: self.analysis.ty_cx.map.get_parent(expr.id), + ref_id: def_id, + })) + } + _ => { + // FIXME ty could legitimately be a TyEnum, but then we will fail + // later if we try to look up the fields. + debug!("expected TyStruct, found {:?}", ty); + None + } } } _ => { @@ -253,10 +385,47 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } } + pub fn get_field_ref_data(&self, + field_ref: &ast::Field, + struct_id: DefId, + parent: NodeId) + -> VariableRefData { + let fields = ty::lookup_struct_fields(&self.analysis.ty_cx, struct_id); + let field_name = get_ident(field_ref.ident.node).to_string(); + for f in &fields { + if f.name == field_ref.ident.node.name { + // We don't really need a sub-span here, but no harm done + let sub_span = self.span_utils.span_for_last_ident(field_ref.ident.span); + return VariableRefData { + name: field_name, + span: sub_span.unwrap(), + scope: parent, + ref_id: f.id, + }; + } + } + + self.sess.span_bug(field_ref.span, + &format!("Couldn't find field {}", field_name)); + } + pub fn get_data_for_id(&self, _id: &NodeId) -> Data { // FIXME unimplemented!(); } + + fn lookup_ref_id(&self, ref_id: NodeId) -> Option { + if !self.analysis.ty_cx.def_map.borrow().contains_key(&ref_id) { + self.sess.bug(&format!("def_map has no key for {} in lookup_type_ref", + ref_id)); + } + let def = self.analysis.ty_cx.def_map.borrow().get(&ref_id).unwrap().full_def(); + match def { + def::DefPrimTy(_) => None, + _ => Some(def.def_id()), + } + } + } // An AST visitor for collecting paths from patterns. @@ -284,7 +453,7 @@ impl<'v> Visitor<'v> for PathCollector { self.collected_paths.push((p.id, path.clone(), ast::MutMutable, - recorder::StructRef)); + recorder::TypeRef)); } ast::PatEnum(ref path, _) | ast::PatQPath(_, ref path) => { diff --git a/src/librustc_trans/save/recorder.rs b/src/librustc_trans/save/recorder.rs index c7759f4266ba5..c53fa22a2c196 100644 --- a/src/librustc_trans/save/recorder.rs +++ b/src/librustc_trans/save/recorder.rs @@ -89,7 +89,6 @@ pub enum Row { ModRef, VarRef, TypeRef, - StructRef, FnRef, } @@ -150,9 +149,6 @@ impl<'a> FmtStrs<'a> { TypeRef => ("type_ref", vec!("refid","refidcrate","qualname","scopeid"), true, true), - StructRef => ("struct_ref", - vec!("refid","refidcrate","qualname","scopeid"), - true, true), FnRef => ("fn_ref", vec!("refid","refidcrate","qualname","scopeid"), true, true) } }