From f723531f8fc255e733f65df99c2ac1da3c9c0743 Mon Sep 17 00:00:00 2001 From: Denis Shienkov Date: Tue, 15 Oct 2019 13:31:46 +0300 Subject: [PATCH] BareMetal: Handle details preceding it message in the KEIL parser We need to handle a multi-line error messages from the KEIL A51 assembler: http://www.keil.com/support/man/docs/a51/a51_er_nonfatalerror.htm This assembler produces an error messages in the form like: 00B0 114 ljmp usb_stub_isr ; (B0) GPIF operation complete. *** _____________________________________^ *** ERROR #A45 IN 114 (autovec_keil.a51, LINE 114): UNDEFINED SYMBOL 00B4 116 ljmp usb_stub_isr ; (B4) GPIF waveform. *** _____________________________________^ *** ERROR #A45 IN 116 (autovec_keil.a51, LINE 116): UNDEFINED SYMBOL where the details places before than a main message text. This patch handles this error messages, but with an one limitation in that a details should start with a four hexadecimal letters (in a common case it can not contains that letters at all). Change-Id: I0c9bf7ab72e1aef32498af5a1ef29c9221c185d5 Reviewed-by: Christian Kandeler --- src/plugins/baremetal/keilparser.cpp | 90 +++++++++++++++++++++++----- src/plugins/baremetal/keilparser.h | 3 +- 2 files changed, 76 insertions(+), 17 deletions(-) diff --git a/src/plugins/baremetal/keilparser.cpp b/src/plugins/baremetal/keilparser.cpp index b41a71c6f2c..ed74d690c08 100644 --- a/src/plugins/baremetal/keilparser.cpp +++ b/src/plugins/baremetal/keilparser.cpp @@ -70,20 +70,24 @@ void KeilParser::newTask(const Task &task) m_lines = 1; } -void KeilParser::amendDescription(const QString &desc) +void KeilParser::amendDescription() { - const int start = m_lastTask.description.count() + 1; - m_lastTask.description.append(QLatin1Char('\n')); - m_lastTask.description.append(desc); + while (!m_snippets.isEmpty()) { + const QString snippet = m_snippets.takeFirst(); - QTextLayout::FormatRange fr; - fr.start = start; - fr.length = m_lastTask.description.count() + 1; - fr.format.setFont(TextEditor::TextEditorSettings::fontSettings().font()); - fr.format.setFontStyleHint(QFont::Monospace); - m_lastTask.formats.append(fr); + const int start = m_lastTask.description.count() + 1; + m_lastTask.description.append('\n'); + m_lastTask.description.append(snippet); - ++m_lines; + QTextLayout::FormatRange fr; + fr.start = start; + fr.length = m_lastTask.description.count() + 1; + fr.format.setFont(TextEditor::TextEditorSettings::fontSettings().font()); + fr.format.setFontStyleHint(QFont::Monospace); + m_lastTask.formats.append(fr); + + ++m_lines; + } } // ARM compiler specific parsers. @@ -205,18 +209,34 @@ void KeilParser::stdError(const QString &line) return; if (lne.startsWith(QLatin1Char(' '))) { - amendDescription(lne); + m_snippets.push_back(lne); return; } doFlush(); } +static bool hasDetailsEntry(const QString &trimmedLine) +{ + const QRegularExpression re("^([0-9A-F]{4})"); + const QRegularExpressionMatch match = re.match(trimmedLine); + return match.hasMatch(); +} + +static bool hasDetailsPointer(const QString &trimmedLine) +{ + if (!trimmedLine.startsWith("*** ")) + return false; + if (!trimmedLine.endsWith('^')) + return false; + return trimmedLine.contains('_'); +} + void KeilParser::stdOutput(const QString &line) { IOutputParser::stdOutput(line); - const QString lne = rightTrimmed(line); + QString lne = rightTrimmed(line); // Check for MSC51 compiler specific patterns. const bool parsed = parseMcs51WarningOrErrorDetailsMessage1(lne) @@ -228,9 +248,27 @@ void KeilParser::stdOutput(const QString &line) return; } - if (lne.startsWith(QLatin1Char(' '))) { - amendDescription(lne); - return; + if (m_lastTask.isNull()) { + // Check for details, which are comes on a previous + // lines, before the message. + + // This code handles the details in a form like: + // 0000 24 ljmp usb_stub_isr ; (00) Setup data available. + // *** _____________________________________^ + // 003C 54 ljmp usb_stub_isr ; (3C) EP8 in/out. + // *** _____________________________________^ + if (hasDetailsEntry(lne) || hasDetailsPointer(lne)) { + lne.replace(0, 4, " "); + m_snippets.push_back(lne); + return; + } + } else { + // Check for details, which are comes on a next + // lines, after the message. + if (lne.startsWith(' ')) { + m_snippets.push_back(lne); + return; + } } doFlush(); @@ -241,6 +279,8 @@ void KeilParser::doFlush() if (m_lastTask.isNull()) return; + amendDescription(); + Task t = m_lastTask; m_lastTask.clear(); emit addTask(t, m_lines, 1); @@ -425,6 +465,24 @@ void BareMetalPlugin::testKeilOutputParsers_data() categoryCompile)) << QString(); + QTest::newRow("MCS51: Assembler details error") + << QString::fromLatin1("01AF Some detail\n" + "*** ___^\n" + "*** ERROR #A45 IN 28 (d:\\foo.a51, LINE 28): Some error") + << OutputParserTester::STDOUT + << QString::fromLatin1("01AF Some detail\n" + "*** ___^\n" + "*** ERROR #A45 IN 28 (d:\\foo.a51, LINE 28): Some error\n") + << QString() + << (Tasks() << Task(Task::Error, + QLatin1String("#A45: Some error\n" + " Some detail\n" + " ___^"), + Utils::FilePath::fromUserInput(QLatin1String("d:\\foo.a51")), + 28, + categoryCompile)) + << QString(); + // Compiler messages. QTest::newRow("MCS51: Compiler simple warning") << QString::fromLatin1("*** WARNING C123 IN LINE 13 OF c:\\foo.c: Some warning") diff --git a/src/plugins/baremetal/keilparser.h b/src/plugins/baremetal/keilparser.h index b837c786364..857e67599f2 100644 --- a/src/plugins/baremetal/keilparser.h +++ b/src/plugins/baremetal/keilparser.h @@ -43,7 +43,7 @@ public: private: void newTask(const ProjectExplorer::Task &task); - void amendDescription(const QString &desc); + void amendDescription(); // ARM compiler specific parsers. bool parseArmWarningOrErrorDetailsMessage(const QString &lne); @@ -61,6 +61,7 @@ private: ProjectExplorer::Task m_lastTask; int m_lines = 0; + QStringList m_snippets; }; } // namespace Internal