about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGuillaume Gomez <guillaume.gomez@huawei.com>2022-01-04 15:44:00 +0100
committerGuillaume Gomez <guillaume.gomez@huawei.com>2022-04-18 20:59:08 +0200
commit264064df36e055c19af2c82145bbbe616b32fb02 (patch)
treeae9031f6c90138a37624c8ccbd75be38a97a6795
parent99c5394ecc92190db16fc8dce1260658cbeedeb1 (diff)
downloadrust-264064df36e055c19af2c82145bbbe616b32fb02.tar.gz
rust-264064df36e055c19af2c82145bbbe616b32fb02.zip
* Greatly improve the rustdoc search parser source code
* Move all functions outside parseQuery
-rw-r--r--src/librustdoc/html/static/js/externs.js44
-rw-r--r--src/librustdoc/html/static/js/search.js851
-rw-r--r--src/test/rustdoc-gui/search-result-color.goml2
-rw-r--r--src/test/rustdoc-js-std/parser-errors.js25
-rw-r--r--src/test/rustdoc-js-std/parser-filter.js9
-rw-r--r--src/test/rustdoc-js-std/parser-generics.js35
-rw-r--r--src/test/rustdoc-js-std/parser-in_args.js6
-rw-r--r--src/test/rustdoc-js-std/parser-invalid.js12
-rw-r--r--src/test/rustdoc-js-std/parser-literal.js3
-rw-r--r--src/test/rustdoc-js-std/parser-paths.js12
-rw-r--r--src/test/rustdoc-js-std/parser-quote.js6
-rw-r--r--src/test/rustdoc-js-std/parser-returned.js6
-rw-r--r--src/test/rustdoc-js-std/vec-new.js2
-rw-r--r--src/test/rustdoc-js/doc-alias-whitespace.js2
-rw-r--r--src/test/rustdoc-js/doc-alias.js42
-rw-r--r--src/tools/rustdoc-js/tester.js16
16 files changed, 563 insertions, 510 deletions
diff --git a/src/librustdoc/html/static/js/externs.js b/src/librustdoc/html/static/js/externs.js
index 15665b1f31a..1fdd3068a03 100644
--- a/src/librustdoc/html/static/js/externs.js
+++ b/src/librustdoc/html/static/js/externs.js
@@ -8,7 +8,6 @@ function initSearch(searchIndex){}
 
 /**
  * @typedef {{
- *     isExact: boolean,
  *     name: string,
  *     fullPath: Array<string>,
  *     pathWithoutLast: Array<string>,
@@ -20,18 +19,23 @@ var QueryElement;
 
 /**
  * @typedef {{
+ *      pos: number,
+ *      totalElems: number,
+ *      typeFilter: (null|string),
+ *      userQuery: string,
+ * }}
+ */
+var ParserState;
+
+/**
+ * @typedef {{
  *     original: string,
  *     userQuery: string,
- *     length: number,
- *     pos: number,
  *     typeFilter: number,
  *     elems: Array<QueryElement>,
- *     elemName: (string|null),
  *     args: Array<QueryElement>,
  *     returned: Array<QueryElement>,
  *     foundElems: number,
- *     id: string,
- *     nameSplit: (string|null),
  * }}
  */
 var ParsedQuery;
@@ -50,3 +54,31 @@ var ParsedQuery;
  * }}
  */
 var Row;
+
+/**
+ * @typedef {{
+ *    in_args: Array<Object>,
+ *    returned: Array<Object>,
+ *    others: Array<Object>,
+ *    query: ParsedQuery,
+ * }}
+ */
+var ResultsTable;
+
+/**
+ * @typedef {{
+ * crate: "std"
+ *     desc: string,
+ *     displayPath: string,
+ *     fullPath: string,
+ *     href: string,
+ *     id: number,
+ *     lev: number,
+ *     name: string,
+ *     normalizedName: string,
+ *     parent: (Object|undefined),
+ *     path: string,
+ *     ty: number,
+ * }}
+ */
+var Results;
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index 469551f2092..7f21fa8bea6 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -124,6 +124,302 @@ window.initSearch = function(rawSearchIndex) {
         searchState.input.value = params.search || "";
     }
 
