forked from qt-creator/qt-creator
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:
@@ -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
|
||||||
|
@@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user