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 { @@ -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 { + let mut v = HashSet::new(); + + if let rustc_hir::Unsafety::Unsafe = header.unsafety { + v.insert(Qualifiers::Unsafe); } - if header.constness == rustc_hir::Constness::Const { - s.push_str("const ") + + if let rustc_hir::IsAsync::Async = header.asyncness { + v.insert(Qualifiers::Async); } - s + + if let rustc_hir::Constness::Const = header.constness { + v.insert(Qualifiers::Const); + } + + v } impl From for Function { @@ -242,7 +252,7 @@ impl From 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 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, 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, 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, pub decl: FnDecl, + pub generic_params: Vec, + pub header: HashSet, 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 +}