Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
fileresolver.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4#include "fileresolver.h"
5
6#include "qdoc/boundaries/filesystem/filepath.h"
7
8#include <QDir>
9
10#include <iostream>
11#include <algorithm>
12
13/*!
14 * \class FileResolver
15 * \brief Encapsulate the logic that QDoc uses to find files whose
16 * path is provided by the user and that are relative to the current
17 * configuration.
18 *
19 * A FileResolver instance is configured during creation, defining the
20 * root directories that the search should be performed on.
21 *
22 * Afterwards, it can be used to resolve paths relative to those
23 * directories, by querying through the resolve() method.
24 *
25 * Queries are resolved through a linear search through root
26 * directories, finding at most one file each time.
27 * A file is considered to be resolved if, from any root directory,
28 * the query represents an existing file.
29 *
30 * For example, consider the following directory structure on some
31 * filesystem:
32 *
33 * \badcode
34 * foo/
35 * |
36 * |-bar/
37 * |-|
38 * | |-anotherfile.txt
39 * |-file.txt
40 * \endcode
41 *
42 * And consider an instance of FileResolver tha considers \e{foo/} to
43 * be a root directory for search.
44 *
45 * Then, queries such as \e {bar/anotherfile.txt} and \e {file.txt}
46 * will be resolved.
47 *
48 * Instead, queries such as \e {foobar.cpp}, \e {bar}, and \e
49 * {foo/bar/anotherfile.txt} will not be resolved, as they do not
50 * represent any file reachable from a root directory for search.
51 *
52 * It is important to note that FileResolver always searches its root
53 * directories in an order that is based on the lexicographic ordering
54 * of the path of its root directories.
55 *
56 * For example, consider the following directory structure on some
57 * filesystem:
58 *
59 * \badcode
60 * foo/
61 * |
62 * |-bar/
63 * |-|
64 * | |-file.txt
65 * |-foobar/
66 * |-|
67 * | |-file.txt
68 * \endcode
69 *
70 * And consider an instance of FileResolver that considers \e
71 * {foo/bar/} and \e {foo/foobar/} to be root directories for search.
72 *
73 * Then, when the query \e {file.txt} is resolved, it will always
74 * resolve to the file in \e {bar}, as \e {bar} will be searched
75 * before \e {foobar}.
76 *
77 * We say that \e {foobar/file.txt} is shadowed by \e {bar/file.txt}.
78 *
79 * Currently, if this is an issue, it is possible to resolve it by
80 * using a common ancestor as a root directory instead of using
81 * multiples directories.
82 *
83 * In the previous example, if \e {foo} is instead chosen as the root
84 * directory for search, then queries \e {bar/file.txt} and \e
85 * {foobar/file.txt} can be used to uniquely resolve the two files,
86 * removing the shadowing.
87 * */
88
89/*!
90 * Constructs an instance of FileResolver with the directories in \a
91 * search_directories as root directories for searching.
92 *
93 * Duplicates in \a search_directories do not affect the resolution of
94 * files for the instance.
95 *
96 * For example, if \a search_directories contains some directory D
97 * more than once, the constructed instance will resolve files
98 * equivalently to an instance constructed with a single appearance of
99 * D.
100 *
101 * The order of \a search_directories does not affect the resolution
102 * of files for an instance.
103 *
104 * For example, if \a search_directories contains a permutation of
105 * directories D1, D2, ..., Dn, then the constructed instance will
106 * resolve files equivalently to an instance constructed from a
107 * difference permutation of the same directories.
108 */
109FileResolver::FileResolver(std::vector<DirectoryPath>&& search_directories)
111{
112 std::sort(this->search_directories.begin(), this->search_directories.end());
113 this->search_directories.erase (
114 std::unique(this->search_directories.begin(), this->search_directories.end()),
115 this->search_directories.end()
116 );
117}
118
119// REMARK: Note that we do not treat absolute path specially.
120// This will in general mean that they cannot get resolved (albeit
121// there is a peculiar instance in which they can considering that
122// most path formats treat multiple adjacent separators as one).
123//
124// While we need to treat them at some point with a specific
125// intention, this was avoided at the current moment as it is
126// unrequired to build the actual documentation.
127//
128// In particular, avoiding this choice now allows us to move it to a
129// later stage where we can work with the origin of the data itself.
130// User-inputted paths come into the picture during the configuration
131// process and when parsing qdoc comments, there is a good chance that
132// some amount of sophistication will be required to handle this data
133// at the code level, for example to ensure that multiplatform
134// handling of paths is performed correctly.
135//
136// This will then define how we should handle absolute paths, if we
137// can receive them at all and so on.
138
139/*!
140* Returns a ResolvedFile if \a query can be resolved or std::nullopt
141* otherwise.
142*
143* The returned ResolvedFile, if any, will contain the provided \a
144* query and the path that the \a query was resolved to.
145*/
146[[nodiscard]] std::optional<ResolvedFile> FileResolver::resolve(QString query) const {
147 for (auto& directory_path : search_directories) {
148 auto maybe_filepath = FilePath::refine(QDir(directory_path.value() + "/" + query).path());
149 if (maybe_filepath) return ResolvedFile{std::move(query), std::move(*maybe_filepath)};
150 }
151
152 return std::nullopt;
153}
154
155/*!
156 * \fn FileResolver::get_search_directories() const
157 *
158 * Returns a const-reference to a collection of root search
159 * directories that this instance will use during the resolution of
160 * files.
161 */
Encapsulate the logic that QDoc uses to find files whose path is provided by the user and that are re...
std::optional< ResolvedFile > resolve(QString filename) const
Returns a ResolvedFile if query can be resolved or std::nullopt otherwise.
FileResolver(std::vector< DirectoryPath > &&search_directories)
Constructs an instance of FileResolver with the directories in search_directories as root directories...
Represents a file that is reachable by QDoc based on its current configuration.