From 7688754b379e0f1d558e815d6ea2e65b14396db6 Mon Sep 17 00:00:00 2001
From: Sergey Shambir <sergey.shambir.auto@gmail.com>
Date: Mon, 29 Apr 2013 02:31:43 +0400
Subject: [PATCH] Autotools: added parsing defines and C/C++ flags from
 Makefile

Change-Id: I7443ba3ada97e4abac5560bb5399ec96e065acee
Reviewed-by: hjk <hjk121@nokiamail.com>
---
 .../autotoolsproject.cpp                      |   8 +-
 .../makefileparser.cpp                        | 102 ++++++++++++++++--
 .../autotoolsprojectmanager/makefileparser.h  |  49 +++++++++
 .../makefileparserthread.cpp                  |  21 ++++
 .../makefileparserthread.h                    |  21 ++++
 5 files changed, 188 insertions(+), 13 deletions(-)

diff --git a/src/plugins/autotoolsprojectmanager/autotoolsproject.cpp b/src/plugins/autotoolsprojectmanager/autotoolsproject.cpp
index 25ea5b47a6b..b9f69f887f6 100644
--- a/src/plugins/autotoolsprojectmanager/autotoolsproject.cpp
+++ b/src/plugins/autotoolsprojectmanager/autotoolsproject.cpp
@@ -411,7 +411,10 @@ void AutotoolsProject::updateCppCodeModel()
     if (!modelManager)
         return;
 
-    const QStringList cxxflags; // FIXME: Autotools should be able to do better than this!
+    const QStringList cflags = m_makefileParserThread->cflags();
+    QStringList cxxflags = m_makefileParserThread->cxxflags();
+    if (cxxflags.isEmpty())
+        cxxflags = cflags;
 
     CppTools::CppModelManagerInterface::ProjectInfo pinfo = modelManager->projectInfo(this);
     pinfo.clearProjectParts();
@@ -420,7 +423,7 @@ void AutotoolsProject::updateCppCodeModel()
     if (activeTarget()) {
         ProjectExplorer::Kit *k = activeTarget()->kit();
         ToolChain *tc = ProjectExplorer::ToolChainKitInformation::toolChain(k);
-        part->evaluateToolchain(tc, cxxflags, cxxflags,
+        part->evaluateToolchain(tc, cxxflags, cflags,
                                 SysRootKitInformation::sysRoot(k));
     }
 
@@ -428,6 +431,7 @@ void AutotoolsProject::updateCppCodeModel()
         part->files << CppTools::ProjectFile(file, CppTools::ProjectFile::CXXSource);
 
     part->includePaths += m_makefileParserThread->includePaths();
+    part->defines += m_makefileParserThread->defines();
     pinfo.appendProjectPart(part);
 
     modelManager->updateProjectInfo(pinfo);
diff --git a/src/plugins/autotoolsprojectmanager/makefileparser.cpp b/src/plugins/autotoolsprojectmanager/makefileparser.cpp
index 760dcb9d903..f1cbae544e0 100644
--- a/src/plugins/autotoolsprojectmanager/makefileparser.cpp
+++ b/src/plugins/autotoolsprojectmanager/makefileparser.cpp
@@ -123,6 +123,21 @@ QStringList MakefileParser::includePaths() const
     return m_includePaths;
 }
 
+QByteArray MakefileParser::defines() const
+{
+    return m_defines;
+}
+
+QStringList MakefileParser::cflags() const
+{
+    return m_cflags;
+}
+
+QStringList MakefileParser::cxxflags() const
+{
+    return m_cxxflags;
+}
+
 void MakefileParser::cancel()
 {
     QMutexLocker locker(&m_mutex);
@@ -424,6 +439,59 @@ QString MakefileParser::parseIdentifierBeforeAssign(const QString &line)
     return (end < line.size() && line[end] == QLatin1Char('=')) ? ret : QString();
 }
 
