diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 41657e290ea21..dddc087d124df 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -1494,7 +1494,9 @@ pub(crate) fn build_index( let search_unbox = match id { RenderTypeId::Mut => false, RenderTypeId::DefId(defid) => utils::has_doc_flag(tcx, defid, sym::search_unbox), - RenderTypeId::Primitive(PrimitiveType::Reference | PrimitiveType::Tuple) => true, + RenderTypeId::Primitive( + PrimitiveType::Reference | PrimitiveType::RawPointer | PrimitiveType::Tuple, + ) => true, RenderTypeId::Primitive(..) => false, RenderTypeId::AssociatedType(..) => false, // this bool is only used by `insert_into_map`, so it doesn't matter what we set here @@ -1855,7 +1857,7 @@ fn get_index_type_id( } clean::Primitive(p) => Some(RenderTypeId::Primitive(p)), clean::BorrowedRef { .. } => Some(RenderTypeId::Primitive(clean::PrimitiveType::Reference)), - clean::RawPointer(_, ref type_) => get_index_type_id(type_, rgen), + clean::RawPointer { .. } => Some(RenderTypeId::Primitive(clean::PrimitiveType::RawPointer)), // The type parameters are converted to generics in `simplify_fn_type` clean::Slice(_) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Slice)), clean::Array(_, _) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Array)), @@ -2113,7 +2115,8 @@ fn simplify_fn_type<'a, 'tcx>( generics: Some(ty_generics), }); } - Type::BorrowedRef { lifetime: _, mutability, ref type_ } => { + Type::BorrowedRef { lifetime: _, mutability, ref type_ } + | Type::RawPointer(mutability, ref type_) => { let mut ty_generics = Vec::new(); if mutability.is_mut() { ty_generics.push(RenderType { diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 42b87d562529b..5e65791bb6695 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -587,6 +587,45 @@ function getNextElem(query, parserState, elems, isInGenerics) { /** @type {rustdoc.ParserQueryElement[]} */ const generics = []; + /** @type {function(string, string): void} */ + const handleRefOrPtr = (chr, name) => { + if (parserState.typeFilter !== null && parserState.typeFilter !== "primitive") { + throw [ + "Invalid search type: primitive ", + chr, + " and ", + parserState.typeFilter, + " both specified", + ]; + } + parserState.typeFilter = null; + parserState.pos += 1; + let c = parserState.userQuery[parserState.pos]; + while (c === " " && parserState.pos < parserState.length) { + parserState.pos += 1; + c = parserState.userQuery[parserState.pos]; + } + const generics = []; + const pos = parserState.pos; + if (parserState.userQuery.slice(pos, pos + 3) === "mut") { + generics.push(makePrimitiveElement("mut", { typeFilter: "keyword" })); + parserState.pos += 3; + c = parserState.userQuery[parserState.pos]; + } else if (chr === "*" && parserState.userQuery.slice(pos, pos + 5) === "const") { + // make *const T parse the same as *T + parserState.pos += 5; + c = parserState.userQuery[parserState.pos]; + } + while (c === " " && parserState.pos < parserState.length) { + parserState.pos += 1; + c = parserState.userQuery[parserState.pos]; + } + if (!isEndCharacter(c) && parserState.pos < parserState.length) { + getFilteredNextElem(query, parserState, generics, isInGenerics); + } + elems.push(makePrimitiveElement(name, { generics })); + }; + skipWhitespace(parserState); let start = parserState.pos; let end; @@ -636,36 +675,9 @@ function getNextElem(query, parserState, elems, isInGenerics) { elems.push(makePrimitiveElement(name, { bindingName, generics })); } } else if (parserState.userQuery[parserState.pos] === "&") { - if (parserState.typeFilter !== null && parserState.typeFilter !== "primitive") { - throw [ - "Invalid search type: primitive ", - "&", - " and ", - parserState.typeFilter, - " both specified", - ]; - } - parserState.typeFilter = null; - parserState.pos += 1; - let c = parserState.userQuery[parserState.pos]; - while (c === " " && parserState.pos < parserState.length) { - parserState.pos += 1; - c = parserState.userQuery[parserState.pos]; - } - const generics = []; - if (parserState.userQuery.slice(parserState.pos, parserState.pos + 3) === "mut") { - generics.push(makePrimitiveElement("mut", { typeFilter: "keyword" })); - parserState.pos += 3; - c = parserState.userQuery[parserState.pos]; - } - while (c === " " && parserState.pos < parserState.length) { - parserState.pos += 1; - c = parserState.userQuery[parserState.pos]; - } - if (!isEndCharacter(c) && parserState.pos < parserState.length) { - getFilteredNextElem(query, parserState, generics, isInGenerics); - } - elems.push(makePrimitiveElement("reference", { generics })); + handleRefOrPtr("&", "reference"); + } else if (parserState.userQuery[parserState.pos] === "*") { + handleRefOrPtr("*", "pointer"); } else { const isStringElem = parserState.userQuery[start] === "\""; // We handle the strings on their own mostly to make code easier to follow. @@ -1185,6 +1197,7 @@ class DocSearch { this.typeNameIdOfUnit = -1; this.typeNameIdOfTupleOrUnit = -1; this.typeNameIdOfReference = -1; + this.typeNameIdOfPointer = -1; this.typeNameIdOfHof = -1; this.utf8decoder = new TextDecoder(); @@ -1224,6 +1237,7 @@ class DocSearch { tupleOrUnit, // reference matches `&` reference, + pointer, // never matches `!` never, ] = await Promise.all([ @@ -1239,6 +1253,7 @@ class DocSearch { nn.search("unit"), nn.search("()"), nn.search("reference"), + nn.search("pointer"), nn.search("never"), ]); /** @@ -1270,6 +1285,7 @@ class DocSearch { this.typeNameIdOfUnit = await first(unit, TY_PRIMITIVE, ""); this.typeNameIdOfTupleOrUnit = await first(tupleOrUnit, TY_PRIMITIVE, ""); this.typeNameIdOfReference = await first(reference, TY_PRIMITIVE, ""); + this.typeNameIdOfPointer = await first(pointer, TY_PRIMITIVE, ""); this.typeNameIdOfHof = await first(hof, TY_PRIMITIVE, ""); this.typeNameIdOfNever = await first(never, TY_PRIMITIVE, ""); } @@ -2309,6 +2325,25 @@ class DocSearch { }, result), ); return true; + } else if (fnType.id === this.typeNameIdOfPointer) { + pushText({ name: "*", highlighted: fnType.highlighted }, result); + if (fnType.generics.length < 2) { + pushText({ name: "const ", highlighted: fnType.highlighted }, result); + } + let prevHighlighted = false; + await onEachBtwnAsync( + fnType.generics, + async value => { + prevHighlighted = !!value.highlighted; + await writeFn(value, result); + }, + // @ts-expect-error + value => pushText({ + name: " ", + highlighted: prevHighlighted && value.highlighted, + }, result), + ); + return true; } else if ( fnType.id === this.typeNameIdOfFn || fnType.id === this.typeNameIdOfFnMut || diff --git a/tests/rustdoc-js-std/parser-errors.js b/tests/rustdoc-js-std/parser-errors.js index 49150cbd570ac..6e11dda8532fa 100644 --- a/tests/rustdoc-js-std/parser-errors.js +++ b/tests/rustdoc-js-std/parser-errors.js @@ -15,14 +15,6 @@ const PARSED = [ returned: [], error: "Found generics without a path", }, - { - query: '-> *', - elems: [], - foundElems: 0, - userQuery: "-> *", - returned: [], - error: "Unexpected `*` after ` ` (not a valid identifier)", - }, { query: 'a<"P">', elems: [], diff --git a/tests/rustdoc-js/pointer.js b/tests/rustdoc-js/pointer.js new file mode 100644 index 0000000000000..b2b556858fdbb --- /dev/null +++ b/tests/rustdoc-js/pointer.js @@ -0,0 +1,240 @@ +// exact-check + +const EXPECTED = [ + // pinkie with explicit names + { + 'query': 'usize, usize -> ()', + 'others': [ + { 'path': 'pointer', 'name': 'pinky' }, + ], + }, + { + 'query': 'pointer, usize -> ()', + 'others': [ + { 'path': 'pointer', 'name': 'pinky' }, + ], + }, + { + 'query': 'pointer, pointer -> ()', + 'others': [], + }, + { + 'query': 'pointer, usize -> ()', + 'others': [], + }, + // thumb with explicit names + { + 'query': 'thumb, thumb -> ()', + 'others': [ + { 'path': 'pointer::Thumb', 'name': 'up' }, + ], + }, + { + 'query': 'pointer, thumb -> ()', + 'others': [ + { 'path': 'pointer::Thumb', 'name': 'up' }, + ], + }, + { + 'query': 'pointer, pointer -> ()', + 'others': [], + }, + { + 'query': 'pointer, thumb -> ()', + 'others': [], + }, + // index with explicit names + { + 'query': 'index, index -> ()', + 'others': [ + { 'path': 'pointer::Index', 'name': 'point' }, + ], + }, + { + 'query': 'pointer, index -> ()', + 'others': [ + { 'path': 'pointer::Index', 'name': 'point' }, + ], + }, + { + 'query': 'pointer, pointer -> ()', + 'others': [], + }, + { + 'query': 'pointer, index -> ()', + 'others': [], + }, + // ring with explicit names + { + 'query': 'ring, ring -> ()', + 'others': [ + { 'path': 'pointer::Ring', 'name': 'wear' }, + ], + }, + { + 'query': 'pointer, ring -> ()', + 'others': [ + { 'path': 'pointer::Ring', 'name': 'wear' }, + ], + }, + { + 'query': 'pointer, pointer -> ()', + // can't leave out the `mut`, because can't reorder like that + 'others': [], + }, + { + 'query': 'pointer, pointer -> ()', + 'others': [ + { 'path': 'pointer::Ring', 'name': 'wear' }, + ], + }, + { + 'query': 'pointer, pointer -> ()', + 'others': [], + }, + // middle with explicit names + { + 'query': 'middle, middle -> ()', + 'others': [ + { 'path': 'pointer', 'name': 'show' }, + ], + }, + { + 'query': 'pointer, pointer -> ()', + // can't leave out the mut + 'others': [], + }, + { + 'query': 'pointer, pointer -> ()', + 'others': [ + { 'path': 'pointer', 'name': 'show' }, + ], + }, + { + 'query': 'pointer>, pointer> -> ()', + 'others': [ + { 'path': 'pointer', 'name': 'show' }, + ], + }, + { + 'query': 'pointer>, pointer> -> ()', + 'others': [ + { 'path': 'pointer', 'name': 'show' }, + ], + }, + { + 'query': 'pointer>, pointer> -> ()', + 'others': [], + }, + { + 'query': 'pointer>, pointer> -> ()', + 'others': [], + }, + // pinkie with shorthand + { + 'query': '*const usize, usize -> ()', + 'others': [ + { 'path': 'pointer', 'name': 'pinky' }, + ], + }, + // you can omit the `const`, if you want. + { + 'query': '*usize, usize -> ()', + 'others': [ + { 'path': 'pointer', 'name': 'pinky' }, + ], + }, + { + 'query': '*const usize, *const usize -> ()', + 'others': [], + }, + { + 'query': '*mut usize, usize -> ()', + 'others': [], + }, + // thumb with shorthand + { + 'query': '*const thumb, thumb -> ()', + 'others': [ + { 'path': 'pointer::Thumb', 'name': 'up' }, + ], + }, + { + 'query': '*const thumb, *const thumb -> ()', + 'others': [], + }, + { + 'query': '*mut thumb, thumb -> ()', + 'others': [], + }, + // index with explicit names + { + 'query': '*const index, index -> ()', + 'others': [ + { 'path': 'pointer::Index', 'name': 'point' }, + ], + }, + { + 'query': '*const index, *const index -> ()', + 'others': [], + }, + { + 'query': '*mut index, index -> ()', + 'others': [], + }, + // ring with shorthand + { + 'query': '*const ring, ring -> ()', + 'others': [ + { 'path': 'pointer::Ring', 'name': 'wear' }, + ], + }, + { + 'query': '*const ring, ring -> ()', + 'others': [ + { 'path': 'pointer::Ring', 'name': 'wear' }, + ], + }, + { + 'query': '*mut ring, *const ring -> ()', + 'others': [ + { 'path': 'pointer::Ring', 'name': 'wear' }, + ], + }, + { + 'query': '*mut ring, *mut ring -> ()', + 'others': [], + }, + // middle with shorthand + { + 'query': '*const middle, *const middle -> ()', + // can't leave out the mut + 'others': [], + }, + { + 'query': '*mut middle, *mut middle -> ()', + 'others': [ + { 'path': 'pointer', 'name': 'show' }, + ], + }, + { + 'query': '*const *mut middle, *mut *const middle -> ()', + 'others': [ + { 'path': 'pointer', 'name': 'show' }, + ], + }, + { + 'query': '*mut *const middle, *const *mut middle -> ()', + 'others': [ + { 'path': 'pointer', 'name': 'show' }, + ], + }, + { + 'query': '*const *mut middle, *const *mut middle -> ()', + 'others': [], + }, + { + 'query': '*mut *const middle, *mut *const middle -> ()', + 'others': [], + }, +]; diff --git a/tests/rustdoc-js/pointer.rs b/tests/rustdoc-js/pointer.rs new file mode 100644 index 0000000000000..8375a17430360 --- /dev/null +++ b/tests/rustdoc-js/pointer.rs @@ -0,0 +1,40 @@ +#![feature(extern_types)] + +pub fn pinky(input: *const usize, manage: usize) { + unimplemented!() +} + +pub struct Thumb; + +impl Thumb { + pub fn up(this: *const Self, finger: Thumb) { + unimplemented!() + } +} + +pub enum Index {} + +impl Index { + pub fn point(self, data: *const Index) { + unimplemented!() + } +} + +pub union Ring { + magic: u32, + marriage: f32, +} + +impl Ring { + pub fn wear(this: *mut Self, extra: *const Ring) { + unimplemented!() + } +} + +extern "C" { + pub type Middle; +} + +pub fn show(left: *const *mut Middle, right: *mut *const Middle) { + unimplemented!() +}