about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDylan DPC <dylan.dpc@gmail.com>2021-02-14 16:54:45 +0100
committerGitHub <noreply@github.com>2021-02-14 16:54:45 +0100
commit641c3785dc875744fae75d5c1db12708a819e235 (patch)
treec9fd4f4f525aaa389a6bba57dcaa061e181ed8e5
parente3b2655c3a37b9655cca934c475672517297b42f (diff)
parentbe4ea06643a5bd4ff3cb91efdaafd7acb070cb30 (diff)
downloadrust-641c3785dc875744fae75d5c1db12708a819e235.tar.gz
rust-641c3785dc875744fae75d5c1db12708a819e235.zip
Rollup merge of #81891 - CraftSpider:fn-header, r=jyn514
[rustdoc-json] Make `header` a vec of modifiers, and FunctionPointer consistent

Bumps version number and adds tests, this is a breaking change. I can split this into two (`is_unsafe` -> `header` and `header: Vec<Modifiers>`) if desired.

Rationale: Modifiers are individual notes on a function, it makes more sense for them to be a list of an independent enum over a String which is inconsistently exposing the HIR representation (prefix_str vs custom literals).
Function pointers currently only support `unsafe`, but there has been talk on and off about allowing them to also support `const`, and this makes handling their modifiers consistent with handling those of a function, allowing better shared code.

`@rustbot` modify labels: +A-rustdoc-json +T-rustdoc
CC: `@HeroicKatora`
r? `@jyn514`
-rw-r--r--src/etc/check_missing_items.py2
-rw-r--r--src/librustdoc/json/conversions.rs36
-rw-r--r--src/librustdoc/json/mod.rs2
-rw-r--r--src/rustdoc-json-types/lib.rs19
-rw-r--r--src/test/rustdoc-json/fn_pointer/header.rs5
-rw-r--r--src/test/rustdoc-json/fns/header.rs22
-rw-r--r--src/test/rustdoc-json/methods/header.rs26
7 files changed, 95 insertions, 17 deletions
diff --git a/src/etc/check_missing_items.py b/src/etc/check_missing_items.py
index c7ca0134f9c..7572b8c6f4a 100644
--- a/src/etc/check_missing_items.py
+++ b/src/etc/check_missing_items.py
@@ -108,7 +108,7 @@ def check_type(ty):
     elif ty["kind"] == "function_pointer":
         for param in ty["inner"]["generic_params"]:
             check_generic_param(param)
-        check_decl(ty["inner"]["inner"])
+        check_decl(ty["inner"]["decl"])
     elif ty["kind"] == "qualified_path":
         check_type(ty["inner"]["self_type"])
         check_type(ty["inner"]["trait"])
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index f96f6d52088..e2652ca378a 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -2,6 +2,8 @@
 //! the `clean` types but with some fields removed or stringified to simplify the output and not
 //! expose unstable compiler internals.
 
+#![allow(rustc::default_hash_types)]
+
 use std::convert::From;
 
 use rustc_ast::ast;
@@ -16,6 +18,7 @@ use crate::clean;
 use crate::clean::utils::print_const_expr;
 use crate::formats::item_type::ItemType;
 use crate::json::JsonRenderer;
+use std::collections::HashSet;
 
 impl JsonRenderer<'_> {
     pub(super) fn convert_item(&self, item: clean::Item) -> Option<Item> {
@@ -225,15 +228,22 @@ crate fn from_ctor_kind(struct_type: CtorKind) -> StructType {
     }
 }
 