+QStringList MakefileParser::parseTermsAfterAssign(const QString &line)
+{
+    int assignPos = line.indexOf(QLatin1Char('=')) + 1;
+    if (assignPos >= line.size())
+        return QStringList();
+    return line.mid(assignPos).split(QLatin1Char(' '), QString::SkipEmptyParts);
+}
+
+bool MakefileParser::maybeParseDefine(const QString &term)
+{
+    if (term.startsWith(QLatin1String("-D"))) {
+        QString def = term.mid(2); // remove the "-D"
+        QByteArray data = def.toUtf8();
+        int pos = data.indexOf('=');
+        if (pos >= 0)
+            data[pos] = ' ';
+        m_defines += (QByteArray("#define ") + data + '\n');
+        return true;
+    }
+    return false;
+}
+
+bool MakefileParser::maybeParseInclude(const QString &term, const QString &dirName)
+{
+    if (term.startsWith(QLatin1String("-I"))) {
+        QString includePath = term.mid(2); // remove the "-I"
+        if (includePath == QLatin1String("."))
+            includePath = dirName;
+        if (!includePath.isEmpty())
+            m_includePaths += includePath;
+        return true;
+    }
+    return false;
+}
+
+bool MakefileParser::maybeParseCFlag(const QString &term)
+{
+    if (term.startsWith(QLatin1Char('-'))) {
+        m_cflags += term;
+        return true;
+    }
+    return false;
+}
+
+bool MakefileParser::maybeParseCXXFlag(const QString &term)
+{
+    if (term.startsWith(QLatin1Char('-'))) {
+        m_cxxflags += term;
+        return true;
+    }
+    return false;
+}
+
 void MakefileParser::addAllSources()
 {
     QStringList extensions;
@@ -446,25 +514,37 @@ void MakefileParser::parseIncludePaths()
     if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
         return;
 
-    // TODO: The parsing is done very poor. Comments are ignored and targets
-    // are ignored too. Whether it is worth to improve this, depends on whether
+    // TODO: Targets are ignored at this moment.
+    // Whether it is worth to improve this, depends on whether
     // we want to parse the generated Makefile at all or whether we want to
     // improve the Makefile.am parsing to be aware of variables.
     QTextStream textStream(&file);
     QString line;
     do {
         line = textStream.readLine();
-        QStringList terms = line.split(QLatin1Char(' '), QString::SkipEmptyParts);
-        foreach (const QString &term, terms) {
-            if (term.startsWith(QLatin1String("-I"))) {
-                QString includePath = term.right(term.length() - 2); // remove the "-I"
-                if (includePath == QLatin1String("."))
-                    includePath = dirName;
-                if (!includePath.isEmpty())
-                    m_includePaths += includePath;
-            }
+        const QString varName = parseIdentifierBeforeAssign(line);
+        if (varName.isEmpty())
+            continue;
+
+        if (varName == QLatin1String("DEFS")) {
+            foreach (const QString &term, parseTermsAfterAssign(line))
+                maybeParseDefine(term);
+        } else if (varName.endsWith(QLatin1String("INCLUDES"))) {
+            foreach (const QString &term, parseTermsAfterAssign(line))
+                maybeParseInclude(term, dirName);
+        } else if (varName.endsWith(QLatin1String("CFLAGS"))) {
+            foreach (const QString &term, parseTermsAfterAssign(line))
+                maybeParseDefine(term) || maybeParseInclude(term, dirName)
+                        || maybeParseCFlag(term);
+        } else if (varName.endsWith(QLatin1String("CPPFLAGS"))
+                   || varName.endsWith(QLatin1String("CXXFLAGS"))) {
+            foreach (const QString &term, parseTermsAfterAssign(line))
+                maybeParseDefine(term) || maybeParseInclude(term, dirName)
+                        || maybeParseCXXFlag(term);
         }
     } while (!line.isNull());
 
     m_includePaths.removeDuplicates();
+    m_cflags.removeDuplicates();
+    m_cxxflags.removeDuplicates();
 }
diff --git a/src/plugins/autotoolsprojectmanager/makefileparser.h b/src/plugins/autotoolsprojectmanager/makefileparser.h
index c62ac2c6c39..9638cebba7c 100644
--- a/src/plugins/autotoolsprojectmanager/makefileparser.h
+++ b/src/plugins/autotoolsprojectmanager/makefileparser.h
@@ -96,6 +96,25 @@ public:
      */
     QStringList includePaths() const;
 
+    /**
+     * @return Concatenated normalized defines, just like in code:
+     * @code
+     * #define X12_DEPRECATED __attribute__((deprecated))
+     * #define X12_HAS_DEPRECATED
+     * @endcode
+     */
+    QByteArray defines() const;
+
+    /**
+     * @return List of compiler flags for C.
+     */
+    QStringList cflags() const;
+
+    /**
+     * @return List of compiler flags for C++.
+     */
+    QStringList cxxflags() const;
+
     /**
      * Cancels the parsing. Calling this method only makes sense, if the
      * parser runs in a different thread than the caller of this method.
@@ -211,6 +230,33 @@ private:
      */
     static QString parseIdentifierBeforeAssign(const QString &line);
 
+    /**
+     * Parses list of space-separated terms after "="
+     */
+    static QStringList parseTermsAfterAssign(const QString &line);
+
+    /**
+     * If term is compiler flag -D<macro>, adds macro to defines and returns true.
+     */
+    bool maybeParseDefine(const QString &term);
+
+    /**
+     * If term is compiler flag -I<path>, adds path to includes and returns true.
+     * @param term Term itself
+     * @param dirName Directory where Makefile placed
+     */
+    bool maybeParseInclude(const QString &term, const QString &dirName);
+
+    /**
+     * If term is compiler flag -<flag>, adds it to cflags and returns true.
+     */
+    bool maybeParseCFlag(const QString &term);
+
+    /**
+     * If term is compiler flag -<flag>, adds it to cxxflags and returns true.
+     */
+    bool maybeParseCXXFlag(const QString &term);
+
 private:
     bool m_success;             ///< Return value for MakefileParser::parse().
 
@@ -222,6 +268,9 @@ private:
     QStringList m_sources;      ///< Return value for MakefileParser::sources()
     QStringList m_makefiles;    ///< Return value for MakefileParser::makefiles()
     QStringList m_includePaths; ///< Return value for MakefileParser::includePaths()
+    QByteArray m_defines;       ///< Return value for MakefileParser::defines()
+    QStringList m_cflags;       ///< Return value for MakefileParser::cflags()
+    QStringList m_cxxflags;       ///< Return value for MakefileParser::cxxflags()
 
     QString m_line;             ///< Current line of the makefile
     QTextStream m_textStream;   ///< Textstream that represents the makefile
diff --git a/src/plugins/autotoolsprojectmanager/makefileparserthread.cpp b/src/plugins/autotoolsprojectmanager/makefileparserthread.cpp
index c19f91f53a7..a6d45870ff8 100644
--- a/src/plugins/autotoolsprojectmanager/makefileparserthread.cpp
+++ b/src/plugins/autotoolsprojectmanager/makefileparserthread.cpp
@@ -72,6 +72,24 @@ QStringList MakefileParserThread::includePaths() const
     return m_includePaths;
 }
 
