about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustdoc/html/static/js/search.js62
-rw-r--r--src/test/rustdoc-js-std/parser-errors.js88
-rw-r--r--src/test/rustdoc-js-std/parser-generics.js27
-rw-r--r--src/test/rustdoc-js-std/parser-returned.js38
-rw-r--r--src/test/rustdoc-js-std/parser-weird-queries.js26
5 files changed, 201 insertions, 40 deletions
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index cb078b5134d..239fef494ad 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -172,7 +172,7 @@ window.initSearch = function(rawSearchIndex) {
             throw new Error("`\"` cannot be used in generics");
         } else if (query.literalSearch) {
             throw new Error("Cannot have more than one literal search element");
-        } else if (parserState.totalElems !== 0) {
+        } else if (parserState.totalElems - parserState.genericsElems > 0) {
             throw new Error("Cannot use literal search when there is more than one element");
         }
         parserState.pos += 1;
@@ -234,11 +234,11 @@ window.initSearch = function(rawSearchIndex) {
      *
      * @return {QueryElement}                - The newly created `QueryElement`.
      */
-    function createQueryElement(query, parserState, name, generics) {
+    function createQueryElement(query, parserState, name, generics, isInGenerics) {
         if (name === '*' || (name.length === 0 && generics.length === 0)) {
             return;
         }
-        if (query.literalSearch && parserState.totalElems > 0) {
+        if (query.literalSearch && parserState.totalElems - parserState.genericsElems > 0) {
             throw new Error("You cannot have more than one element if you use quotes");
         }
         var pathSegments = name.split("::");
@@ -261,6 +261,9 @@ window.initSearch = function(rawSearchIndex) {
             throw new Error("Found generics without a path");
         }
         parserState.totalElems += 1;
+        if (isInGenerics) {
+            parserState.genericsElems += 1;
+        }
         return {
             name: name,
             fullPath: pathSegments,
@@ -315,6 +318,8 @@ window.initSearch = function(rawSearchIndex) {
         {
             if (isInGenerics) {
                 throw new Error("Unexpected `<` after `<`");
+            } else if (start >= end) {
+                throw new Error("Found generics without a path");
             }
             parserState.pos += 1;
             getItemsBefore(query, parserState, generics, ">");
@@ -327,7 +332,8 @@ window.initSearch = function(rawSearchIndex) {
                 query,
                 parserState,
                 parserState.userQuery.slice(start, end),
-                generics
+                generics,
+                isInGenerics
             )
         );
     }
@@ -346,13 +352,15 @@ window.initSearch = function(rawSearchIndex) {
      *                                      character.
      */
     function getItemsBefore(query, parserState, elems, endChar) {
-        var turns = 0;
+        var foundStopChar = true;
+
         while (parserState.pos < parserState.length) {
             var c = parserState.userQuery[parserState.pos];
             if (c === endChar) {
                 break;
-            } else if (c === "," && endChar !== "" && turns > 0) {
+            } else if (c === "," || c === " ") {
                 parserState.pos += 1;
+                foundStopChar = true;
                 continue;
             } else if (c === ":" && isPathStart(parserState)) {
                 throw new Error("Unexpected `::`: paths cannot start with `::`");
@@ -365,15 +373,21 @@ window.initSearch = function(rawSearchIndex) {
                 }
                 throw new Error("Unexpected `" + c + "` after " + extra);
             }
+            if (!foundStopChar) {
+                if (endChar !== "") {
+                    throw new Error(`Expected \`,\`, \` \` or \`${endChar}\`, found \`${c}\``);
+                }
+                throw new Error(`Expected \`,\` or \` \`, found \`${c}\``);
+            }
             var posBefore = parserState.pos;
             getNextElem(query, parserState, elems, endChar === ">");
-            turns += 1;
             // This case can be encountered if `getNextElem` encounted a "stop character" right from
-            // the start. For example if you have `,,`. In this case, we simply move up the current
-            // position to continue the parsing.
+            // the start. For example if you have `,,` or `<>`. In this case, we simply move up the
+            // current position to continue the parsing.
             if (posBefore === parserState.pos) {
                 parserState.pos += 1;
             }
+            foundStopChar = false;
         }
         // We are either at the end of the string or on the `endChar`` character, let's move forward
         // in any case.
@@ -389,10 +403,12 @@ window.initSearch = function(rawSearchIndex) {
      */
     function parseInput(query, parserState) {
         var c, before;
+        var foundStopChar = true;
 
         while (parserState.pos < parserState.length) {
             c = parserState.userQuery[parserState.pos];
             if (isStopCharacter(c)) {
+                foundStopChar = true;
                 if (c === "," || c === " ") {
                     parserState.pos += 1;
                     continue;
@@ -402,6 +418,7 @@ window.initSearch = function(rawSearchIndex) {
                     }
                     throw new Error(`Unexpected \`${c}\` (did you mean \`->\`?)`);
                 }
+                throw new Error(`Unexpected \`${c}\``);
             } else if (c === ":" &&
                 parserState.typeFilter === null &&
                 !isPathStart(parserState))
@@ -419,8 +436,15 @@ window.initSearch = function(rawSearchIndex) {
                 parserState.pos += 1;
                 parserState.totalElems = 0;
                 query.literalSearch = false;
+                foundStopChar = true;
                 continue;
             }
+            if (!foundStopChar) {
+                if (parserState.typeFilter !== null) {
+                    throw new Error(`Expected \`,\`, \` \` or \`->\`, found \`${c}\``);
+                }
+                throw new Error(`Expected \`,\`, \` \`, \`:\` or \`->\`, found \`${c}\``);
+            }
             before = query.elems.length;
             getNextElem(query, parserState, query.elems, false);
             if (query.elems.length === before) {
@@ -432,6 +456,7 @@ window.initSearch = function(rawSearchIndex) {
                 }
                 parserState.pos += 1;
             }
+            foundStopChar = false;
         }
         while (parserState.pos < parserState.length) {
             c = parserState.userQuery[parserState.pos];
@@ -515,17 +540,17 @@ window.initSearch = function(rawSearchIndex) {
      * arg = path [generics]
      * arg-without-generic = path
      * type-sep = COMMA/WS *(COMMA/WS)
-     * nonempty-arg-list = arg *(type-sep arg) *(COMMA/WS)
-     * nonempty-arg-list-without-generics = arg-without-generic *(type-sep arg-without-generic)
-     *                                      *(COMMA/WS)
-     * generics = OPEN-ANGLE-BRACKET *WS [ nonempty-arg-list-without-generics ] *WS
+     * nonempty-arg-list = *(type-sep) arg *(type-sep arg) *(type-sep)
+     * nonempty-arg-list-without-generics = *(type-sep) arg-without-generic
+     *                                      *(type-sep arg-without-generic) *(type-sep)
+     * generics = OPEN-ANGLE-BRACKET [ nonempty-arg-list-without-generics ] *(type-sep)
      *            CLOSE-ANGLE-BRACKET
-     * return-args = RETURN-ARROW *WS nonempty-arg-list
+     * return-args = RETURN-ARROW *(type-sep) nonempty-arg-list
      *
-     * exact-search = [type-filter *WS COLON] *WS QUOTE ident QUOTE *WS [generics]
-     * type-search = [type-filter *WS COLON] *WS path *WS nonempty-arg-list
+     * exact-search = [type-filter *WS COLON] [ RETURN-ARROW ] *WS QUOTE ident QUOTE [ generics ]
+     * type-search = [type-filter *WS COLON] [ nonempty-arg-list ] [ return-args ]
      *
-     * query = *WS (exact-search / type-search / return-args) *WS
+     * query = *WS (exact-search / type-search) *WS
      *
      * type-filter = (
      *     "mod" /
@@ -578,6 +603,7 @@ window.initSearch = function(rawSearchIndex) {
             pos: 0,
             // Total number of elements (includes generics).
             totalElems: 0,
+            genericsElems: 0,
             typeFilter: null,
             userQuery: userQuery.toLowerCase(),
         };
@@ -606,7 +632,7 @@ window.initSearch = function(rawSearchIndex) {
         query.foundElems = query.elems.length + query.returned.length;
         if (query.foundElems === 0 && parserState.length !== 0) {
             // In this case, we'll simply keep whatever was entered by the user...
-            query.elems.push(createQueryElement(query, parserState, userQuery, []));
+            query.elems.push(createQueryElement(query, parserState, userQuery, [], false));
             query.foundElems += 1;
         }
         return query;
diff --git a/src/test/rustdoc-js-std/parser-errors.js b/src/test/rustdoc-js-std/parser-errors.js
index 42d69ed3fe0..bd024a932a1 100644
--- a/src/test/rustdoc-js-std/parser-errors.js
+++ b/src/test/rustdoc-js-std/parser-errors.js
@@ -1,15 +1,14 @@
 const QUERY = [
     '<P>',
     '-> <P>',
-    '<"P">',
+    'a<"P">',
     '"P" "P"',
     'P "P"',
     '"p" p',
     '"const": p',
-    "<:a>",
-    "<::a>",
+    "a<:a>",
+    "a<::a>",
     "((a))",
-    "->,a",
     "(p -> p",
     "::a::b",
     "a::::b",
@@ -22,6 +21,12 @@ const QUERY = [
     "a>bb",
     "ab'",
     "a->",
+    '"p" <a>',
+    '"p" a<a>',
+    "a,<",
+    "aaaaa<>b",
+    "fn:aaaaa<>b",
+    "->a<>b",
 ];
 
 const PARSED = [
@@ -46,10 +51,10 @@ const PARSED = [
     {
         elems: [],
         foundElems: 0,
-        original: "<\"P\">",
+        original: "a<\"P\">",
         returned: [],
         typeFilter: -1,
-        userQuery: "<\"p\">",
+        userQuery: "a<\"p\">",
         error: "`\"` cannot be used in generics",
     },
     {
@@ -91,19 +96,19 @@ const PARSED = [
     {
         elems: [],
         foundElems: 0,
-        original: "<:a>",
+        original: "a<:a>",
         returned: [],
         typeFilter: -1,
-        userQuery: "<:a>",
+        userQuery: "a<:a>",
         error: "Unexpected `:` after `<`",
     },
     {
         elems: [],
         foundElems: 0,
-        original: "<::a>",
+        original: "a<::a>",
         returned: [],
         typeFilter: -1,
-        userQuery: "<::a>",
+        userQuery: "a<::a>",
         error: "Unexpected `::`: paths cannot start with `::`",
     },
     {
@@ -118,15 +123,6 @@ const PARSED = [
     {
         elems: [],
         foundElems: 0,
-        original: "->,a",
-        returned: [],
-        typeFilter: -1,
-        userQuery: "->,a",
-        error: "Unexpected `,` after `->`",
-    },
-    {
-        elems: [],
-        foundElems: 0,
         original: "(p -> p",
         returned: [],
         typeFilter: -1,
@@ -232,4 +228,58 @@ const PARSED = [
         userQuery: "a->",
         error: "Expected at least one item after `->`",
     },
+    {
+        elems: [],
+        foundElems: 0,
+        original: '"p" <a>',
+        returned: [],
+        typeFilter: -1,
+        userQuery: '"p" <a>',
+        error: "Found generics without a path",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: '"p" a<a>',
+        returned: [],
+        typeFilter: -1,
+        userQuery: '"p" a<a>',
+        error: "You cannot have more than one element if you use quotes",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: 'a,<',
+        returned: [],
+        typeFilter: -1,
+        userQuery: 'a,<',
+        error: 'Found generics without a path',
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: 'aaaaa<>b',
+        returned: [],
+        typeFilter: -1,
+        userQuery: 'aaaaa<>b',
+        error: 'Expected `,`, ` `, `:` or `->`, found `b`',
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: 'fn:aaaaa<>b',
+        returned: [],
+        typeFilter: -1,
+        userQuery: 'fn:aaaaa<>b',
+        error: 'Expected `,`, ` ` or `->`, found `b`',
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: '->a<>b',
+        returned: [],
+        typeFilter: -1,
+        userQuery: '->a<>b',
+        error: 'Expected `,` or ` `, found `b`',
+    },
 ];
diff --git a/src/test/rustdoc-js-std/parser-generics.js b/src/test/rustdoc-js-std/parser-generics.js
index cc92f2333d2..0cf7f5019aa 100644
--- a/src/test/rustdoc-js-std/parser-generics.js
+++ b/src/test/rustdoc-js-std/parser-generics.js
@@ -1,4 +1,4 @@
-const QUERY = ['A<B<C<D>,  E>', 'p<> u8'];
+const QUERY = ['A<B<C<D>,  E>', 'p<> u8', '"p"<a>'];
 
 const PARSED = [
     {
@@ -34,4 +34,29 @@ const PARSED = [
         userQuery: "p<> u8",
         error: null,
     },
+    {
+        elems: [
+            {
+                name: "p",
+                fullPath: ["p"],
+                pathWithoutLast: [],
+                pathLast: "p",
+                generics: [
+                    {
+                        name: "a",
+                        fullPath: ["a"],
+                        pathWithoutLast: [],
+                        pathLast: "a",
+                        generics: [],
+                    },
+                ],
+            },
+        ],
+        foundElems: 1,
+        original: '"p"<a>',
+        returned: [],
+        typeFilter: -1,
+        userQuery: '"p"<a>',
+        error: null,
+    },
 ];
diff --git a/src/test/rustdoc-js-std/parser-returned.js b/src/test/rustdoc-js-std/parser-returned.js
index 8910275c91e..b45466aa940 100644
--- a/src/test/rustdoc-js-std/parser-returned.js
+++ b/src/test/rustdoc-js-std/parser-returned.js
@@ -1,4 +1,4 @@
-const QUERY = ['-> F<P>', '-> P'];
+const QUERY = ['-> F<P>', '-> P', '->,a', 'aaaaa->a'];
 
 const PARSED = [
     {
@@ -39,4 +39,40 @@ const PARSED = [
         userQuery: "-> p",
         error: null,
     },
+    {
+        elems: [],
+        foundElems: 1,
+        original: "->,a",
+        returned: [{
+            name: "a",
+            fullPath: ["a"],
+            pathWithoutLast: [],
+            pathLast: "a",
+            generics: [],
+        }],
+        typeFilter: -1,
+        userQuery: "->,a",
+        error: null,
+    },
+    {
+        elems: [{
+            name: "aaaaa",
+            fullPath: ["aaaaa"],
+            pathWithoutLast: [],
+            pathLast: "aaaaa",
+            generics: [],
+        }],
+        foundElems: 2,
+        original: "aaaaa->a",
+        returned: [{
+            name: "a",
+            fullPath: ["a"],
+            pathWithoutLast: [],
+            pathLast: "a",
+            generics: [],
+        }],
+        typeFilter: -1,
+        userQuery: "aaaaa->a",
+        error: null,
+    },
 ];
diff --git a/src/test/rustdoc-js-std/parser-weird-queries.js b/src/test/rustdoc-js-std/parser-weird-queries.js
index 87ebe21c49b..4b4ce64284e 100644
--- a/src/test/rustdoc-js-std/parser-weird-queries.js
+++ b/src/test/rustdoc-js-std/parser-weird-queries.js
@@ -1,7 +1,7 @@
 // This test is mostly to check that the parser still kinda outputs something
 // (and doesn't enter an infinite loop!) even though the query is completely
 // invalid.
-const QUERY = ['a b', 'a   b', 'a,b(c)'];
+const QUERY = ['a b', 'a   b', 'a,b(c)', 'aaa,a'];
 
 const PARSED = [
     {
@@ -61,4 +61,28 @@ const PARSED = [
         userQuery: "a,b(c)",
         error: "Unexpected `(`",
     },
+    {
+        elems: [
+            {
+                name: "aaa",
+                fullPath: ["aaa"],
+                pathWithoutLast: [],
+                pathLast: "aaa",
+                generics: [],
+            },
+            {
+                name: "a",
+                fullPath: ["a"],
+                pathWithoutLast: [],
+                pathLast: "a",
+                generics: [],
+            },
+        ],
+        foundElems: 2,
+        original: "aaa,a",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "aaa,a",
+        error: null,
+    },
 ];