Rollup merge of #73155 - marmeladema:save-analysis-various-fixes, r=Xanewok

save_analysis: better handle paths and functions signature

This should improve slightly some possible regressions due to hir rework.

r? @Xanewok
This commit is contained in:
Dylan DPC 2020-06-11 13:16:00 +02:00 committed by GitHub
commit b4af87406b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 142 additions and 77 deletions

View File

@ -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<Symbol>,
generics: &hir::Generics<'_>,
vis: &hir::Visibility<'_>,
arg_names: &[Ident],
body_id: Option<hir::BodyId>,
) -> 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);

View File

@ -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<Item = &'tcx hir::PathSegment<'tcx>>) {
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>) {

View File

@ -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::<Vec<_>>().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<Ref> {
path.segments.last().and_then(|seg| {
pub fn get_path_data(&self, id: hir::HirId, path: &hir::QPath<'_>) -> Option<Ref> {
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::<Vec<_>>()
.join(", "),
);
sig.push_str("> ");
}
sig.push('(');
sig.push_str(&decl.inputs.iter().map(ty_to_string).collect::<Vec<_>>().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> {

View File

@ -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<hir::GenericBound<'_>> = 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"),
}
}
}