// Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "linuxiccparser.h" #include "ldparser.h" #include "lldparser.h" #include #ifdef WITH_TESTS #include "outputparser_test.h" #include #endif using namespace Utils; namespace ProjectExplorer::Internal { LinuxIccParser::LinuxIccParser() { setObjectName(QLatin1String("LinuxIccParser")); setOrigin("ICC compiler"); // main.cpp(53): error #308: function \"AClass::privatefunc\" (declared at line 4 of \"main.h\") is inaccessible m_firstLine.setPattern(QLatin1String("^([^\\(\\)]+?)" // filename (cap 1) "\\((\\d+?)\\):" // line number including : (cap 2) " ((error|warning)( #\\d+?)?: )?" // optional type (cap 4) and optional error number // TODO really optional ? "(.*?)$")); // description (cap 6) QTC_CHECK(m_firstLine.isValid()); // Note pattern also matches caret lines m_continuationLines.setPattern(QLatin1String("^\\s+" // At least one whitespace "(.*)$"));// description QTC_CHECK(m_continuationLines.isValid()); m_caretLine.setPattern(QLatin1String("^\\s*?" // Whitespaces "\\^" // a caret "\\s*?$")); // and again whitespaces QTC_CHECK(m_caretLine.isValid()); // ".pch/Qt5Core.pchi.cpp": creating precompiled header file ".pch/Qt5Core.pchi" // "animation/qabstractanimation.cpp": using precompiled header file ".pch/Qt5Core.pchi" m_pchInfoLine.setPattern(QLatin1String("^\".*?\": (creating|using) precompiled header file \".*?\"$")); QTC_CHECK(m_pchInfoLine.isValid()); } OutputLineParser::Result LinuxIccParser::handleLine(const QString &line, OutputFormat type) { if (type != Utils::StdErrFormat) return Status::NotHandled; if (line.indexOf(m_pchInfoLine) != -1) return Status::Done; // totally ignore this line if (m_expectFirstLine) { const QRegularExpressionMatch match = m_firstLine.match(line); if (match.hasMatch()) { Task::TaskType type = Task::Unknown; QString category = match.captured(4); if (category == QLatin1String("error")) type = Task::Error; else if (category == QLatin1String("warning")) type = Task::Warning; const FilePath filePath = absoluteFilePath(FilePath::fromUserInput(match.captured(1))); const int lineNo = match.captured(2).toInt(); LinkSpecs linkSpecs; addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, lineNo, -1, match, 1); createOrAmendTask(type, match.captured(6).trimmed(), line, false, filePath, lineNo); m_expectFirstLine = false; return Status::InProgress; } } if (!m_expectFirstLine && line.indexOf(m_caretLine) != -1) { // FIXME: m_temporary.details.append(line); return Status::InProgress; } if (!m_expectFirstLine && line.trimmed().isEmpty()) { // last Line m_expectFirstLine = true; flush(); return Status::Done; } const QRegularExpressionMatch match = m_continuationLines.match(line); if (!m_expectFirstLine && match.hasMatch()) { createOrAmendTask(Task::Unknown, {}, line, true); return Status::InProgress; } return Status::NotHandled; } Utils::Id LinuxIccParser::id() { return Utils::Id("ProjectExplorer.OutputParser.Icc"); } QList LinuxIccParser::iccParserSuite() { return {new LinuxIccParser, new Internal::LldParser, new Internal::LdParser}; } #ifdef WITH_TESTS class LinuxIccParserTest : public QObject { Q_OBJECT private slots: void test_data() { QTest::addColumn("input"); QTest::addColumn("inputChannel"); QTest::addColumn("childStdOutLines"); QTest::addColumn("childStdErrLines"); QTest::addColumn("tasks"); QTest::newRow("pass-through stdout") << QString::fromLatin1("Sometext") << OutputParserTester::STDOUT << QStringList("Sometext") << QStringList() << Tasks(); QTest::newRow("pass-through stderr") << QString::fromLatin1("Sometext") << OutputParserTester::STDERR << QStringList() << QStringList("Sometext") << Tasks(); QTest::newRow("pch creation") << QString::fromLatin1("\".pch/Qt5Core.pchi.cpp\": creating precompiled header file \".pch/Qt5Core.pchi\"") << OutputParserTester::STDERR << QStringList() << QStringList() << Tasks(); QTest::newRow("undeclared function") << QString::fromLatin1("main.cpp(13): error: identifier \"f\" is undefined\n" " f(0);\n" " ^\n" "\n") << OutputParserTester::STDERR << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Error, "identifier \"f\" is undefined\n" "main.cpp(13): error: identifier \"f\" is undefined\n" " f(0);", FilePath::fromUserInput(QLatin1String("main.cpp")), 13)); // same, with PCH remark QTest::newRow("pch use+undeclared function") << QString::fromLatin1("\"main.cpp\": using precompiled header file \".pch/Qt5Core.pchi\"\n" "main.cpp(13): error: identifier \"f\" is undefined\n" " f(0);\n" " ^\n" "\n") << OutputParserTester::STDERR << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Error, "identifier \"f\" is undefined\n" "main.cpp(13): error: identifier \"f\" is undefined\n" " f(0);", FilePath::fromUserInput("main.cpp"), 13)); QTest::newRow("private function") << QString::fromLatin1("main.cpp(53): error #308: function \"AClass::privatefunc\" (declared at line 4 of \"main.h\") is inaccessible\n" " b.privatefunc();\n" " ^\n" "\n") << OutputParserTester::STDERR << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Error, "function \"AClass::privatefunc\" (declared at line 4 of \"main.h\") is inaccessible\n" "main.cpp(53): error #308: function \"AClass::privatefunc\" (declared at line 4 of \"main.h\") is inaccessible\n" " b.privatefunc();", FilePath::fromUserInput("main.cpp"), 53)); QTest::newRow("simple warning") << QString::fromLatin1("main.cpp(41): warning #187: use of \"=\" where \"==\" may have been intended\n" " while (a = true)\n" " ^\n" "\n") << OutputParserTester::STDERR << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Warning, "use of \"=\" where \"==\" may have been intended\n" "main.cpp(41): warning #187: use of \"=\" where \"==\" may have been intended\n" " while (a = true)", FilePath::fromUserInput("main.cpp"), 41)); } void test() { OutputParserTester testbench; testbench.setLineParsers(LinuxIccParser::iccParserSuite()); QFETCH(QString, input); QFETCH(OutputParserTester::Channel, inputChannel); QFETCH(Tasks, tasks); QFETCH(QStringList, childStdOutLines); QFETCH(QStringList, childStdErrLines); testbench.testParsing(input, inputChannel, tasks, childStdOutLines, childStdErrLines); } }; QObject *createLinuxIccParserTest() { return new LinuxIccParserTest; } #endif // WITH_TESTS } // ProjectExplorer::Internal #ifdef WITH_TESTS #include #endif