about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJacob Pratt <jacob@jhpratt.dev>2025-08-22 22:00:55 -0400
committerGitHub <noreply@github.com>2025-08-22 22:00:55 -0400
commit779818575efc0b462df96c463383a018be84fd24 (patch)
treefddf72f2542822464e2b252edb27a18f2a524927
parent566c13c88e790b96997c689ce9a0f067b9f0d6cf (diff)
parent401f40f1c19bb7055918b6409a73adc55edde39f (diff)
downloadrust-779818575efc0b462df96c463383a018be84fd24.tar.gz
rust-779818575efc0b462df96c463383a018be84fd24.zip
Rollup merge of #145731 - lolbinarycat:rustdoc-search-generic-pointer-142385, r=notriddle
Make raw pointers work in type-based search

fixes rust-lang/rust#142385
-rw-r--r--src/librustdoc/html/render/search_index.rs9
-rw-r--r--src/librustdoc/html/static/js/search.js95
-rw-r--r--tests/rustdoc-js-std/parser-errors.js8
-rw-r--r--tests/rustdoc-js/pointer.js240
-rw-r--r--tests/rustdoc-js/pointer.rs40
5 files changed, 351 insertions, 41 deletions
diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs
index 41657e290ea..dddc087d124 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 42b87d56252..5e65791bb66 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 49150cbd570..6e11dda8532 100644
--- a/tests/rustdoc-js-std/parser-errors.js
+++ b/tests/rustdoc-js-std/parser-errors.js
@@ -16,14 +16,6 @@ const PARSED = [
         error: "Found generics without a path",
     },
     {
-        query: '-> *',
-        elems: [],
-        foundElems: 0,
-        userQuery: "-> *",
-        returned: [],
-        error: "Unexpected `*` after ` ` (not a valid identifier)",
-    },
-    {
         query: 'a<"P">',
         elems: [],
         foundElems: 0,
diff --git a/tests/rustdoc-js/pointer.js b/tests/rustdoc-js/pointer.js
new file mode 100644
index 00000000000..b2b556858fd
--- /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>, usize -> ()',
+        'others': [
+            { 'path': 'pointer', 'name': 'pinky' },
+        ],
+    },
+    {
+        'query': 'pointer<usize>, pointer<usize> -> ()',
+        'others': [],
+    },
+    {
+        'query': 'pointer<mut, usize>, usize -> ()',
+        'others': [],
+    },
+    // thumb with explicit names
+    {
+        'query': 'thumb, thumb -> ()',
+        'others': [
+            { 'path': 'pointer::Thumb', 'name': 'up' },
+        ],
+    },
+    {
+        'query': 'pointer<thumb>, thumb -> ()',
+        'others': [
+            { 'path': 'pointer::Thumb', 'name': 'up' },
+        ],
+    },
+    {
+        'query': 'pointer<thumb>, pointer<thumb> -> ()',
+        'others': [],
+    },
+    {
+        'query': 'pointer<mut, thumb>, thumb -> ()',
+        'others': [],
+    },
+    // index with explicit names
+    {
+        'query': 'index, index -> ()',
+        'others': [
+            { 'path': 'pointer::Index', 'name': 'point' },
+        ],
+    },
+    {
+        'query': 'pointer<index>, index -> ()',
+        'others': [
+            { 'path': 'pointer::Index', 'name': 'point' },
+        ],
+    },
+    {
+        'query': 'pointer<index>, pointer<index> -> ()',
+        'others': [],
+    },
+    {
+        'query': 'pointer<mut, index>, index -> ()',
+        'others': [],
+    },
+    // ring with explicit names
+    {
+        'query': 'ring, ring -> ()',
+        'others': [
+            { 'path': 'pointer::Ring', 'name': 'wear' },
+        ],
+    },
+    {
+        'query': 'pointer<ring>, ring -> ()',
+        'others': [
+            { 'path': 'pointer::Ring', 'name': 'wear' },
+        ],
+    },
+    {
+        'query': 'pointer<ring>, pointer<ring> -> ()',
+        // can't leave out the `mut`, because can't reorder like that
+        'others': [],
+    },
+    {
+        'query': 'pointer<mut, ring>, pointer<ring> -> ()',
+        'others': [
+            { 'path': 'pointer::Ring', 'name': 'wear' },
+        ],
+    },
+    {
+        'query': 'pointer<mut, ring>, pointer<mut, ring> -> ()',
+        'others': [],
+    },
+    // middle with explicit names
+    {
+        'query': 'middle, middle -> ()',
+        'others': [
+            { 'path': 'pointer', 'name': 'show' },
+        ],
+    },
+    {
+        'query': 'pointer<middle>, pointer<middle> -> ()',
+        // can't leave out the mut
+        'others': [],
+    },
+    {
+        'query': 'pointer<mut, middle>, pointer<mut, middle> -> ()',
+        'others': [
+            { 'path': 'pointer', 'name': 'show' },
+        ],
+    },
+    {
+        'query': 'pointer<pointer<mut, middle>>, pointer<mut, pointer<middle>> -> ()',
+        'others': [
+            { 'path': 'pointer', 'name': 'show' },
+        ],
+    },
+    {
+        'query': 'pointer<mut, pointer<middle>>, pointer<pointer<mut, middle>> -> ()',
+        'others': [
+            { 'path': 'pointer', 'name': 'show' },
+        ],
+    },
+    {
+        'query': 'pointer<pointer<mut, middle>>, pointer<pointer<mut, middle>> -> ()',
+        'others': [],
+    },
+    {
+        'query': 'pointer<mut, pointer<middle>>, pointer<mut, pointer<middle>> -> ()',
+        '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 00000000000..8375a174303
--- /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!()
+}