From 30e495edfbdb8e3bbb1f8eb9677f676cee5b6565 Mon Sep 17 00:00:00 2001
From: Tobias Hunger <tobias.hunger@nokia.com>
Date: Thu, 2 Sep 2010 16:43:22 +0200
Subject: [PATCH] Improve MSVC parser

 * Properly handle additional information text without
   file information by appending it to the previous task.
---
 src/plugins/projectexplorer/msvcparser.cpp | 107 ++++++++++++++++-----
 src/plugins/projectexplorer/msvcparser.h   |  10 +-
 2 files changed, 92 insertions(+), 25 deletions(-)

diff --git a/src/plugins/projectexplorer/msvcparser.cpp b/src/plugins/projectexplorer/msvcparser.cpp
index 615d39a81de..83630748bf8 100644
--- a/src/plugins/projectexplorer/msvcparser.cpp
+++ b/src/plugins/projectexplorer/msvcparser.cpp
@@ -48,52 +48,82 @@ MsvcParser::MsvcParser()
     m_nonFileRegExp.setMinimal(true);
 }
 
+MsvcParser::~MsvcParser()
+{
+    sendQueuedTask();
+}
+
 void MsvcParser::stdOutput(const QString &line)
 {
-    QString lne = line.trimmed();
-    if (m_compileRegExp.indexIn(lne) > -1 && m_compileRegExp.numCaptures() == 5) {
-        Task task(Task::Unknown,
-                  m_compileRegExp.cap(4) /* description */,
-                  m_compileRegExp.cap(1) /* filename */,
-                  m_compileRegExp.cap(2).toInt() /* linenumber */,
-                  Constants::TASK_CATEGORY_COMPILE);
+    if (line.startsWith(QLatin1String("        ")) && m_additionalInfoRegExp.indexIn(line) < 0) {
+        if (m_lastTask.isNull())
+            return;
+
+        m_lastTask.description.append(QChar('\n'));
+        m_lastTask.description.append(line.mid(8));
+        // trim trailing spaces:
+        int i = 0;
+        for (i = m_lastTask.description.length() - 1; i >= 0; --i) {
+            if (!m_lastTask.description.at(i).isSpace())
+                break;
+        }
+        m_lastTask.description.truncate(i + 1);
+
+        if (m_lastTask.formats.isEmpty()) {
+            QTextLayout::FormatRange fr;
+            fr.start = m_lastTask.description.indexOf('\n') + 1;
+            fr.length = m_lastTask.description.length() - fr.start;
+            fr.format.setFontItalic(true);
+            m_lastTask.formats.append(fr);
+        } else {
+            m_lastTask.formats[0].length = m_lastTask.description.length() - m_lastTask.formats[0].start;
+        }
+        return;
+    }
+    sendQueuedTask();
+
+    if (m_compileRegExp.indexIn(line) > -1 && m_compileRegExp.numCaptures() == 5) {
+        m_lastTask = Task(Task::Unknown,
+                          m_compileRegExp.cap(4).trimmed() /* description */,
+                          m_compileRegExp.cap(1) /* filename */,
+                          m_compileRegExp.cap(2).toInt() /* linenumber */,
+                          Constants::TASK_CATEGORY_COMPILE);
         if (m_compileRegExp.cap(3) == QLatin1String(" warning"))
-            task.type = Task::Warning;
+            m_lastTask.type = Task::Warning;
         else if (m_compileRegExp.cap(3) == QLatin1String(" error"))
-            task.type = Task::Error;
+            m_lastTask.type = Task::Error;
         else
-            task.type = toType(m_compileRegExp.cap(5).toInt());
-        addTask(task);
+            m_lastTask.type = toType(m_compileRegExp.cap(5).toInt());
         return;
     }
     if (m_additionalInfoRegExp.indexIn(line) > -1 && m_additionalInfoRegExp.numCaptures() == 3) {
-        addTask(Task(Task::Unknown,
-                     m_additionalInfoRegExp.cap(3),
-                     m_additionalInfoRegExp.cap(1),
-                     m_additionalInfoRegExp.cap(2).toInt(),
-                     Constants::TASK_CATEGORY_COMPILE));
+        m_lastTask = Task(Task::Unknown,
+                          m_additionalInfoRegExp.cap(3).trimmed(),
+                          m_additionalInfoRegExp.cap(1),
+                          m_additionalInfoRegExp.cap(2).toInt(),
+                          Constants::TASK_CATEGORY_COMPILE);
         return;
     }
-    if (m_linkRegExp.indexIn(lne) > -1 && m_linkRegExp.numCaptures() == 3) {
+    if (m_linkRegExp.indexIn(line) > -1 && m_linkRegExp.numCaptures() == 3) {
         QString fileName = m_linkRegExp.cap(1);
         if (fileName.contains(QLatin1String("LINK"), Qt::CaseSensitive))
             fileName.clear();
 
-        emit addTask(Task(toType(m_linkRegExp.cap(2).toInt()) /* task type */,
-                          m_linkRegExp.cap(3) /* description */,
+        m_lastTask = Task(toType(m_linkRegExp.cap(2).toInt()) /* task type */,
+                          m_linkRegExp.cap(3).trimmed() /* description */,
                           fileName /* filename */,
                           -1 /* line number */,
-                          Constants::TASK_CATEGORY_COMPILE));
+                          Constants::TASK_CATEGORY_COMPILE);
         return;
     }
-    if (m_nonFileRegExp.indexIn(lne) > -1) {
+    if (m_nonFileRegExp.indexIn(line) > -1) {
         Task::TaskType type = Task::Unknown;
         if (m_nonFileRegExp.cap(2) == QLatin1String("warning"))
             type = Task::Warning;
         if (m_nonFileRegExp.cap(2) == QLatin1String("error"))
             type = Task::Error;
-        emit addTask(Task(type, m_nonFileRegExp.cap(3) /* description */,
-                          QString(), -1, Constants::TASK_CATEGORY_COMPILE));
+        m_lastTask = Task(type, m_nonFileRegExp.cap(3).trimmed() /* description */,
+                          QString(), -1, Constants::TASK_CATEGORY_COMPILE);
         return;
     }
     IOutputParser::stdOutput(line);
@@ -101,6 +131,8 @@ void MsvcParser::stdOutput(const QString &line)
 
 void MsvcParser::stdError(const QString &line)
 {
+    sendQueuedTask();
+
     if (m_nonFileRegExp.indexIn(line) > -1) {
         Task::TaskType type = Task::Unknown;
         if (m_nonFileRegExp.cap(2) == QLatin1String("warning"))
@@ -114,6 +146,15 @@ void MsvcParser::stdError(const QString &line)
     IOutputParser::stdError(line);
 }
 
+void MsvcParser::sendQueuedTask()
+{
+    if (m_lastTask.isNull())
+        return;
+
+    addTask(m_lastTask);
+    m_lastTask = Task();
+}
+
 Task::TaskType MsvcParser::toType(int number)
 {
     // This is unfortunately not true for all possible kinds of errors, but better
@@ -214,6 +255,26 @@ void ProjectExplorerPlugin::testMsvcOutputParsers_data()
                         QString(), -1,
                         QLatin1String(ProjectExplorer::Constants::TASK_CATEGORY_COMPILE)))
             << QString();
+    QTest::newRow("complex error")
+            << QString::fromLatin1("..\\untitled\\main.cpp(19) : error C2440: 'initializing' : cannot convert from 'int' to 'std::_Tree<_Traits>::iterator'\n"
+                                   "        with\n"
+                                   "        [\n"
+                                   "            _Traits=std::_Tmap_traits<int,double,std::less<int>,std::allocator<std::pair<const int,double>>,false>\n"
+                                   "        ]\n"
+                                   "        No constructor could take the source type, or constructor overload resolution was ambiguous")
+            << OutputParserTester::STDOUT
+            << QString() << QString()
+            << (QList<ProjectExplorer::Task>()
+                << Task(Task::Error,
+                        QLatin1String("C2440: 'initializing' : cannot convert from 'int' to 'std::_Tree<_Traits>::iterator'\n"
+                                      "with\n"
+                                      "[\n"
+                                      "    _Traits=std::_Tmap_traits<int,double,std::less<int>,std::allocator<std::pair<const int,double>>,false>\n"
+                                      "]\n"
+                                      "No constructor could take the source type, or constructor overload resolution was ambiguous"),
+                        QLatin1String("..\\untitled\\main.cpp"), 19,
+                        QLatin1String(ProjectExplorer::Constants::TASK_CATEGORY_COMPILE)))
+            << QString();
 }
 
 void ProjectExplorerPlugin::testMsvcOutputParsers()
diff --git a/src/plugins/projectexplorer/msvcparser.h b/src/plugins/projectexplorer/msvcparser.h
index 707cb3bb148..11c6c2b0bd7 100644
--- a/src/plugins/projectexplorer/msvcparser.h
+++ b/src/plugins/projectexplorer/msvcparser.h
@@ -44,16 +44,22 @@ class MsvcParser :  public ProjectExplorer::IOutputParser
 
 public:
     MsvcParser();
+    ~MsvcParser();
 
-    virtual void stdOutput(const QString &line);
-    virtual void stdError(const QString &line);
+    void stdOutput(const QString &line);
+    void stdError(const QString &line);
+    void flush();
 
 private:
+    void sendQueuedTask();
     Task::TaskType toType(int number);
+
     QRegExp m_compileRegExp;
     QRegExp m_additionalInfoRegExp;
     QRegExp m_linkRegExp;
     QRegExp m_nonFileRegExp;
+
+    Task m_lastTask;
 };
 
 } // namespace ProjectExplorer
-- 
GitLab