summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qdoc/clangcodeparser.cpp36
-rw-r--r--src/qdoc/config.cpp77
-rw-r--r--src/qdoc/config.h9
-rw-r--r--src/qdoc/doc/qdoc-manual-qdocconf.qdoc70
-rw-r--r--src/qdoc/generator.cpp2
-rw-r--r--src/qdoc/location.h2
-rw-r--r--tests/auto/qdoc/config/testdata/configs/includepaths.qdocconf2
-rw-r--r--tests/auto/qdoc/config/testdata/includepaths/include/framework/ignore.h1
-rw-r--r--tests/auto/qdoc/config/testdata/includepaths/include/more/ignore.h1
-rw-r--r--tests/auto/qdoc/config/testdata/includepaths/include/purpose.h1
-rw-r--r--tests/auto/qdoc/config/testdata/includepaths/include/system/ignore.h1
-rw-r--r--tests/auto/qdoc/config/testdata/includepaths/includepaths.qdocconf16
-rw-r--r--tests/auto/qdoc/config/tst_config.cpp23
13 files changed, 197 insertions, 44 deletions
diff --git a/src/qdoc/clangcodeparser.cpp b/src/qdoc/clangcodeparser.cpp
index b8feca108..d61b24270 100644
--- a/src/qdoc/clangcodeparser.cpp
+++ b/src/qdoc/clangcodeparser.cpp
@@ -1096,38 +1096,18 @@ void ClangCodeParser::initializeParser()
{
Config &config = Config::instance();
m_version = config.getString(CONFIG_VERSION);
- auto args = config.getStringList(CONFIG_INCLUDEPATHS);
- QSet<QString> seen;
- m_includePaths.clear();
-
+ auto args = config.getCanonicalPathList(CONFIG_INCLUDEPATHS,
+ Config::IncludePaths);
#ifdef Q_OS_MACOS
args.append(Utilities::getInternalIncludePaths(QStringLiteral("clang++")));
#endif
-
- // Remove empty paths and duplicates and add -I and canonicalize if necessary
- for (const auto &p : args) {
- QByteArray option;
- QString rawpath;
- if (p.startsWith(QLatin1String("-I")) || p.startsWith(QLatin1String("-F"))) {
- rawpath = p.mid(2).trimmed();
- option = p.left(2).toUtf8();
- } else if (p.startsWith(QLatin1String("-isystem"))) {
- rawpath = p.mid(8).trimmed();
- option = "-isystem";
- } else {
- rawpath = p;
- option = "-I";
- }
- if (rawpath.isEmpty() || seen.contains(rawpath))
- continue;
- seen.insert(rawpath);
- QByteArray path(rawpath.toUtf8());
- QFileInfo fi(QDir::current(), rawpath);
- if (fi.exists())
- path = fi.canonicalFilePath().toUtf8();
- path.prepend(option);
- m_includePaths.append(path);
+ m_includePaths.clear();
+ for (const auto &path : qAsConst(args)) {
+ if (!path.isEmpty())
+ m_includePaths.append(path.toUtf8());
}
+ m_includePaths.erase(std::unique(m_includePaths.begin(), m_includePaths.end()),
+ m_includePaths.end());
CppCodeParser::initializeParser();
m_pchFileDir.reset(nullptr);
m_allHeaders.clear();
diff --git a/src/qdoc/config.cpp b/src/qdoc/config.cpp
index c2beda80d..41dc9b2c6 100644
--- a/src/qdoc/config.cpp
+++ b/src/qdoc/config.cpp
@@ -235,10 +235,29 @@ QMap<QString, QStringList> Config::m_includeFilesMap;
\brief The Config class contains the configuration variables
for controlling how qdoc produces documentation.
- Its load() function, reads, parses, and processes a qdocconf file.
+ Its load() function reads, parses, and processes a qdocconf file.
*/
/*!
+ \enum Config::PathFlags
+
+ Flags used for retrieving canonicalized paths from Config.
+
+ \value Validate
+ Issue a warning for paths that do not exist and
+ remove them from the returned list.
+
+ \value IncludePaths
+ Assume the variable contains include paths with
+ prefixes such as \c{-I} that are to be removed
+ before canonicalizing and then re-inserted.
+
+ \omitvalue None
+
+ \sa getCanonicalPathList()
+*/
+
+/*!
Initializes the Config with \a programName and sets all
internal state variables to either default values or to ones
defined in command line arguments \a args.
@@ -573,12 +592,16 @@ QStringList Config::getStringList(const QString &var) const
}
/*!
- Returns the a path list where all paths from the config variable \a var
- are canonicalized. If \a validate is true, outputs a warning for invalid
- paths. If \a var is defined, updates the internal location to the
- location of \a var for the purposes of error reporting.
+ Returns a path list where all paths from the config variable \a var
+ are canonicalized. If \a flags contains \c Validate, outputs a warning
+ for invalid paths. The \c IncludePaths flag is used as a hint to strip
+ away potential prefixes found in include paths before attempting to
+ canonicalize.
+
+ \note The internal location is updated to the location of \a var for
+ the purposes of error reporting.
*/
-QStringList Config::getCanonicalPathList(const QString &var, bool validate) const
+QStringList Config::getCanonicalPathList(const QString &var, PathFlags flags) const
{
QStringList result;
const auto &configVar = m_configVars.value(var);
@@ -586,19 +609,47 @@ QStringList Config::getCanonicalPathList(const QString &var, bool validate) cons
for (const auto &value : configVar.m_values) {
const QString &currentPath = value.m_path;
- QDir dir(value.m_value.simplified());
+ QString rawValue = value.m_value.simplified();
+ QString prefix;
+
+ if (flags & IncludePaths) {
+ const QStringList prefixes = QStringList()
+ << QLatin1String("-I")
+ << QLatin1String("-F")
+ << QLatin1String("-isystem");
+ const auto end = std::end(prefixes);
+ const auto it =
+ std::find_if(std::begin(prefixes), end,
+ [&rawValue](const QString &p) {
+ return rawValue.startsWith(p);
+ });
+ if (it != end) {
+ prefix = *it;
+ rawValue.remove(0, it->size());
+ if (rawValue.isEmpty())
+ continue;
+ } else {
+ prefix = prefixes[0]; // -I as default
+ }
+ }
+
+ QDir dir(rawValue.trimmed());
const QString path = dir.path();
if (dir.isRelative())
dir.setPath(currentPath + QLatin1Char('/') + path);
- if (validate && !QFileInfo::exists(dir.path()))
+ if ((flags & Validate) && !QFileInfo::exists(dir.path()))
m_lastLocation.warning(QStringLiteral("Cannot find file or directory: %1").arg(path));
else {
const QString canonicalPath = dir.canonicalPath();
if (!canonicalPath.isEmpty())
- result.append(canonicalPath);
+ result.append(prefix + canonicalPath);
else if (path.contains(QLatin1Char('*')) || path.contains(QLatin1Char('?')))
result.append(path);
+ else
+ qCDebug(lcQdoc) <<
+ qUtf8Printable(QStringLiteral("%1: Ignored nonexistent path \'%2\'")
+ .arg(m_lastLocation.toString()).arg(rawValue));
}
}
return result;
@@ -607,8 +658,8 @@ QStringList Config::getCanonicalPathList(const QString &var, bool validate) cons
/*!
Calls getRegExpList() with the control variable \a var and
iterates through the resulting list of regular expressions,
- concatening them with some extras characters to form a single
- QRegularExpression, which is returned/
+ concatenating them with extra characters to form a single
+ QRegularExpression, which is then returned.
\sa getRegExpList()
*/
@@ -712,8 +763,8 @@ QStringList Config::getAllFiles(const QString &filesVar, const QString &dirsVar,
const QSet<QString> &excludedDirs,
const QSet<QString> &excludedFiles)
{
- QStringList result = getCanonicalPathList(filesVar, true);
- const QStringList dirs = getCanonicalPathList(dirsVar, true);
+ QStringList result = getCanonicalPathList(filesVar, Validate);
+ const QStringList dirs = getCanonicalPathList(dirsVar, Validate);
const QString nameFilter = getString(filesVar + dot + CONFIG_FILEEXTENSIONS);
diff --git a/src/qdoc/config.h b/src/qdoc/config.h
index 00c741d9e..e3b8bf9d8 100644
--- a/src/qdoc/config.h
+++ b/src/qdoc/config.h
@@ -118,6 +118,12 @@ public:
enum QDocPass { Neither, Prepare, Generate };
+ enum PathFlags : unsigned char {
+ None = 0x0,
+ Validate = 0x1,
+ IncludePaths = 0x2
+ };
+
void init(const QString &programName, const QStringList &args);
[[nodiscard]] bool getDebug() const { return m_debug; }
[[nodiscard]] bool showInternal() const { return m_showInternal; }
@@ -142,7 +148,8 @@ public:
const QString &defaultString = QString()) const;
[[nodiscard]] QSet<QString> getStringSet(const QString &var) const;
[[nodiscard]] QStringList getStringList(const QString &var) const;
- [[nodiscard]] QStringList getCanonicalPathList(const QString &var, bool validate = false) const;
+ [[nodiscard]] QStringList getCanonicalPathList(const QString &var,
+ PathFlags flags = None) const;
[[nodiscard]] QRegularExpression getRegExp(const QString &var) const;
[[nodiscard]] QList<QRegularExpression> getRegExpList(const QString &var) const;
[[nodiscard]] QSet<QString> subVars(const QString &var) const;
diff --git a/src/qdoc/doc/qdoc-manual-qdocconf.qdoc b/src/qdoc/doc/qdoc-manual-qdocconf.qdoc
index b1bda2955..c47d49784 100644
--- a/src/qdoc/doc/qdoc-manual-qdocconf.qdoc
+++ b/src/qdoc/doc/qdoc-manual-qdocconf.qdoc
@@ -182,6 +182,7 @@
\li \l {HTML.footer-variable} {HTML.footer}
\li \l {HTML.postheader-variable} {HTML.postheader}
\li \l {HTML.style-variable} {HTML.style}
+ \li \l {includepaths-variable} {includepaths}
\li \l {ignorewords-variable} {ignorewords}
\li \l {ignoresince-variable} {ignoresince}
\li \l {imagedirs-variable} {imagedirs}
@@ -192,6 +193,7 @@
\li \l {locationinfo-variable} {locationinfo}
\li \l {macro-variable} {macro}
\li \l {manifestmeta-variable} {manifestmeta}
+ \li \l {moduleheader-variable} {moduleheader}
\li \l {navigation-variable} {navigation}
\li \l {outputdir-variable} {outputdir}
\li \l {outputformats-variable} {outputformats}
@@ -697,6 +699,28 @@
See also \l headerdirs.
+ \target includepaths-variable
+ \section1 includepaths
+
+ The \c includepaths variable is used for passing additional
+ include paths to the Clang parser that QDoc uses for parsing C++
+ code for documentation comments.
+
+ The variable accepts a list of paths, prefixed with \c{-I} (include
+ path), \c {-F} (\macos framework include path), or \c{-isystem}
+ (system include path). If a prefix is omitted, \c{-I} is used by
+ default.
+
+ Paths relative to the current .qdocconf file are resolved into
+ absolute paths. Paths that do not exist in the file system are
+ ignored.
+
+ \note For Qt documentation projects, the build system typically
+ provides the required include paths as command line
+ arguments when invoking QDoc.
+
+ See also \l moduleheader.
+
\target ignorewords-variable
\section1 ignorewords
@@ -982,6 +1006,52 @@
See the \l{Manifest Meta Content} section for more information.
+ \target moduleheader-variable
+ \section1 moduleheader
+
+ The \c moduleheader variable defines the name of the module
+ header of a documented C++ module.
+
+ Projects that document C++ APIs require a module-level header
+ that includes all public classes, namespaces and header files
+ for the module. The Clang parser in QDoc uses this file to
+ build a pre-compiled header (PCH) for the module to increase
+ the speed of parsing source files.
+
+ By default, the \l{project-variable}{project} name is used
+ also as the module header name.
+
+ \badcode
+ project = QtCore
+ \endcode
+
+ With the above project name, QDoc searches a module header
+ \e QtCore in all known include paths; first using the paths
+ passed as command line arguments, then the paths listed in
+ the \l includepaths variable.
+
+ QDoc will issue a warning if the module header is not found.
+ It will then attempt to build an artificial module header
+ based on the headers listed in the \l {headerdirs-variable}
+ {headerdirs} variable.
+
+ For Qt documentation projects, the build system typically
+ provides QDoc with correct include paths to locate the
+ module header, provided that the \c project variable is set
+ correctly. The \c moduleheader variable provides an
+ alternative file name for QDoc to search for.
+
+ If the project contains no C++ documentation, QDoc should be
+ instructed to skip generating a PCH by setting \c moduleheader
+ to an empty string:
+
+ \badcode
+ # No C++ code to document in this project
+ moduleheader =
+ \endcode
+
+ See also \l includepaths and \l project.
+
\target naturallanguage-variable
\section1 naturallanguage
diff --git a/src/qdoc/generator.cpp b/src/qdoc/generator.cpp
index 50904cb49..5f65236f2 100644
--- a/src/qdoc/generator.cpp
+++ b/src/qdoc/generator.cpp
@@ -1715,7 +1715,7 @@ void Generator::initialize()
void Generator::copyTemplateFiles(const QString &configVar, const QString &subDir)
{
Config &config = Config::instance();
- QStringList files = config.getCanonicalPathList(configVar, true);
+ QStringList files = config.getCanonicalPathList(configVar, Config::Validate);
if (!files.isEmpty()) {
QDir dirInfo;
QString templateDir = s_outDir + QLatin1Char('/') + subDir;
diff --git a/src/qdoc/location.h b/src/qdoc/location.h
index dbf603394..bb1b6f01f 100644
--- a/src/qdoc/location.h
+++ b/src/qdoc/location.h
@@ -68,6 +68,7 @@ public:
[[nodiscard]] int lineNo() const { return m_stkTop->m_lineNo; }
[[nodiscard]] int columnNo() const { return m_stkTop->m_columnNo; }
[[nodiscard]] bool etc() const { return m_etc; }
+ [[nodiscard]] QString toString() const;
void warning(const QString &message, const QString &details = QString()) const;
void error(const QString &message, const QString &details = QString()) const;
void fatal(const QString &message, const QString &details = QString()) const;
@@ -92,7 +93,6 @@ private:
friend class QTypeInfo<StackEntry>;
void emitMessage(MessageType type, const QString &message, const QString &details) const;
- [[nodiscard]] QString toString() const;
[[nodiscard]] QString top() const;
private:
diff --git a/tests/auto/qdoc/config/testdata/configs/includepaths.qdocconf b/tests/auto/qdoc/config/testdata/configs/includepaths.qdocconf
new file mode 100644
index 000000000..2d6ff22af
--- /dev/null
+++ b/tests/auto/qdoc/config/testdata/configs/includepaths.qdocconf
@@ -0,0 +1,2 @@
+project = IncludePaths
+include(../includepaths/includepaths.qdocconf)
diff --git a/tests/auto/qdoc/config/testdata/includepaths/include/framework/ignore.h b/tests/auto/qdoc/config/testdata/includepaths/include/framework/ignore.h
new file mode 100644
index 000000000..b2a4ba591
--- /dev/null
+++ b/tests/auto/qdoc/config/testdata/includepaths/include/framework/ignore.h
@@ -0,0 +1 @@
+# nothing here
diff --git a/tests/auto/qdoc/config/testdata/includepaths/include/more/ignore.h b/tests/auto/qdoc/config/testdata/includepaths/include/more/ignore.h
new file mode 100644
index 000000000..b2a4ba591
--- /dev/null
+++ b/tests/auto/qdoc/config/testdata/includepaths/include/more/ignore.h
@@ -0,0 +1 @@
+# nothing here
diff --git a/tests/auto/qdoc/config/testdata/includepaths/include/purpose.h b/tests/auto/qdoc/config/testdata/includepaths/include/purpose.h
new file mode 100644
index 000000000..0f7af352b
--- /dev/null
+++ b/tests/auto/qdoc/config/testdata/includepaths/include/purpose.h
@@ -0,0 +1 @@
+#define PURPOSE "Pass butter"
diff --git a/tests/auto/qdoc/config/testdata/includepaths/include/system/ignore.h b/tests/auto/qdoc/config/testdata/includepaths/include/system/ignore.h
new file mode 100644
index 000000000..b2a4ba591
--- /dev/null
+++ b/tests/auto/qdoc/config/testdata/includepaths/include/system/ignore.h
@@ -0,0 +1 @@
+# nothing here
diff --git a/tests/auto/qdoc/config/testdata/includepaths/includepaths.qdocconf b/tests/auto/qdoc/config/testdata/includepaths/includepaths.qdocconf
new file mode 100644
index 000000000..6288c4258
--- /dev/null
+++ b/tests/auto/qdoc/config/testdata/includepaths/includepaths.qdocconf
@@ -0,0 +1,16 @@
+includepaths = -I./include
+
+# without prefix but same path, should be identical
+# (Config should not remove duplicates)
+includepaths += include
+
+# space between prefix and path - incorrect but we allow it
+includepaths += -I include/more
+
+# system paths and framework paths
+includepaths += \
+ -F./include/framework \
+ -isysteminclude/system
+
+# nonexistent paths are to be ignored
+includepaths += invalid
diff --git a/tests/auto/qdoc/config/tst_config.cpp b/tests/auto/qdoc/config/tst_config.cpp
index 58d8eae15..dddfd0878 100644
--- a/tests/auto/qdoc/config/tst_config.cpp
+++ b/tests/auto/qdoc/config/tst_config.cpp
@@ -43,6 +43,7 @@ private slots:
void includePathsFromCommandLine();
void variables();
void paths();
+ void includepaths();
void getExampleProjectFile();
void expandVars();
@@ -142,6 +143,28 @@ void tst_Config::paths()
QCOMPARE(paths[2], rootDir.absoluteFilePath("configs/includes"));
}
+// Tests whether includepaths are resolved correctly
+void tst_Config::includepaths()
+{
+ auto &config = initConfig();
+ const auto docConfig = QFINDTESTDATA("/testdata/configs/includepaths.qdocconf");
+ if (!docConfig.isEmpty())
+ config.load(docConfig);
+
+ auto rootDir = QFileInfo(docConfig).dir();
+ QVERIFY(rootDir.cdUp());
+
+ const auto paths = config.getCanonicalPathList("includepaths",
+ Config::IncludePaths);
+ QVERIFY(paths.size() == 5);
+
+ QCOMPARE(paths[0], "-I" + rootDir.absoluteFilePath("includepaths/include"));
+ QCOMPARE(paths[0], paths[1]);
+ QCOMPARE(paths[2], "-I" + rootDir.absoluteFilePath("includepaths/include/more"));
+ QCOMPARE(paths[3], "-F" + rootDir.absoluteFilePath("includepaths/include/framework"));
+ QCOMPARE(paths[4], "-isystem" + rootDir.absoluteFilePath("includepaths/include/system"));
+}
+
void::tst_Config::getExampleProjectFile()
{
auto &config = initConfig();