From 5b205769a6f898093fd9f04d33856e5686414303 Mon Sep 17 00:00:00 2001
From: Friedemann Kleint <Friedemann.Kleint@qt.io>
Date: Fri, 26 Jan 2018 11:12:47 +0100
Subject: [PATCH] qdoc: Add a logging category

Remove the debug functionality from the Generator class and add
a logging category instead. Add some debug statements outputting
the command line arguments and clang arguments.

This makes it possible to obtain logging output by setting for
example QT_LOGGING_RULES=qt.qdoc.debug=true .

Task-number: PYSIDE-363
Change-Id: I3ecfe548e14aa3e2d03f19d07fc61a2647b75111
Reviewed-by: Martin Smith <martin.smith@qt.io>
---
 src/qdoc/clangcodeparser.cpp | 29 +++++++++++++++++++++++++-
 src/qdoc/generator.cpp       | 25 +++++++++++-----------
 src/qdoc/generator.h         |  4 +---
 src/qdoc/loggingcategory.h   | 40 ++++++++++++++++++++++++++++++++++++
 src/qdoc/main.cpp            | 35 +++++++++++++++++--------------
 src/qdoc/qdoc.pro            |  1 +
 6 files changed, 103 insertions(+), 31 deletions(-)
 create mode 100644 src/qdoc/loggingcategory.h

diff --git a/src/qdoc/clangcodeparser.cpp b/src/qdoc/clangcodeparser.cpp
index 3c5d615c2..ea4ffb18e 100644
--- a/src/qdoc/clangcodeparser.cpp
+++ b/src/qdoc/clangcodeparser.cpp
@@ -47,6 +47,7 @@
 #include "codechunk.h"
 #include "config.h"
 #include "clangcodeparser.h"
+#include "loggingcategory.h"
 #include "qdocdatabase.h"
 #include <qdebug.h>
 #include <qscopedvaluerollback.h>
@@ -61,6 +62,25 @@ QT_BEGIN_NAMESPACE
 static CXTranslationUnit_Flags flags_ = (CXTranslationUnit_Flags)0;
 static CXIndex index_ = 0;
 
+#ifndef QT_NO_DEBUG_STREAM
+template <class T>
+static QDebug operator<<(QDebug debug, const std::vector<T> &v)
+{
+    QDebugStateSaver saver(debug);
+    debug.noquote();
+    debug.nospace();
+    const size_t size = v.size();
+    debug << "std::vector<>[" << size << "](";
+    for (size_t i = 0; i < size; ++i) {
+        if (i)
+            debug << ", ";
+        debug << v[i];
+    }
+    debug << ')';
+    return debug;
+}
+#endif // !QT_NO_DEBUG_STREAM
+
 /*!
    Call clang_visitChildren on the given cursor with the lambda as a callback
    T can be any functor that is callable with a CXCursor parameter and returns a CXChildVisitResult
@@ -975,6 +995,8 @@ void ClangCodeParser::initializeParser(const Config &config)
             }
         }
     }
+    qCDebug(lcQdoc).nospace() << __FUNCTION__ << " Clang v" << CINDEX_VERSION_MAJOR
+        << '.' << CINDEX_VERSION_MINOR;
 }
 
 /*!
@@ -1170,6 +1192,8 @@ void ClangCodeParser::buildPCH()
                     tmpHeader.toLatin1().data(),
                     args_.data(), static_cast<int>(args_.size()), nullptr, 0,
                     flags_ | CXTranslationUnit_ForSerialization, &tu);
+                qCDebug(lcQdoc) << __FUNCTION__ << "clang_parseTranslationUnit2("
+                    << tmpHeader <<  args_ << ") returns" << err;
                 if (!err && tu) {
                     pchName_ = pchFileDir_->path().toUtf8() + "/" + module + ".pch";
                     auto error = clang_saveTranslationUnit(tu, pchName_.constData(), clang_defaultSaveOptions(tu));
@@ -1238,6 +1262,8 @@ void ClangCodeParser::parseSourceFile(const Location& /*location*/, const QStrin
     CXTranslationUnit tu;
     CXErrorCode err = clang_parseTranslationUnit2(index_, filePath.toLocal8Bit(), args_.data(),
                                                   static_cast<int>(args_.size()), nullptr, 0, flags_, &tu);
