ProjectExplorer: Improve MSVC output parsing

- Recognize "note:" messages as continuations.
- Do not remove leading spaces from continuation messages, as that
  hurts readability.

Fixes: QTCREATORBUG-25321
Change-Id: Ia8eebb688296ad4829648bc66e8afcd0198cf2d4
Reviewed-by: Orgad Shaneh <orgads@gmail.com>
This commit is contained in:
Christian Kandeler
2021-02-12 15:15:15 +01:00
parent 032407a6fe
commit 63cd4c1b58
2 changed files with 58 additions and 34 deletions

View File

@@ -30,6 +30,8 @@
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <utils/fileutils.h> #include <utils/fileutils.h>
#include <numeric>
using namespace Utils; using namespace Utils;
// As of MSVC 2015: "foo.cpp(42) :" -> "foo.cpp(42):" // As of MSVC 2015: "foo.cpp(42) :" -> "foo.cpp(42):"
@@ -65,7 +67,7 @@ static QPair<FilePath, int> parseFileName(const QString &input)
using namespace ProjectExplorer; using namespace ProjectExplorer;
// nmake/jom messages. // nmake/jom messages.
static bool handleNmakeJomMessage(const QString &line, Task *task) static Task handleNmakeJomMessage(const QString &line)
{ {
int matchLength = 0; int matchLength = 0;
if (line.startsWith("Error:")) if (line.startsWith("Error:"))
@@ -74,10 +76,9 @@ static bool handleNmakeJomMessage(const QString &line, Task *task)
matchLength = 8; matchLength = 8;
if (!matchLength) if (!matchLength)
return false; return {};
*task = CompileTask(Task::Error, line.mid(matchLength).trimmed()); return CompileTask(Task::Error, line.mid(matchLength).trimmed());
return true;
} }
static Task::TaskType taskType(const QString &category) static Task::TaskType taskType(const QString &category)
@@ -113,7 +114,7 @@ OutputLineParser::Result MsvcParser::handleLine(const QString &line, OutputForma
if (m_lastTask.isNull()) if (m_lastTask.isNull())
return Status::NotHandled; return Status::NotHandled;
m_lastTask.details.append(rightTrimmed(line.mid(8))); m_lastTask.details.append(rightTrimmed(line));
++m_lines; ++m_lines;
return Status::InProgress; return Status::InProgress;
} }
@@ -121,7 +122,10 @@ OutputLineParser::Result MsvcParser::handleLine(const QString &line, OutputForma
const Result res = processCompileLine(line); const Result res = processCompileLine(line);
if (res.status != Status::NotHandled) if (res.status != Status::NotHandled)
return res; return res;
if (handleNmakeJomMessage(line, &m_lastTask)) { const Task t = handleNmakeJomMessage(line);
if (!t.isNull()) {
flush();
m_lastTask = t;
m_lines = 1; m_lines = 1;
return Status::InProgress; return Status::InProgress;
} }
@@ -145,7 +149,10 @@ OutputLineParser::Result MsvcParser::handleLine(const QString &line, OutputForma
if (res.status != Status::NotHandled) if (res.status != Status::NotHandled)
return res; return res;
// Jom outputs errors to stderr // Jom outputs errors to stderr
if (handleNmakeJomMessage(line, &m_lastTask)) { const Task t = handleNmakeJomMessage(line);
if (!t.isNull()) {
flush();
m_lastTask = t;
m_lines = 1; m_lines = 1;
return Status::InProgress; return Status::InProgress;
} }
@@ -154,20 +161,32 @@ OutputLineParser::Result MsvcParser::handleLine(const QString &line, OutputForma
MsvcParser::Result MsvcParser::processCompileLine(const QString &line) MsvcParser::Result MsvcParser::processCompileLine(const QString &line)
{ {
flush();
QRegularExpressionMatch match = m_compileRegExp.match(line); QRegularExpressionMatch match = m_compileRegExp.match(line);
if (match.hasMatch()) { if (match.hasMatch()) {
QPair<FilePath, int> position = parseFileName(match.captured(1)); QPair<FilePath, int> position = parseFileName(match.captured(1));
const FilePath filePath = absoluteFilePath(position.first); const FilePath filePath = absoluteFilePath(position.first);
m_lastTask = CompileTask(taskType(match.captured(2)),
match.captured(3) + match.captured(4).trimmed(), // description
filePath, position.second);
m_lines = 1;
LinkSpecs linkSpecs; LinkSpecs linkSpecs;
addLinkSpecForAbsoluteFilePath(linkSpecs, m_lastTask.file, m_lastTask.line, match, 1); if (!m_lastTask.isNull() && line.contains("note: ")) {
addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, position.second, match, 1);
const int offset = std::accumulate(m_lastTask.details.cbegin(),
m_lastTask.details.cend(), 0,
[](int total, const QString &line) { return total + line.length() + 1;});
for (LinkSpec &ls : linkSpecs)
ls.startPos += offset;
m_linkSpecs << linkSpecs;
m_lastTask.details.append(line);
++m_lines;
} else {
flush();
m_lastTask = CompileTask(taskType(match.captured(2)),
match.captured(3) + match.captured(4).trimmed(), // description
filePath, position.second);
m_lines = 1;
}
return {Status::InProgress, linkSpecs}; return {Status::InProgress, linkSpecs};
} }
flush();
return Status::NotHandled; return Status::NotHandled;
} }
@@ -176,9 +195,10 @@ void MsvcParser::flush()
if (m_lastTask.isNull()) if (m_lastTask.isNull())
return; return;
setDetailsFormat(m_lastTask); setDetailsFormat(m_lastTask, m_linkSpecs);
Task t = m_lastTask; Task t = m_lastTask;
m_lastTask.clear(); m_lastTask.clear();
m_linkSpecs.clear();
scheduleTask(t, m_lines, 1); scheduleTask(t, m_lines, 1);
} }
@@ -212,7 +232,10 @@ static inline bool isClangCodeMarker(const QString &trimmedLine)
OutputLineParser::Result ClangClParser::handleLine(const QString &line, OutputFormat type) OutputLineParser::Result ClangClParser::handleLine(const QString &line, OutputFormat type)
{ {
if (type == StdOutFormat) { if (type == StdOutFormat) {
if (handleNmakeJomMessage(line, &m_lastTask)) { const Task t = handleNmakeJomMessage(line);
if (!t.isNull()) {
flush();
m_lastTask = t;
m_linkedLines = 1; m_linkedLines = 1;
flush(); flush();
return Status::Done; return Status::Done;
@@ -221,7 +244,10 @@ OutputLineParser::Result ClangClParser::handleLine(const QString &line, OutputFo
} }
const QString lne = rightTrimmed(line); // Strip \n. const QString lne = rightTrimmed(line); // Strip \n.
if (handleNmakeJomMessage(lne, &m_lastTask)) { const Task t = handleNmakeJomMessage(lne);
if (!t.isNull()) {
flush();
m_lastTask = t;
m_linkedLines = 1; m_linkedLines = 1;
flush(); flush();
return Status::Done; return Status::Done;
@@ -412,11 +438,11 @@ void ProjectExplorerPlugin::testMsvcOutputParsers_data()
<< (Tasks() << (Tasks()
<< CompileTask(Task::Error, << CompileTask(Task::Error,
"C2440: 'initializing' : cannot convert from 'int' to 'std::_Tree<_Traits>::iterator'\n" "C2440: 'initializing' : cannot convert from 'int' to 'std::_Tree<_Traits>::iterator'\n"
"with\n" " with\n"
"[\n" " [\n"
" _Traits=std::_Tmap_traits<int,double,std::less<int>,std::allocator<std::pair<const int,double>>,false>\n" " _Traits=std::_Tmap_traits<int,double,std::less<int>,std::allocator<std::pair<const int,double>>,false>\n"
"]\n" " ]\n"
"No constructor could take the source type, or constructor overload resolution was ambiguous", " No constructor could take the source type, or constructor overload resolution was ambiguous",
FilePath::fromUserInput("..\\untitled\\main.cpp"), 19)) FilePath::fromUserInput("..\\untitled\\main.cpp"), 19))
<< ""; << "";
@@ -478,11 +504,11 @@ void ProjectExplorerPlugin::testMsvcOutputParsers_data()
FilePath::fromUserInput("c:\\Program Files (x86)\\Microsoft Visual Studio 10.0\\VC\\INCLUDE\\xutility"), 2212) FilePath::fromUserInput("c:\\Program Files (x86)\\Microsoft Visual Studio 10.0\\VC\\INCLUDE\\xutility"), 2212)
<< CompileTask(Task::Unknown, << CompileTask(Task::Unknown,
"see reference to function template instantiation '_OutIt std::copy<const unsigned char*,unsigned short*>(_InIt,_InIt,_OutIt)' being compiled\n" "see reference to function template instantiation '_OutIt std::copy<const unsigned char*,unsigned short*>(_InIt,_InIt,_OutIt)' being compiled\n"
"with\n" " with\n"
"[\n" " [\n"
" _OutIt=unsigned short *,\n" " _OutIt=unsigned short *,\n"
" _InIt=const unsigned char *\n" " _InIt=const unsigned char *\n"
"]", " ]",
FilePath::fromUserInput("symbolgroupvalue.cpp"), 2314)) FilePath::fromUserInput("symbolgroupvalue.cpp"), 2314))
<< ""; << "";
@@ -516,13 +542,10 @@ void ProjectExplorerPlugin::testMsvcOutputParsers_data()
"main.cpp(6): note: see declaration of 'func'" "main.cpp(6): note: see declaration of 'func'"
<< OutputParserTester::STDOUT << OutputParserTester::STDOUT
<< "" << "" << "" << ""
<< (Tasks() << Tasks{CompileTask(Task::Error,
<< CompileTask(Task::Error, "C2733: 'func': second C linkage of overloaded function not allowed\n"
"C2733: 'func': second C linkage of overloaded function not allowed", "main.cpp(6): note: see declaration of 'func'",
FilePath::fromUserInput("main.cpp"), 7) FilePath::fromUserInput("main.cpp"), 7)}
<< CompileTask(Task::Unknown,
"see declaration of 'func'",
FilePath::fromUserInput("main.cpp"), 6))
<< ""; << "";
QTest::newRow("cyrillic warning") // QTCREATORBUG-20297 QTest::newRow("cyrillic warning") // QTCREATORBUG-20297

View File

@@ -52,6 +52,7 @@ private:
QRegularExpression m_additionalInfoRegExp; QRegularExpression m_additionalInfoRegExp;
Task m_lastTask; Task m_lastTask;
LinkSpecs m_linkSpecs;
int m_lines = 0; int m_lines = 0;
}; };