Fix a bug in qdocs handling of excludedirs

The bug was there because the way qdoc tries to exclude the directories
given in the "excludedirs" variable:
It did a simple string comparision on the candidate path (to include)
with every string in the "excludedirs" variable.

However, this did not work for all cases, since the paths are not
canonicalized.
For instance, the problem I faced was that the following qdocconf
fragment: (config file located in doc/qtwidgets.qdocconf)
sourcedirs  += ..
excludedirs += snippets

Since qdoc would recursively parse all subfolders of sourcedirs, it
would at one point visit the snippets folder, but it would have the
relative path "../doc/snippets", which did not match with "snippets",
causing snippets to not be excluded.

In addition, it seems that qdoc tries hard not to use absolute paths
(maybe because of more human-friendly error messages). I therefore
chose to canonicalize the relative paths.

As a side-effect this also give a better output from qdoc, as
../doc/foo.qdoc:42: Missing link
will become
foo.qdoc:42: Missing link

Change-Id: If9c25fa569abd03542bd12675acd44d8f4e0282c
Reviewed-by: Martin Smith <martin.smith@nokia.com>
This commit is contained in:
Jan-Arve Saether 2012-08-17 11:52:40 +02:00 committed by Qt by Nokia
parent 8160ca6dfd
commit 526da72e99
6 changed files with 60 additions and 13 deletions

View File