+    qCDebug(lcQdoc) << __FUNCTION__ << "clang_parseTranslationUnit2("
+        << filePath <<  args_ << ") returns" << err;
     if (err || !tu) {
         qWarning() << "(qdoc) Could not parse source file" << filePath << " error code:" << err;
         clang_disposeIndex(index_);
@@ -1397,7 +1423,8 @@ Node* ClangCodeParser::parseFnArg(const Location& location, const QString& fnArg
                                                   1,
                                                   flags,
                                                   &tu);
-
+    qCDebug(lcQdoc) << __FUNCTION__ << "clang_parseTranslationUnit2("
+        << dummyFileName <<  args_ << ") returns" << err;
     if (err || !tu) {
         location.error(ClangCodeParser::tr("clang could not parse \\fn %1").arg(fnArg));
         clang_disposeTranslationUnit(tu);
diff --git a/src/qdoc/generator.cpp b/src/qdoc/generator.cpp
index 8d088b13f..760488bea 100644
--- a/src/qdoc/generator.cpp
+++ b/src/qdoc/generator.cpp
@@ -36,6 +36,7 @@
 #include "doc.h"
 #include "editdistance.h"
 #include "generator.h"
+#include "loggingcategory.h"
 #include "openedlist.h"
 #include "quoter.h"
 #include "separator.h"
@@ -83,7 +84,6 @@ QString Generator::sinceTitles[] =
 };
 QStringList Generator::styleDirs;
 QStringList Generator::styleFiles;
-bool Generator::debugging_ = false;
 bool Generator::noLinkErrors_ = false;
 bool Generator::autolinkErrors_ = false;
 bool Generator::redirectDocumentationToDevNull_ = false;
@@ -99,25 +99,26 @@ static QLatin1String gt("&gt;");
 static QLatin1String lt("&lt;");
 static QLatin1String quot("&quot;");
 
+static inline void setDebugEnabled(bool v)
+{
+    const_cast<QLoggingCategory &>(lcQdoc()).setEnabled(QtDebugMsg, v);
+}
+
 void Generator::startDebugging(const QString& message)
 {
-    debugging_ = true;
-    qDebug() << "START DEBUGGING:" << message;
+    setDebugEnabled(true);
+    qCDebug(lcQdoc, "START DEBUGGING: %s", qPrintable(message));
 }
 
 void Generator::stopDebugging(const QString& message)
 {
-    debugging_ = false;
-    qDebug() << "STOP DEBUGGING:" << message;
+    qCDebug(lcQdoc, "STOP DEBUGGING: %s", qPrintable(message));
+    setDebugEnabled(false);
 }
 
-/*!
-  Prints \a message as an aid to debugging the release version.
- */
-void Generator::debug(const QString& message)
+bool Generator::debugging()
 {
-    if (debugging())
-        qDebug() << "  DEBUG:" << message;
+    return lcQdoc().isEnabled(QtDebugMsg);
 }
 
 /*!
@@ -306,7 +307,7 @@ void Generator::beginSubPage(const Node* node, const QString& fileName)
         node->location().error(tr("Output file already exists; overwriting %1").arg(outFile->fileName()));
     if (!outFile->open(QFile::WriteOnly))
         node->location().fatal(tr("Cannot open output file '%1'").arg(outFile->fileName()));
-    Generator::debug("Writing: " + path);
+    qCDebug(lcQdoc, "Writing: %s", qPrintable(path));
     outFileNames_ << fileName;
     QTextStream* out = new QTextStream(outFile);
 
diff --git a/src/qdoc/generator.h b/src/qdoc/generator.h
index ac8fbbbcf..0bcabc90f 100644
--- a/src/qdoc/generator.h
+++ b/src/qdoc/generator.h
@@ -81,10 +81,9 @@ public:
     static const QStringList& outputFileNames() { return outFileNames_; }
     static void writeOutFileNames();
     static void augmentImageDirs(QSet<QString>& moreImageDirs);
-    static void debug(const QString& message);
     static void startDebugging(const QString& message);
     static void stopDebugging(const QString& message);
-    static bool debugging() { return debugging_; }
+    static bool debugging();
     static bool noLinkErrors() { return noLinkErrors_; }
     static bool autolinkErrors() { return autolinkErrors_; }
     static void setQDocPass(QDocPass t) { qdocPass_ = t; }
@@ -221,7 +220,6 @@ private:
     static QStringList scriptFiles;
     static QStringList styleDirs;
     static QStringList styleFiles;
-    static bool debugging_;
     static bool noLinkErrors_;
     static bool autolinkErrors_;
     static bool redirectDocumentationToDevNull_;
diff --git a/src/qdoc/loggingcategory.h b/src/qdoc/loggingcategory.h
new file mode 100644
index 000000000..812ef7af8
--- /dev/null
+++ b/src/qdoc/loggingcategory.h
@@ -0,0 +1,40 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef LOGGINGCATEGORY_H
+#define LOGGINGCATEGORY_H
+
+#include <QtCore/qloggingcategory.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(lcQdoc)
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qdoc/main.cpp b/src/qdoc/main.cpp
index 4dd307541..172261281 100644
--- a/src/qdoc/main.cpp
+++ b/src/qdoc/main.cpp
@@ -46,6 +46,7 @@
 #include "cppcodeparser.h"
 #include "doc.h"
 #include "htmlgenerator.h"
+#include "loggingcategory.h"
 #include "webxmlgenerator.h"
 #include "location.h"
 #include "plaincodemarker.h"
@@ -70,6 +71,8 @@
 
 QT_BEGIN_NAMESPACE
 
+Q_LOGGING_CATEGORY(lcQdoc, "qt.qdoc")
+
 bool creationTimeBefore(const QFileInfo &fi1, const QFileInfo &fi2)
 {
     return fi1.lastModified() < fi2.lastModified();
@@ -363,9 +366,9 @@ static void processQdocconfFile(const QString &fileName)
     qdb->clearSearchOrder();
     if (!Generator::singleExec()) {
         if (!Generator::preparing()) {
-            Generator::debug("  loading index files");
+            qCDebug(lcQdoc, "  loading index files");
             loadIndexFiles(config, outputFormats);
-            Generator::debug("  done loading index files");
+            qCDebug(lcQdoc, "  done loading index files");
         }
         qdb->newPrimaryTree(project);
     }
@@ -392,7 +395,7 @@ static void processQdocconfFile(const QString &fileName)
     QSet<QString> excludedDirs = QSet<QString>::fromList(config.getCanonicalPathList(CONFIG_EXCLUDEDIRS));
     QSet<QString> excludedFiles = QSet<QString>::fromList(config.getCanonicalPathList(CONFIG_EXCLUDEFILES));
 
-    Generator::debug("Adding doc/image dirs found in exampledirs to imagedirs");
+    qCDebug(lcQdoc, "Adding doc/image dirs found in exampledirs to imagedirs");
     QSet<QString> exampleImageDirs;
     QStringList exampleImageList = config.getExampleImageFiles(excludedDirs, excludedFiles);
     for (int i = 0; i < exampleImageList.size(); ++i) {
@@ -409,7 +412,7 @@ static void processQdocconfFile(const QString &fileName)
         QStringList headerList;
         QStringList sourceList;
 
-        Generator::debug("Reading headerdirs");
+        qCDebug(lcQdoc, "Reading headerdirs");
         headerList = config.getAllFiles(CONFIG_HEADERS,CONFIG_HEADERDIRS,excludedDirs,excludedFiles);
         QMap<QString,QString> headers;
         QMultiMap<QString,QString> headerFileNames;
@@ -423,7 +426,7 @@ static void processQdocconfFile(const QString &fileName)
             headerFileNames.insert(t,t);
         }
 
-        Generator::debug("Reading sourcedirs");
+        qCDebug(lcQdoc, "Reading sourcedirs");
         sourceList = config.getAllFiles(CONFIG_SOURCES,CONFIG_SOURCEDIRS,excludedDirs,excludedFiles);
         QMap<QString,QString> sources;
         QMultiMap<QString,QString> sourceFileNames;
@@ -440,7 +443,7 @@ static void processQdocconfFile(const QString &fileName)
           Find all the qdoc files in the example dirs, and add
           them to the source files to be parsed.
         */
-        Generator::debug("Reading exampledirs");
+        qCDebug(lcQdoc, "Reading exampledirs");
         QStringList exampleQdocList = config.getExampleQdocFiles(excludedDirs, excludedFiles);
         for (int i=0; i<exampleQdocList.size(); ++i) {
             if (!sources.contains(exampleQdocList[i])) {
@@ -454,14 +457,14 @@ static void processQdocconfFile(const QString &fileName)
           to the big tree.
         */
 
-        Generator::debug("Parsing header files");
+        qCDebug(lcQdoc, "Parsing header files");
         int parsed = 0;
         QMap<QString,QString>::ConstIterator h = headers.constBegin();
         while (h != headers.constEnd()) {
             CodeParser *codeParser = CodeParser::parserForHeaderFile(h.key());
             if (codeParser) {
                 ++parsed;
-                Generator::debug(QString("Parsing " + h.key()));
+                qCDebug(lcQdoc, "Parsing %s", qPrintable(h.key()));
                 codeParser->parseHeaderFile(config.location(), h.key());
             }
             ++h;
@@ -476,25 +479,25 @@ static void processQdocconfFile(const QString &fileName)
           add it to the big tree.
         */
         parsed = 0;
-        Generator::debug("Parsing source files");
+        qCDebug(lcQdoc, "Parsing source files");
         QMap<QString,QString>::ConstIterator s = sources.constBegin();
         while (s != sources.constEnd()) {
             CodeParser *codeParser = CodeParser::parserForSourceFile(s.key());
             if (codeParser) {
                 ++parsed;
-                Generator::debug(QString("Parsing " + s.key()));
+                qCDebug(lcQdoc, "Parsing %s", qPrintable(s.key()));
                 codeParser->parseSourceFile(config.location(), s.key());
             }
             ++s;
         }
-        Generator::debug(QString("Parsing done."));
+        qCDebug(lcQdoc, "Parsing done.");
 
         /*
           Now the primary tree has been built from all the header and
           source files. Resolve all the class names, function names,
           targets, URLs, links, and other stuff that needs resolving.
         */
-        Generator::debug("Resolving stuff prior to generating docs");
+        qCDebug(lcQdoc, "Resolving stuff prior to generating docs");
         qdb->resolveIssues();
     }
     else {
@@ -508,7 +511,7 @@ static void processQdocconfFile(const QString &fileName)
       format can be requested. The tree is traversed for each
       one.
      */
-    Generator::debug("Generating docs");
+    qCDebug(lcQdoc, "Generating docs");
     QSet<QString>::ConstIterator of = outputFormats.constBegin();
     while (of != outputFormats.constEnd()) {
         Generator* generator = Generator::generatorForFormat(*of);
@@ -525,7 +528,7 @@ static void processQdocconfFile(const QString &fileName)
 #endif
     qdb->clearLinkCounts();
 
-    Generator::debug("Terminating qdoc classes");
+    qCDebug(lcQdoc, "Terminating qdoc classes");
     if (Generator::debugging())
         Generator::stopDebugging(project);
 
@@ -538,7 +541,7 @@ static void processQdocconfFile(const QString &fileName)
     Location::terminate();
     QDir::setCurrent(prevCurrentDir);
 
-    Generator::debug("qdoc classes terminated");
+    qCDebug(lcQdoc, "qdoc classes terminated");
 }
 
 class QDocCommandLineParser : public QCommandLineParser
@@ -708,6 +711,8 @@ void QDocCommandLineParser::process(const QCoreApplication &app)
     autolinkErrors = isSet(autoLinkErrorsOption);
     if (isSet(debugOption))
         Generator::startDebugging(QString("command line"));
+    qCDebug(lcQdoc).noquote() << "Arguments :" << QCoreApplication::arguments();
+
     if (isSet(prepareOption))
         Generator::setQDocPass(Generator::Prepare);
     if (isSet(generateOption))
diff --git a/src/qdoc/qdoc.pro b/src/qdoc/qdoc.pro
index 5364ed0ef..30de9df08 100644
--- a/src/qdoc/qdoc.pro
+++ b/src/qdoc/qdoc.pro
@@ -44,6 +44,7 @@ HEADERS += atom.h \
            helpprojectwriter.h \
            htmlgenerator.h \
            location.h \
+           loggingcategory.h \
            node.h \
            openedlist.h \
            plaincodemarker.h \
-- 
GitLab