+QByteArray MakefileParserThread::defines() const
+{
+    QMutexLocker locker(&m_mutex);
+    return m_defines;
+}
+
+QStringList MakefileParserThread::cflags() const
+{
+    QMutexLocker locker(&m_mutex);
+    return m_cflags;
+}
+
+QStringList MakefileParserThread::cxxflags() const
+{
+    QMutexLocker locker(&m_mutex);
+    return m_cxxflags;
+}
+
 bool MakefileParserThread::hasError() const
 {
     QMutexLocker locker(&m_mutex);
@@ -102,4 +120,7 @@ void MakefileParserThread::run()
     m_sources = m_parser.sources();
     m_makefiles = m_parser.makefiles();
     m_includePaths = m_parser.includePaths();
+    m_defines = m_parser.defines();
+    m_cflags = m_parser.cflags();
+    m_cxxflags = m_parser.cxxflags();
 }
diff --git a/src/plugins/autotoolsprojectmanager/makefileparserthread.h b/src/plugins/autotoolsprojectmanager/makefileparserthread.h
index 05eff169efb..c119de7c550 100644
--- a/src/plugins/autotoolsprojectmanager/makefileparserthread.h
+++ b/src/plugins/autotoolsprojectmanager/makefileparserthread.h
@@ -86,6 +86,24 @@ public:
      */
     QStringList includePaths() const;
 
+    /**
+     * @return Concatenated defines. Should be invoked, after the signal
+     *         finished() has been emitted.
+     */
+    QByteArray defines() const;
+
+    /**
+     * @return List of compiler flags for C. Should be invoked, after the signal
+     *         finished() has been emitted.
+     */
+    QStringList cflags() const;
+
+    /**
+     * @return List of compiler flags for C++. Should be invoked, after the
+     *         signal finished() has been emitted.
+     */
+    QStringList cxxflags() const;
+
     /**
      * @return True, if an error occurred during the parsing. Should be invoked,
      *         after the signal finished() has been emitted.
@@ -122,6 +140,9 @@ private:
     QStringList m_sources;      ///< Return value for MakefileParserThread::sources()
     QStringList m_makefiles;    ///< Return value for MakefileParserThread::makefiles()
     QStringList m_includePaths; ///< Return value for MakefileParserThread::includePaths()
+    QByteArray m_defines;       ///< Return value for MakefileParserThread::defines()
+    QStringList m_cflags;       ///< Return value for MakefileParserThread::cflags()
+    QStringList m_cxxflags;     ///< Return value for MakefileParserThread::cxxflags()
 };
 
 } // namespace Internal
-- 
GitLab