-fn stringify_header(header: &rustc_hir::FnHeader) -> String {
-    let mut s = String::from(header.unsafety.prefix_str());
-    if header.asyncness == rustc_hir::IsAsync::Async {
-        s.push_str("async ")
+crate fn from_fn_header(header: &rustc_hir::FnHeader) -> HashSet<Qualifiers> {
+    let mut v = HashSet::new();
+
+    if let rustc_hir::Unsafety::Unsafe = header.unsafety {
+        v.insert(Qualifiers::Unsafe);
+    }
+
+    if let rustc_hir::IsAsync::Async = header.asyncness {
+        v.insert(Qualifiers::Async);
     }
-    if header.constness == rustc_hir::Constness::Const {
-        s.push_str("const ")
+
+    if let rustc_hir::Constness::Const = header.constness {
+        v.insert(Qualifiers::Const);
     }
-    s
+
+    v
 }
 
 impl From<clean::Function> for Function {
@@ -242,7 +252,7 @@ impl From<clean::Function> for Function {
         Function {
             decl: decl.into(),
             generics: generics.into(),
-            header: stringify_header(&header),
+            header: from_fn_header(&header),
             abi: header.abi.to_string(),
         }
     }
@@ -364,7 +374,13 @@ impl From<clean::BareFunctionDecl> for FunctionPointer {
     fn from(bare_decl: clean::BareFunctionDecl) -> Self {
         let clean::BareFunctionDecl { unsafety, generic_params, decl, abi } = bare_decl;
         FunctionPointer {
-            is_unsafe: unsafety == rustc_hir::Unsafety::Unsafe,
+            header: if let rustc_hir::Unsafety::Unsafe = unsafety {
+                let mut hs = HashSet::new();
+                hs.insert(Qualifiers::Unsafe);
+                hs
+            } else {
+                HashSet::new()
+            },
             generic_params: generic_params.into_iter().map(Into::into).collect(),
             decl: decl.into(),
             abi: abi.to_string(),
@@ -439,7 +455,7 @@ crate fn from_function_method(function: clean::Function, has_body: bool) -> Meth
     Method {
         decl: decl.into(),
         generics: generics.into(),
-        header: stringify_header(&header),
+        header: from_fn_header(&header),
         abi: header.abi.to_string(),
         has_body,
     }
diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs
index 876b1b56dee..b31276c9dcb 100644
--- a/src/librustdoc/json/mod.rs
+++ b/src/librustdoc/json/mod.rs
@@ -243,7 +243,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
                     )
                 })
                 .collect(),
-            format_version: 3,
+            format_version: 4,
         };
         let mut p = self.out_path.clone();
         p.push(output.index.get(&output.root).unwrap().name.clone().unwrap());
diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs
index 297fc95006b..6188b87d2c6 100644
--- a/src/rustdoc-json-types/lib.rs
+++ b/src/rustdoc-json-types/lib.rs
@@ -3,7 +3,7 @@
 //! These types are the public API exposed through the `--output-format json` flag. The [`Crate`]
 //! struct is the root of the JSON blob and all other items are contained within.
 
-use std::collections::HashMap;
+use std::collections::{HashMap, HashSet};
 use std::path::PathBuf;
 
 use serde::{Deserialize, Serialize};
@@ -281,11 +281,20 @@ pub enum StructType {
     Unit,
 }
 
+#[non_exhaustive]
+#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
+#[serde(rename_all = "snake_case")]
+pub enum Qualifiers {
+    Const,
+    Unsafe,
+    Async,
+}
+
 #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
 pub struct Function {
     pub decl: FnDecl,
     pub generics: Generics,
-    pub header: String,
+    pub header: HashSet<Qualifiers>,
     pub abi: String,
 }
 
@@ -293,7 +302,7 @@ pub struct Function {
 pub struct Method {
     pub decl: FnDecl,
     pub generics: Generics,
-    pub header: String,
+    pub header: HashSet<Qualifiers>,
     pub abi: String,
     pub has_body: bool,
 }
@@ -404,9 +413,9 @@ pub enum Type {
 
 #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
 pub struct FunctionPointer {
-    pub is_unsafe: bool,
-    pub generic_params: Vec<GenericParamDef>,
     pub decl: FnDecl,
+    pub generic_params: Vec<GenericParamDef>,
+    pub header: HashSet<Qualifiers>,
     pub abi: String,
 }
 
diff --git a/src/test/rustdoc-json/fn_pointer/header.rs b/src/test/rustdoc-json/fn_pointer/header.rs
new file mode 100644
index 00000000000..a5038e0cd2a
--- /dev/null
+++ b/src/test/rustdoc-json/fn_pointer/header.rs
@@ -0,0 +1,5 @@
+// @has header.json "$.index[*][?(@.name=='FnPointer')].inner.type.inner.header" "[]"
+pub type FnPointer = fn();
+
+// @has - "$.index[*][?(@.name=='UnsafePointer')].inner.type.inner.header" '["unsafe"]'
+pub type UnsafePointer = unsafe fn();
diff --git a/src/test/rustdoc-json/fns/header.rs b/src/test/rustdoc-json/fns/header.rs
new file mode 100644
index 00000000000..29741dd50da
--- /dev/null
+++ b/src/test/rustdoc-json/fns/header.rs
@@ -0,0 +1,22 @@
+// edition:2018
+
+// @has header.json "$.index[*][?(@.name=='nothing_fn')].inner.header" "[]"
+pub fn nothing_fn() {}
+
+// @has - "$.index[*][?(@.name=='const_fn')].inner.header" '["const"]'
+pub const fn const_fn() {}
+
+// @has - "$.index[*][?(@.name=='async_fn')].inner.header" '["async"]'
+pub async fn async_fn() {}
+
+// @count - "$.index[*][?(@.name=='async_unsafe_fn')].inner.header[*]" 2
+// @has - "$.index[*][?(@.name=='async_unsafe_fn')].inner.header[*]" '"async"'
+// @has - "$.index[*][?(@.name=='async_unsafe_fn')].inner.header[*]" '"unsafe"'
+pub async unsafe fn async_unsafe_fn() {}
+
+// @count - "$.index[*][?(@.name=='const_unsafe_fn')].inner.header[*]" 2
+// @has - "$.index[*][?(@.name=='const_unsafe_fn')].inner.header[*]" '"const"'
+// @has - "$.index[*][?(@.name=='const_unsafe_fn')].inner.header[*]" '"unsafe"'
+pub const unsafe fn const_unsafe_fn() {}
+
+// It's impossible for a function to be both const and async, so no test for that
diff --git a/src/test/rustdoc-json/methods/header.rs b/src/test/rustdoc-json/methods/header.rs
new file mode 100644
index 00000000000..50a3db75ef3
--- /dev/null
+++ b/src/test/rustdoc-json/methods/header.rs
@@ -0,0 +1,26 @@
+// edition:2018
+
+pub struct Foo;
+
+impl Foo {
+    // @has header.json "$.index[*][?(@.name=='nothing_meth')].inner.header" "[]"
+    pub fn nothing_meth() {}
+
+    // @has - "$.index[*][?(@.name=='const_meth')].inner.header" '["const"]'
+    pub const fn const_meth() {}
+
+    // @has - "$.index[*][?(@.name=='async_meth')].inner.header" '["async"]'
+    pub async fn async_meth() {}
+
+    // @count - "$.index[*][?(@.name=='async_unsafe_meth')].inner.header[*]" 2
+    // @has - "$.index[*][?(@.name=='async_unsafe_meth')].inner.header[*]" '"async"'
+    // @has - "$.index[*][?(@.name=='async_unsafe_meth')].inner.header[*]" '"unsafe"'
+    pub async unsafe fn async_unsafe_meth() {}
+
+    // @count - "$.index[*][?(@.name=='const_unsafe_meth')].inner.header[*]" 2
+    // @has - "$.index[*][?(@.name=='const_unsafe_meth')].inner.header[*]" '"const"'
+    // @has - "$.index[*][?(@.name=='const_unsafe_meth')].inner.header[*]" '"unsafe"'
+    pub const unsafe fn const_unsafe_meth() {}
+
+    // It's impossible for a method to be both const and async, so no test for that
+}