@ -327,6 +327,32 @@ QStringList Config::getStringList(const QString& var) const
return stringListValueMap[var]; return stringListValueMap[var];
} }
/*!
\brief Returns the a path list where all paths are canonicalized, then
made relative to the config file.
\param var The variable containing the list of paths.
\see Location::canonicalRelativePath()
*/
QStringList Config::getCanonicalRelativePathList(const QString& var) const
{
if (!locMap[var].isEmpty())
(Location&) lastLoc = locMap[var];
QStringList t;
QMap<QString,QStringList>::const_iterator it = stringListValueMap.constFind(var);
if (it != stringListValueMap.constEnd()) {
const QStringList& sl = it.value();
if (!sl.isEmpty()) {
t.reserve(sl.size());
for (int i=0; i<sl.size(); ++i) {
const QString &canonicalized = location().canonicalRelativePath(sl[i]);
t.append(canonicalized);
}
}
}
return t;
}
/*! /*!
This function should only be called when the configuration This function should only be called when the configuration
variable \a var maps to a string list that contains file paths. variable \a var maps to a string list that contains file paths.
@ -465,13 +491,13 @@ QStringList Config::getAllFiles(const QString &filesVar,
const QSet<QString> &excludedFiles) const QSet<QString> &excludedFiles)
{ {
QStringList result = getStringList(filesVar); QStringList result = getStringList(filesVar);
QStringList dirs = getStringList(dirsVar); QStringList dirs = getCanonicalRelativePathList(dirsVar);
QString nameFilter = getString(filesVar + dot + QLatin1String(CONFIG_FILEEXTENSIONS)); QString nameFilter = getString(filesVar + dot + QLatin1String(CONFIG_FILEEXTENSIONS));
QStringList::ConstIterator d = dirs.constBegin(); QStringList::ConstIterator d = dirs.constBegin();
while (d != dirs.constEnd()) { while (d != dirs.constEnd()) {
result += getFilesHere(*d, nameFilter, excludedDirs, excludedFiles); result += getFilesHere(*d, nameFilter, location(), excludedDirs, excludedFiles);
++d; ++d;
} }
return result; return result;
@ -487,7 +513,7 @@ QStringList Config::getExampleQdocFiles()
QStringList::ConstIterator d = dirs.constBegin(); QStringList::ConstIterator d = dirs.constBegin();
while (d != dirs.constEnd()) { while (d != dirs.constEnd()) {
result += getFilesHere(*d, nameFilter, excludedDirs, excludedFiles); result += getFilesHere(*d, nameFilter, location(), excludedDirs, excludedFiles);
++d; ++d;
} }
return result; return result;
@ -948,10 +974,12 @@ void Config::load(Location location, const QString& fileName)
QStringList Config::getFilesHere(const QString& uncleanDir, QStringList Config::getFilesHere(const QString& uncleanDir,
const QString& nameFilter, const QString& nameFilter,
const Location &location,
const QSet<QString> &excludedDirs, const QSet<QString> &excludedDirs,
const QSet<QString> &excludedFiles) const QSet<QString> &excludedFiles)
{ {
QString dir = QDir::cleanPath(uncleanDir); //
QString dir = location.isEmpty() ? QDir::cleanPath(uncleanDir) : location.canonicalRelativePath(uncleanDir);
QStringList result; QStringList result;
if (excludedDirs.contains(dir)) if (excludedDirs.contains(dir))
return result; return result;
@ -981,7 +1009,7 @@ QStringList Config::getFilesHere(const QString& uncleanDir,
fileNames = dirInfo.entryList(); fileNames = dirInfo.entryList();
fn = fileNames.constBegin(); fn = fileNames.constBegin();
while (fn != fileNames.constEnd()) { while (fn != fileNames.constEnd()) {
result += getFilesHere(dirInfo.filePath(*fn), nameFilter, excludedDirs, excludedFiles); result += getFilesHere(dirInfo.filePath(*fn), nameFilter, location, excludedDirs, excludedFiles);
++fn; ++fn;
} }
return result; return result;

View File

@ -76,6 +76,7 @@ public:
QString getString(const QString& var) const; QString getString(const QString& var) const;
QSet<QString> getStringSet(const QString& var) const; QSet<QString> getStringSet(const QString& var) const;
QStringList getStringList(const QString& var) const; QStringList getStringList(const QString& var) const;
QStringList getCanonicalRelativePathList(const QString& var) const;
QStringList getCleanPathList(const QString& var) const; QStringList getCleanPathList(const QString& var) const;
QRegExp getRegExp(const QString& var) const; QRegExp getRegExp(const QString& var) const;
QList<QRegExp> getRegExpList(const QString& var) const; QList<QRegExp> getRegExpList(const QString& var) const;
@ -88,6 +89,7 @@ public:
QStringList getExampleQdocFiles(); QStringList getExampleQdocFiles();
static QStringList getFilesHere(const QString& dir, static QStringList getFilesHere(const QString& dir,
const QString& nameFilter, const QString& nameFilter,
const Location &location = Location(),
const QSet<QString> &excludedDirs = QSet<QString>(), const QSet<QString> &excludedDirs = QSet<QString>(),
const QSet<QString> &excludedFiles = QSet<QString>()); const QSet<QString> &excludedFiles = QSet<QString>());
static QString findFile(const Location& location, static QString findFile(const Location& location,

View File

@ -5634,7 +5634,7 @@
colons (\c{::}). colons (\c{::}).
\code \code
A link to the UI Component's TabWidget is \l {UIComponent::TabWidget}. A link to the UI Component's TabWidget is \l {UIComponent::TabWidget}.
\endcode \endcode
QDoc will generate a page for the module with a listing of the members QDoc will generate a page for the module with a listing of the members
@ -7599,14 +7599,11 @@
\l {sourcedirs-variable} {sourcedirs} or \l {headerdirs-variable} {headerdirs} \l {sourcedirs-variable} {sourcedirs} or \l {headerdirs-variable} {headerdirs}
variables. variables.
For example in \l qt.qdocconf For example,
\code \code
excludedirs = $QTDIR/extensions/activeqt \ sourcedirs = src/corelib
$QTDIR/extensions/motif \ excludedirs = src/corelib/tmp
$QTDIR/tools/designer/src/lib/extension \
$QTDIR/tools/designer/src/lib/sdk \
$QTDIR/tools/designer/src/lib/uilib
\endcode \endcode
When executed, QDoc will exclude the listed directories from When executed, QDoc will exclude the listed directories from

View File

@ -43,6 +43,7 @@
#include "config.h" #include "config.h"
#include "location.h" #include "location.h"
#include <qdir.h>
#include <qregexp.h> #include <qregexp.h>
#include <stdlib.h> #include <stdlib.h>
#include <limits.h> #include <limits.h>
@ -225,6 +226,24 @@ QString Location::fileName() const
return fp.mid(fp.lastIndexOf('/') + 1); return fp.mid(fp.lastIndexOf('/') + 1);
} }
/*!
* \brief Returns \a path which is canonicalized and relative to the config file.
*
* QDir::relativeFilePath does not canonicalize the paths, so
* if the config file is located at qtbase\src\widgets\doc\qtwidgets.qdocconf
* and it has a reference to any ancestor folder (e.g. ".." or even "../doc")
* \param path
* \return
*/
QString Location::canonicalRelativePath(const QString &path) const
{
QDir configFileDir(QFileInfo(filePath()).dir());
QDir dir(path);
const QString canon = dir.canonicalPath();
return configFileDir.relativeFilePath(canon);
}
/*! \fn int Location::lineNo() const /*! \fn int Location::lineNo() const
Returns the current line number. Returns the current line number.
Must not be called on an empty Location object. Must not be called on an empty Location object.

View File

@ -79,6 +79,7 @@ public:
int depth() const { return stkDepth; } int depth() const { return stkDepth; }
const QString& filePath() const { return stkTop->filePath; } const QString& filePath() const { return stkTop->filePath; }
QString fileName() const; QString fileName() const;
QString canonicalRelativePath(const QString &path) const;
int lineNo() const { return stkTop->lineNo; } int lineNo() const { return stkTop->lineNo; }
int columnNo() const { return stkTop->columnNo; } int columnNo() const { return stkTop->columnNo; }
bool etc() const { return etcetera; } bool etc() const { return etcetera; }

View File

@ -334,7 +334,7 @@ static void processQdocconfFile(const QString &fileName)
QStringList excludedDirsList; QStringList excludedDirsList;
QStringList excludedFilesList; QStringList excludedFilesList;
excludedDirsList = config.getCleanPathList(CONFIG_EXCLUDEDIRS); excludedDirsList = config.getCanonicalRelativePathList(CONFIG_EXCLUDEDIRS);
foreach (const QString &excludeDir, excludedDirsList) { foreach (const QString &excludeDir, excludedDirsList) {
QString p = QDir::fromNativeSeparators(excludeDir); QString p = QDir::fromNativeSeparators(excludeDir);
excludedDirs.insert(p); excludedDirs.insert(p);