summaryrefslogtreecommitdiffstats
path: root/src/qdoc/qdoc/src/qdoc/filesystem/fileresolver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qdoc/qdoc/src/qdoc/filesystem/fileresolver.cpp')
-rw-r--r--src/qdoc/qdoc/src/qdoc/filesystem/fileresolver.cpp161
1 files changed, 161 insertions, 0 deletions
diff --git a/src/qdoc/qdoc/src/qdoc/filesystem/fileresolver.cpp b/src/qdoc/qdoc/src/qdoc/filesystem/fileresolver.cpp
new file mode 100644
index 000000000..aaa489085
--- /dev/null
+++ b/src/qdoc/qdoc/src/qdoc/filesystem/fileresolver.cpp
@@ -0,0 +1,161 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "fileresolver.h"
+
+#include "qdoc/boundaries/filesystem/filepath.h"
+
+#include <QDir>
+
+#include <iostream>
+#include <algorithm>
+
+/*!
+ * \class FileResolver
+ * \brief Encapsulate the logic that QDoc uses to find files whose
+ * path is provided by the user and that are relative to the current
+ * configuration.
+ *
+ * A FileResolver instance is configured during creation, defining the
+ * root directories that the search should be performed on.
+ *
+ * Afterwards, it can be used to resolve paths relative to those
+ * directories, by querying through the resolve() method.
+ *
+ * Queries are resolved through a linear search through root
+ * directories, finding at most one file each time.
+ * A file is considered to be resolved if, from any root directory,
+ * the query represents an existing file.
+ *
+ * For example, consider the following directory structure on some
+ * filesystem:
+ *
+ * \badcode
+ * foo/
+ * |
+ * |-bar/
+ * |-|
+ * | |-anotherfile.txt
+ * |-file.txt
+ * \endcode
+ *
+ * And consider an instance of FileResolver tha considers \e{foo/} to
+ * be a root directory for search.
+ *
+ * Then, queries such as \e {bar/anotherfile.txt} and \e {file.txt}
+ * will be resolved.
+ *
+ * Instead, queries such as \e {foobar.cpp}, \e {bar}, and \e
+ * {foo/bar/anotherfile.txt} will not be resolved, as they do not
+ * represent any file reachable from a root directory for search.
+ *
+ * It is important to note that FileResolver always searches its root
+ * directories in an order that is based on the lexicographic ordering
+ * of the path of its root directories.
+ *
+ * For example, consider the following directory structure on some
+ * filesystem:
+ *
+ * \badcode
+ * foo/
+ * |
+ * |-bar/
+ * |-|
+ * | |-file.txt
+ * |-foobar/
+ * |-|
+ * | |-file.txt
+ * \endcode
+ *
+ * And consider an instance of FileResolver that considers \e
+ * {foo/bar/} and \e {foo/foobar/} to be root directories for search.
+ *
+ * Then, when the query \e {file.txt} is resolved, it will always
+ * resolve to the file in \e {bar}, as \e {bar} will be searched
+ * before \e {foobar}.
+ *
+ * We say that \e {foobar/file.txt} is shadowed by \e {bar/file.txt}.
+ *
+ * Currently, if this is an issue, it is possible to resolve it by
+ * using a common ancestor as a root directory instead of using
+ * multiples directories.
+ *
+ * In the previous example, if \e {foo} is instead chosen as the root
+ * directory for search, then queries \e {bar/file.txt} and \e
+ * {foobar/file.txt} can be used to uniquely resolve the two files,
+ * removing the shadowing.
+ * */
+
+/*!
+ * Constructs an instance of FileResolver with the directories in \a
+ * search_directories as root directories for searching.
+ *
+ * Duplicates in \a search_directories do not affect the resolution of
+ * files for the instance.
+ *
+ * For example, if \a search_directories contains some directory D
+ * more than once, the constructed instance will resolve files
+ * equivalently to an instance constructed with a single appearance of
+ * D.
+ *
+ * The order of \a search_directories does not affect the resolution
+ * of files for an instance.
+ *
+ * For example, if \a search_directories contains a permutation of
+ * directories D1, D2, ..., Dn, then the constructed instance will
+ * resolve files equivalently to an instance constructed from a
+ * difference permutation of the same directories.
+ */
+FileResolver::FileResolver(std::vector<DirectoryPath>&& search_directories)
+ : search_directories{std::move(search_directories)}
+{
+ std::sort(this->search_directories.begin(), this->search_directories.end());
+ this->search_directories.erase (
+ std::unique(this->search_directories.begin(), this->search_directories.end()),
+ this->search_directories.end()
+ );
+}
+
+// REMARK: Note that we do not treat absolute path specially.
+// This will in general mean that they cannot get resolved (albeit
+// there is a peculiar instance in which they can considering that
+// most path formats treat multiple adjacent separators as one).
+//
+// While we need to treat them at some point with a specific
+// intention, this was avoided at the current moment as it is
+// unrequired to build the actual documentation.
+//
+// In particular, avoiding this choice now allows us to move it to a
+// later stage where we can work with the origin of the data itself.
+// User-inputted paths come into the picture during the configuration
+// process and when parsing qdoc comments, there is a good chance that
+// some amount of sophistication will be required to handle this data
+// at the code level, for example to ensure that multiplatform
+// handling of paths is performed correctly.
+//
+// This will then define how we should handle absolute paths, if we
+// can receive them at all and so on.
+
+/*!
+* Returns a ResolvedFile if \a query can be resolved or std::nullopt
+* otherwise.
+*
+* The returned ResolvedFile, if any, will contain the provided \a
+* query and the path that the \a query was resolved to.
+*/
+[[nodiscard]] std::optional<ResolvedFile> FileResolver::resolve(QString query) const {
+ for (auto& directory_path : search_directories) {
+ auto maybe_filepath = FilePath::refine(QDir(directory_path.value() + "/" + query).path());
+ if (maybe_filepath) return ResolvedFile{std::move(query), std::move(*maybe_filepath)};
+ }
+
+ return std::nullopt;
+}
+
+/*!
+ * \fn FileResolver::get_search_directories() const
+ *
+ * Returns a const-reference to a collection of root search
+ * directories that this instance will use during the resolution of
+ * files.
+ */