]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_save_analysis/lib.rs
save_analysis: improve handling of enum struct variant
[rust.git] / src / librustc_save_analysis / lib.rs
index 69e3758941929bd209b1711d59a35f976dcff3b2..f5c3e84c624267788ac42e888ff06da83a631a0c 100644 (file)
 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 @@ pub fn get_extern_item_data(&self, item: &hir::ForeignItem<'_>) -> Option<Data>
         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 @@ pub fn get_extern_item_data(&self, item: &hir::ForeignItem<'_>) -> Option<Data>
                     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 @@ pub fn get_item_data(&self, item: &hir::Item<'_>) -> Option<Data> {
                     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 @@ pub fn get_item_data(&self, item: &hir::Item<'_>) -> Option<Data> {
                     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),
@@ -495,24 +518,13 @@ pub fn get_trait_ref_data(&self, trait_ref: &hir::TraitRef<'_>) -> Option<Ref> {
     }
 
     pub fn get_expr_data(&self, expr: &hir::Expr<'_>) -> Option<Data> {
-        let hir_node = self.tcx.hir().expect_expr(expr.hir_id);
-        let ty = self.tables.expr_ty_adjusted_opt(&hir_node);
-        if ty.is_none() || ty.unwrap().kind == ty::Error {
+        let ty = self.tables.expr_ty_adjusted_opt(expr)?;
+        if matches!(ty.kind, ty::Error(_)) {
             return None;
         }
         match expr.kind {
             hir::ExprKind::Field(ref sub_ex, ident) => {
-                let hir_node = match self.tcx.hir().find(sub_ex.hir_id) {
-                    Some(Node::Expr(expr)) => expr,
-                    _ => {
-                        debug!(
-                            "Missing or weird node for sub-expression {} in {:?}",
-                            sub_ex.hir_id, expr
-                        );
-                        return None;
-                    }
-                };
-                match self.tables.expr_ty_adjusted(&hir_node).kind {
+                match self.tables.expr_ty_adjusted(&sub_ex).kind {
                     ty::Adt(def, _) if !def.is_enum() => {
                         let variant = &def.non_enum_variant();
                         filter!(self.span_utils, ident.span);
@@ -539,8 +551,8 @@ pub fn get_expr_data(&self, expr: &hir::Expr<'_>) -> Option<Data> {
                     hir::QPath::Resolved(_, path) => path.segments.last().unwrap(),
                     hir::QPath::TypeRelative(_, segment) => segment,
                 };
-                match self.tables.expr_ty_adjusted(&hir_node).kind {
-                    ty::Adt(def, _) if !def.is_enum() => {
+                match ty.kind {
+                    ty::Adt(def, _) => {
                         let sub_span = segment.ident.span;
                         filter!(self.span_utils, sub_span);
                         let span = self.span_from_span(sub_span);
@@ -551,9 +563,7 @@ pub fn get_expr_data(&self, expr: &hir::Expr<'_>) -> Option<Data> {
                         }))
                     }
                     _ => {
-                        // FIXME ty could legitimately be an enum, but then we will fail
-                        // later if we try to look up the fields.
-                        debug!("expected struct or union, found {:?}", ty);
+                        debug!("expected adt, found {:?}", ty);
                         None
                     }
                 }
@@ -579,7 +589,7 @@ pub fn get_expr_data(&self, expr: &hir::Expr<'_>) -> Option<Data> {
                     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 +641,12 @@ pub fn get_path_res(&self, hir_id: hir::HirId) -> Res {
         }
     }
 
-    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))
         })
     }
@@ -671,7 +685,6 @@ fn fn_type(seg: &hir::PathSegment<'_>) -> bool {
                 | HirDefKind::TyAlias
                 | HirDefKind::ForeignTy
                 | HirDefKind::TraitAlias
-                | HirDefKind::AssocOpaqueTy
                 | HirDefKind::AssocTy
                 | HirDefKind::Trait
                 | HirDefKind::OpaqueTy
@@ -681,20 +694,16 @@ fn fn_type(seg: &hir::PathSegment<'_>) -> bool {
             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 +853,6 @@ fn next_impl_id(&self) -> u32 {
     }
 }
 
-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> {