diff --git a/src/librustc_hir_pretty/lib.rs b/src/librustc_hir_pretty/lib.rs index e642915b86a..da8956ccb4d 100644 --- a/src/librustc_hir_pretty/lib.rs +++ b/src/librustc_hir_pretty/lib.rs @@ -227,6 +227,28 @@ pub fn path_to_string(segment: &hir::Path<'_>) -> String { to_string(NO_ANN, |s| s.print_path(segment, false)) } +pub fn fn_to_string( + decl: &hir::FnDecl<'_>, + header: hir::FnHeader, + name: Option, + generics: &hir::Generics<'_>, + vis: &hir::Visibility<'_>, + arg_names: &[Ident], + body_id: Option, +) -> String { + to_string(NO_ANN, |s| s.print_fn(decl, header, name, generics, vis, arg_names, body_id)) +} + +pub fn enum_def_to_string( + enum_definition: &hir::EnumDef<'_>, + generics: &hir::Generics<'_>, + name: Symbol, + span: rustc_span::Span, + visibility: &hir::Visibility<'_>, +) -> String { + to_string(NO_ANN, |s| s.print_enum_def(enum_definition, generics, name, span, visibility)) +} + impl<'a> State<'a> { pub fn cbox(&mut self, u: usize) { self.s.cbox(u); diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 489d38b00df..fbde6bfd9aa 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -20,7 +20,7 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind as HirDefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir_pretty::{bounds_to_string, generic_params_to_string, ty_to_string}; +use rustc_hir_pretty::{bounds_to_string, fn_to_string, generic_params_to_string, ty_to_string}; use rustc_middle::hir::map::Map; use rustc_middle::span_bug; use rustc_middle::ty::{self, DefIdTree, TyCtxt}; @@ -199,23 +199,23 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> { self.dumper.compilation_opts(data); } - fn write_sub_paths(&mut self, path: &'tcx hir::Path<'tcx>) { - for seg in path.segments { + fn write_segments(&mut self, segments: impl IntoIterator>) { + for seg in segments { if let Some(data) = self.save_ctxt.get_path_segment_data(seg) { self.dumper.dump_ref(data); } } } + fn write_sub_paths(&mut self, path: &'tcx hir::Path<'tcx>) { + self.write_segments(path.segments) + } + // As write_sub_paths, but does not process the last ident in the path (assuming it // will be processed elsewhere). See note on write_sub_paths about global. fn write_sub_paths_truncated(&mut self, path: &'tcx hir::Path<'tcx>) { if let [segments @ .., _] = path.segments { - for seg in segments { - if let Some(data) = self.save_ctxt.get_path_segment_data(seg) { - self.dumper.dump_ref(data); - } - } + self.write_segments(segments) } } @@ -276,7 +276,8 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> { } v.process_generic_params(&generics, &method_data.qualname, hir_id); - method_data.value = crate::make_signature(&sig.decl, &generics); + method_data.value = + fn_to_string(sig.decl, sig.header, Some(ident.name), generics, vis, &[], None); method_data.sig = sig::method_signature(hir_id, ident, generics, sig, &v.save_ctxt); v.dumper.dump_def(&access_from_vis!(v.save_ctxt, vis, hir_id), method_data); @@ -643,7 +644,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> { self.nest_tables(map.local_def_id(item.hir_id), |v| { v.visit_ty(&typ); if let &Some(ref trait_ref) = trait_ref { - v.process_path(trait_ref.hir_ref_id, &trait_ref.path); + v.process_path(trait_ref.hir_ref_id, &hir::QPath::Resolved(None, &trait_ref.path)); } v.process_generic_params(generics, "", item.hir_id); for impl_item in impl_items { @@ -746,7 +747,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> { } } - fn dump_path_ref(&mut self, id: hir::HirId, path: &hir::Path<'tcx>) { + fn dump_path_ref(&mut self, id: hir::HirId, path: &hir::QPath<'tcx>) { let path_data = self.save_ctxt.get_path_data(id, path); if let Some(path_data) = path_data { self.dumper.dump_ref(path_data); @@ -760,14 +761,30 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> { } } - fn process_path(&mut self, id: hir::HirId, path: &'tcx hir::Path<'tcx>) { - if self.span.filter_generated(path.span) { + fn process_path(&mut self, id: hir::HirId, path: &hir::QPath<'tcx>) { + let span = match path { + hir::QPath::Resolved(_, path) => path.span, + hir::QPath::TypeRelative(_, segment) => segment.ident.span, + }; + if self.span.filter_generated(span) { return; } self.dump_path_ref(id, path); // Type arguments - for seg in path.segments { + let segments = match path { + hir::QPath::Resolved(ty, path) => { + if let Some(ty) = ty { + self.visit_ty(ty); + } + path.segments + } + hir::QPath::TypeRelative(ty, segment) => { + self.visit_ty(ty); + std::slice::from_ref(*segment) + } + }; + for seg in segments { if let Some(ref generic_args) = seg.args { for arg in generic_args.args { if let hir::GenericArg::Type(ref ty) = arg { @@ -777,7 +794,9 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> { } } - self.write_sub_paths_truncated(path); + if let hir::QPath::Resolved(_, path) = path { + self.write_sub_paths_truncated(path); + } } fn process_struct_lit( @@ -931,9 +950,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> { } for (id, ref path) in collector.collected_paths { - if let hir::QPath::Resolved(_, path) = path { - self.process_path(id, path); - } + self.process_path(id, path); } } @@ -1135,7 +1152,10 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> { fn process_bounds(&mut self, bounds: hir::GenericBounds<'tcx>) { for bound in bounds { if let hir::GenericBound::Trait(ref trait_ref, _) = *bound { - self.process_path(trait_ref.trait_ref.hir_ref_id, &trait_ref.trait_ref.path) + self.process_path( + trait_ref.trait_ref.hir_ref_id, + &hir::QPath::Resolved(None, &trait_ref.trait_ref.path), + ) } } } @@ -1330,13 +1350,16 @@ impl<'l, 'tcx> Visitor<'tcx> for DumpVisitor<'l, 'tcx> { fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) { self.process_macro_use(t.span); match t.kind { - hir::TyKind::Path(hir::QPath::Resolved(_, path)) => { + hir::TyKind::Path(ref path) => { if generated_code(t.span) { return; } if let Some(id) = self.lookup_def_id(t.hir_id) { - let sub_span = path.segments.last().unwrap().ident.span; + let sub_span = match path { + hir::QPath::Resolved(_, path) => path.segments.last().unwrap().ident.span, + hir::QPath::TypeRelative(_, segment) => segment.ident.span, + }; let span = self.span_from_span(sub_span); self.dumper.dump_ref(Ref { kind: RefKind::Type, @@ -1345,8 +1368,10 @@ impl<'l, 'tcx> Visitor<'tcx> for DumpVisitor<'l, 'tcx> { }); } - self.write_sub_paths_truncated(path); - intravisit::walk_path(self, path); + if let hir::QPath::Resolved(_, path) = path { + self.write_sub_paths_truncated(path); + } + intravisit::walk_qpath(self, path, t.hir_id, t.span); } hir::TyKind::Array(ref ty, ref anon_const) => { self.visit_ty(ty); @@ -1355,6 +1380,10 @@ impl<'l, 'tcx> Visitor<'tcx> for DumpVisitor<'l, 'tcx> { v.visit_expr(&map.body(anon_const.body).value) }); } + hir::TyKind::Def(item_id, _) => { + let item = self.tcx.hir().item(item_id.id); + self.nest_tables(self.tcx.hir().local_def_id(item_id.id), |v| v.visit_item(item)); + } _ => intravisit::walk_ty(self, t), } } @@ -1432,8 +1461,8 @@ impl<'l, 'tcx> Visitor<'tcx> for DumpVisitor<'l, 'tcx> { self.visit_expr(&arm.body); } - fn visit_path(&mut self, p: &'tcx hir::Path<'tcx>, id: hir::HirId) { - self.process_path(id, p); + fn visit_qpath(&mut self, path: &'tcx hir::QPath<'tcx>, id: hir::HirId, _: Span) { + self.process_path(id, path); } fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) { diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 0341b542526..8a456c903ec 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -13,11 +13,11 @@ use rustc_ast::ast::{self}; use rustc_ast::util::comments::strip_doc_comment_decoration; use rustc_ast_pretty::pprust::attribute_to_string; use rustc_hir as hir; -use rustc_hir::def::{CtorOf, DefKind as HirDefKind, Res}; +use rustc_hir::def::{DefKind as HirDefKind, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::Node; -use rustc_hir_pretty::ty_to_string; +use rustc_hir_pretty::{enum_def_to_string, fn_to_string, ty_to_string}; use rustc_middle::hir::map::Map; use rustc_middle::middle::cstore::ExternCrate; use rustc_middle::middle::privacy::AccessLevels; @@ -135,7 +135,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { let def_id = self.tcx.hir().local_def_id(item.hir_id).to_def_id(); let qualname = format!("::{}", self.tcx.def_path_str(def_id)); match item.kind { - hir::ForeignItemKind::Fn(ref decl, _, ref generics) => { + hir::ForeignItemKind::Fn(ref decl, arg_names, ref generics) => { filter!(self.span_utils, item.ident.span); Some(Data::DefData(Def { @@ -144,7 +144,23 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { span: self.span_from_span(item.ident.span), name: item.ident.to_string(), qualname, - value: make_signature(decl, generics), + value: fn_to_string( + decl, + hir::FnHeader { + // functions in extern block are implicitly unsafe + unsafety: hir::Unsafety::Unsafe, + // functions in extern block cannot be const + constness: hir::Constness::NotConst, + abi: self.tcx.hir().get_foreign_abi(item.hir_id), + // functions in extern block cannot be async + asyncness: hir::IsAsync::NotAsync, + }, + Some(item.ident.name), + generics, + &item.vis, + arg_names, + None, + ), parent: None, children: vec![], decl_id: None, @@ -191,7 +207,15 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { span: self.span_from_span(item.ident.span), name: item.ident.to_string(), qualname, - value: make_signature(&sig.decl, generics), + value: fn_to_string( + sig.decl, + sig.header, + Some(item.ident.name), + generics, + &item.vis, + &[], + None, + ), parent: None, children: vec![], decl_id: None, @@ -268,13 +292,12 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { attributes: lower_attributes(item.attrs.to_vec(), self), })) } - hir::ItemKind::Enum(ref def, _) => { + hir::ItemKind::Enum(ref def, ref generics) => { let name = item.ident.to_string(); let qualname = format!("::{}", self.tcx.def_path_str(def_id)); filter!(self.span_utils, item.ident.span); - let variants_str = - def.variants.iter().map(|v| v.ident.to_string()).collect::>().join(", "); - let value = format!("{}::{{{}}}", name, variants_str); + let value = + enum_def_to_string(def, generics, item.ident.name, item.span, &item.vis); Some(Data::DefData(Def { kind: DefKind::Enum, id: id_from_def_id(def_id), @@ -579,7 +602,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { ref_id: def_id.or(decl_id).map(id_from_def_id).unwrap_or_else(null_id), })) } - hir::ExprKind::Path(hir::QPath::Resolved(_, path)) => { + hir::ExprKind::Path(ref path) => { self.get_path_data(expr.hir_id, path).map(Data::RefData) } _ => { @@ -631,8 +654,12 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { } } - pub fn get_path_data(&self, id: hir::HirId, path: &hir::Path<'_>) -> Option { - path.segments.last().and_then(|seg| { + pub fn get_path_data(&self, id: hir::HirId, path: &hir::QPath<'_>) -> Option { + let segment = match path { + hir::QPath::Resolved(_, path) => path.segments.last(), + hir::QPath::TypeRelative(_, segment) => Some(*segment), + }; + segment.and_then(|seg| { self.get_path_segment_data(seg).or_else(|| self.get_path_segment_data_with_id(seg, id)) }) } @@ -681,20 +708,16 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { Res::Def(HirDefKind::ConstParam, def_id) => { Some(Ref { kind: RefKind::Variable, span, ref_id: id_from_def_id(def_id) }) } - Res::Def(HirDefKind::Ctor(CtorOf::Struct, ..), def_id) => { - // This is a reference to a tuple struct where the def_id points + Res::Def(HirDefKind::Ctor(_, ..), def_id) => { + // This is a reference to a tuple struct or an enum variant where the def_id points // to an invisible constructor function. That is not a very useful - // def, so adjust to point to the tuple struct itself. + // def, so adjust to point to the tuple struct or enum variant itself. let parent_def_id = self.tcx.parent(def_id).unwrap(); Some(Ref { kind: RefKind::Type, span, ref_id: id_from_def_id(parent_def_id) }) } - Res::Def( - HirDefKind::Static - | HirDefKind::Const - | HirDefKind::AssocConst - | HirDefKind::Ctor(..), - _, - ) => Some(Ref { kind: RefKind::Variable, span, ref_id: id_from_def_id(res.def_id()) }), + Res::Def(HirDefKind::Static | HirDefKind::Const | HirDefKind::AssocConst, _) => { + Some(Ref { kind: RefKind::Variable, span, ref_id: id_from_def_id(res.def_id()) }) + } Res::Def(HirDefKind::AssocFn, decl_id) => { let def_id = if decl_id.is_local() { let ti = self.tcx.associated_item(decl_id); @@ -844,31 +867,6 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { } } -fn make_signature(decl: &hir::FnDecl<'_>, generics: &hir::Generics<'_>) -> String { - let mut sig = "fn ".to_owned(); - if !generics.params.is_empty() { - sig.push('<'); - sig.push_str( - &generics - .params - .iter() - .map(|param| param.name.ident().to_string()) - .collect::>() - .join(", "), - ); - sig.push_str("> "); - } - sig.push('('); - sig.push_str(&decl.inputs.iter().map(ty_to_string).collect::>().join(", ")); - sig.push(')'); - match decl.output { - hir::FnRetTy::DefaultReturn(_) => sig.push_str(" -> ()"), - hir::FnRetTy::Return(ref t) => sig.push_str(&format!(" -> {}", ty_to_string(t))), - } - - sig -} - // An AST visitor for collecting paths (e.g., the names of structs) and formal // variables (idents) from patterns. struct PathCollector<'l> { diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index 6fec5cdba8b..5f337f5f770 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -281,6 +281,22 @@ impl<'hir> Sig for hir::Ty<'hir> { }) } } + hir::TyKind::Path(hir::QPath::TypeRelative(ty, segment)) => { + let nested_ty = ty.make(offset + 1, id, scx)?; + let prefix = format!("<{}>::", nested_ty.text,); + + let name = path_segment_to_string(segment); + let res = scx.get_path_res(id.ok_or("Missing id for Path")?); + let id = id_from_def_id(res.def_id()); + + let start = offset + prefix.len(); + let end = start + name.len(); + Ok(Signature { + text: prefix + &name, + defs: vec![], + refs: vec![SigElement { id, start, end }], + }) + } hir::TyKind::TraitObject(bounds, ..) => { // FIXME recurse into bounds let bounds: Vec> = bounds @@ -308,11 +324,11 @@ impl<'hir> Sig for hir::Ty<'hir> { let text = format!("[{}; {}]", nested_ty.text, expr); Ok(replace_text(nested_ty, text)) } - hir::TyKind::Typeof(_) - | hir::TyKind::Infer - | hir::TyKind::Def(..) - | hir::TyKind::Path(..) - | hir::TyKind::Err => Err("Ty"), + hir::TyKind::Def(item_id, _) => { + let item = scx.tcx.hir().item(item_id.id); + item.make(offset, Some(item_id.id), scx) + } + hir::TyKind::Typeof(_) | hir::TyKind::Infer | hir::TyKind::Err => Err("Ty"), } } }