+    function isWhitespace(c) {
+        return " \t\n\r".indexOf(c) !== -1;
+    }
+
+    function isSpecialStartCharacter(c) {
+        return "(<\"".indexOf(c) !== -1;
+    }
+
+    function isStopCharacter(c) {
+        return isWhitespace(c) || "),>-=".indexOf(c) !== -1;
+    }
+
+    function removeEmptyStringsFromArray(arr) {
+        for (var i = 0, len = arr.length; i < len; ++i) {
+            if (arr[i] === "") {
+                arr.splice(i, 1);
+                i -= 1;
+            }
+        }
+    }
+
+    function itemTypeFromName(typename) {
+        for (var i = 0, len = itemTypes.length; i < len; ++i) {
+            if (itemTypes[i] === typename) {
+                return i;
+            }
+        }
+        return NO_TYPE_FILTER;
+    }
+
+    /**
+     * If we encounter a `"`, then we try to extract the string from it until we find another `"`.
+     *
+     * This function will throw an error in the following cases:
+     * * There is already another string element.
+     * * We are parsing a generic argument.
+     * * There is more than one element.
+     * * There is no closing `"`.
+     *
+     * @param {ParsedQuery} query
+     * @param {ParserState} parserState
+     * @param {boolean} isInGenerics
+     */
+    function getStringElem(query, parserState, isInGenerics) {
+        if (isInGenerics) {
+            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) {
+            throw new Error("Cannot use literal search when there is more than one element");
+        }
+        parserState.pos += 1;
+        while (parserState.pos < parserState.length &&
+            parserState.userQuery[parserState.pos] !== "\"")
+        {
+            parserState.pos += 1;
+        }
+        if (parserState.pos >= parserState.length) {
+            throw new Error("Unclosed `\"`");
+        }
+        // To skip the quote at the end.
+        parserState.pos += 1;
+        query.literalSearch = true;
+    }
+
+    /**
+     * Increase the parser position as long as the character is a whitespace. This check is
+     * performed with the `isWhitespace` function.
+     *
+     * @param {ParserState} parserState
+     */
+    function skipWhitespaces(parserState) {
+        while (parserState.pos < parserState.length) {
+            var c = parserState.userQuery[parserState.pos];
+            if (!isWhitespace(c)) {
+                break;
+            }
+            parserState.pos += 1;
+        }
+    }
+
+    /**
+     * Returns `true` if the current parser position is starting with "::".
+     *
+     * @param {ParserState} parserState
+     * @return {boolean}
+     */
+    function isPathStart(parserState) {
+        return parserState.userQuery.slice(parserState.pos, parserState.pos + 2) == '::';
+    }
+
+    /**
+     * Returns `true` if the current parser position is starting with "->".
+     *
+     * @param {ParserState} parserState
+     * @return {boolean}
+     */
+    function isReturnArrow(parserState) {
+        return parserState.userQuery.slice(parserState.pos, parserState.pos + 2) == '->';
+    }
+
+    /**
+     * @param {ParsedQuery} query
+     * @param {ParserState} parserState
+     * @param {Array<QueryElement>} elems    - This is where the new {QueryElement} will be added.
+     * @param {string} name                  - Name of the query element.
+     * @param {Array<QueryElement>} generics - List of generics of this query element.
+     */
+    function createQueryElement(query, parserState, elems, name, generics) {
+        removeEmptyStringsFromArray(generics);
+        if (name === '*' || (name.length === 0 && generics.length === 0)) {
+            return;
+        }
+        if (query.literalSearch && parserState.totalElems > 0) {
+            throw new Error("You cannot have more than one element if you use quotes");
+        }
+        var pathSegments = name.split("::");
+        removeEmptyStringsFromArray(pathSegments);
+        // In case we only have something like `<p>`, there is no name but it remains valid.
+        if (pathSegments.length === 0) {
+            pathSegments = [""];
+        }
+        elems.push({
+            name: name,
+            fullPath: pathSegments,
+            pathWithoutLast: pathSegments.slice(0, pathSegments.length - 1),
+            pathLast: pathSegments[pathSegments.length - 1],
+            generics: generics,
+        });
+        parserState.totalElems += 1;
+    }
+
+    /**
+     * @param {ParsedQuery} query
+     * @param {ParserState} parserState
+     * @param {Array<QueryElement>} elems - This is where the new {QueryElement} will be added.
+     * @param {boolean} isInGenerics
+     */
+    function getNextElem(query, parserState, elems, isInGenerics) {
+        var generics = [];
+
+        var start = parserState.pos;
+        var end = start;
+        // We handle the strings on their own mostly to make code easier to follow.
+        if (parserState.userQuery[parserState.pos] === "\"") {
+            start += 1;
+            getStringElem(query, parserState, isInGenerics);
+            end = parserState.pos - 1;
+            skipWhitespaces(parserState);
+        } else {
+            while (parserState.pos < parserState.length) {
+                var c = parserState.userQuery[parserState.pos];
+                if (isStopCharacter(c) || isSpecialStartCharacter(c)) {
+                    break;
+                }
+                // If we allow paths ("str::string" for example).
+                else if (c === ":") {
+                    if (!isPathStart(parserState)) {
+                        break;
+                    }
+                    // Skip current ":".
+                    parserState.pos += 1;
+                }
+                parserState.pos += 1;
+                end = parserState.pos;
+                skipWhitespaces(parserState);
+            }
+        }
+        if (parserState.pos < parserState.length &&
+            parserState.userQuery[parserState.pos] === "<")
+        {
+            parserState.pos += 1;
+            getItemsBefore(query, parserState, generics, ">");
+        }
+        if (start >= end && generics.length === 0) {
+            return;
+        }
+        createQueryElement(
+            query,
+            parserState,
+            elems,
+            parserState.userQuery.slice(start, end),
+            generics);
+    }
+
+    /**
+     * @param {ParsedQuery} query
+     * @param {ParserState} parserState
+     * @param {Array<QueryElement>} elems - This is where the new {QueryElement} will be added.
+     * @param {string} limit              - This function will stop when it'll encounter this
+     *                                      character.
+     */
+    function getItemsBefore(query, parserState, elems, limit) {
+        while (parserState.pos < parserState.length) {
+            var c = parserState.userQuery[parserState.pos];
+            if (c === limit) {
+                break;
+            } else if (c === '(' || c === ":") {
+                // Something weird is going on in here. Ignoring it!
+                parserState.pos += 1;
+                continue;
+            }
+            var posBefore = parserState.pos;
+            getNextElem(query, parserState, elems, limit === ">");
+            if (posBefore === parserState.pos) {
+                parserState.pos += 1;
+            }
+        }
+        // We skip the "limit".
+        parserState.pos += 1;
+    }
+
+    /**
+     * @param {ParsedQuery} query
+     * @param {ParserState} parserState
+     */
+    function parseInput(query, parserState) {
+        var c, before;
+
+        while (parserState.pos < parserState.length) {
+            c = parserState.userQuery[parserState.pos];
+            if (isStopCharacter(c)) {
+                if (c === "," || c === " ") {
+                    parserState.pos += 1;
+                    continue;
+                } else if (c === "-" && isReturnArrow(parserState)) {
+                    break;
+                }
+            } else if (c == "(") {
+                break;
+            } else if (c === ":" &&
+                parserState.typeFilter === null &&
+                !isPathStart(parserState) &&
+                query.elems.length === 1)
+            {
+                if (query.literalSearch) {
+                    throw new Error("You cannot use quotes on type filter");
+                }
+                // The type filter doesn't count as an element since it's a modifier.
+                parserState.typeFilter = query.elems.pop().name;
+                parserState.pos += 1;
+                parserState.totalElems = 0;
+                query.literalSearch = false;
+                continue;
+            }
+            before = query.elems.length;
+            getNextElem(query, parserState, query.elems, false);
+            if (query.elems.length === before) {
+                // Nothing was added, let's check it's not because of a solo ":"!
+                if (parserState.pos >= parserState.length ||
+                    parserState.userQuery[parserState.pos] !== ":")
+                {
+                    break;
+                }
+                parserState.pos += 1;
+            }
+        }
+        while (parserState.pos < parserState.length) {
+            c = parserState.userQuery[parserState.pos];
+            if (query.args.length === 0 && c === "(") {
+                parserState.pos += 1;
+                // Check for function/method arguments.
+                getItemsBefore(query, parserState, query.args, ")");
+            } else if (isReturnArrow(parserState)) {
+                parserState.pos += 2;
+                // Get returned elements.
+                getItemsBefore(query, parserState, query.returned, "");
+                // Nothing can come afterward!
+                break;
+            } else {
+                parserState.pos += 1;
+            }
+        }
+    }
+
+    /**
+     * Takes the user search input and returns an empty `ParsedQuery`.
+     *
+     * @param {string} userQuery
+     * @return {ParsedQuery}
+     */
+    function newParsedQuery(userQuery) {
+        return {
+            original: userQuery,
+            userQuery: userQuery.toLowerCase(),
+            typeFilter: NO_TYPE_FILTER,
+            elems: [],
+            args: [],
+            returned: [],
+            // Total number of "top" elements (does not include generics).
+            foundElems: 0,
+            literalSearch: false,
+            error: null,
+        };
+    }
+
     /**
      * Build an URL with search parameters.
      *
@@ -158,7 +454,7 @@ window.initSearch = function(rawSearchIndex) {
     }
 
     /**
-     * Executes the query and builds an index of results
+     * Parses the query.
      *
      * The supported syntax by this parser is as follow:
      *
@@ -222,274 +518,39 @@ window.initSearch = function(rawSearchIndex) {
      * @return {ParsedQuery}    - The parsed query
      */
     function parseQuery(userQuery) {
-        function isWhitespace(c) {
-            return " \t\n\r".indexOf(c) !== -1;
-        }
-        function isSpecialStartCharacter(c) {
-            return "(<\"".indexOf(c) !== -1;
-        }
-        function isStopCharacter(c) {
-            return isWhitespace(c) || "),>-=".indexOf(c) !== -1;
-        }
-        function getStringElem(query, isInGenerics) {
-            if (isInGenerics) {
-                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 (query.totalElems !== 0) {
-                throw new Error("Cannot use literal search when there is more than one element");
-            }
-            query.pos += 1;
-            while (query.pos < query.length && query.userQuery[query.pos] !== "\"") {
-                if (query.userQuery[query.pos] === "\\") {
-                    // We ignore the next coming character.
-                    query.pos += 1;
-                }
-                query.pos += 1;
-            }
-            if (query.pos >= query.length) {
-                throw new Error("Unclosed `\"`");
-            }
-            // To skip the quote at the end.
-            query.pos += 1;
-            query.literalSearch = true;
-        }
-        function skipWhitespaces(query) {
-            while (query.pos < query.length) {
-                var c = query.userQuery[query.pos];
-                if (!isWhitespace(c)) {
-                    break;
-                }
-                query.pos += 1;
-            }
-        }
-        function skipStopCharacters(query) {
-            while (query.pos < query.length) {
-                var c = query.userQuery[query.pos];
-                if (!isStopCharacter(c)) {
-                    break;
-                }
-                query.pos += 1;
-            }
-        }
-        function isPathStart(query) {
-            var pos = query.pos;
-            return pos + 1 < query.length && query.userQuery[pos] === ':' &&
-                query.userQuery[pos + 1] === ':';
-        }
-        function isReturnArrow(query) {
-            var pos = query.pos;
-            return pos + 1 < query.length && query.userQuery[pos] === '-' &&
-                query.userQuery[pos + 1] === '>';
-        }
-        function removeEmptyStringsFromArray(x) {
-            for (var i = 0, len = x.length; i < len; ++i) {
-                if (x[i] === "") {
-                    x.splice(i, 1);
-                    i -= 1;
-                }
-            }
-        }
-        function createQueryElement(query, elems, name, generics) {
-            removeEmptyStringsFromArray(generics);
-            if (name === '*' || (name.length === 0 && generics.length === 0)) {
-                return;
-            }
-            if (query.literalSearch && query.totalElems > 0) {
-                throw new Error("You cannot have more than one element if you use quotes");
-            }
-            var paths = name.split("::");
-            removeEmptyStringsFromArray(paths);
-            // In case we only have something like `<p>`, there is no name but it remains valid.
-            if (paths.length === 0) {
-                paths = [""];
-            }
-            elems.push({
-                name: name,
-                fullPath: paths,
-                pathWithoutLast: paths.slice(0, paths.length - 1),
-                pathLast: paths[paths.length - 1],
-                generics: generics,
-            });
-            query.totalElems += 1;
-        }
-        function getNextElem(query, elems, isInGenerics) {
-            var generics = [];
-
-            skipStopCharacters(query);
-            var start = query.pos;
-            var end = start;
-            // We handle the strings on their own mostly to make code easier to follow.
-            if (query.userQuery[query.pos] === "\"") {
-                start += 1;
-                getStringElem(query, isInGenerics);
-                end = query.pos - 1;
-                skipWhitespaces(query);
-            } else {
-                while (query.pos < query.length) {
-                    var c = query.userQuery[query.pos];
-                    if (isStopCharacter(c) || isSpecialStartCharacter(c)) {
-                        break;
-                    }
-                    // If we allow paths ("str::string" for example).
-                    else if (c === ":") {
-                        if (!isPathStart(query)) {
-                            break;
-                        }
-                        // Skip current ":".
-                        query.pos += 1;
-                    }
-                    query.pos += 1;
-                    end = query.pos;
-                    skipWhitespaces(query);
-                }
-            }
-            if (query.pos < query.length && query.userQuery[query.pos] === "<") {
-                getItemsBefore(query, generics, ">");
-            }
-            if (start >= end && generics.length === 0) {
-                return;
-            }
-            createQueryElement(query, elems, query.userQuery.slice(start, end), generics);
-        }
-        function getItemsBefore(query, elems, limit) {
-            while (query.pos < query.length) {
-                var c = query.userQuery[query.pos];
-                if (c === limit) {
-                    break;
-                } else if (isSpecialStartCharacter(c) || c === ":") {
-                    // Something weird is going on in here. Ignoring it!
-                    query.pos += 1;
-                }
-                getNextElem(query, elems, limit === ">");
-            }
-            // We skip the "limit".
-            query.pos += 1;
-        }
-        function parseInput(query) {
-            var c, before;
-
-            while (query.pos < query.length) {
-                c = query.userQuery[query.pos];
-                if (isStopCharacter(c)) {
-                    if (c === ",") {
-                        query.pos += 1;
-                        continue;
-                    } else if (c === "-" && isReturnArrow(query)) {
-                        break;
-                    }
-                } else if (c == "(") {
-                    break;
-                } else if (c === ":" && query.typeFilter === null && !isPathStart(query) &&
-                           query.elems.length === 1)
-                {
-                    if (query.literalSearch) {
-                        throw new Error("You cannot use quotes on type filter");
-                    }
-                    // The type filter doesn't count as an element since it's a modifier.
-                    query.typeFilter = query.elems.pop().name;
-                    query.pos += 1;
-                    query.totalElems = 0;
-                    query.literalSearch = false;
-                    continue;
-                }
-                before = query.elems.length;
-                getNextElem(query, query.elems, false);
-                if (query.elems.length === before) {
-                    // Nothing was added, let's check it's not because of a solo ":"!
-                    if (query.pos >= query.length || query.userQuery[query.pos] !== ":") {
-                        break;
-                    }
-                    query.pos += 1;
-                }
-            }
-            while (query.pos < query.length) {
-                c = query.userQuery[query.pos];
-                if (query.args.length === 0 && c === "(") {
-                    if (query.elemName === null && query.elems.length === 1) {
-                        query.elemName = query.elems.pop();
-                    }
-                    // Check for function/method arguments.
-                    getItemsBefore(query, query.args, ")");
-                } else if (isReturnArrow(query)) {
-                    // Get returned elements.
-                    getItemsBefore(query, query.returned, "");
-                    // Nothing can come afterward!
-                    break;
-                } else {
-                    query.pos += 1;
-                }
-            }
-        }
-        function itemTypeFromName(typename) {
-            for (var i = 0, len = itemTypes.length; i < len; ++i) {
-                if (itemTypes[i] === typename) {
-                    return i;
-                }
-            }
-            return NO_TYPE_FILTER;
-        }
-
         userQuery = userQuery.trim();
-        var query = {
-            original: userQuery,
-            userQuery: userQuery.toLowerCase(),
+        var parserState = {
             length: userQuery.length,
             pos: 0,
-            typeFilter: null,
-            elems: [],
-            elemName: null,
-            args: [],
-            returned: [],
             // Total number of elements (includes generics).
             totalElems: 0,
-            // Total number of "top" elements (does not include generics).
-            foundElems: 0,
-            // This field is used to check if it's needed to re-run a search or not.
-            id: "",
-            // This field is used in `sortResults`.
-            nameSplit: null,
-            literalSearch: false,
-            error: null,
+            typeFilter: null,
+            userQuery: userQuery.toLowerCase(),
         };
-        query.id = userQuery;
+        var query = newParsedQuery(userQuery);
+
         try {
-            parseInput(query);
+            parseInput(query, parserState);
         } catch (err) {
+            query = newParsedQuery(userQuery);
             query.error = err.message;
-            query.elems = [];
-            query.returned = [];
-            query.args = [];
             return query;
         }
-        query.foundElems = query.elems.length + query.args.length + query.returned.length;
+
         if (!query.literalSearch) {
             // If there is more than one element in the query, we switch to literalSearch in any
             // case.
-            query.literalSearch = query.totalElems > 1;
-        }
-        if (query.elemName !== null) {
-            query.foundElems += 1;
+            query.literalSearch = parserState.totalElems > 1;
         }
-        if (query.foundElems === 0 && userQuery.length !== 0) {
+        query.foundElems = query.elems.length + query.args.length + query.returned.length;
+        if (query.foundElems === 0 && parserState.length !== 0) {
             // In this case, we'll simply keep whatever was entered by the user...
-            createQueryElement(query, query.elems, userQuery, []);
+            createQueryElement(query, parserState, query.elems, userQuery, []);
             query.foundElems += 1;
         }
-        if (query.typeFilter !== null) {
-            query.typeFilter = query.typeFilter.replace(/^const$/, "constant");
-            query.typeFilter = itemTypeFromName(query.typeFilter);
-        } else {
-            query.typeFilter = NO_TYPE_FILTER;
-        }
-        // In case we only have one argument, we move it back to `elems` to keep things simple.
-        if (query.foundElems === 1 && query.elemName !== null) {
-            query.elems.push(query.elemName);
-            query.elemName = null;
-        }
-        if (query.elemName !== null || query.elems.length === 1) {
-            userQuery = query.elemName || query.elems[0];
-            query.nameSplit = typeof userQuery.path === "undefined" ? null : userQuery.path;
+        if (parserState.typeFilter !== null) {
+            var typeFilter = parserState.typeFilter.replace(/^const$/, "constant");
+            query.typeFilter = itemTypeFromName(typeFilter);
         }
         return query;
     }
@@ -497,32 +558,32 @@ window.initSearch = function(rawSearchIndex) {
     /**
      * Creates the query results.
      *
-     * @param {Array<Object>} results_in_args
-     * @param {Array<Object>} results_returned
-     * @param {Array<Object>} results_in_args
-     * @param {ParsedQuery} queryInfo
-     * @return {Object}                        - A search index of results
+     * @param {Array<Result>} results_in_args
+     * @param {Array<Result>} results_returned
+     * @param {Array<Result>} results_in_args
+     * @param {ParsedQuery} parsedQuery
+     * @return {ResultsTable}
      */
-    function createQueryResults(results_in_args, results_returned, results_others, queryInfo) {
+    function createQueryResults(results_in_args, results_returned, results_others, parsedQuery) {
         return {
             "in_args": results_in_args,
             "returned": results_returned,
             "others": results_others,
-            "query": queryInfo,
+            "query": parsedQuery,
         };
     }
 
     /**
-     * Executes the query and builds an index of results
+     * Executes the parsed query and builds a {ResultsTable}.
      *
-     * @param  {ParsedQuery} query   - The user query
-     * @param  {Object} searchWords  - The list of search words to query against
-     * @param  {Object} filterCrates - Crate to search in if defined
-     * @return {Object}              - A search index of results
+     * @param  {ParsedQuery} parsedQuery - The parsed user query
+     * @param  {Object} searchWords      - The list of search words to query against
+     * @param  {Object} [filterCrates]   - Crate to search in if defined
+     * @return {ResultsTable}
      */
-    function execQuery(queryInfo, searchWords, filterCrates) {
-        if (queryInfo.error !== null) {
-            createQueryResults([], [], [], queryInfo);
+    function execQuery(parsedQuery, searchWords, filterCrates) {
+        if (parsedQuery.error !== null) {
+            createQueryResults([], [], [], parsedQuery);
         }
         var results_others = {}, results_in_args = {}, results_returned = {};
 
@@ -558,8 +619,12 @@ window.initSearch = function(rawSearchIndex) {
         }
 
         function sortResults(results, isType) {
-            var nameSplit = queryInfo.nameSplit;
-            var query = queryInfo.userQuery;
+            var nameSplit = null;
+            if (parsedQuery.elems.length === 1) {
+                var hasPath = typeof parsedQuery.elems[0].path === "undefined";
+                nameSplit = hasPath ? null : parsedQuery.elems[0].path;
+            }
+            var query = parsedQuery.userQuery;
             var ar = [];
             for (var entry in results) {
                 if (hasOwnPropertyRustdoc(results, entry)) {
@@ -661,26 +726,26 @@ window.initSearch = function(rawSearchIndex) {
         }
 
         /**
-         * This function checks if the object (`obj`) generics match the given type (`val`)
-         * generics. If there are no generics on `obj`, `defaultLev` is returned.
+         * This function checks if the object (`row`) generics match the given type (`elem`)
+         * generics. If there are no generics on `row`, `defaultLev` is returned.
          *
-         * @param {Row} obj            - The object to check.
-         * @param {QueryElement} val   - The element from the parsed query.
+         * @param {Row} row            - The object to check.
+         * @param {QueryElement} elem  - The element from the parsed query.
          * @param {integer} defaultLev - This is the value to return in case there are no generics.
          *
          * @return {integer}           - Returns the best match (if any) or `MAX_LEV_DISTANCE + 1`.
          */
-        function checkGenerics(obj, val, defaultLev) {
-            if (obj.length <= GENERICS_DATA || obj[GENERICS_DATA].length === 0) {
-                return val.generics.length === 0 ? defaultLev : MAX_LEV_DISTANCE + 1;
+        function checkGenerics(row, elem, defaultLev) {
+            if (row.length <= GENERICS_DATA || row[GENERICS_DATA].length === 0) {
+                return elem.generics.length === 0 ? defaultLev : MAX_LEV_DISTANCE + 1;
             }
             // The names match, but we need to be sure that all generics kinda
             // match as well.
             var elem_name;
-            if (val.generics.length > 0 && obj[GENERICS_DATA].length >= val.generics.length) {
+            if (elem.generics.length > 0 && row[GENERICS_DATA].length >= elem.generics.length) {
                 var elems = {};
-                for (var x = 0, length = obj[GENERICS_DATA].length; x < length; ++x) {
-                    elem_name = obj[GENERICS_DATA][x][NAME];
+                for (var x = 0, length = row[GENERICS_DATA].length; x < length; ++x) {
+                    elem_name = row[GENERICS_DATA][x][NAME];
                     if (!elems[elem_name]) {
                         elems[elem_name] = 0;
                     }
@@ -688,8 +753,8 @@ window.initSearch = function(rawSearchIndex) {
                 }
                 // We need to find the type that matches the most to remove it in order
                 // to move forward.
-                for (x = 0, length = val.generics.length; x < length; ++x) {
-                    var generic = val.generics[x];
+                for (x = 0, length = elem.generics.length; x < length; ++x) {
+                    var generic = elem.generics[x];
                     var match = null;
                     if (elems[generic.name]) {
                         match = generic.name;
@@ -718,19 +783,19 @@ window.initSearch = function(rawSearchIndex) {
         }
 
         /**
-          * This function checks if the object (`obj`) matches the given type (`val`) and its
+          * This function checks if the object (`row`) matches the given type (`elem`) and its
           * generics (if any).
           *
-          * @param {Row} obj
-          * @param {QueryElement} val    - The element from the parsed query.
+          * @param {Row} row
+          * @param {QueryElement} elem    - The element from the parsed query.
           *
           * @return {integer} - Returns a Levenshtein distance to the best match.
           */
-        function checkIfInGenerics(obj, val) {
+        function checkIfInGenerics(row, elem) {
             var lev = MAX_LEV_DISTANCE + 1;
-            for (var x = 0, length = obj[GENERICS_DATA].length; x < length && lev !== 0; ++x) {
+            for (var x = 0, length = row[GENERICS_DATA].length; x < length && lev !== 0; ++x) {
                 lev = Math.min(
-                    checkType(obj[GENERICS_DATA][x], val, true),
+                    checkType(row[GENERICS_DATA][x], elem, true),
                     lev
                 );
             }
@@ -738,51 +803,51 @@ window.initSearch = function(rawSearchIndex) {
         }
 
         /**
-          * This function checks if the object (`obj`) matches the given type (`val`) and its
+          * This function checks if the object (`row`) matches the given type (`elem`) and its
           * generics (if any).
           *
-          * @param {Row} obj
-          * @param {QueryElement} val      - The element from the parsed query.
+          * @param {Row} row
+          * @param {QueryElement} elem      - The element from the parsed query.
           * @param {boolean} literalSearch
           *
           * @return {integer} - Returns a Levenshtein distance to the best match. If there is
           *                     no match, returns `MAX_LEV_DISTANCE + 1`.
           */
-        function checkType(obj, val, literalSearch) {
-            if (val.name.length === 0 || obj[NAME].length === 0) {
+        function checkType(row, elem, literalSearch) {
+            if (elem.name.length === 0 || row[NAME].length === 0) {
                 // This is a pure "generic" search, no need to run other checks.
-                if (obj.length > GENERICS_DATA) {
-                    return checkIfInGenerics(obj, val);
+                if (row.length > GENERICS_DATA) {
+                    return checkIfInGenerics(row, elem);
                 }
                 return MAX_LEV_DISTANCE + 1;
             }
 
-            var lev = levenshtein(obj[NAME], val.name);
+            var lev = levenshtein(row[NAME], elem.name);
             if (literalSearch) {
                 if (lev !== 0) {
                     // The name didn't match, let's try to check if the generics do.
-                    if (val.generics.length === 0) {
-                        var checkGeneric = (obj.length > GENERICS_DATA &&
-                            obj[GENERICS_DATA].length > 0);
-                        if (checkGeneric && obj[GENERICS_DATA].findIndex(function(elem) {
-                            return elem[NAME] === val.name;
+                    if (elem.generics.length === 0) {
+                        var checkGeneric = (row.length > GENERICS_DATA &&
+                            row[GENERICS_DATA].length > 0);
+                        if (checkGeneric && row[GENERICS_DATA].findIndex(function(tmp_elem) {
+                            return tmp_elem[NAME] === elem.name;
                         }) !== -1) {
                             return 0;
                         }
                     }
                     return MAX_LEV_DISTANCE + 1;
-                } else if (val.generics.length > 0) {
-                    return checkGenerics(obj, val, MAX_LEV_DISTANCE + 1);
+                } else if (elem.generics.length > 0) {
+                    return checkGenerics(row, elem, MAX_LEV_DISTANCE + 1);
                 }
                 return 0;
-            } else if (obj.length > GENERICS_DATA) {
-                if (val.generics.length === 0) {
+            } else if (row.length > GENERICS_DATA) {
+                if (elem.generics.length === 0) {
                     if (lev === 0) {
                         return 0;
                     }
                     // The name didn't match so we now check if the type we're looking for is inside
                     // the generics!
-                    lev = checkIfInGenerics(obj, val);
+                    lev = checkIfInGenerics(row, elem);
                     // Now whatever happens, the returned distance is "less good" so we should mark
                     // it as such, and so we add 0.5 to the distance to make it "less good".
                     return lev + 0.5;
@@ -791,18 +856,18 @@ window.initSearch = function(rawSearchIndex) {
                     //
                     // Maybe it's present in a sub generic? For example "f<A<B<C>>>()", if we're
                     // looking for "B<C>", we'll need to go down.
-                    return checkIfInGenerics(obj, val);
+                    return checkIfInGenerics(row, elem);
                 } else {
                     // At this point, the name kinda match and we have generics to check, so
                     // let's go!
-                    var tmp_lev = checkGenerics(obj, val, lev);
+                    var tmp_lev = checkGenerics(row, elem, lev);
                     if (tmp_lev > MAX_LEV_DISTANCE) {
                         return MAX_LEV_DISTANCE + 1;
                     }
                     // We compute the median value of both checks and return it.
                     return (tmp_lev + lev) / 2;
                 }
-            } else if (val.generics.length > 0) {
+            } else if (elem.generics.length > 0) {
                 // In this case, we were expecting generics but there isn't so we simply reject this
                 // one.
                 return MAX_LEV_DISTANCE + 1;
@@ -813,64 +878,62 @@ window.initSearch = function(rawSearchIndex) {
         }
 
         /**
-         * This function checks if the object (`obj`) has an argument with the given type (`val`).
+         * This function checks if the object (`row`) has an argument with the given type (`elem`).
          *
-         * @param {Row} obj
-         * @param {QueryElement} val    - The element from the parsed query.
+         * @param {Row} row
+         * @param {QueryElement} elem    - The element from the parsed query.
          * @param {integer} typeFilter
          *
          * @return {integer} - Returns a Levenshtein distance to the best match. If there is no
          *                      match, returns `MAX_LEV_DISTANCE + 1`.
          */
-        function findArg(obj, val, typeFilter) {
+        function findArg(row, elem, typeFilter) {
             var lev = MAX_LEV_DISTANCE + 1;
-            var tmp;
 
-            if (obj && obj.type && obj.type[INPUTS_DATA] && obj.type[INPUTS_DATA].length > 0) {
-                var length = obj.type[INPUTS_DATA].length;
+            if (row && row.type && row.type[INPUTS_DATA] && row.type[INPUTS_DATA].length > 0) {
+                var length = row.type[INPUTS_DATA].length;
                 for (var i = 0; i < length; i++) {
-                    tmp = obj.type[INPUTS_DATA][i];
+                    var tmp = row.type[INPUTS_DATA][i];
                     if (!typePassesFilter(typeFilter, tmp[1])) {
                         continue;
                     }
-                    lev = Math.min(lev, checkType(tmp, val, queryInfo.literalSearch));
+                    lev = Math.min(lev, checkType(tmp, elem, parsedQuery.literalSearch));
                     if (lev === 0) {
                         return 0;
                     }
                 }
             }
-            return queryInfo.literalSearch ? MAX_LEV_DISTANCE + 1 : lev;
+            return parsedQuery.literalSearch ? MAX_LEV_DISTANCE + 1 : lev;
         }
 
         /**
-         * @param {Row} obj
-         * @param {QueryElement} val   - The element from the parsed query.
+         * @param {Row} row
+         * @param {QueryElement} elem   - The element from the parsed query.
          * @param {integer} typeFilter
          *
          * @return {integer} - Returns a Levenshtein distance to the best match. If there is no
          *                      match, returns `MAX_LEV_DISTANCE + 1`.
          */
-        function checkReturned(obj, val, typeFilter) {
+        function checkReturned(row, elem, typeFilter) {
             var lev = MAX_LEV_DISTANCE + 1;
-            var tmp;
 
-            if (obj && obj.type && obj.type.length > OUTPUT_DATA) {
-                var ret = obj.type[OUTPUT_DATA];
+            if (row && row.type && row.type.length > OUTPUT_DATA) {
+                var ret = row.type[OUTPUT_DATA];
                 if (typeof ret[0] === "string") {
                     ret = [ret];
                 }
                 for (var x = 0, len = ret.length; x < len; ++x) {
-                    tmp = ret[x];
+                    var tmp = ret[x];
                     if (!typePassesFilter(typeFilter, tmp[1])) {
                         continue;
                     }
-                    lev = Math.min(lev, checkType(tmp, val, queryInfo.literalSearch));
+                    lev = Math.min(lev, checkType(tmp, elem, parsedQuery.literalSearch));
                     if (lev === 0) {
                         return 0;
                     }
                 }
             }
-            return queryInfo.literalSearch ? MAX_LEV_DISTANCE + 1 : lev;
+            return parsedQuery.literalSearch ? MAX_LEV_DISTANCE + 1 : lev;
         }
 
         function checkPath(contains, lastElem, ty) {
@@ -945,13 +1008,14 @@ window.initSearch = function(rawSearchIndex) {
         }
 
         function handleAliases(ret, query, filterCrates) {
+            var lowerQuery = query.toLowerCase();
             // We separate aliases and crate aliases because we want to have current crate
             // aliases to be before the others in the displayed results.
             var aliases = [];
             var crateAliases = [];
             if (filterCrates !== null) {
-                if (ALIASES[filterCrates] && ALIASES[filterCrates][query]) {
-                    var query_aliases = ALIASES[filterCrates][query];
+                if (ALIASES[filterCrates] && ALIASES[filterCrates][lowerQuery]) {
+                    var query_aliases = ALIASES[filterCrates][lowerQuery];
                     var len = query_aliases.length;
                     for (var i = 0; i < len; ++i) {
                         aliases.push(createAliasFromItem(searchIndex[query_aliases[i]]));
@@ -959,9 +1023,9 @@ window.initSearch = function(rawSearchIndex) {
                 }
             } else {
                 Object.keys(ALIASES).forEach(function(crate) {
-                    if (ALIASES[crate][query]) {
+                    if (ALIASES[crate][lowerQuery]) {
                         var pushTo = crate === window.currentCrate ? crateAliases : aliases;
-                        var query_aliases = ALIASES[crate][query];
+                        var query_aliases = ALIASES[crate][lowerQuery];
                         var len = query_aliases.length;
                         for (var i = 0; i < len; ++i) {
                             pushTo.push(createAliasFromItem(searchIndex[query_aliases[i]]));
@@ -998,37 +1062,37 @@ window.initSearch = function(rawSearchIndex) {
         }
 
         /**
-         * This function adds the given result into the provided `res` map if it matches the
+         * This function adds the given result into the provided `results` map if it matches the
          * following condition:
          *
-         * * If it is a "literal search" (`queryInfo.literalSearch`), then `lev` must be 0.
+         * * If it is a "literal search" (`parsedQuery.literalSearch`), then `lev` must be 0.
          * * If it is not a "literal search", `lev` must be <= `MAX_LEV_DISTANCE`.
          *
-         * The `res` map contains information which will be used to sort the search results:
+         * The `results` map contains information which will be used to sort the search results:
          *
-         * * `fullId` is a `string`` used as the key of the object we use for the `res` map.
+         * * `fullId` is a `string`` used as the key of the object we use for the `results` map.
          * * `id` is the index in both `searchWords` and `searchIndex` arrays for this element.
          * * `index` is an `integer`` used to sort by the position of the word in the item's name.
          * * `lev` is the main metric used to sort the search results.
          *
-         * @param {Object} res
+         * @param {Object} results
          * @param {string} fullId
          * @param {integer} id
          * @param {integer} index
          * @param {integer} lev
          */
-        function addIntoResults(res, fullId, id, index, lev) {
-            if (lev === 0 || (!queryInfo.literalSearch && lev <= MAX_LEV_DISTANCE)) {
-                if (res[fullId] !== undefined) {
-                    var result = res[fullId];
+        function addIntoResults(results, fullId, id, index, lev) {
+            if (lev === 0 || (!parsedQuery.literalSearch && lev <= MAX_LEV_DISTANCE)) {
+                if (results[fullId] !== undefined) {
+                    var result = results[fullId];
                     if (result.dontValidate || result.lev <= lev) {
                         return;
                     }
                 }
-                res[fullId] = {
+                results[fullId] = {
                     id: id,
                     index: index,
-                    dontValidate: queryInfo.literalSearch,
+                    dontValidate: parsedQuery.literalSearch,
                     lev: lev,
                 };
             }
@@ -1037,29 +1101,29 @@ window.initSearch = function(rawSearchIndex) {
         /**
          * This function is called in case the query is only one element (with or without generics).
          *
-         * @param {Row} ty
+         * @param {Row} row
          * @param {integer} pos           - Position in the `searchIndex`.
          * @param {QueryElement} elem     - The element from the parsed query.
          */
-        function handleSingleArg(ty, pos, elem) {
-            if (!ty || (filterCrates !== null && ty.crate !== filterCrates)) {
+        function handleSingleArg(row, pos, elem) {
+            if (!row || (filterCrates !== null && row.crate !== filterCrates)) {
                 return;
             }
             var lev, lev_add = 0, index = -1;
-            var fullId = ty.id;
+            var fullId = row.id;
 
-            var in_args = findArg(ty, elem, queryInfo.typeFilter);
-            var returned = checkReturned(ty, elem, queryInfo.typeFilter);
+            var in_args = findArg(row, elem, parsedQuery.typeFilter);
+            var returned = checkReturned(row, elem, parsedQuery.typeFilter);
 
             addIntoResults(results_in_args, fullId, pos, index, in_args);
             addIntoResults(results_returned, fullId, pos, index, returned);
 
-            if (!typePassesFilter(queryInfo.typeFilter, ty.ty)) {
+            if (!typePassesFilter(parsedQuery.typeFilter, row.ty)) {
                 return;
             }
             var searchWord = searchWords[pos];
 
-            if (queryInfo.literalSearch) {
+            if (parsedQuery.literalSearch) {
                 if (searchWord === elem.name) {
                     addIntoResults(results_others, fullId, pos, -1, 0);
                 }
@@ -1068,16 +1132,16 @@ window.initSearch = function(rawSearchIndex) {
 
             // No need to check anything else if it's a "pure" generics search.
             if (elem.name.length === 0) {
-                if (ty.type !== null) {
-                    lev = checkGenerics(ty.type, elem, MAX_LEV_DISTANCE + 1);
+                if (row.type !== null) {
+                    lev = checkGenerics(row.type, elem, MAX_LEV_DISTANCE + 1);
                     addIntoResults(results_others, fullId, pos, index, lev);
                 }
                 return;
             }
 
             if (elem.fullPath.length > 1) {
-                lev = checkPath(elem.pathWithoutLast, elem.pathLast, ty);
-                if (lev > MAX_LEV_DISTANCE || (queryInfo.literalSearch && lev !== 0)) {
+                lev = checkPath(elem.pathWithoutLast, elem.pathLast, row);
+                if (lev > MAX_LEV_DISTANCE || (parsedQuery.literalSearch && lev !== 0)) {
                     return;
                 } else if (lev > 0) {
                     lev_add = lev / 10;
@@ -1085,16 +1149,16 @@ window.initSearch = function(rawSearchIndex) {
             }
 
             if (searchWord.indexOf(elem.pathLast) > -1 ||
-                ty.normalizedName.indexOf(elem.pathLast) > -1)
+                row.normalizedName.indexOf(elem.pathLast) > -1)
             {
                 // filter type: ... queries
                 if (!results_others[fullId] !== undefined) {
-                    index = ty.normalizedName.indexOf(elem.pathLast);
+                    index = row.normalizedName.indexOf(elem.pathLast);
                 }
             }
             lev = levenshtein(searchWord, elem.pathLast);
             lev += lev_add;
-            if (lev > 0 && elem.pathLast.length > 3 && searchWord.indexOf(elem.pathLast) > -1)
+            if (lev > 0 && elem.pathLast.length > 2 && searchWord.indexOf(elem.pathLast) > -1)
             {
                 if (elem.pathLast.length < 6) {
                     lev = 1;
@@ -1116,27 +1180,25 @@ window.initSearch = function(rawSearchIndex) {
         /**
          * This function is called in case the query has more than one element.
          *
-         * @param {Object} ty
-         * @param {integer} pos     - Position in the `searchIndex`.
-         * @param {Object} elem     - The element from the parsed query.
+         * @param {Row} row
+         * @param {integer} pos      - Position in the `searchIndex`.
+         * @param {Object} results
          */
-        function handleArgs(ty, pos, results) {
-            if (!ty || (filterCrates !== null && ty.crate !== filterCrates)) {
+        function handleArgs(row, pos, results) {
+            if (!row || (filterCrates !== null && row.crate !== filterCrates)) {
                 return;
             }
 
             var totalLev = 0;
             var nbLev = 0;
             var lev;
-            var i, len;
-            var el;
 
             // If the result is too "bad", we return false and it ends this search.
-            function checkArgs(args, callback) {
-                for (i = 0, len = args.length; i < len; ++i) {
-                    el = args[i];
+            function checkArgs(elems, callback) {
+                for (var i = 0, len = elems.length; i < len; ++i) {
+                    var elem = elems[i];
                     // There is more than one parameter to the query so all checks should be "exact"
-                    lev = callback(ty, el, NO_TYPE_FILTER);
+                    lev = callback(row, elem, NO_TYPE_FILTER);
                     if (lev <= 1) {
                         nbLev += 1;
                         totalLev += lev;
@@ -1146,13 +1208,13 @@ window.initSearch = function(rawSearchIndex) {
                 }
                 return true;
             }
-            if (!checkArgs(queryInfo.elems, findArg)) {
+            if (!checkArgs(parsedQuery.elems, findArg)) {
                 return;
             }
-            if (!checkArgs(queryInfo.args, findArg)) {
+            if (!checkArgs(parsedQuery.args, findArg)) {
                 return;
             }
-            if (!checkArgs(queryInfo.returned, checkReturned)) {
+            if (!checkArgs(parsedQuery.returned, checkReturned)) {
                 return;
             }
 
@@ -1160,43 +1222,43 @@ window.initSearch = function(rawSearchIndex) {
                 return;
             }
             lev = Math.round(totalLev / nbLev);
-            addIntoResults(results, ty.id, pos, 0, lev);
+            addIntoResults(results, row.id, pos, 0, lev);
         }
 
         function innerRunQuery() {
-            var elem, i, nSearchWords, in_args, in_returned, ty;
+            var elem, i, nSearchWords, in_args, in_returned, row;
 
-            if (queryInfo.foundElems === 1) {
-                if (queryInfo.elems.length === 1) {
-                    elem = queryInfo.elems[0];
+            if (parsedQuery.foundElems === 1) {
+                if (parsedQuery.elems.length === 1) {
+                    elem = parsedQuery.elems[0];
                     for (i = 0, nSearchWords = searchWords.length; i < nSearchWords; ++i) {
                         // It means we want to check for this element everywhere (in names, args and
                         // returned).
                         handleSingleArg(searchIndex[i], i, elem);
                     }
-                } else if (queryInfo.args.length === 1) {
+                } else if (parsedQuery.args.length === 1) {
                     // We received one argument to check, so looking into args.
-                    elem = queryInfo.args[0];
+                    elem = parsedQuery.args[0];
                     for (i = 0, nSearchWords = searchWords.length; i < nSearchWords; ++i) {
-                        ty = searchIndex[i];
-                        in_args = findArg(ty, elem, queryInfo.typeFilter);
-                        addIntoResults(results_in_args, ty.id, i, -1, in_args);
+                        row = searchIndex[i];
+                        in_args = findArg(row, elem, parsedQuery.typeFilter);
+                        addIntoResults(results_in_args, row.id, i, -1, in_args);
                     }
-                } else if (queryInfo.returned.length === 1) {
+                } else if (parsedQuery.returned.length === 1) {
                     // We received one returned argument to check, so looking into returned values.
-                    elem = queryInfo.returned[0];
+                    elem = parsedQuery.returned[0];
                     for (i = 0, nSearchWords = searchWords.length; i < nSearchWords; ++i) {
-                        ty = searchIndex[i];
-                        in_returned = checkReturned(ty, elem, queryInfo.typeFilter);
-                        addIntoResults(results_returned, ty.id, i, -1, in_returned);
+                        row = searchIndex[i];
+                        in_returned = checkReturned(row, elem, parsedQuery.typeFilter);
+                        addIntoResults(results_returned, row.id, i, -1, in_returned);
                     }
                 }
-            } else if (queryInfo.foundElems > 0) {
+            } else if (parsedQuery.foundElems > 0) {
                 var container = results_others;
                 // In the special case where only a "returned" information is available, we want to
                 // put the information into the "results_returned" dict.
-                if (queryInfo.returned.length !== 0 && queryInfo.elemName === null &&
-                        queryInfo.args.length === 0 && queryInfo.elems.length === 0)
+                if (parsedQuery.returned.length !== 0 && parsedQuery.args.length === 0 &&
+                    parsedQuery.elems.length === 0)
                 {
                     container = results_returned;
                 }
@@ -1211,8 +1273,8 @@ window.initSearch = function(rawSearchIndex) {
             sortResults(results_in_args, true),
             sortResults(results_returned, true),
             sortResults(results_others, false),
-            queryInfo);
-        handleAliases(ret, queryInfo.original.replace(/"/g, "").toLowerCase(), filterCrates);
+            parsedQuery);
+        handleAliases(ret, parsedQuery.original.replace(/"/g, ""), filterCrates);
         return ret;
     }
 
@@ -1434,6 +1496,11 @@ window.initSearch = function(rawSearchIndex) {
         return "<button>" + text + " <div class=\"count\">(" + nbElems + ")</div></button>";
     }
 
+    /**
+     * @param {ResultsTable} results
+     * @param {boolean} go_to_first
+     * @param {string} filterCrates
+     */
     function showResults(results, go_to_first, filterCrates) {
         var search = searchState.outputElement();
         if (go_to_first || (results.others.length === 1
@@ -1455,7 +1522,7 @@ window.initSearch = function(rawSearchIndex) {
             results.query = parseQuery(searchState.input.value);
         }
 
-        currentResults = results.query.id;
+        currentResults = results.query.userQuery;
 
         var ret_others = addTab(results.others, results.query, true);
         var ret_in_args = addTab(results.in_args, results.query, false);
@@ -1535,7 +1602,7 @@ window.initSearch = function(rawSearchIndex) {
             e.preventDefault();
         }
 
-        if (!forced && query.id === currentResults) {
+        if (!forced && query.userQuery === currentResults) {
             if (query.userQuery.length > 0) {
                 putBackSearch();
             }
diff --git a/src/test/rustdoc-gui/search-result-color.goml b/src/test/rustdoc-gui/search-result-color.goml
index 828c20860a6..901634fe0e6 100644
--- a/src/test/rustdoc-gui/search-result-color.goml
+++ b/src/test/rustdoc-gui/search-result-color.goml
@@ -1,5 +1,5 @@
 // The goal of this test is to ensure the color of the text is the one expected.
-goto: file://|DOC_PATH|/test_docs/index.html?search=cook
+goto: file://|DOC_PATH|/test_docs/index.html?search=coo
 
 // This is needed so that the text color is computed.
 show-text: true
diff --git a/src/test/rustdoc-js-std/parser-errors.js b/src/test/rustdoc-js-std/parser-errors.js
index c5d106120ad..887ac38f417 100644
--- a/src/test/rustdoc-js-std/parser-errors.js
+++ b/src/test/rustdoc-js-std/parser-errors.js
@@ -3,66 +3,51 @@ const QUERY = ['<"P">', '"P" "P"', 'P "P"', '"p" p', '"const": p'];
 const PARSED = [
     {
         args: [],
-        elemName: null,
         elems: [],
         foundElems: 0,
-        id: "<\"P\">",
-        nameSplit: null,
         original: "<\"P\">",
         returned: [],
-        typeFilter: null,
+        typeFilter: -1,
         userQuery: "<\"p\">",
         error: "`\"` cannot be used in generics",
     },
     {
         args: [],
-        elemName: null,
         elems: [],
         foundElems: 0,
-        id: "\"P\" \"P\"",
-        nameSplit: null,
         original: "\"P\" \"P\"",
         returned: [],
-        typeFilter: null,
+        typeFilter: -1,
         userQuery: "\"p\" \"p\"",
         error: "Cannot have more than one literal search element",
     },
     {
         args: [],
-        elemName: null,
         elems: [],
         foundElems: 0,
-        id: "P \"P\"",
-        nameSplit: null,
         original: "P \"P\"",
         returned: [],
-        typeFilter: null,
+        typeFilter: -1,
         userQuery: "p \"p\"",
         error: "Cannot use literal search when there is more than one element",
     },
     {
         args: [],
-        elemName: null,
         elems: [],
         foundElems: 0,
-        id: "\"p\" p",
-        nameSplit: null,
         original: "\"p\" p",
         returned: [],
-        typeFilter: null,
+        typeFilter: -1,
         userQuery: "\"p\" p",
         error: "You cannot have more than one element if you use quotes",
     },
     {
         args: [],
-        elemName: null,
         elems: [],
         foundElems: 0,
-        id: "\"const\": p",
-        nameSplit: null,
         original: "\"const\": p",
         returned: [],
-        typeFilter: null,
+        typeFilter: -1,
         userQuery: "\"const\": p",
         error: "You cannot use quotes on type filter",
     },
diff --git a/src/test/rustdoc-js-std/parser-filter.js b/src/test/rustdoc-js-std/parser-filter.js
index 60eb8aa92b2..49fa66b5bb3 100644
--- a/src/test/rustdoc-js-std/parser-filter.js
+++ b/src/test/rustdoc-js-std/parser-filter.js
@@ -3,7 +3,6 @@ const QUERY = ['fn:foo', 'enum : foo', 'macro<f>:foo'];
 const PARSED = [
     {
         args: [],
-        elemName: null,
         elems: [{
             name: "foo",
             fullPath: ["foo"],
@@ -12,8 +11,6 @@ const PARSED = [
             generics: [],
         }],
         foundElems: 1,
-        id: "fn:foo",
-        nameSplit: null,
         original: "fn:foo",
         returned: [],
         typeFilter: 5,
@@ -22,7 +19,6 @@ const PARSED = [
     },
     {
         args: [],
-        elemName: null,
         elems: [{
             name: "foo",
             fullPath: ["foo"],
@@ -31,8 +27,6 @@ const PARSED = [
             generics: [],
         }],
         foundElems: 1,
-        id: "enum : foo",
-        nameSplit: null,
         original: "enum : foo",
         returned: [],
         typeFilter: 4,
@@ -41,7 +35,6 @@ const PARSED = [
     },
     {
         args: [],
-        elemName: null,
         elems: [{
             name: "foo",
             fullPath: ["foo"],
@@ -50,8 +43,6 @@ const PARSED = [
             generics: [],
         }],
         foundElems: 1,
-        id: "macro<f>:foo",
-        nameSplit: null,
         original: "macro<f>:foo",
         returned: [],
         typeFilter: 14,
diff --git a/src/test/rustdoc-js-std/parser-generics.js b/src/test/rustdoc-js-std/parser-generics.js
index d21adf767de..34d33ed4d67 100644
--- a/src/test/rustdoc-js-std/parser-generics.js
+++ b/src/test/rustdoc-js-std/parser-generics.js
@@ -1,9 +1,8 @@
-const QUERY = ['<P>', 'A<B<C<D>, E>'];
+const QUERY = ['<P>', 'A<B<C<D>, E>', 'p<> u8'];
 
 const PARSED = [
     {
         args: [],
-        elemName: null,
         elems: [{
             name: "",
             fullPath: [""],
@@ -20,8 +19,6 @@ const PARSED = [
             ],
         }],
         foundElems: 1,
-        id: "<P>",
-        nameSplit: null,
         original: "<P>",
         returned: [],
         typeFilter: -1,
@@ -30,7 +27,6 @@ const PARSED = [
     },
     {
         args: [],
-        elemName: null,
         elems: [{
             name: "a",
             fullPath: ["a"],
@@ -70,12 +66,35 @@ const PARSED = [
             ],
         }],
         foundElems: 1,
-        id: 'A<B<C<D>, E>',
-        nameSplit: null,
         original: 'A<B<C<D>, E>',
         returned: [],
         typeFilter: -1,
         userQuery: 'a<b<c<d>, e>',
         error: null,
-    }
+    },
+    {
+        args: [],
+        elems: [
+            {
+                name: "p",
+                fullPath: ["p"],
+                pathWithoutLast: [],
+                pathLast: "p",
+                generics: [],
+            },
+            {
+                name: "u8",
+                fullPath: ["u8"],
+                pathWithoutLast: [],
+                pathLast: "u8",
+                generics: [],
+            },
+        ],
+        foundElems: 2,
+        original: "p<> u8",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "p<> u8",
+        error: null,
+    },
 ];
diff --git a/src/test/rustdoc-js-std/parser-in_args.js b/src/test/rustdoc-js-std/parser-in_args.js
index 88761771d9d..e74e423ceed 100644
--- a/src/test/rustdoc-js-std/parser-in_args.js
+++ b/src/test/rustdoc-js-std/parser-in_args.js
@@ -9,11 +9,8 @@ const PARSED = [
             pathLast: "whatever",
             generics: [],
         }],
-        elemName: null,
         elems: [],
         foundElems: 1,
-        id: "(whatever)",
-        nameSplit: null,
         original: "(whatever)",
         returned: [],
         typeFilter: -1,
@@ -36,11 +33,8 @@ const PARSED = [
                 },
             ],
         }],
-        elemName: null,
         elems: [],
         foundElems: 1,
-        id: "(<P>)",
-        nameSplit: null,
         original: "(<P>)",
         returned: [],
         typeFilter: -1,
diff --git a/src/test/rustdoc-js-std/parser-invalid.js b/src/test/rustdoc-js-std/parser-invalid.js
index b5d96e9f507..5e7be3c73b0 100644
--- a/src/test/rustdoc-js-std/parser-invalid.js
+++ b/src/test/rustdoc-js-std/parser-invalid.js
@@ -6,11 +6,8 @@ const QUERY = ['-> <P> (p2)', '(p -> p2', 'a b', 'a,b(c)'];
 const PARSED = [
     {
         args: [],
-        elemName: null,
         elems: [],
         foundElems: 2,
-        id: "-> <P> (p2)",
-        nameSplit: null,
         original: "-> <P> (p2)",
         returned: [
             {
@@ -57,11 +54,8 @@ const PARSED = [
                 generics: [],
             },
         ],
-        elemName: null,
         elems: [],
         foundElems: 2,
-        id: "(p -> p2",
-        nameSplit: null,
         original: "(p -> p2",
         returned: [],
         typeFilter: -1,
@@ -70,7 +64,6 @@ const PARSED = [
     },
     {
         args: [],
-        elemName: null,
         elems: [
             {
                 name: "a b",
@@ -81,8 +74,6 @@ const PARSED = [
             },
         ],
         foundElems: 1,
-        id: "a b",
-        nameSplit: null,
         original: "a b",
         returned: [],
         typeFilter: -1,
@@ -99,7 +90,6 @@ const PARSED = [
                 generics: [],
             },
         ],
-        elemName: null,
         elems: [
             {
                 name: "a",
@@ -117,8 +107,6 @@ const PARSED = [
             },
         ],
         foundElems: 3,
-        id: "a,b(c)",
-        nameSplit: null,
         original: "a,b(c)",
         returned: [],
         typeFilter: -1,
diff --git a/src/test/rustdoc-js-std/parser-literal.js b/src/test/rustdoc-js-std/parser-literal.js
index f1713fbaf88..f8c73672922 100644
--- a/src/test/rustdoc-js-std/parser-literal.js
+++ b/src/test/rustdoc-js-std/parser-literal.js
@@ -3,7 +3,6 @@ const QUERY = ['R<P>'];
 const PARSED = [
     {
         args: [],
-        elemName: null,
         elems: [{
             name: "r",
             fullPath: ["r"],
@@ -20,8 +19,6 @@ const PARSED = [
             ],
         }],
         foundElems: 1,
-        id: "R<P>",
-        nameSplit: null,
         original: "R<P>",
         returned: [],
         typeFilter: -1,
diff --git a/src/test/rustdoc-js-std/parser-paths.js b/src/test/rustdoc-js-std/parser-paths.js
index 980a396ba7f..1bd3bb61dc9 100644
--- a/src/test/rustdoc-js-std/parser-paths.js
+++ b/src/test/rustdoc-js-std/parser-paths.js
@@ -3,7 +3,6 @@ const QUERY = ['A::B', '::A::B', 'A::B::,C',  'A::B::<f>,C'];
 const PARSED = [
     {
         args: [],
-        elemName: null,
         elems: [{
             name: "a::b",
             fullPath: ["a", "b"],
@@ -12,8 +11,6 @@ const PARSED = [
             generics: [],
         }],
         foundElems: 1,
-        id: "A::B",
-        nameSplit: null,
         original: "A::B",
         returned: [],
         typeFilter: -1,
@@ -22,7 +19,6 @@ const PARSED = [
     },
     {
         args: [],
-        elemName: null,
         elems: [{
             name: "::a::b",
             fullPath: ["a", "b"],
@@ -31,8 +27,6 @@ const PARSED = [
             generics: [],
         }],
         foundElems: 1,
-        id: '::A::B',
-        nameSplit: null,
         original: '::A::B',
         returned: [],
         typeFilter: -1,
@@ -41,7 +35,6 @@ const PARSED = [
     },
     {
         args: [],
-        elemName: null,
         elems: [
             {
                 name: "a::b::",
@@ -59,8 +52,6 @@ const PARSED = [
             },
         ],
         foundElems: 2,
-        id: 'A::B::,C',
-        nameSplit: null,
         original: 'A::B::,C',
         returned: [],
         typeFilter: -1,
@@ -69,7 +60,6 @@ const PARSED = [
     },
     {
         args: [],
-        elemName: null,
         elems: [
             {
                 name: "a::b::",
@@ -95,8 +85,6 @@ const PARSED = [
             },
         ],
         foundElems: 2,
-        id: 'A::B::<f>,C',
-        nameSplit: null,
         original: 'A::B::<f>,C',
         returned: [],
         typeFilter: -1,
diff --git a/src/test/rustdoc-js-std/parser-quote.js b/src/test/rustdoc-js-std/parser-quote.js
index 1c59a3d50ee..07af9249172 100644
--- a/src/test/rustdoc-js-std/parser-quote.js
+++ b/src/test/rustdoc-js-std/parser-quote.js
@@ -3,11 +3,8 @@ const QUERY = ['-> "p"', '("p")'];
 const PARSED = [
     {
         args: [],
-        elemName: null,
         elems: [],
         foundElems: 1,
-        id: "-> \"p\"",
-        nameSplit: null,
         original: "-> \"p\"",
         returned: [{
             name: "p",
@@ -28,11 +25,8 @@ const PARSED = [
             pathLast: "p",
             generics: [],
         }],
-        elemName: null,
         elems: [],
         foundElems: 1,
-        id: "(\"p\")",
-        nameSplit: null,
         original: "(\"p\")",
         returned: [],
         typeFilter: -1,
diff --git a/src/test/rustdoc-js-std/parser-returned.js b/src/test/rustdoc-js-std/parser-returned.js
index ceecda67050..face0a7461d 100644
--- a/src/test/rustdoc-js-std/parser-returned.js
+++ b/src/test/rustdoc-js-std/parser-returned.js
@@ -3,11 +3,8 @@ const QUERY = ['-> <P>', '-> P'];
 const PARSED = [
     {
         args: [],
-        elemName: null,
         elems: [],
         foundElems: 1,
-        id: "-> <P>",
-        nameSplit: null,
         original: "-> <P>",
         returned: [{
             name: "",
@@ -30,11 +27,8 @@ const PARSED = [
     },
     {
         args: [],
-        elemName: null,
         elems: [],
         foundElems: 1,
-        id: "-> P",
-        nameSplit: null,
         original: "-> P",
         returned: [{
             name: "p",
diff --git a/src/test/rustdoc-js-std/vec-new.js b/src/test/rustdoc-js-std/vec-new.js
index e1a3256876b..cd0e8e7b4a9 100644
--- a/src/test/rustdoc-js-std/vec-new.js
+++ b/src/test/rustdoc-js-std/vec-new.js
@@ -4,6 +4,6 @@ const EXPECTED = {
     'others': [
         { 'path': 'std::vec::Vec', 'name': 'new' },
         { 'path': 'std::vec::Vec', 'name': 'ne' },
-        { 'path': 'std::rc::Rc', 'name': 'ne' },
+        { 'path': 'alloc::vec::Vec', 'name': 'ne' },
     ],
 };
diff --git a/src/test/rustdoc-js/doc-alias-whitespace.js b/src/test/rustdoc-js/doc-alias-whitespace.js
index 3ee55fe455d..c9fc0c4311f 100644
--- a/src/test/rustdoc-js/doc-alias-whitespace.js
+++ b/src/test/rustdoc-js/doc-alias-whitespace.js
@@ -10,7 +10,7 @@ const EXPECTED = [
             {
                 'path': 'doc_alias_whitespace',
                 'name': 'Struct',
-                'alias': 'demon lord',
+                'alias': 'Demon Lord',
                 'href': '../doc_alias_whitespace/struct.Struct.html',
                 'is_alias': true
             },
diff --git a/src/test/rustdoc-js/doc-alias.js b/src/test/rustdoc-js/doc-alias.js
index f450bf97981..7bb0cbe388f 100644
--- a/src/test/rustdoc-js/doc-alias.js
+++ b/src/test/rustdoc-js/doc-alias.js
@@ -32,7 +32,7 @@ const EXPECTED = [
             {
                 'path': 'doc_alias',
                 'name': 'Struct',
-                'alias': 'structitem',
+                'alias': 'StructItem',
                 'href': '../doc_alias/struct.Struct.html',
                 'is_alias': true
             },
@@ -44,7 +44,7 @@ const EXPECTED = [
             {
                 'path': 'doc_alias::Struct',
                 'name': 'field',
-                'alias': 'structfielditem',
+                'alias': 'StructFieldItem',
                 'href': '../doc_alias/struct.Struct.html#structfield.field',
                 'is_alias': true
             },
@@ -56,7 +56,7 @@ const EXPECTED = [
             {
                 'path': 'doc_alias::Struct',
                 'name': 'method',
-                'alias': 'structmethoditem',
+                'alias': 'StructMethodItem',
                 'href': '../doc_alias/struct.Struct.html#method.method',
                 'is_alias': true
             },
@@ -72,7 +72,7 @@ const EXPECTED = [
             {
                 'path': 'doc_alias::Struct',
                 'name': 'ImplConstItem',
-                'alias': 'structimplconstitem',
+                'alias': 'StructImplConstItem',
                 'href': '../doc_alias/struct.Struct.html#associatedconstant.ImplConstItem',
                 'is_alias': true
             },
@@ -84,7 +84,7 @@ const EXPECTED = [
             {
                 'path': 'doc_alias::Struct',
                 'name': 'function',
-                'alias': 'impltraitfunction',
+                'alias': 'ImplTraitFunction',
                 'href': '../doc_alias/struct.Struct.html#method.function',
                 'is_alias': true
             },
@@ -96,7 +96,7 @@ const EXPECTED = [
             {
                 'path': 'doc_alias',
                 'name': 'Enum',
-                'alias': 'enumitem',
+                'alias': 'EnumItem',
                 'href': '../doc_alias/enum.Enum.html',
                 'is_alias': true
             },
@@ -108,7 +108,7 @@ const EXPECTED = [
             {
                 'path': 'doc_alias::Enum',
                 'name': 'Variant',
-                'alias': 'variantitem',
+                'alias': 'VariantItem',
                 'href': '../doc_alias/enum.Enum.html#variant.Variant',
                 'is_alias': true
             },
@@ -120,7 +120,7 @@ const EXPECTED = [
             {
                 'path': 'doc_alias::Enum',
                 'name': 'method',
-                'alias': 'enummethoditem',
+                'alias': 'EnumMethodItem',
                 'href': '../doc_alias/enum.Enum.html#method.method',
                 'is_alias': true
             },
@@ -132,7 +132,7 @@ const EXPECTED = [
             {
                 'path': 'doc_alias',
                 'name': 'Typedef',
-                'alias': 'typedefitem',
+                'alias': 'TypedefItem',
                 'href': '../doc_alias/type.Typedef.html',
                 'is_alias': true
             },
@@ -144,7 +144,7 @@ const EXPECTED = [
             {
                 'path': 'doc_alias',
                 'name': 'Trait',
-                'alias': 'traititem',
+                'alias': 'TraitItem',
                 'href': '../doc_alias/trait.Trait.html',
                 'is_alias': true
             },
@@ -156,7 +156,7 @@ const EXPECTED = [
             {
                 'path': 'doc_alias::Trait',
                 'name': 'Target',
-                'alias': 'traittypeitem',
+                'alias': 'TraitTypeItem',
                 'href': '../doc_alias/trait.Trait.html#associatedtype.Target',
                 'is_alias': true
             },
@@ -168,7 +168,7 @@ const EXPECTED = [
             {
                 'path': 'doc_alias::Trait',
                 'name': 'AssociatedConst',
-                'alias': 'associatedconstitem',
+                'alias': 'AssociatedConstItem',
                 'href': '../doc_alias/trait.Trait.html#associatedconstant.AssociatedConst',
                 'is_alias': true
             },
@@ -180,7 +180,7 @@ const EXPECTED = [
             {
                 'path': 'doc_alias::Trait',
                 'name': 'function',
-                'alias': 'traitfunctionitem',
+                'alias': 'TraitFunctionItem',
                 'href': '../doc_alias/trait.Trait.html#tymethod.function',
                 'is_alias': true
             },
@@ -192,7 +192,7 @@ const EXPECTED = [
             {
                 'path': 'doc_alias',
                 'name': 'function',
-                'alias': 'functionitem',
+                'alias': 'FunctionItem',
                 'href': '../doc_alias/fn.function.html',
                 'is_alias': true
             },
@@ -204,7 +204,7 @@ const EXPECTED = [
             {
                 'path': 'doc_alias',
                 'name': 'Module',
-                'alias': 'moduleitem',
+                'alias': 'ModuleItem',
                 'href': '../doc_alias/Module/index.html',
                 'is_alias': true
             },
@@ -216,7 +216,7 @@ const EXPECTED = [
             {
                 'path': 'doc_alias',
                 'name': 'Const',
-                'alias': 'constitem',
+                'alias': 'ConstItem',
                 'href': '../doc_alias/constant.Const.html',
                 'is_alias': true
             },
@@ -232,7 +232,7 @@ const EXPECTED = [
             {
                 'path': 'doc_alias',
                 'name': 'Static',
-                'alias': 'staticitem',
+                'alias': 'StaticItem',
                 'href': '../doc_alias/static.Static.html',
                 'is_alias': true
             },
@@ -244,7 +244,7 @@ const EXPECTED = [
             {
                 'path': 'doc_alias',
                 'name': 'Union',
-                'alias': 'unionitem',
+                'alias': 'UnionItem',
                 'href': '../doc_alias/union.Union.html',
                 'is_alias': true
             },
@@ -262,7 +262,7 @@ const EXPECTED = [
             {
                 'path': 'doc_alias::Union',
                 'name': 'union_item',
-                'alias': 'unionfielditem',
+                'alias': 'UnionFieldItem',
                 'href': '../doc_alias/union.Union.html#structfield.union_item',
                 'is_alias': true
             },
@@ -274,7 +274,7 @@ const EXPECTED = [
             {
                 'path': 'doc_alias::Union',
                 'name': 'method',
-                'alias': 'unionmethoditem',
+                'alias': 'UnionMethodItem',
                 'href': '../doc_alias/union.Union.html#method.method',
                 'is_alias': true
             },
@@ -286,7 +286,7 @@ const EXPECTED = [
             {
                 'path': 'doc_alias',
                 'name': 'Macro',
-                'alias': 'macroitem',
+                'alias': 'MacroItem',
                 'href': '../doc_alias/macro.Macro.html',
                 'is_alias': true
             },
diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js
index 5b051523cea..4ef08f53dab 100644
--- a/src/tools/rustdoc-js/tester.js
+++ b/src/tools/rustdoc-js/tester.js
@@ -270,7 +270,12 @@ function loadSearchJsAndIndex(searchJs, searchIndex, storageJs, crate) {
     // execQuery last parameter is built in buildIndex.
     // buildIndex requires the hashmap from search-index.
     var functionsToLoad = ["buildHrefAndPath", "pathSplitter", "levenshtein", "validateResult",
-                           "buildIndex", "execQuery", "parseQuery", "createQueryResults"];
+                           "buildIndex", "execQuery", "parseQuery", "createQueryResults",
+                           "isWhitespace", "isSpecialStartCharacter", "isStopCharacter",
+                           "removeEmptyStringsFromArray", "parseInput", "getItemsBefore",
+                           "getNextElem", "createQueryElement", "isReturnArrow", "isPathStart",
+                           "skipWhitespaces", "getStringElem", "itemTypeFromName",
+                           "newParsedQuery"];
 
     const functions = ["hasOwnPropertyRustdoc", "onEach"];
     ALIASES = {};
@@ -286,13 +291,12 @@ function loadSearchJsAndIndex(searchJs, searchIndex, storageJs, crate) {
     return [loaded, index];
 }
 
-function checkFieldNeededFields(fullPath, expected, error_text, queryName, position) {
+// This function checks if `expected` has all the required fields needed for the checks.
+function checkNeededFields(fullPath, expected, error_text, queryName, position) {
     let fieldsToCheck;
     if (fullPath.length === 0) {
         fieldsToCheck = [
             "foundElems",
-            "id",
-            "nameSplit",
             "original",
             "returned",
             "typeFilter",
@@ -328,7 +332,7 @@ function checkFieldNeededFields(fullPath, expected, error_text, queryName, posit
 function valueCheck(fullPath, expected, result, error_text, queryName) {
     if (Array.isArray(expected)) {
         for (var i = 0; i < expected.length; ++i) {
-            checkFieldNeededFields(fullPath, expected[i], error_text, queryName, i);
+            checkNeededFields(fullPath, expected[i], error_text, queryName, i);
             if (i >= result.length) {
                 error_text.push(`${queryName}==> EXPECTED has extra value in array from field ` +
                     `\`${fullPath}\` (position ${i}): \`${JSON.stringify(expected[i])}\``);
@@ -367,7 +371,7 @@ function valueCheck(fullPath, expected, result, error_text, queryName) {
 
 function runParser(query, expected, loaded, loadedFile, queryName) {
     var error_text = [];
-    checkFieldNeededFields("", expected, error_text, queryName, null);
+    checkNeededFields("", expected, error_text, queryName, null);
     if (error_text.length === 0) {
         valueCheck('', expected, loaded.parseQuery(query), error_text, queryName);
     }