From 7745eacc7afae4acf3e07325ab01cf6e6821037c Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 7 Apr 2020 13:49:34 +0200 Subject: [PATCH] Output parsers: Generalize the search directory concept All parsers can now have search directories, not just the GnuMakeParser. This allows us to get rid of the "task mangling", removing another instance where the order of parsers in the chain mattered. Task-number: QTCREATORBUG-22665 Change-Id: Id0d55522ae6800afd9f50ff36546224b0d8bb382 Reviewed-by: hjk --- .../androidpackageinstallationstep.cpp | 2 +- src/plugins/android/javaparser.cpp | 2 +- src/plugins/baremetal/iarewparser.cpp | 2 +- src/plugins/baremetal/keilparser.cpp | 6 +- src/plugins/baremetal/sdccparser.cpp | 4 +- .../cmakeprojectmanager/cmakebuildstep.cpp | 2 +- .../cmakeprojectmanager/cmakeparser.cpp | 4 +- src/plugins/ios/iosbuildstep.cpp | 2 +- src/plugins/ios/iosdsymbuildstep.cpp | 2 +- src/plugins/nim/project/nimblebuildstep.cpp | 5 +- .../nim/project/nimcompilerbuildstep.cpp | 5 +- src/plugins/projectexplorer/clangparser.cpp | 4 +- src/plugins/projectexplorer/customparser.cpp | 13 +- src/plugins/projectexplorer/customparser.h | 1 - src/plugins/projectexplorer/gccparser.cpp | 4 +- src/plugins/projectexplorer/gnumakeparser.cpp | 169 ++++-------------- src/plugins/projectexplorer/gnumakeparser.h | 11 +- src/plugins/projectexplorer/ioutputparser.cpp | 62 +++++-- src/plugins/projectexplorer/ioutputparser.h | 9 +- src/plugins/projectexplorer/ldparser.cpp | 2 +- .../projectexplorer/linuxiccparser.cpp | 2 +- src/plugins/projectexplorer/lldparser.cpp | 3 +- src/plugins/projectexplorer/makestep.cpp | 2 +- src/plugins/projectexplorer/msvcparser.cpp | 6 +- .../projectexplorer/outputparser_test.cpp | 34 +--- .../projectexplorer/outputparser_test.h | 6 +- src/plugins/projectexplorer/projectexplorer.h | 1 - .../projectexplorer/xcodebuildparser.cpp | 4 +- .../qbsprojectmanager/qbsbuildstep.cpp | 6 +- .../qmakeprojectmanager/qmakemakestep.cpp | 2 +- .../qmakeprojectmanager/qmakeparser.cpp | 2 +- src/plugins/qmakeprojectmanager/qmakestep.cpp | 2 +- src/plugins/qtsupport/qtparser.cpp | 4 +- src/plugins/qtsupport/qttestparser.cpp | 4 +- 34 files changed, 140 insertions(+), 249 deletions(-) diff --git a/src/plugins/android/androidpackageinstallationstep.cpp b/src/plugins/android/androidpackageinstallationstep.cpp index 4e029fda6b2..3c61a32915d 100644 --- a/src/plugins/android/androidpackageinstallationstep.cpp +++ b/src/plugins/android/androidpackageinstallationstep.cpp @@ -115,7 +115,7 @@ bool AndroidPackageInstallationStep::init() IOutputParser *parser = target()->kit()->createOutputParser(); if (parser) appendOutputParser(parser); - outputParser()->setWorkingDirectory(pp->effectiveWorkingDirectory()); + outputParser()->addSearchDir(pp->effectiveWorkingDirectory()); m_androidDirsToClean.clear(); // don't remove gradle's cache, it takes ages to rebuild it. diff --git a/src/plugins/android/javaparser.cpp b/src/plugins/android/javaparser.cpp index 359d9be8195..cc93adc0fb2 100644 --- a/src/plugins/android/javaparser.cpp +++ b/src/plugins/android/javaparser.cpp @@ -86,7 +86,7 @@ void JavaParser::parse(const QString &line) CompileTask task(Task::Error, m_javaRegExp.cap(4).trimmed(), - file /* filename */, + absoluteFilePath(file), lineno); emit addTask(task, 1); return; diff --git a/src/plugins/baremetal/iarewparser.cpp b/src/plugins/baremetal/iarewparser.cpp index 2686f58d900..7c4e9955610 100644 --- a/src/plugins/baremetal/iarewparser.cpp +++ b/src/plugins/baremetal/iarewparser.cpp @@ -158,7 +158,7 @@ bool IarParser::parseWarningOrErrorOrFatalErrorDetailsMessage1(const QString &ln const int lineno = match.captured(LineNumberIndex).toInt(); const Task::TaskType type = taskType(match.captured(MessageTypeIndex)); // A full description will be received later on next lines. - newTask(CompileTask(type, {}, fileName, lineno)); + newTask(CompileTask(type, {}, absoluteFilePath(fileName), lineno)); const QString firstPart = QString("[%1]: ").arg(match.captured(MessageCodeIndex)); m_descriptionParts.append(firstPart); m_expectDescription = true; diff --git a/src/plugins/baremetal/keilparser.cpp b/src/plugins/baremetal/keilparser.cpp index 1a09a68b2da..8511727910e 100644 --- a/src/plugins/baremetal/keilparser.cpp +++ b/src/plugins/baremetal/keilparser.cpp @@ -106,7 +106,7 @@ bool KeilParser::parseArmWarningOrErrorDetailsMessage(const QString &lne) const int lineno = match.captured(LineNumberIndex).toInt(); const Task::TaskType type = taskType(match.captured(MessageTypeIndex)); const QString descr = match.captured(DescriptionIndex); - newTask(CompileTask(type, descr, fileName, lineno)); + newTask(CompileTask(type, descr, absoluteFilePath(fileName), lineno)); return true; } @@ -139,7 +139,7 @@ bool KeilParser::parseMcs51WarningOrErrorDetailsMessage1(const QString &lne) match.captured(FilePathIndex)); const QString descr = QString("%1: %2").arg(match.captured(MessageCodeIndex), match.captured(MessageTextIndex)); - newTask(CompileTask(type, descr, fileName, lineno)); + newTask(CompileTask(type, descr, absoluteFilePath(fileName), lineno)); return true; } @@ -157,7 +157,7 @@ bool KeilParser::parseMcs51WarningOrErrorDetailsMessage2(const QString &lne) match.captured(FilePathIndex)); const QString descr = QString("%1: %2").arg(match.captured(MessageCodeIndex), match.captured(MessageTextIndex)); - newTask(CompileTask(type, descr, fileName, lineno)); + newTask(CompileTask(type, descr, absoluteFilePath(fileName), lineno)); return true; } diff --git a/src/plugins/baremetal/sdccparser.cpp b/src/plugins/baremetal/sdccparser.cpp index 5a12b5d66e3..e94656c4121 100644 --- a/src/plugins/baremetal/sdccparser.cpp +++ b/src/plugins/baremetal/sdccparser.cpp @@ -106,7 +106,7 @@ void SdccParser::stdError(const QString &line) const int lineno = match.captured(LineNumberIndex).toInt(); const Task::TaskType type = taskType(match.captured(MessageTypeIndex)); const QString descr = match.captured(MessageTextIndex); - newTask(CompileTask(type, descr, fileName, lineno)); + newTask(CompileTask(type, descr, absoluteFilePath(fileName), lineno)); return; } @@ -120,7 +120,7 @@ void SdccParser::stdError(const QString &line) const int lineno = match.captured(LineNumberIndex).toInt(); const Task::TaskType type = taskType(match.captured(MessageTypeIndex)); const QString descr = match.captured(MessageTextIndex); - newTask(CompileTask(type, descr, fileName, lineno)); + newTask(CompileTask(type, descr, absoluteFilePath(fileName), lineno)); return; } diff --git a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp index 6a7e5196e15..519433e894e 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp @@ -217,7 +217,7 @@ bool CMakeBuildStep::init() IOutputParser *parser = target()->kit()->createOutputParser(); if (parser) appendOutputParser(parser); - outputParser()->setWorkingDirectory(pp->effectiveWorkingDirectory()); + outputParser()->addSearchDir(pp->effectiveWorkingDirectory()); return AbstractProcessStep::init(); } diff --git a/src/plugins/cmakeprojectmanager/cmakeparser.cpp b/src/plugins/cmakeprojectmanager/cmakeparser.cpp index 970dd64eee3..01fd9bd3e59 100644 --- a/src/plugins/cmakeprojectmanager/cmakeparser.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeparser.cpp @@ -80,13 +80,13 @@ void CMakeParser::stdError(const QString &line) m_lastTask = BuildSystemTask(Task::Error, QString(), - FilePath::fromUserInput(path), + absoluteFilePath(FilePath::fromUserInput(path)), m_commonError.cap(2).toInt()); m_lines = 1; return; } else if (m_nextSubError.indexIn(trimmedLine) != -1) { m_lastTask = BuildSystemTask(Task::Error, QString(), - FilePath::fromUserInput(m_nextSubError.cap(1))); + absoluteFilePath(FilePath::fromUserInput(m_nextSubError.cap(1)))); m_lines = 1; return; } else if (trimmedLine.startsWith(QLatin1String(" ")) && !m_lastTask.isNull()) { diff --git a/src/plugins/ios/iosbuildstep.cpp b/src/plugins/ios/iosbuildstep.cpp index fbf500b0992..65661343987 100644 --- a/src/plugins/ios/iosbuildstep.cpp +++ b/src/plugins/ios/iosbuildstep.cpp @@ -226,7 +226,7 @@ bool IosBuildStep::init() IOutputParser *parser = target()->kit()->createOutputParser(); if (parser) appendOutputParser(parser); - outputParser()->setWorkingDirectory(pp->effectiveWorkingDirectory()); + outputParser()->addSearchDir(pp->effectiveWorkingDirectory()); return AbstractProcessStep::init(); } diff --git a/src/plugins/ios/iosdsymbuildstep.cpp b/src/plugins/ios/iosdsymbuildstep.cpp index 0221624201d..937811bcd38 100644 --- a/src/plugins/ios/iosdsymbuildstep.cpp +++ b/src/plugins/ios/iosdsymbuildstep.cpp @@ -82,7 +82,7 @@ bool IosDsymBuildStep::init() setOutputParser(target()->kit()->createOutputParser()); if (outputParser()) - outputParser()->setWorkingDirectory(pp->effectiveWorkingDirectory()); + outputParser()->addSearchDir(pp->effectiveWorkingDirectory()); return AbstractProcessStep::init(); } diff --git a/src/plugins/nim/project/nimblebuildstep.cpp b/src/plugins/nim/project/nimblebuildstep.cpp index 97014cc17ae..6c45f4fb157 100644 --- a/src/plugins/nim/project/nimblebuildstep.cpp +++ b/src/plugins/nim/project/nimblebuildstep.cpp @@ -87,7 +87,8 @@ private: else return; - emit addTask(CompileTask(type, message, FilePath::fromUserInput(filename), lineNumber)); + emit addTask(CompileTask(type, message, absoluteFilePath(FilePath::fromUserInput(filename)), + lineNumber)); } }; @@ -107,7 +108,7 @@ NimbleBuildStep::NimbleBuildStep(BuildStepList *parentList, Core::Id id) bool NimbleBuildStep::init() { auto parser = new NimParser(); - parser->setWorkingDirectory(project()->projectDirectory()); + parser->addSearchDir(project()->projectDirectory()); setOutputParser(parser); ProcessParameters* params = processParameters(); diff --git a/src/plugins/nim/project/nimcompilerbuildstep.cpp b/src/plugins/nim/project/nimcompilerbuildstep.cpp index 521c038afd6..83bf618ba8a 100644 --- a/src/plugins/nim/project/nimcompilerbuildstep.cpp +++ b/src/plugins/nim/project/nimcompilerbuildstep.cpp @@ -89,7 +89,8 @@ private: else return; - emit addTask(CompileTask(type, message, FilePath::fromUserInput(filename), lineNumber)); + emit addTask(CompileTask(type, message, absoluteFilePath(FilePath::fromUserInput(filename)), + lineNumber)); } }; @@ -116,7 +117,7 @@ bool NimCompilerBuildStep::init() setOutputParser(new NimParser()); if (IOutputParser *parser = target()->kit()->createOutputParser()) appendOutputParser(parser); - outputParser()->setWorkingDirectory(processParameters()->effectiveWorkingDirectory()); + outputParser()->addSearchDir(processParameters()->effectiveWorkingDirectory()); return AbstractProcessStep::init(); } diff --git a/src/plugins/projectexplorer/clangparser.cpp b/src/plugins/projectexplorer/clangparser.cpp index cc62f32cf74..c1238a5cc25 100644 --- a/src/plugins/projectexplorer/clangparser.cpp +++ b/src/plugins/projectexplorer/clangparser.cpp @@ -76,7 +76,7 @@ void ClangParser::stdError(const QString &line) m_expectSnippet = true; newTask(CompileTask(Task::Unknown, lne.trimmed(), - FilePath::fromUserInput(match.captured(2)), /* filename */ + absoluteFilePath(FilePath::fromUserInput(match.captured(2))), match.captured(3).toInt() /* line */)); return; } @@ -90,7 +90,7 @@ void ClangParser::stdError(const QString &line) lineNo = match.captured(5).toInt(&ok); newTask(CompileTask(taskType(match.captured(7)), match.captured(8), - FilePath::fromUserInput(match.captured(1)), /* filename */ + absoluteFilePath(FilePath::fromUserInput(match.captured(1))), lineNo)); return; } diff --git a/src/plugins/projectexplorer/customparser.cpp b/src/plugins/projectexplorer/customparser.cpp index 22ad09c3075..b7b3cb1ef77 100644 --- a/src/plugins/projectexplorer/customparser.cpp +++ b/src/plugins/projectexplorer/customparser.cpp @@ -145,13 +145,6 @@ Core::Id CustomParser::id() return Core::Id("ProjectExplorer.OutputParser.Custom"); } -FilePath CustomParser::absoluteFilePath(const QString &filePath) const -{ - if (workingDirectory().isEmpty()) - return FilePath::fromUserInput(filePath); - return workingDirectory().resolvePath(filePath); -} - bool CustomParser::hasMatch(const QString &line, CustomParserExpression::CustomParserChannel channel, const CustomParserExpression &expression, Task::TaskType taskType) { @@ -165,7 +158,8 @@ bool CustomParser::hasMatch(const QString &line, CustomParserExpression::CustomP if (!match.hasMatch()) return false; - const FilePath fileName = absoluteFilePath(match.captured(expression.fileNameCap())); + const FilePath fileName = absoluteFilePath(FilePath::fromString( + match.captured(expression.fileNameCap()))); const int lineNumber = match.captured(expression.lineNumberCap()).toInt(); const QString message = match.captured(expression.messageCap()); @@ -475,7 +469,8 @@ void ProjectExplorerPlugin::testCustomOutputParsers() CustomParser *parser = new CustomParser; parser->setSettings(settings); - parser->setWorkingDirectory(FilePath::fromString(workDir)); + parser->addSearchDir(FilePath::fromString(workDir)); + parser->skipFileExistsCheck(); OutputParserTester testbench; testbench.appendOutputParser(parser); diff --git a/src/plugins/projectexplorer/customparser.h b/src/plugins/projectexplorer/customparser.h index 6435bc13fae..e1490baeabc 100644 --- a/src/plugins/projectexplorer/customparser.h +++ b/src/plugins/projectexplorer/customparser.h @@ -94,7 +94,6 @@ public: static Core::Id id(); private: - Utils::FilePath absoluteFilePath(const QString &filePath) const; bool hasMatch(const QString &line, CustomParserExpression::CustomParserChannel channel, const CustomParserExpression &expression, Task::TaskType taskType); bool parseLine(const QString &rawLine, CustomParserExpression::CustomParserChannel channel); diff --git a/src/plugins/projectexplorer/gccparser.cpp b/src/plugins/projectexplorer/gccparser.cpp index 2fc6c4da44e..dcfe8ffc53e 100644 --- a/src/plugins/projectexplorer/gccparser.cpp +++ b/src/plugins/projectexplorer/gccparser.cpp @@ -113,7 +113,7 @@ void GccParser::stdError(const QString &line) if (match.captured(5).startsWith(QLatin1Char('#'))) description = match.captured(5) + description; - newTask(CompileTask(type, description, filename, lineno)); + newTask(CompileTask(type, description, absoluteFilePath(filename), lineno)); return; } @@ -121,7 +121,7 @@ void GccParser::stdError(const QString &line) if (match.hasMatch()) { newTask(CompileTask(Task::Unknown, lne.trimmed() /* description */, - Utils::FilePath::fromUserInput(match.captured(1)) /* filename */, + absoluteFilePath(Utils::FilePath::fromUserInput(match.captured(1))), match.captured(3).toInt() /* linenumber */)); return; } else if (lne.startsWith(' ') && !m_currentTask.isNull()) { diff --git a/src/plugins/projectexplorer/gnumakeparser.cpp b/src/plugins/projectexplorer/gnumakeparser.cpp index c1453445317..1e3616e6270 100644 --- a/src/plugins/projectexplorer/gnumakeparser.cpp +++ b/src/plugins/projectexplorer/gnumakeparser.cpp @@ -29,7 +29,7 @@ #include "task.h" #include -#include +#include #include #include @@ -68,9 +68,9 @@ void GnuMakeParser::stdOutput(const QString &line) QRegularExpressionMatch match = m_makeDir.match(lne); if (match.hasMatch()) { if (match.captured(6) == QLatin1String("Leaving")) - removeDirectory(match.captured(7)); + dropSearchDir(FilePath::fromString(match.captured(7))); else - addDirectory(match.captured(7)); + addSearchDir(FilePath::fromString(match.captured(7))); return; } @@ -128,10 +128,9 @@ void GnuMakeParser::stdError(const QString &line) if (res.isFatal) ++m_fatalErrorCount; if (!m_suppressIssues) { - taskAdded(BuildSystemTask(res.type, res.description, - FilePath::fromUserInput(match.captured(1)) /* filename */, - match.captured(4).toInt() /* line */), - 1, 0); + emitTask(BuildSystemTask(res.type, res.description, + absoluteFilePath(FilePath::fromUserInput(match.captured(1))), + match.captured(4).toInt() /* line */)); } return; } @@ -142,61 +141,18 @@ void GnuMakeParser::stdError(const QString &line) if (res.isFatal) ++m_fatalErrorCount; if (!m_suppressIssues) - taskAdded(BuildSystemTask(res.type, res.description), 1, 0); + emitTask(BuildSystemTask(res.type, res.description)); return; } IOutputParser::stdError(line); } -void GnuMakeParser::addDirectory(const QString &dir) +void GnuMakeParser::emitTask(const ProjectExplorer::Task &task) { - if (dir.isEmpty()) - return; - m_directories.append(dir); -} - -void GnuMakeParser::removeDirectory(const QString &dir) -{ - m_directories.removeOne(dir); -} - -void GnuMakeParser::taskAdded(const Task &task, int linkedLines, int skippedLines) -{ - Task editable(task); - - if (task.type == Task::Error) { - // assume that all make errors will be follow up errors: + if (task.type == Task::Error) // Assume that all make errors will be follow up errors. m_suppressIssues = true; - } - - QString filePath(task.file.toString()); - - if (!filePath.isEmpty() && !QDir::isAbsolutePath(filePath)) { - QFileInfoList possibleFiles; - foreach (const QString &dir, searchDirectories()) { - QFileInfo candidate(dir + QLatin1Char('/') + filePath); - if (candidate.exists() - && !possibleFiles.contains(candidate)) { - possibleFiles << candidate; - } - } - if (possibleFiles.size() == 1) - editable.file = Utils::FilePath::fromFileInfo(possibleFiles.first()); - // Let the Makestep apply additional heuristics (based on - // files in ther project) if we cannot uniquely - // identify the file! - } - - IOutputParser::taskAdded(editable, linkedLines, skippedLines); -} - -QStringList GnuMakeParser::searchDirectories() const -{ - QStringList dirs = m_directories; - if (!workingDirectory().isEmpty()) - dirs << workingDirectory().toString(); - return dirs; + emit addTask(task, 1, 0); } } // ProjectExplorer @@ -417,117 +373,52 @@ void ProjectExplorerPlugin::testGnuMakeParserParsing() QFETCH(QString, outputLines); QFETCH(QStringList, additionalSearchDirs); - QStringList searchDirs = childParser->searchDirectories(); + FilePaths searchDirs = childParser->searchDirectories(); // add extra directories: foreach (const QString &dir, extraSearchDirs) - childParser->addDirectory(dir); + childParser->addSearchDir(FilePath::fromString(dir)); testbench.testParsing(input, inputChannel, tasks, childStdOutLines, childStdErrLines, outputLines); // make sure we still have all the original dirs - QStringList newSearchDirs = tester->directories; - foreach (const QString &dir, searchDirs) { + FilePaths newSearchDirs = tester->directories; + foreach (const FilePath &dir, searchDirs) { QVERIFY(newSearchDirs.contains(dir)); newSearchDirs.removeOne(dir); } // make sure we have all additional dirs: foreach (const QString &dir, additionalSearchDirs) { - QVERIFY(newSearchDirs.contains(dir)); - newSearchDirs.removeOne(dir); + const FilePath fp = FilePath::fromString(dir); + QVERIFY(newSearchDirs.contains(fp)); + newSearchDirs.removeOne(fp); } // make sure we have no extra cruft: QVERIFY(newSearchDirs.isEmpty()); delete tester; } -void ProjectExplorerPlugin::testGnuMakeParserTaskMangling_data() -{ - QTest::addColumn("files"); - QTest::addColumn("searchDirectories"); - QTest::addColumn("inputTask"); - QTest::addColumn("outputTask"); - - QTest::newRow("no filename") - << QStringList() - << QStringList() - << Task(CompileTask(Task::Error, - "no filename, no mangling")) - << Task(CompileTask(Task::Error, - "no filename, no mangling")); - - QTest::newRow("no mangling") - << QStringList() - << QStringList() - << Task(CompileTask(Task::Error, - "unknown filename, no mangling", - FilePath::fromUserInput("some/path/unknown.cpp"))) - << Task(CompileTask(Task::Error, - "unknown filename, no mangling", - FilePath::fromUserInput("some/path/unknown.cpp"))); - - QTest::newRow("find file") - << QStringList("test/file.cpp") - << QStringList("test") - << Task(CompileTask(Task::Error, - "mangling", - FilePath::fromUserInput("file.cpp"), - 10)) - << Task(CompileTask(Task::Error, - "mangling", - FilePath::fromUserInput("$TMPDIR/test/file.cpp"), - 10)); -} - void ProjectExplorerPlugin::testGnuMakeParserTaskMangling() { + TemporaryFile theMakeFile("Makefile.XXXXXX"); + QVERIFY2(theMakeFile.open(), qPrintable(theMakeFile.errorString())); + QFileInfo fi(theMakeFile); + QVERIFY2(fi.fileName().startsWith("Makefile"), qPrintable(theMakeFile.fileName())); + OutputParserTester testbench; auto *childParser = new GnuMakeParser; testbench.appendOutputParser(childParser); - - QFETCH(QStringList, files); - QFETCH(QStringList, searchDirectories); - QFETCH(Task, inputTask); - QFETCH(Task, outputTask); - - // setup files: - const QString tempdir - = Utils::TemporaryDirectory::masterDirectoryPath() + '/' + QUuid::createUuid().toString() + '/'; - QDir filedir(tempdir); - foreach (const QString &file, files) { - Q_ASSERT(!file.startsWith('/')); - Q_ASSERT(!file.contains("../")); - - filedir.mkpath(file.left(file.lastIndexOf('/'))); - - QFile tempfile(tempdir + file); - if (!tempfile.open(QIODevice::WriteOnly)) - continue; - tempfile.write("Delete me again!"); - tempfile.close(); - } - - // setup search dirs: - foreach (const QString &dir, searchDirectories) { - Q_ASSERT(!dir.startsWith(QLatin1Char('/'))); - Q_ASSERT(!dir.contains(QLatin1String("../"))); - childParser->addDirectory(tempdir + dir); - } - - // fix up output task file: - QString filePath = outputTask.file.toString(); - if (filePath.startsWith(QLatin1String("$TMPDIR/"))) - outputTask.file = Utils::FilePath::fromString(filePath.replace(QLatin1String("$TMPDIR/"), tempdir)); - - // test mangling: - testbench.testTaskMangling(inputTask, outputTask); - - // clean up: - foreach (const QString &file, files) - filedir.rmpath(tempdir + file); + childParser->addSearchDir(FilePath::fromString(fi.absolutePath())); + testbench.testParsing( + fi.fileName() + ":360: *** missing separator (did you mean TAB instead of 8 spaces?). Stop.", + OutputParserTester::STDERR, + {BuildSystemTask(Task::Error, + "missing separator (did you mean TAB instead of 8 spaces?). Stop.", + FilePath::fromString(theMakeFile.fileName()), 360)}, + QString(), QString(), QString()); } } // ProjectExplorer diff --git a/src/plugins/projectexplorer/gnumakeparser.h b/src/plugins/projectexplorer/gnumakeparser.h index c2d126f30bc..647fd5d9502 100644 --- a/src/plugins/projectexplorer/gnumakeparser.h +++ b/src/plugins/projectexplorer/gnumakeparser.h @@ -42,23 +42,16 @@ public: void stdOutput(const QString &line) override; void stdError(const QString &line) override; - QStringList searchDirectories() const; - bool hasFatalErrors() const override; - void taskAdded(const ProjectExplorer::Task &task, int linkedLines, int skippedLines) override; - private: - void addDirectory(const QString &dir); - void removeDirectory(const QString &dir); + void emitTask(const ProjectExplorer::Task &task); QRegularExpression m_makeDir; QRegularExpression m_makeLine; QRegularExpression m_threeStarError; QRegularExpression m_errorInMakefile; - QStringList m_directories; - bool m_suppressIssues = false; int m_fatalErrorCount = 0; @@ -77,7 +70,7 @@ public: explicit GnuMakeParserTester(GnuMakeParser *parser, QObject *parent = nullptr); void parserIsAboutToBeDeleted(); - QStringList directories; + Utils::FilePaths directories; GnuMakeParser *parser; }; #endif diff --git a/src/plugins/projectexplorer/ioutputparser.cpp b/src/plugins/projectexplorer/ioutputparser.cpp index 3190c52f1a6..4abe41aa931 100644 --- a/src/plugins/projectexplorer/ioutputparser.cpp +++ b/src/plugins/projectexplorer/ioutputparser.cpp @@ -28,6 +28,9 @@ #include +#include +#include + /*! \class ProjectExplorer::IOutputParser @@ -162,9 +165,10 @@ public: IOutputParser *childParser = nullptr; QList filters; - Utils::FilePath workingDir; + Utils::FilePaths searchDirs; OutputChannelState stdoutState; OutputChannelState stderrState; + bool skipFileExistsCheck = false; }; IOutputParser::IOutputParser() : d(new IOutputParserPrivate(this)) @@ -197,7 +201,7 @@ void IOutputParser::appendOutputParser(IOutputParser *parser) } d->childParser = parser; - connect(parser, &IOutputParser::addTask, this, &IOutputParser::taskAdded); + connect(parser, &IOutputParser::addTask, this, &IOutputParser::addTask); } IOutputParser *IOutputParser::childParser() const @@ -211,7 +215,7 @@ void IOutputParser::setChildParser(IOutputParser *parser) delete d->childParser; d->childParser = parser; if (parser) - connect(parser, &IOutputParser::addTask, this, &IOutputParser::taskAdded); + connect(parser, &IOutputParser::addTask, this, &IOutputParser::addTask); } void IOutputParser::stdOutput(const QString &line) @@ -226,28 +230,18 @@ void IOutputParser::stdError(const QString &line) d->childParser->stdError(line); } -Utils::FilePath IOutputParser::workingDirectory() const { return d->workingDir; } - -void IOutputParser::taskAdded(const Task &task, int linkedOutputLines, int skipLines) +void IOutputParser::skipFileExistsCheck() { - emit addTask(task, linkedOutputLines, skipLines); + d->skipFileExistsCheck = true; } -void IOutputParser::doFlush() -{ } +void IOutputParser::doFlush() { } bool IOutputParser::hasFatalErrors() const { return d->childParser && d->childParser->hasFatalErrors(); } -void IOutputParser::setWorkingDirectory(const Utils::FilePath &fn) -{ - d->workingDir = fn; - if (d->childParser) - d->childParser->setWorkingDirectory(fn); -} - void IOutputParser::flush() { flushTasks(); @@ -278,4 +272,40 @@ void IOutputParser::addFilter(const Filter &filter) d->filters << filter; } +void IOutputParser::addSearchDir(const Utils::FilePath &dir) +{ + d->searchDirs << dir; + if (d->childParser) + d->childParser->addSearchDir(dir); +} + +void IOutputParser::dropSearchDir(const Utils::FilePath &dir) +{ + const int idx = d->searchDirs.lastIndexOf(dir); + QTC_ASSERT(idx != -1, return); + d->searchDirs.removeAt(idx); + if (d->childParser) + d->childParser->dropSearchDir(dir); +} + +const Utils::FilePaths IOutputParser::searchDirectories() const +{ + return d->searchDirs; +} + +Utils::FilePath IOutputParser::absoluteFilePath(const Utils::FilePath &filePath) +{ + if (filePath.isEmpty() || filePath.toFileInfo().isAbsolute()) + return filePath; + Utils::FilePaths candidates; + for (const Utils::FilePath &dir : searchDirectories()) { + const Utils::FilePath candidate = dir.pathAppended(filePath.toString()); + if (candidate.exists() || d->skipFileExistsCheck) + candidates << candidate; + } + if (candidates.count() == 1) + return Utils::FilePath::fromString(QDir::cleanPath(candidates.first().toString())); + return filePath; +} + } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/ioutputparser.h b/src/plugins/projectexplorer/ioutputparser.h index e288873fd35..9e8d980c1a0 100644 --- a/src/plugins/projectexplorer/ioutputparser.h +++ b/src/plugins/projectexplorer/ioutputparser.h @@ -56,15 +56,16 @@ public: using Filter = std::function; void addFilter(const Filter &filter); - void setWorkingDirectory(const Utils::FilePath &fn); + void addSearchDir(const Utils::FilePath &dir); + void dropSearchDir(const Utils::FilePath &dir); + const Utils::FilePaths searchDirectories() const; + void skipFileExistsCheck(); // For testing only void flush(); // flush pending tasks & output void flushTasks(); // flush pending tasks only static QString rightTrimmed(const QString &in); - virtual void taskAdded(const ProjectExplorer::Task &task, int linkedOutputLines = 0, int skipLines = 0); - signals: void addTask(const ProjectExplorer::Task &task, int linkedOutputLines = 0, int skipLines = 0); @@ -72,7 +73,7 @@ protected: virtual void stdOutput(const QString &line); virtual void stdError(const QString &line); - Utils::FilePath workingDirectory() const; + Utils::FilePath absoluteFilePath(const Utils::FilePath &filePath); private: virtual void doFlush(); diff --git a/src/plugins/projectexplorer/ldparser.cpp b/src/plugins/projectexplorer/ldparser.cpp index 9d8aee037f7..1f86de84055 100644 --- a/src/plugins/projectexplorer/ldparser.cpp +++ b/src/plugins/projectexplorer/ldparser.cpp @@ -133,7 +133,7 @@ void LdParser::stdError(const QString &line) type = Task::Warning; description = description.mid(9); } - emit addTask(CompileTask(type, description, filename, lineno), 1); + emit addTask(CompileTask(type, description, absoluteFilePath(filename), lineno), 1); return; } diff --git a/src/plugins/projectexplorer/linuxiccparser.cpp b/src/plugins/projectexplorer/linuxiccparser.cpp index 95ccb4dfce0..b6d417630fd 100644 --- a/src/plugins/projectexplorer/linuxiccparser.cpp +++ b/src/plugins/projectexplorer/linuxiccparser.cpp @@ -85,7 +85,7 @@ void LinuxIccParser::stdError(const QString &line) type = Task::Warning; m_temporary = CompileTask(type, m_firstLine.cap(6).trimmed(), - Utils::FilePath::fromUserInput(m_firstLine.cap(1)), + absoluteFilePath(Utils::FilePath::fromUserInput(m_firstLine.cap(1))), m_firstLine.cap(2).toInt()); m_lines = 1; diff --git a/src/plugins/projectexplorer/lldparser.cpp b/src/plugins/projectexplorer/lldparser.cpp index 179bd742d3a..356ea74a022 100644 --- a/src/plugins/projectexplorer/lldparser.cpp +++ b/src/plugins/projectexplorer/lldparser.cpp @@ -64,7 +64,8 @@ void LldParser::stdError(const QString &line) const int filePathLen = locOffset == -1 ? -1 : locOffset - filePathOffset; const auto file = Utils::FilePath::fromUserInput( trimmedLine.mid(filePathOffset, filePathLen).trimmed()); - emit addTask(CompileTask(Task::Unknown, trimmedLine.mid(4).trimmed(), file, lineNo)); + emit addTask(CompileTask(Task::Unknown, trimmedLine.mid(4).trimmed(), + absoluteFilePath(file), lineNo)); return; } IOutputParser::stdError(line); diff --git a/src/plugins/projectexplorer/makestep.cpp b/src/plugins/projectexplorer/makestep.cpp index 807cb14f315..8a067cc1e1d 100644 --- a/src/plugins/projectexplorer/makestep.cpp +++ b/src/plugins/projectexplorer/makestep.cpp @@ -106,7 +106,7 @@ bool MakeStep::init() IOutputParser *parser = target()->kit()->createOutputParser(); if (parser) appendOutputParser(parser); - outputParser()->setWorkingDirectory(pp->effectiveWorkingDirectory()); + outputParser()->addSearchDir(pp->effectiveWorkingDirectory()); return AbstractProcessStep::init(); } diff --git a/src/plugins/projectexplorer/msvcparser.cpp b/src/plugins/projectexplorer/msvcparser.cpp index 39a41f36632..145a02d5c29 100644 --- a/src/plugins/projectexplorer/msvcparser.cpp +++ b/src/plugins/projectexplorer/msvcparser.cpp @@ -142,7 +142,7 @@ void MsvcParser::stdOutput(const QString &line) if (!match.captured(1).isEmpty()) description.chop(1); // Remove trailing quote m_lastTask = CompileTask(Task::Unknown, description, - FilePath::fromUserInput(match.captured(2)), /* fileName */ + absoluteFilePath(FilePath::fromUserInput(match.captured(2))), match.captured(3).toInt() /* linenumber */); m_lines = 1; return; @@ -176,7 +176,7 @@ bool MsvcParser::processCompileLine(const QString &line) QPair position = parseFileName(match.captured(1)); m_lastTask = CompileTask(taskType(match.captured(2)), match.captured(3) + match.captured(4).trimmed(), // description - position.first, position.second); + absoluteFilePath(position.first), position.second); m_lines = 1; return true; } @@ -257,7 +257,7 @@ void ClangClParser::stdError(const QString &lineIn) doFlush(); const QPair position = parseFileName(match.captured(1)); m_lastTask = CompileTask(taskType(match.captured(2)), match.captured(3).trimmed(), - position.first, position.second); + absoluteFilePath(position.first), position.second); m_linkedLines = 1; return; } diff --git a/src/plugins/projectexplorer/outputparser_test.cpp b/src/plugins/projectexplorer/outputparser_test.cpp index ea7b9be7ce0..9dfa5e48269 100644 --- a/src/plugins/projectexplorer/outputparser_test.cpp +++ b/src/plugins/projectexplorer/outputparser_test.cpp @@ -39,6 +39,13 @@ static inline QByteArray msgFileComparisonFail(const Utils::FilePath &f1, const } // test functions: +OutputParserTester::OutputParserTester() +{ + connect(this, &IOutputParser::addTask, this, [this](const Task &t) { + m_receivedTasks.append(t); + }); +} + void OutputParserTester::testParsing(const QString &lines, Channel inputChannel, Tasks tasks, @@ -79,38 +86,11 @@ void OutputParserTester::testParsing(const QString &lines, } } -void OutputParserTester::testTaskMangling(const Task &input, - const Task &output) -{ - reset(); - childParser()->taskAdded(input); - - QVERIFY(m_receivedOutput.isNull()); - QVERIFY(m_receivedStdErrChildLine.isNull()); - QVERIFY(m_receivedStdOutChildLine.isNull()); - QVERIFY(m_receivedTasks.size() == 1); - if (m_receivedTasks.size() == 1) { - QCOMPARE(m_receivedTasks.at(0).category, output.category); - QCOMPARE(m_receivedTasks.at(0).description, output.description); - QVERIFY2(m_receivedTasks.at(0).file == output.file, - msgFileComparisonFail(m_receivedTasks.at(0).file, output.file)); - QCOMPARE(m_receivedTasks.at(0).line, output.line); - QCOMPARE(m_receivedTasks.at(0).type, output.type); - } -} - void OutputParserTester::setDebugEnabled(bool debug) { m_debug = debug; } -void OutputParserTester::taskAdded(const Task &task, int linkedLines, int skipLines) -{ - Q_UNUSED(linkedLines) - Q_UNUSED(skipLines) - m_receivedTasks.append(task); -} - void OutputParserTester::reset() { m_receivedStdErrChildLine.clear(); diff --git a/src/plugins/projectexplorer/outputparser_test.h b/src/plugins/projectexplorer/outputparser_test.h index dec7e974d5f..2525c36477c 100644 --- a/src/plugins/projectexplorer/outputparser_test.h +++ b/src/plugins/projectexplorer/outputparser_test.h @@ -46,14 +46,14 @@ public: STDERR }; + OutputParserTester(); + // test functions: void testParsing(const QString &lines, Channel inputChannel, Tasks tasks, const QString &childStdOutLines, const QString &childStdErrLines, const QString &outputLines); - void testTaskMangling(const Task &input, - const Task &output); void setDebugEnabled(bool); @@ -61,8 +61,6 @@ signals: void aboutToDeleteParser(); private: - void taskAdded(const ProjectExplorer::Task &task, int linkedLines, int skipLines) override; - void reset(); bool m_debug = false; diff --git a/src/plugins/projectexplorer/projectexplorer.h b/src/plugins/projectexplorer/projectexplorer.h index afc84671cb2..c7b7a19f5e4 100644 --- a/src/plugins/projectexplorer/projectexplorer.h +++ b/src/plugins/projectexplorer/projectexplorer.h @@ -229,7 +229,6 @@ private slots: void testGnuMakeParserParsing_data(); void testGnuMakeParserParsing(); - void testGnuMakeParserTaskMangling_data(); void testGnuMakeParserTaskMangling(); void testXcodebuildParserParsing_data(); diff --git a/src/plugins/projectexplorer/xcodebuildparser.cpp b/src/plugins/projectexplorer/xcodebuildparser.cpp index 13dc96ace94..54976415349 100644 --- a/src/plugins/projectexplorer/xcodebuildparser.cpp +++ b/src/plugins/projectexplorer/xcodebuildparser.cpp @@ -74,8 +74,8 @@ void XcodebuildParser::stdOutput(const QString &line) if (lne.endsWith(QLatin1String(signatureChangeEndsWithPattern))) { CompileTask task(Task::Warning, tr("Replacing signature"), - FilePath::fromString( - lne.left(lne.size() - QLatin1String(signatureChangeEndsWithPattern).size()))); + absoluteFilePath(FilePath::fromString( + lne.left(lne.size() - QLatin1String(signatureChangeEndsWithPattern).size())))); emit addTask(task, 1); return; } diff --git a/src/plugins/qbsprojectmanager/qbsbuildstep.cpp b/src/plugins/qbsprojectmanager/qbsbuildstep.cpp index 038c8a1a6d1..43034fd87dc 100644 --- a/src/plugins/qbsprojectmanager/qbsbuildstep.cpp +++ b/src/plugins/qbsprojectmanager/qbsbuildstep.cpp @@ -376,7 +376,7 @@ void QbsBuildStep::handleProcessResult( return; if (m_parser) - m_parser->setWorkingDirectory(workingDir); + m_parser->addSearchDir(workingDir); emit addOutput(executable.toUserOutput() + ' ' + QtcProcess::joinArgs(arguments), OutputFormat::Stdout); for (const QString &line : stdErr) { @@ -389,8 +389,10 @@ void QbsBuildStep::handleProcessResult( m_parser->handleStdout(line + '\n'); emit addOutput(line, OutputFormat::Stdout); } - if (m_parser) + if (m_parser) { m_parser->flush(); + m_parser->dropSearchDir(workingDir); + } } void QbsBuildStep::createTaskAndOutput(ProjectExplorer::Task::TaskType type, const QString &message, diff --git a/src/plugins/qmakeprojectmanager/qmakemakestep.cpp b/src/plugins/qmakeprojectmanager/qmakemakestep.cpp index 118df07c11d..f3c85b388c1 100644 --- a/src/plugins/qmakeprojectmanager/qmakemakestep.cpp +++ b/src/plugins/qmakeprojectmanager/qmakemakestep.cpp @@ -171,7 +171,7 @@ bool QmakeMakeStep::init() IOutputParser *parser = target()->kit()->createOutputParser(); if (parser) appendOutputParser(parser); - outputParser()->setWorkingDirectory(pp->effectiveWorkingDirectory()); + outputParser()->addSearchDir(pp->effectiveWorkingDirectory()); appendOutputParser(new QMakeParser); // make may cause qmake to be run, add last to make sure // it has a low priority. diff --git a/src/plugins/qmakeprojectmanager/qmakeparser.cpp b/src/plugins/qmakeprojectmanager/qmakeparser.cpp index 46ad10a0a00..bbc711e9582 100644 --- a/src/plugins/qmakeprojectmanager/qmakeparser.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeparser.cpp @@ -61,7 +61,7 @@ void QMakeParser::stdError(const QString &line) type = Task::Error; emit addTask(BuildSystemTask(type, description, - FilePath::fromUserInput(fileName), + absoluteFilePath(FilePath::fromUserInput(fileName)), m_error.cap(2).toInt() /* line */), 1); return; diff --git a/src/plugins/qmakeprojectmanager/qmakestep.cpp b/src/plugins/qmakeprojectmanager/qmakestep.cpp index 320a786af6c..2faaa4e0cbf 100644 --- a/src/plugins/qmakeprojectmanager/qmakestep.cpp +++ b/src/plugins/qmakeprojectmanager/qmakestep.cpp @@ -338,7 +338,7 @@ void QMakeStep::runNextCommand() case State::RUN_MAKE_QMAKE_ALL: { auto *parser = new GnuMakeParser; - parser->setWorkingDirectory(processParameters()->workingDirectory()); + parser->addSearchDir(processParameters()->workingDirectory()); setOutputParser(parser); m_nextState = State::POST_PROCESS; startOneCommand(m_makeCommand); diff --git a/src/plugins/qtsupport/qtparser.cpp b/src/plugins/qtsupport/qtparser.cpp index 7b01fb874d7..364286c9f12 100644 --- a/src/plugins/qtsupport/qtparser.cpp +++ b/src/plugins/qtsupport/qtparser.cpp @@ -58,7 +58,7 @@ void QtParser::stdError(const QString &line) if (level.compare(QLatin1String("Note"), Qt::CaseInsensitive) == 0) type = Task::Unknown; CompileTask task(type, m_mocRegExp.cap(5).trimmed() /* description */, - Utils::FilePath::fromUserInput(m_mocRegExp.cap(1)) /* filename */, + absoluteFilePath(Utils::FilePath::fromUserInput(m_mocRegExp.cap(1))), lineno); emit addTask(task, 1); return; @@ -68,7 +68,7 @@ void QtParser::stdError(const QString &line) if (m_translationRegExp.cap(1) == QLatin1String("Error")) type = Task::Error; CompileTask task(type, m_translationRegExp.cap(2), - Utils::FilePath::fromUserInput(m_translationRegExp.cap(3))); + absoluteFilePath(Utils::FilePath::fromUserInput(m_translationRegExp.cap(3)))); emit addTask(task, 1); return; } diff --git a/src/plugins/qtsupport/qttestparser.cpp b/src/plugins/qtsupport/qttestparser.cpp index 40db932ca4c..45a8602e2fd 100644 --- a/src/plugins/qtsupport/qttestparser.cpp +++ b/src/plugins/qtsupport/qttestparser.cpp @@ -68,8 +68,8 @@ void QtTestParser::stdOutput(const QString &line) QTC_CHECK(locationPattern.isValid()); const QRegularExpressionMatch match = locationPattern.match(theLine); if (match.hasMatch()) { - m_currentTask.file = FilePath::fromString( - QDir::fromNativeSeparators(match.captured("file"))); + m_currentTask.file = absoluteFilePath(FilePath::fromString( + QDir::fromNativeSeparators(match.captured("file")))); m_currentTask.line = match.captured("line").toInt(); emitCurrentTask(); return;