From d52ac9a7084df220a5349468703c11cc1c0794c4 Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Fri, 19 Oct 2018 10:20:27 +0200 Subject: [PATCH] Clang: Fix unresolved #includes for ui_*.h headers ...with an extra parse. Previously, the creation of an e.g. "Qt Widgets Application" from the wizard could show code model errors in mainwindow.cpp. Depending on timing issues, the first error is either 1. 'ui_mainwindow.h' file not found (QTCREATORBUG-15187) The parse happened before the in-memory ui_mainwindow.h was generated by uic. The file system watcher can't help here as the #include was not resolved successfully. And libclang's reparse does not handle this case (it would need to remember all failed #include stats...). ==> Detect this case with the help of the include paths and trigger a full parse. 2. or: allocation of incomplete type... (QTCREATORBUG-15187) The parse happened after the generation of the in-memory ui_mainwindow.h, but before the clangbackend received the unsaved file. ==> Fix this by also writing the content of the unsaved file to our behind-the-scenes-created ui_mainwindow.h. Fixes: QTCREATORBUG-15187 Fixes: QTCREATORBUG-17002 Change-Id: I4f3a81adaa3d604746977a402c29f83fbc5b0e44 Reviewed-by: Ivan Donchevskii --- src/libs/clangsupport/filecontainer.cpp | 1 + src/libs/clangsupport/filecontainer.h | 7 ++ .../clangbackendcommunicator.cpp | 5 +- .../clangcodemodelunittestfiles.pri | 6 +- .../clangeditordocumentprocessor.cpp | 13 +++- .../clangeditordocumentprocessor.h | 3 +- .../clangmodelmanagersupport.cpp | 6 +- .../clanguiheaderondiskmanager.cpp | 10 +-- .../clanguiheaderondiskmanager.h | 2 +- .../source/clangcodemodelserver.cpp | 61 +++++++++++++++- .../source/clangcodemodelserver.h | 3 + .../clangbackend/source/clangdocument.cpp | 29 ++++++++ src/tools/clangbackend/source/clangdocument.h | 5 ++ .../clangbackend/source/clangdocumentjob.h | 3 + .../source/clangdocumentprocessor.cpp | 5 ++ .../source/clangdocumentprocessor.h | 2 + .../source/clangdocumentprocessors.cpp | 3 + .../clangbackend/source/clangdocuments.cpp | 1 + src/tools/clangbackend/source/clangjobs.cpp | 7 +- src/tools/clangbackend/source/clangjobs.h | 3 +- ...ngsupportivetranslationunitinitializer.cpp | 5 +- .../source/clangupdateannotationsjob.cpp | 27 +++++++ .../source/clangupdateannotationsjob.h | 4 + .../clangcodecompleteresults-test.cpp | 6 +- .../unittest/clangcodemodelserver-test.cpp | 73 +++++++++++++++++-- tests/unit/unittest/clangdocument-test.cpp | 12 +-- tests/unit/unittest/clangdocuments-test.cpp | 42 +++++------ .../unit/unittest/clangfollowsymbol-test.cpp | 4 +- .../clangreferencescollector-test.cpp | 1 + tests/unit/unittest/clangtooltipinfo-test.cpp | 1 + .../clangupdateannotationsjob-test.cpp | 14 +++- tests/unit/unittest/codecompleter-test.cpp | 22 +++++- .../codecompletionsextractor-test.cpp | 20 +++-- tests/unit/unittest/cursor-test.cpp | 1 + tests/unit/unittest/data/translationunits.cpp | 1 + tests/unit/unittest/data/uicmain.cpp | 3 + tests/unit/unittest/diagnostic-test.cpp | 1 + tests/unit/unittest/diagnosticset-test.cpp | 2 + tests/unit/unittest/fixit-test.cpp | 3 +- .../highlightingresultreporter-test.cpp | 1 + .../unittest/skippedsourceranges-test.cpp | 4 +- tests/unit/unittest/sourcelocation-test.cpp | 3 +- tests/unit/unittest/sourcerange-test.cpp | 1 + tests/unit/unittest/token-test.cpp | 2 +- tests/unit/unittest/tokenprocessor-test.cpp | 1 + 45 files changed, 359 insertions(+), 70 deletions(-) create mode 100644 tests/unit/unittest/data/uicmain.cpp diff --git a/src/libs/clangsupport/filecontainer.cpp b/src/libs/clangsupport/filecontainer.cpp index 7f95e4b1d47..0f6f8288c90 100644 --- a/src/libs/clangsupport/filecontainer.cpp +++ b/src/libs/clangsupport/filecontainer.cpp @@ -36,6 +36,7 @@ QDebug operator<<(QDebug debug, const FileContainer &container) debug.nospace() << "FileContainer(" << container.filePath << ", " << container.compilationArguments << ", " + << container.headerPaths << ", " << container.documentRevision << ", " << container.textCodecName; diff --git a/src/libs/clangsupport/filecontainer.h b/src/libs/clangsupport/filecontainer.h index 16beff0bac0..4f9595f5baf 100644 --- a/src/libs/clangsupport/filecontainer.h +++ b/src/libs/clangsupport/filecontainer.h @@ -53,11 +53,13 @@ public: FileContainer(const Utf8String &filePath, const Utf8StringVector &compilationArguments, + const Utf8StringVector &headerPaths, const Utf8String &unsavedFileContent = Utf8String(), bool hasUnsavedFileContent = false, quint32 documentRevision = 0) : filePath(filePath), compilationArguments(compilationArguments), + headerPaths(headerPaths), unsavedFileContent(unsavedFileContent), documentRevision(documentRevision), hasUnsavedFileContent(hasUnsavedFileContent) @@ -66,9 +68,11 @@ public: FileContainer(const Utf8String &filePath, const Utf8StringVector &compilationArguments, + const Utf8StringVector &headerPaths, quint32 documentRevision) : filePath(filePath), compilationArguments(compilationArguments), + headerPaths(headerPaths), documentRevision(documentRevision), hasUnsavedFileContent(false) { @@ -78,6 +82,7 @@ public: { out << container.filePath; out << container.compilationArguments; + out << container.headerPaths; out << container.unsavedFileContent; out << container.textCodecName; out << container.documentRevision; @@ -90,6 +95,7 @@ public: { in >> container.filePath; in >> container.compilationArguments; + in >> container.headerPaths; in >> container.unsavedFileContent; in >> container.textCodecName; in >> container.documentRevision; @@ -106,6 +112,7 @@ public: public: Utf8String filePath; Utf8StringVector compilationArguments; + Utf8StringVector headerPaths; Utf8String unsavedFileContent; Utf8String textCodecName; quint32 documentRevision = 0; diff --git a/src/plugins/clangcodemodel/clangbackendcommunicator.cpp b/src/plugins/clangcodemodel/clangbackendcommunicator.cpp index 34a363407a8..48b6de99599 100644 --- a/src/plugins/clangcodemodel/clangbackendcommunicator.cpp +++ b/src/plugins/clangcodemodel/clangbackendcommunicator.cpp @@ -374,9 +374,8 @@ void BackendCommunicator::documentsChangedWithRevisionCheck(Core::IDocument *doc const auto textDocument = qobject_cast(document); const auto filePath = textDocument->filePath().toString(); - documentsChangedWithRevisionCheck(FileContainer(filePath, - Utf8StringVector(), - textDocument->document()->revision())); + documentsChangedWithRevisionCheck( + FileContainer(filePath, {}, {}, textDocument->document()->revision())); } void BackendCommunicator::updateChangeContentStartPosition(const QString &filePath, int position) diff --git a/src/plugins/clangcodemodel/clangcodemodelunittestfiles.pri b/src/plugins/clangcodemodel/clangcodemodelunittestfiles.pri index 4d4bb226391..a7ef679399d 100644 --- a/src/plugins/clangcodemodel/clangcodemodelunittestfiles.pri +++ b/src/plugins/clangcodemodel/clangcodemodelunittestfiles.pri @@ -7,7 +7,8 @@ SOURCES += \ $$PWD/clangcompletioncontextanalyzer.cpp \ $$PWD/clangdiagnosticfilter.cpp \ $$PWD/clangfixitoperation.cpp \ - $$PWD/clanghighlightingresultreporter.cpp + $$PWD/clanghighlightingresultreporter.cpp \ + $$PWD/clanguiheaderondiskmanager.cpp HEADERS += \ $$PWD/clangactivationsequencecontextprocessor.h \ @@ -17,4 +18,5 @@ HEADERS += \ $$PWD/clangdiagnosticfilter.h \ $$PWD/clangfixitoperation.h \ $$PWD/clanghighlightingresultreporter.h \ - $$PWD/clangisdiagnosticrelatedtolocation.h + $$PWD/clangisdiagnosticrelatedtolocation.h \ + $$PWD/clanguiheaderondiskmanager.h diff --git a/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp b/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp index 959e90d22cc..0738aa8e70d 100644 --- a/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp +++ b/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp @@ -56,6 +56,7 @@ #include +#include #include #include #include @@ -614,7 +615,7 @@ void ClangEditorDocumentProcessor::updateBackendDocument(CppTools::ProjectPart & const QStringList compilationArguments = projectPartOptions + fileOptions.options(); m_communicator.documentsOpened( - {fileContainerWithOptionsAndDocumentContent(compilationArguments)}); + {fileContainerWithOptionsAndDocumentContent(compilationArguments, projectPart.headerPaths)}); ClangCodeModel::Utils::setLastSentDocumentRevision(filePath(), revision()); } @@ -672,10 +673,18 @@ ClangBackEnd::FileContainer ClangEditorDocumentProcessor::simpleFileContainer( } ClangBackEnd::FileContainer ClangEditorDocumentProcessor::fileContainerWithOptionsAndDocumentContent( - const QStringList &compilationArguments) const + const QStringList &compilationArguments, const ProjectExplorer::HeaderPaths headerPaths) const { + auto theHeaderPaths + = ::Utils::transform(headerPaths, [](const ProjectExplorer::HeaderPath path) { + return Utf8String(QDir::toNativeSeparators(path.path)); + }); + theHeaderPaths << QDir::toNativeSeparators( + ClangModelManagerSupport::instance()->dummyUiHeaderOnDiskDirPath()); + return ClangBackEnd::FileContainer(filePath(), Utf8StringVector(compilationArguments), + theHeaderPaths, textDocument()->toPlainText(), true, revision()); diff --git a/src/plugins/clangcodemodel/clangeditordocumentprocessor.h b/src/plugins/clangcodemodel/clangeditordocumentprocessor.h index 9229a601324..78d777ddfa9 100644 --- a/src/plugins/clangcodemodel/clangeditordocumentprocessor.h +++ b/src/plugins/clangcodemodel/clangeditordocumentprocessor.h @@ -124,7 +124,8 @@ private: const ClangBackEnd::DiagnosticContainer &firstHeaderErrorDiagnostic); ClangBackEnd::FileContainer simpleFileContainer(const QByteArray &codecName = QByteArray()) const; ClangBackEnd::FileContainer fileContainerWithOptionsAndDocumentContent( - const QStringList &compilationArguments) const; + const QStringList &compilationArguments, + const ProjectExplorer::HeaderPaths headerPaths) const; ClangBackEnd::FileContainer fileContainerWithDocumentContent() const; private: diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp index b3ac6005dfc..ee6f9847679 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp @@ -56,6 +56,7 @@ #include #include #include +#include using namespace ClangCodeModel; using namespace ClangCodeModel::Internal; @@ -317,7 +318,10 @@ void ClangModelManagerSupport::onAbstractEditorSupportContentsUpdated(const QStr { QTC_ASSERT(!filePath.isEmpty(), return); - const QString mappedPath = m_uiHeaderOnDiskManager.createIfNeeded(filePath); + if (content.size() == 0) + return; // Generation not yet finished. + + const QString mappedPath = m_uiHeaderOnDiskManager.write(filePath, content); m_communicator.unsavedFilesUpdated(mappedPath, content, 0); } diff --git a/src/plugins/clangcodemodel/clanguiheaderondiskmanager.cpp b/src/plugins/clangcodemodel/clanguiheaderondiskmanager.cpp index d08d3a55197..d17f69ed50a 100644 --- a/src/plugins/clangcodemodel/clanguiheaderondiskmanager.cpp +++ b/src/plugins/clangcodemodel/clanguiheaderondiskmanager.cpp @@ -38,13 +38,13 @@ UiHeaderOnDiskManager::UiHeaderOnDiskManager() : m_temporaryDir("clang-uiheader- QTC_CHECK(m_temporaryDir.isValid()); } -QString UiHeaderOnDiskManager::createIfNeeded(const QString &filePath) +QString UiHeaderOnDiskManager::write(const QString &filePath, const QByteArray &content) { const QString mappedPath = mapPath(filePath); - if (!QFileInfo::exists(mappedPath)) { - const bool fileCreated = QFile(mappedPath).open(QFile::WriteOnly); // touch file - QTC_CHECK(fileCreated); - } + QFile file(mappedPath); + const bool fileCreated = file.open(QFile::WriteOnly); + const qint64 bytesWritten = file.write(content); + QTC_CHECK(fileCreated && bytesWritten != -1); return mappedPath; } diff --git a/src/plugins/clangcodemodel/clanguiheaderondiskmanager.h b/src/plugins/clangcodemodel/clanguiheaderondiskmanager.h index dd90054d73e..a244fdb1781 100644 --- a/src/plugins/clangcodemodel/clanguiheaderondiskmanager.h +++ b/src/plugins/clangcodemodel/clanguiheaderondiskmanager.h @@ -36,7 +36,7 @@ class UiHeaderOnDiskManager public: UiHeaderOnDiskManager(); - QString createIfNeeded(const QString &filePath); + QString write(const QString &filePath, const QByteArray &content); QString remove(const QString &filePath); QString mapPath(const QString &filePath) const; diff --git a/src/tools/clangbackend/source/clangcodemodelserver.cpp b/src/tools/clangbackend/source/clangcodemodelserver.cpp index 619ea1c6a31..e82766cf5ee 100644 --- a/src/tools/clangbackend/source/clangcodemodelserver.cpp +++ b/src/tools/clangbackend/source/clangcodemodelserver.cpp @@ -28,11 +28,13 @@ #include "clangdocuments.h" #include "clangdocumentsuspenderresumer.h" #include "clangfilesystemwatcher.h" +#include "clangupdateannotationsjob.h" #include "codecompleter.h" #include "diagnosticset.h" #include "tokenprocessor.h" #include "clangexceptions.h" #include "skippedsourceranges.h" +#include "unsavedfile.h" #include #include @@ -42,7 +44,9 @@ #include #include +#include #include +#include Q_LOGGING_CATEGORY(serverLog, "qtc.clangbackend.server", QtWarningMsg); @@ -97,7 +101,10 @@ void ClangCodeModelServer::documentsOpened(const ClangBackEnd::DocumentsOpenedMe std::vector createdDocuments = documents.create(toCreate); for (auto &document : createdDocuments) { document.setDirtyIfDependencyIsMet(document.filePath()); - documentProcessors().create(document); + DocumentProcessor processor = documentProcessors().create(document); + processor.jobs().setJobFinishedCallback([this](const Jobs::RunningJob &a, IAsyncJob *b) { + onJobFinished(a, b); + }); } const std::vector resetDocuments_ = resetDocuments(toReset); @@ -163,6 +170,7 @@ void ClangCodeModelServer::unsavedFilesUpdated(const UnsavedFilesUpdatedMessage try { unsavedFiles.createOrUpdate(message.fileContainers); documents.updateDocumentsWithChangedDependencies(message.fileContainers); + resetDocumentsWithUnresolvedIncludes(documents.documents()); updateAnnotationsTimer.start(updateAnnotationsTimeOutInMs); } catch (const std::exception &exception) { @@ -393,6 +401,14 @@ void ClangCodeModelServer::processSuspendResumeJobs(const std::vector } } +void ClangCodeModelServer::onJobFinished(const Jobs::RunningJob &jobRecord, IAsyncJob *job) +{ + if (jobRecord.jobRequest.type == JobRequest::Type::UpdateAnnotations) { + const auto updateJob = static_cast(job); + resetDocumentsWithUnresolvedIncludes({updateJob->pinnedDocument()}); + } +} + void ClangCodeModelServer::categorizeFileContainers(const QVector &fileContainers, QVector &toCreate, DocumentResetInfos &toReset) const @@ -432,6 +448,49 @@ std::vector ClangCodeModelServer::resetDocuments(const DocumentResetIn return newDocuments; } +static bool isDocumentWithUnresolvedIncludesFixable(const Document &document, + const UnsavedFiles &unsavedFiles) +{ + for (uint i = 0; i < unsavedFiles.count(); ++i) { + const UnsavedFile &unsavedFile = unsavedFiles.at(i); + const Utf8String unsavedFilePath = QDir::cleanPath(unsavedFile.filePath()); + + for (const Utf8String &unresolvedPath : document.unresolvedFilePaths()) { + const QString documentDir = QFileInfo(document.filePath()).absolutePath(); + const QString candidate = QDir::cleanPath(documentDir + "/" + unresolvedPath.toString()); + + if (Utf8String(candidate) == unsavedFilePath) + return true; + + for (const Utf8String &headerPath : document.headerPaths()) { + Utf8String candidate = headerPath; + candidate.append(QStringLiteral("/")); + candidate.append(unresolvedPath); + candidate = QDir::cleanPath(candidate); + if (candidate == unsavedFilePath) + return true; + } + } + } + + return false; +} + +void ClangCodeModelServer::resetDocumentsWithUnresolvedIncludes( + const std::vector &documents) +{ + DocumentResetInfos toReset; + + for (const Document &document : documents) { + if (document.unresolvedFilePaths().isEmpty()) + continue; + if (isDocumentWithUnresolvedIncludesFixable(document, unsavedFiles)) + toReset << DocumentResetInfo{document, document.fileContainer()}; + } + + resetDocuments(toReset); +} + void ClangCodeModelServer::setUpdateAnnotationsTimeOutInMsForTestsOnly(int value) { updateAnnotationsTimeOutInMs = value; diff --git a/src/tools/clangbackend/source/clangcodemodelserver.h b/src/tools/clangbackend/source/clangcodemodelserver.h index 7379aafe333..14fefadcf25 100644 --- a/src/tools/clangbackend/source/clangcodemodelserver.h +++ b/src/tools/clangbackend/source/clangcodemodelserver.h @@ -83,10 +83,13 @@ private: void processTimerForVisibleButNotCurrentDocuments(); void processSuspendResumeJobs(const std::vector &documents); + void onJobFinished(const Jobs::RunningJob &jobRecord, IAsyncJob *job); + void categorizeFileContainers(const QVector &fileContainers, QVector &toCreate, DocumentResetInfos &toReset) const; std::vector resetDocuments(const DocumentResetInfos &infos); + void resetDocumentsWithUnresolvedIncludes(const std::vector &documents); void addAndRunUpdateJobs(std::vector documents); diff --git a/src/tools/clangbackend/source/clangdocument.cpp b/src/tools/clangbackend/source/clangdocument.cpp index 067864e60fe..672c9028541 100644 --- a/src/tools/clangbackend/source/clangdocument.cpp +++ b/src/tools/clangbackend/source/clangdocument.cpp @@ -51,6 +51,7 @@ class DocumentData public: DocumentData(const Utf8String &filePath, const Utf8StringVector &compilationArguments, + const Utf8StringVector &headerPaths, Documents &documents); ~DocumentData(); @@ -59,10 +60,12 @@ public: const Utf8String filePath; const Utf8StringVector compilationArguments; + const Utf8StringVector headerPaths; TranslationUnits translationUnits; QSet dependedFilePaths; + QSet unresolvedFilePaths; uint documentRevision = 0; @@ -80,10 +83,12 @@ public: DocumentData::DocumentData(const Utf8String &filePath, const Utf8StringVector &compilationArguments, + const Utf8StringVector &headerPaths, Documents &documents) : documents(documents), filePath(filePath), compilationArguments(compilationArguments), + headerPaths(headerPaths), translationUnits(filePath), isDirtyChangeTimePoint(Clock::now()) { @@ -97,10 +102,12 @@ DocumentData::~DocumentData() Document::Document(const Utf8String &filePath, const Utf8StringVector &compilationArguments, + const Utf8StringVector &headerPaths, Documents &documents, FileExistsCheck fileExistsCheck) : d(std::make_shared(filePath, compilationArguments, + headerPaths, documents)) { if (fileExistsCheck == FileExistsCheck::Check) @@ -164,12 +171,20 @@ Utf8StringVector Document::compilationArguments() const return d->compilationArguments; } +Utf8StringVector Document::headerPaths() const +{ + checkIfNull(); + + return d->headerPaths; +} + FileContainer Document::fileContainer() const { checkIfNull(); return FileContainer(d->filePath, d->compilationArguments, + d->headerPaths, Utf8String(), false, d->documentRevision); @@ -330,6 +345,20 @@ void Document::incorporateUpdaterResult(const TranslationUnitUpdateResult &resul } } +const QSet Document::unresolvedFilePaths() const +{ + checkIfNull(); + + return d->unresolvedFilePaths; +} + +void Document::setUnresolvedFilePaths(const QSet &unresolved) +{ + checkIfNull(); + + d->unresolvedFilePaths = unresolved; +} + TranslationUnit Document::translationUnit(PreferredTranslationUnit preferredTranslationUnit) const { checkIfNull(); diff --git a/src/tools/clangbackend/source/clangdocument.h b/src/tools/clangbackend/source/clangdocument.h index 90f5dd71b23..bb2eb42ab4b 100644 --- a/src/tools/clangbackend/source/clangdocument.h +++ b/src/tools/clangbackend/source/clangdocument.h @@ -61,6 +61,7 @@ public: Document() = default; Document(const Utf8String &filePath, const Utf8StringVector &compilationArguments, + const Utf8StringVector &headerPaths, Documents &documents, FileExistsCheck fileExistsCheck = FileExistsCheck::Check); ~Document(); @@ -80,6 +81,7 @@ public: Utf8String filePath() const; Utf8StringVector compilationArguments() const; + Utf8StringVector headerPaths() const; FileContainer fileContainer() const; uint documentRevision() const; @@ -106,6 +108,9 @@ public: TranslationUnitUpdateInput createUpdateInput() const; void incorporateUpdaterResult(const TranslationUnitUpdateResult &result) const; + const QSet unresolvedFilePaths() const; + void setUnresolvedFilePaths(const QSet &unresolved); + TranslationUnit translationUnit(PreferredTranslationUnit preferredTranslationUnit = PreferredTranslationUnit::RecentlyParsed) const; TranslationUnits &translationUnits() const; diff --git a/src/tools/clangbackend/source/clangdocumentjob.h b/src/tools/clangbackend/source/clangdocumentjob.h index 7808286ce0b..d9b71d3a438 100644 --- a/src/tools/clangbackend/source/clangdocumentjob.h +++ b/src/tools/clangbackend/source/clangdocumentjob.h @@ -37,6 +37,9 @@ namespace ClangBackEnd { template class DocumentJob : public AsyncJob { +public: + Document pinnedDocument() const { return m_pinnedDocument; } + protected: bool acquireDocument() { diff --git a/src/tools/clangbackend/source/clangdocumentprocessor.cpp b/src/tools/clangbackend/source/clangdocumentprocessor.cpp index e50195dbdbd..dd390c6ba68 100644 --- a/src/tools/clangbackend/source/clangdocumentprocessor.cpp +++ b/src/tools/clangbackend/source/clangdocumentprocessor.cpp @@ -76,6 +76,11 @@ DocumentProcessor::DocumentProcessor(const Document &document, { } +Jobs &DocumentProcessor::jobs() const +{ + return d->jobs; +} + JobRequest DocumentProcessor::createJobRequest( JobRequest::Type type, PreferredTranslationUnit preferredTranslationUnit) const diff --git a/src/tools/clangbackend/source/clangdocumentprocessor.h b/src/tools/clangbackend/source/clangdocumentprocessor.h index e4b49854465..7de2664322a 100644 --- a/src/tools/clangbackend/source/clangdocumentprocessor.h +++ b/src/tools/clangbackend/source/clangdocumentprocessor.h @@ -47,6 +47,8 @@ public: UnsavedFiles &unsavedFiles, ClangCodeModelClientInterface &client); + Jobs &jobs() const; + JobRequest createJobRequest(JobRequest::Type type, PreferredTranslationUnit preferredTranslationUnit = PreferredTranslationUnit::RecentlyParsed) const; diff --git a/src/tools/clangbackend/source/clangdocumentprocessors.cpp b/src/tools/clangbackend/source/clangdocumentprocessors.cpp index b4d4fbcdbd0..951e4ef7a17 100644 --- a/src/tools/clangbackend/source/clangdocumentprocessors.cpp +++ b/src/tools/clangbackend/source/clangdocumentprocessors.cpp @@ -84,6 +84,8 @@ void DocumentProcessors::reset(const Document &oldDocument, const Document &newD [](const JobRequest &job) { return job.isTakeOverable(); }); + const Jobs::JobFinishedCallback jobFinishedCallback + = processor(oldDocument).jobs().jobFinishedCallback(); // Remove current processor remove(oldDocument); @@ -92,6 +94,7 @@ void DocumentProcessors::reset(const Document &oldDocument, const Document &newD DocumentProcessor newProcessor = create(newDocument); for (const JobRequest &job : jobsForNewProcessor) newProcessor.addJob(job); + newProcessor.jobs().setJobFinishedCallback(jobFinishedCallback); } JobRequests DocumentProcessors::process() diff --git a/src/tools/clangbackend/source/clangdocuments.cpp b/src/tools/clangbackend/source/clangdocuments.cpp index 83178f3d627..7b274d7755c 100644 --- a/src/tools/clangbackend/source/clangdocuments.cpp +++ b/src/tools/clangbackend/source/clangdocuments.cpp @@ -206,6 +206,7 @@ Document Documents::createDocument(const FileContainer &fileContainer) documents_.emplace_back(fileContainer.filePath, fileContainer.compilationArguments, + fileContainer.headerPaths, *this, checkIfFileExists); diff --git a/src/tools/clangbackend/source/clangjobs.cpp b/src/tools/clangbackend/source/clangjobs.cpp index 9e33788da3e..572bb9bde3d 100644 --- a/src/tools/clangbackend/source/clangjobs.cpp +++ b/src/tools/clangbackend/source/clangjobs.cpp @@ -121,6 +121,11 @@ JobRequests Jobs::stop() return queuedJobs; } +Jobs::JobFinishedCallback Jobs::finishedCallback() const +{ + return m_jobFinishedCallback; +} + JobRequests Jobs::runJobs(const JobRequests &jobsRequests) { JobRequests jobsStarted; @@ -165,7 +170,7 @@ void Jobs::onJobFinished(IAsyncJob *asyncJob) if (m_jobFinishedCallback) { const RunningJob runningJob = m_running.value(asyncJob); - m_jobFinishedCallback(runningJob); + m_jobFinishedCallback(runningJob, asyncJob); } m_running.remove(asyncJob); diff --git a/src/tools/clangbackend/source/clangjobs.h b/src/tools/clangbackend/source/clangjobs.h index 5d5b2d460cb..3b4966a8e1b 100644 --- a/src/tools/clangbackend/source/clangjobs.h +++ b/src/tools/clangbackend/source/clangjobs.h @@ -50,7 +50,7 @@ public: }; using RunningJobs = QHash; - using JobFinishedCallback = std::function; + using JobFinishedCallback = std::function; public: Jobs(Documents &documents, @@ -72,6 +72,7 @@ public: JobRequests process(); JobRequests stop(); + JobFinishedCallback finishedCallback() const; void setJobFinishedCallback(const JobFinishedCallback &jobFinishedCallback); public /*for tests*/: diff --git a/src/tools/clangbackend/source/clangsupportivetranslationunitinitializer.cpp b/src/tools/clangbackend/source/clangsupportivetranslationunitinitializer.cpp index ac9a1dfb853..07d50a14116 100644 --- a/src/tools/clangbackend/source/clangsupportivetranslationunitinitializer.cpp +++ b/src/tools/clangbackend/source/clangsupportivetranslationunitinitializer.cpp @@ -58,7 +58,7 @@ void SupportiveTranslationUnitInitializer::startInitializing() m_document.translationUnits().createAndAppend(); - m_jobs.setJobFinishedCallback([this](const Jobs::RunningJob &runningJob) { + m_jobs.setJobFinishedCallback([this](const Jobs::RunningJob &runningJob, IAsyncJob *) { checkIfParseJobFinished(runningJob); }); addJob(JobRequest::Type::ParseSupportiveTranslationUnit); @@ -69,7 +69,8 @@ void SupportiveTranslationUnitInitializer::startInitializing() void SupportiveTranslationUnitInitializer::abort() { - m_jobs.setJobFinishedCallback(Jobs::JobFinishedCallback()); + if (m_document.translationUnits().size() > 1) + m_jobs.setJobFinishedCallback(Jobs::JobFinishedCallback()); m_state = State::Aborted; } diff --git a/src/tools/clangbackend/source/clangupdateannotationsjob.cpp b/src/tools/clangbackend/source/clangupdateannotationsjob.cpp index 6d836633d74..5a28d64ac2b 100644 --- a/src/tools/clangbackend/source/clangupdateannotationsjob.cpp +++ b/src/tools/clangbackend/source/clangupdateannotationsjob.cpp @@ -31,8 +31,30 @@ #include +#include + namespace ClangBackEnd { +// TODO: Add libclang API for this. +static QSet unresolvedFilePaths(const QVector &diagnostics) +{ + // We expect something like: + // fatal error: 'ops.h' file not found + QRegularExpression re("'(.*)' file not found"); + QSet unresolved; + + for (const DiagnosticContainer &diagnostic : diagnostics) { + if (diagnostic.severity == DiagnosticSeverity::Fatal + && diagnostic.category == Utf8StringLiteral("Lexical or Preprocessor Issue")) { + const QString path = re.match(diagnostic.text).captured(1); + if (!path.isEmpty()) + unresolved << path; + } + } + + return unresolved; +} + IAsyncJob::AsyncPrepareResult UpdateAnnotationsJob::prepareAsyncRun() { const JobRequest jobRequest = context().jobRequest; @@ -53,6 +75,9 @@ IAsyncJob::AsyncPrepareResult UpdateAnnotationsJob::prepareAsyncRun() asyncResult.diagnostics, asyncResult.tokenInfos, asyncResult.skippedSourceRanges); + asyncResult.unresolvedFilePaths.unite( + unresolvedFilePaths({asyncResult.firstHeaderErrorDiagnostic})); + asyncResult.unresolvedFilePaths.unite(unresolvedFilePaths(asyncResult.diagnostics)); return asyncResult; }); @@ -66,6 +91,8 @@ void UpdateAnnotationsJob::finalizeAsyncRun() const AsyncResult result = asyncResult(); m_pinnedDocument.incorporateUpdaterResult(result.updateResult); + m_pinnedDocument.setUnresolvedFilePaths(result.unresolvedFilePaths); + context().client->annotations(AnnotationsMessage(m_pinnedFileContainer, result.diagnostics, result.firstHeaderErrorDiagnostic, diff --git a/src/tools/clangbackend/source/clangupdateannotationsjob.h b/src/tools/clangbackend/source/clangupdateannotationsjob.h index 8c0f89f430f..8a813586ea7 100644 --- a/src/tools/clangbackend/source/clangupdateannotationsjob.h +++ b/src/tools/clangbackend/source/clangupdateannotationsjob.h @@ -31,11 +31,15 @@ #include #include +#include +#include + namespace ClangBackEnd { struct UpdateAnnotationsJobResult { TranslationUnitUpdateResult updateResult; + QSet unresolvedFilePaths; ClangBackEnd::DiagnosticContainer firstHeaderErrorDiagnostic; QVector diagnostics; diff --git a/tests/unit/unittest/clangcodecompleteresults-test.cpp b/tests/unit/unittest/clangcodecompleteresults-test.cpp index b95e1db266a..30356a3744b 100644 --- a/tests/unit/unittest/clangcodecompleteresults-test.cpp +++ b/tests/unit/unittest/clangcodecompleteresults-test.cpp @@ -56,7 +56,8 @@ TEST(ClangCodeCompleteResultsSlowTest, GetData) ClangBackEnd::UnsavedFiles unsavedFiles; ClangBackEnd::Documents documents{unsavedFiles}; Document document(Utf8StringLiteral(TESTDATA_DIR"/complete_testfile_1.cpp"), - Utf8StringVector(), + {}, + {}, documents); Utf8String nativeFilePath = FilePath::toNativeSeparators(document.filePath()); document.parse(); @@ -85,7 +86,8 @@ TEST(ClangCodeCompleteResultsSlowTest, MoveClangCodeCompleteResults) ClangBackEnd::UnsavedFiles unsavedFiles; ClangBackEnd::Documents documents{unsavedFiles}; Document document(Utf8StringLiteral(TESTDATA_DIR"/complete_testfile_1.cpp"), - Utf8StringVector(), + {}, + {}, documents); Utf8String nativeFilePath = FilePath::toNativeSeparators(document.filePath()); document.parse(); diff --git a/tests/unit/unittest/clangcodemodelserver-test.cpp b/tests/unit/unittest/clangcodemodelserver-test.cpp index ea0be4a6187..c74e2a96d8e 100644 --- a/tests/unit/unittest/clangcodemodelserver-test.cpp +++ b/tests/unit/unittest/clangcodemodelserver-test.cpp @@ -37,7 +37,10 @@ #include +#include + #include +#include #include #include @@ -119,11 +122,13 @@ protected: int expectedAnnotationsMessages = AnnotationJobsMultiplier); void openDocument(const Utf8String &filePath, const Utf8StringVector &compilationArguments, + const Utf8StringVector &headerPaths, int expectedAnnotationsMessages = AnnotationJobsMultiplier); void openDocuments(int expectedAnnotationsMessages); void openDocumentWithUnsavedContent(const Utf8String &filePath, const Utf8String &content); void closeDocument(const Utf8String &filePath); + void updateUnsavedFile(const Utf8String &filePath, const Utf8String &fileContent); void updateUnsavedContent(const Utf8String &filePath, const Utf8String &fileContent, quint32 revisionNumber); @@ -172,6 +177,8 @@ protected: const Utf8String aFilePath = Utf8StringLiteral("afile.cpp"); const Utf8String anExistingFilePath = Utf8StringLiteral(TESTDATA_DIR"/complete_translationunit_parse_error.cpp"); + + const Utf8String uicMainPath = Utf8StringLiteral(TESTDATA_DIR"/uicmain.cpp"); }; using ClangCodeModelServerSlowTest = ClangCodeModelServer; @@ -428,6 +435,52 @@ TEST_F(ClangCodeModelServerSlowTest, TakeOverJobsOnDocumentChange) updateVisibilty(filePathC, filePathC); // Enable processing jobs } +TEST_F(ClangCodeModelServerSlowTest, UicHeaderAvailableBeforeParse) +{ + // Write ui file + ClangCodeModel::Internal::UiHeaderOnDiskManager uiManager; + const QByteArray content = "class UicObject{};"; + const QString uiHeaderFilePath = uiManager.write("uicheader.h", content); + + // Open document + openDocument(uicMainPath, + {Utf8StringLiteral("-I"), Utf8String(uiManager.directoryPath())}, + {uiManager.directoryPath()}, + AnnotationJobsMultiplier); + updateVisibilty(uicMainPath, uicMainPath); + ASSERT_TRUE(waitUntilAllJobsFinished()); + + // Check + ASSERT_THAT(documents.document(uicMainPath).dependedFilePaths(), + Contains(uiHeaderFilePath)); +} + +TEST_F(ClangCodeModelServerSlowTest, UicHeaderAvailableAfterParse) +{ + ClangCodeModel::Internal::UiHeaderOnDiskManager uiManager; + const QString uiHeaderFilePath = uiManager.mapPath("uicheader.h"); + + // Open document + openDocument(uicMainPath, + {Utf8StringLiteral("-I"), Utf8String(uiManager.directoryPath())}, + {uiManager.directoryPath()}, + 2 * AnnotationJobsMultiplier); + updateVisibilty(uicMainPath, uicMainPath); + ASSERT_TRUE(waitUntilAllJobsFinished()); + ASSERT_THAT(documents.document(uicMainPath).dependedFilePaths(), + Not(Contains(uiHeaderFilePath))); + + // Write ui file and notify backend + const QByteArray content = "class UicObject{};"; + uiManager.write("uicheader.h", content); + updateUnsavedFile(Utf8String(uiHeaderFilePath), Utf8String::fromByteArray(content)); + + // Check + ASSERT_TRUE(waitUntilAllJobsFinished()); + ASSERT_THAT(documents.document(uicMainPath).dependedFilePaths(), + Contains(uiHeaderFilePath)); +} + void ClangCodeModelServer::SetUp() { clangServer.setClient(&mockClangCodeModelClient); @@ -454,14 +507,15 @@ bool ClangCodeModelServer::waitUntilAllJobsFinished(int timeOutInMs) void ClangCodeModelServer::openDocument(const Utf8String &filePath, int expectedAnnotationsMessages) { - openDocument(filePath, {}, expectedAnnotationsMessages); + openDocument(filePath, {}, {}, expectedAnnotationsMessages); } void ClangCodeModelServer::openDocument(const Utf8String &filePath, const Utf8StringVector &compilationArguments, + const Utf8StringVector &headerPaths, int expectedAnnotationsMessages) { - const FileContainer fileContainer(filePath, compilationArguments); + const FileContainer fileContainer(filePath, compilationArguments, headerPaths); const DocumentsOpenedMessage message({fileContainer}, filePath, {filePath}); expectAnnotations(expectedAnnotationsMessages); @@ -608,7 +662,7 @@ void ClangCodeModelServer::requestAnnotations(const Utf8String &filePath) void ClangCodeModelServer::requestReferences(quint32 documentRevision) { - const FileContainer fileContainer{filePathC, Utf8StringVector(), documentRevision}; + const FileContainer fileContainer{filePathC, {}, {}, documentRevision}; const RequestReferencesMessage message{fileContainer, 3, 9}; clangServer.requestReferences(message); @@ -616,7 +670,7 @@ void ClangCodeModelServer::requestReferences(quint32 documentRevision) void ClangCodeModelServer::requestFollowSymbol(quint32 documentRevision) { - const FileContainer fileContainer{filePathC, Utf8StringVector(), documentRevision}; + const FileContainer fileContainer{filePathC, {}, {}, documentRevision}; const RequestFollowSymbolMessage message{fileContainer, 43, 9}; clangServer.requestFollowSymbol(message); @@ -647,7 +701,7 @@ void ClangCodeModelServer::updateUnsavedContent(const Utf8String &filePath, void ClangCodeModelServer::removeUnsavedFile(const Utf8String &filePath) { - const FileContainer fileContainer(filePath, Utf8StringVector(), 74); + const FileContainer fileContainer(filePath, {}, {}, 74); const DocumentsChangedMessage message({fileContainer}); clangServer.documentsChanged(message); @@ -661,6 +715,15 @@ void ClangCodeModelServer::closeDocument(const Utf8String &filePath) clangServer.documentsClosed(message); } +void ClangCodeModelServer::updateUnsavedFile(const Utf8String &filePath, + const Utf8String &fileContent) +{ + const FileContainer fileContainer(filePath, fileContent, true, 0); + const UnsavedFilesUpdatedMessage message({fileContainer}); + + clangServer.unsavedFilesUpdated(message); +} + void ClangCodeModelServer::openDocumentAndWaitForFinished( const Utf8String &filePath, int expectedAnnotationsMessages) { diff --git a/tests/unit/unittest/clangdocument-test.cpp b/tests/unit/unittest/clangdocument-test.cpp index cf7b7dcb9df..26a4ab1bfd8 100644 --- a/tests/unit/unittest/clangdocument-test.cpp +++ b/tests/unit/unittest/clangdocument-test.cpp @@ -100,15 +100,17 @@ TEST_F(Document, DefaultDocumentIsNotIntact) TEST_F(Document, ThrowExceptionForNonExistingFilePath) { - ASSERT_THROW(::Document(Utf8StringLiteral("file.cpp"), Utf8StringVector(), - documents), + ASSERT_THROW(::Document(Utf8StringLiteral("file.cpp"), {}, {}, documents), ClangBackEnd::DocumentFileDoesNotExistException); } TEST_F(Document, ThrowNoExceptionForNonExistingFilePathIfDoNotCheckIfFileExistsIsSet) { - ASSERT_NO_THROW(::Document(Utf8StringLiteral("file.cpp"), Utf8StringVector(), - documents, ::Document::FileExistsCheck::DoNotCheck)); + ASSERT_NO_THROW(::Document(Utf8StringLiteral("file.cpp"), + {}, + {}, + documents, + ::Document::FileExistsCheck::DoNotCheck)); } TEST_F(Document, DocumentIsValid) @@ -342,7 +344,7 @@ void Document::SetUp() QTemporaryFile temporaryFile; EXPECT_TRUE(temporaryFile.open()); EXPECT_TRUE(temporaryFile.write(readContentFromDocumentFile())); - ::Document document(temporaryFile.fileName(), Utf8StringVector(), documents); + ::Document document(temporaryFile.fileName(), {}, {}, documents); return document; } diff --git a/tests/unit/unittest/clangdocuments-test.cpp b/tests/unit/unittest/clangdocuments-test.cpp index 3597df810df..71a2ebed804 100644 --- a/tests/unit/unittest/clangdocuments-test.cpp +++ b/tests/unit/unittest/clangdocuments-test.cpp @@ -99,7 +99,7 @@ TEST_F(Documents, DoNotThrowForAddingNonExistingFileWithUnsavedContent) TEST_F(Documents, Add) { - ClangBackEnd::FileContainer fileContainer(filePath, Utf8StringVector(), 74u); + ClangBackEnd::FileContainer fileContainer(filePath, {}, {}, 74u); documents.create({fileContainer}); @@ -109,8 +109,8 @@ TEST_F(Documents, Add) TEST_F(Documents, CreateWithUnsavedContentSetsDependenciesDirty) { - ClangBackEnd::FileContainer fileContainer(filePath, Utf8StringVector(), 74u); - ClangBackEnd::FileContainer fileContainerWithUnsavedContent(otherFilePath, Utf8StringVector(), Utf8String(), true, 2u); + ClangBackEnd::FileContainer fileContainer(filePath, {}, {}, 74u); + ClangBackEnd::FileContainer fileContainerWithUnsavedContent(otherFilePath, {}, {}, Utf8String(), true, 2u); auto dependentDocument = documents.create({fileContainer}).at(0); dependentDocument.setDependedFilePaths(QSet() << filePath << otherFilePath); @@ -121,7 +121,7 @@ TEST_F(Documents, CreateWithUnsavedContentSetsDependenciesDirty) TEST_F(Documents, AddAndTestCreatedTranslationUnit) { - ClangBackEnd::FileContainer fileContainer(filePath, Utf8StringVector(), 74u); + ClangBackEnd::FileContainer fileContainer(filePath, {}, {}, 74u); auto createdDocuments = documents.create({fileContainer}); @@ -130,7 +130,7 @@ TEST_F(Documents, AddAndTestCreatedTranslationUnit) TEST_F(Documents, ThrowForCreatingAnExistingDocument) { - ClangBackEnd::FileContainer fileContainer(filePath, Utf8StringVector(), 74u); + ClangBackEnd::FileContainer fileContainer(filePath, {}, {}, 74u); documents.create({fileContainer}); ASSERT_THROW(documents.create({fileContainer}), ClangBackEnd::DocumentAlreadyExistsException); @@ -138,15 +138,15 @@ TEST_F(Documents, ThrowForCreatingAnExistingDocument) TEST_F(Documents, ThrowForUpdatingANonExistingDocument) { - ClangBackEnd::FileContainer fileContainer(filePath, Utf8StringVector(), 74u); + ClangBackEnd::FileContainer fileContainer(filePath, {}, {}, 74u); ASSERT_THROW(documents.update({fileContainer}), ClangBackEnd::DocumentDoesNotExistException); } TEST_F(Documents, UpdateSingle) { - ClangBackEnd::FileContainer createFileContainer(filePath, Utf8StringVector(), 74u); - ClangBackEnd::FileContainer updateFileContainer(filePath, Utf8StringVector(), 75u); + ClangBackEnd::FileContainer createFileContainer(filePath, {}, {}, 74u); + ClangBackEnd::FileContainer updateFileContainer(filePath, {}, {}, 75u); documents.create({createFileContainer}); documents.update({updateFileContainer}); @@ -156,8 +156,8 @@ TEST_F(Documents, UpdateSingle) TEST_F(Documents, UpdateReturnsUpdatedDocument) { - ClangBackEnd::FileContainer createFileContainer(filePath, Utf8StringVector(), 74u); - ClangBackEnd::FileContainer updateFileContainer(filePath, Utf8StringVector(), 75u); + ClangBackEnd::FileContainer createFileContainer(filePath, {}, {}, 74u); + ClangBackEnd::FileContainer updateFileContainer(filePath, {}, {}, 75u); documents.create({createFileContainer}); const std::vector updatedDocuments = documents.update({updateFileContainer}); @@ -169,9 +169,9 @@ TEST_F(Documents, UpdateReturnsUpdatedDocument) // TODO: Does this test still makes sense? TEST_F(Documents, UpdateMultiple) { - ClangBackEnd::FileContainer fileContainer(filePath, Utf8StringVector(), 74u); - ClangBackEnd::FileContainer fileContainerWithOtherProject(filePath, Utf8StringVector(), 74u); - ClangBackEnd::FileContainer updatedFileContainer(filePath, Utf8StringVector(), 75u); + ClangBackEnd::FileContainer fileContainer(filePath, {}, {}, 74u); + ClangBackEnd::FileContainer fileContainerWithOtherProject(filePath, {}, {}, 74u); + ClangBackEnd::FileContainer updatedFileContainer(filePath, {}, {}, 75u); documents.create({fileContainer, fileContainerWithOtherProject}); documents.update({updatedFileContainer}); @@ -181,8 +181,8 @@ TEST_F(Documents, UpdateMultiple) TEST_F(DocumentsSlowTest, UpdateUnsavedFileAndCheckForReparse) { - ClangBackEnd::FileContainer fileContainer(filePath, Utf8StringVector(), 74u); - ClangBackEnd::FileContainer headerContainer(headerPath, Utf8StringVector(), 74u); + ClangBackEnd::FileContainer fileContainer(filePath, {}, {}, 74u); + ClangBackEnd::FileContainer headerContainer(headerPath, {}, {}, 74u); ClangBackEnd::FileContainer headerContainerWithUnsavedContent(headerPath, Utf8String(), true, 75u); documents.create({fileContainer, headerContainer}); Document document = documents.document(filePath); @@ -195,8 +195,8 @@ TEST_F(DocumentsSlowTest, UpdateUnsavedFileAndCheckForReparse) TEST_F(DocumentsSlowTest, RemoveFileAndCheckForReparse) { - ClangBackEnd::FileContainer fileContainer(filePath, Utf8StringVector(), 74u); - ClangBackEnd::FileContainer headerContainer(headerPath, Utf8StringVector(), 74u); + ClangBackEnd::FileContainer fileContainer(filePath, {}, {}, 74u); + ClangBackEnd::FileContainer headerContainer(headerPath, {}, {}, 74u); ClangBackEnd::FileContainer headerContainerWithUnsavedContent(headerPath, Utf8String(), true, 75u); documents.create({fileContainer, headerContainer}); Document document = documents.document(filePath); @@ -209,7 +209,7 @@ TEST_F(DocumentsSlowTest, RemoveFileAndCheckForReparse) TEST_F(Documents, DontGetNewerFileContainerIfRevisionIsTheSame) { - ClangBackEnd::FileContainer fileContainer(filePath, Utf8StringVector(), 74u); + ClangBackEnd::FileContainer fileContainer(filePath, {}, {}, 74u); documents.create({fileContainer}); auto newerFileContainers = documents.newerFileContainers({fileContainer}); @@ -219,8 +219,8 @@ TEST_F(Documents, DontGetNewerFileContainerIfRevisionIsTheSame) TEST_F(Documents, GetNewerFileContainerIfRevisionIsDifferent) { - ClangBackEnd::FileContainer fileContainer(filePath, Utf8StringVector(), 74u); - ClangBackEnd::FileContainer newerContainer(filePath, Utf8StringVector(), 75u); + ClangBackEnd::FileContainer fileContainer(filePath, {}, {}, 74u); + ClangBackEnd::FileContainer newerContainer(filePath, {}, {}, 75u); documents.create({fileContainer}); auto newerFileContainers = documents.newerFileContainers({newerContainer}); @@ -256,7 +256,7 @@ TEST_F(Documents, RemoveAllValidIfExceptionIsThrown) ClangBackEnd::DocumentDoesNotExistException); ASSERT_THAT(documents.documents(), - Not(Contains(Document(filePath, Utf8StringVector(), documents)))); + Not(Contains(Document(filePath, {}, {}, documents)))); } TEST_F(Documents, HasDocument) diff --git a/tests/unit/unittest/clangfollowsymbol-test.cpp b/tests/unit/unittest/clangfollowsymbol-test.cpp index d4dabfbf878..628aa076186 100644 --- a/tests/unit/unittest/clangfollowsymbol-test.cpp +++ b/tests/unit/unittest/clangfollowsymbol-test.cpp @@ -114,8 +114,8 @@ public: ClangBackEnd::Documents documents{unsavedFiles}; Utf8StringVector compilationArguments{ TestEnvironment::addPlatformArguments({Utf8StringLiteral("-std=c++14")})}; - Document document = {sourceFilePath, compilationArguments, documents}; - Document headerDocument = {headerFilePath, compilationArguments, documents}; + Document document = {sourceFilePath, compilationArguments, {}, documents}; + Document headerDocument = {headerFilePath, compilationArguments, {}, documents}; QVector deps{sourceFilePath, cursorPath}; }; diff --git a/tests/unit/unittest/clangreferencescollector-test.cpp b/tests/unit/unittest/clangreferencescollector-test.cpp index 177fc6d8567..acf7c42ac3d 100644 --- a/tests/unit/unittest/clangreferencescollector-test.cpp +++ b/tests/unit/unittest/clangreferencescollector-test.cpp @@ -60,6 +60,7 @@ struct Data { ClangBackEnd::Documents documents{unsavedFiles}; Document document{Utf8StringLiteral(TESTDATA_DIR"/references.cpp"), TestEnvironment::addPlatformArguments({Utf8StringLiteral("-std=c++14")}), + {}, documents}; }; diff --git a/tests/unit/unittest/clangtooltipinfo-test.cpp b/tests/unit/unittest/clangtooltipinfo-test.cpp index 520af95f67a..baca6cb623d 100644 --- a/tests/unit/unittest/clangtooltipinfo-test.cpp +++ b/tests/unit/unittest/clangtooltipinfo-test.cpp @@ -85,6 +85,7 @@ struct Data { ClangBackEnd::Documents documents{unsavedFiles}; Document document{Utf8StringLiteral(TESTDATA_DIR "/tooltipinfo.cpp"), {Utf8StringLiteral("-std=c++14")}, + {}, documents}; UnitTest::RunDocumentParse _1{document}; }; diff --git a/tests/unit/unittest/clangupdateannotationsjob-test.cpp b/tests/unit/unittest/clangupdateannotationsjob-test.cpp index 53a593973d7..0bcd5a67c0d 100644 --- a/tests/unit/unittest/clangupdateannotationsjob-test.cpp +++ b/tests/unit/unittest/clangupdateannotationsjob-test.cpp @@ -97,7 +97,7 @@ TEST_F(UpdateAnnotationsJobSlowTest, DontSendAnnotationsIfDocumentRevisionChange ASSERT_TRUE(waitUntilJobFinished(job)); } -TEST_F(UpdateAnnotationsJobSlowTest, UpdatesTranslationUnit) +TEST_F(UpdateAnnotationsJobSlowTest, UpdatesDependendFilePaths) { const QSet dependendOnFilesBefore = document.dependedFilePaths(); job.setContext(jobContext); @@ -109,4 +109,16 @@ TEST_F(UpdateAnnotationsJobSlowTest, UpdatesTranslationUnit) ASSERT_THAT(dependendOnFilesBefore, Not(document.dependedFilePaths())); } +TEST_F(UpdateAnnotationsJobSlowTest, UpdatesUnresolvedFilePaths) +{ + const QSet unresolvedBefore = document.unresolvedFilePaths(); + job.setContext(jobContext); + job.prepareAsyncRun(); + + job.runAsync(); + ASSERT_TRUE(waitUntilJobFinished(job)); + + ASSERT_THAT(unresolvedBefore, Not(document.unresolvedFilePaths())); +} + } // anonymous diff --git a/tests/unit/unittest/codecompleter-test.cpp b/tests/unit/unittest/codecompleter-test.cpp index 539afba9b67..ec865aacbde 100644 --- a/tests/unit/unittest/codecompleter-test.cpp +++ b/tests/unit/unittest/codecompleter-test.cpp @@ -109,119 +109,139 @@ protected: QString targetHeaderPath{includeDirectory.path() + QStringLiteral("/complete_target_header.h")}; ClangBackEnd::FileContainer mainFileContainer{Utf8StringLiteral(TESTDATA_DIR "/complete_completer_main.cpp"), - Utf8StringVector{includePathArgument}}; + Utf8StringVector{includePathArgument}, + {}}; ClangBackEnd::UnsavedFiles unsavedFiles; ClangBackEnd::Documents documents{unsavedFiles}; ClangBackEnd::Document document; QScopedPointer completer; ClangBackEnd::FileContainer unsavedMainFileContainer{mainFileContainer.filePath, {includePathArgument}, + {}, readFileContent("/complete_completer_main_unsaved.cpp"), true}; ClangBackEnd::FileContainer unsavedTargetHeaderFileContainer{targetHeaderPath, {includePathArgument}, + {}, readFileContent("/complete_target_header_unsaved.h"), true}; ClangBackEnd::FileContainer arrowFileContainer{ Utf8StringLiteral(TESTDATA_DIR"/complete_arrow.cpp"), {includePathArgument}, + {}, readFileContent("/complete_arrow.cpp"), true }; ClangBackEnd::FileContainer dotArrowCorrectionForPointerFileContainer{ Utf8StringLiteral(TESTDATA_DIR"/complete_withDotArrowCorrectionForPointer.cpp"), {includePathArgument}, + {}, readFileContent("/complete_withDotArrowCorrectionForPointer.cpp"), true }; ClangBackEnd::FileContainer dotArrowCorrectionForPointerFileContainerBeforeTyping{ Utf8StringLiteral(TESTDATA_DIR"/complete_withDotArrowCorrectionForPointer.cpp"), {includePathArgument}, + {}, readFileContent("/complete_withDotArrowCorrectionForPointer_beforeTyping.cpp"), true }; ClangBackEnd::FileContainer dotArrowCorrectionForPointerFileContainerAfterTyping{ Utf8StringLiteral(TESTDATA_DIR"/complete_withDotArrowCorrectionForPointer.cpp"), {includePathArgument}, + {}, readFileContent("/complete_withDotArrowCorrectionForPointer_afterTyping.cpp"), true }; ClangBackEnd::FileContainer dotArrowCorrectionForPointerFileContainerInitial{ Utf8StringLiteral(TESTDATA_DIR"/complete_withDotArrowCorrectionForPointer.cpp"), {includePathArgument}, + {}, readFileContent("/complete_withDotArrowCorrectionForPointerInitial.cpp"), true }; ClangBackEnd::FileContainer dotArrowCorrectionForPointerFileContainerUpdated{ Utf8StringLiteral(TESTDATA_DIR"/complete_withDotArrowCorrectionForPointer.cpp"), {includePathArgument}, + {}, readFileContent("/complete_withDotArrowCorrectionForPointerUpdated.cpp"), true }; ClangBackEnd::FileContainer noDotArrowCorrectionForObjectFileContainer{ Utf8StringLiteral(TESTDATA_DIR"/complete_withNoDotArrowCorrectionForObject.cpp"), {includePathArgument}, + {}, readFileContent("/complete_withNoDotArrowCorrectionForObject.cpp"), true }; ClangBackEnd::FileContainer noDotArrowCorrectionForFloatFileContainer{ Utf8StringLiteral(TESTDATA_DIR"/complete_withNoDotArrowCorrectionForFloat.cpp"), {includePathArgument}, + {}, readFileContent("/complete_withNoDotArrowCorrectionForFloat.cpp"), true }; ClangBackEnd::FileContainer noDotArrowCorrectionForObjectWithArrowOperatortFileContainer{ Utf8StringLiteral(TESTDATA_DIR"/complete_withNoDotArrowCorrectionForObjectWithArrowOperator.cpp"), {includePathArgument}, + {}, readFileContent("/complete_withNoDotArrowCorrectionForObjectWithArrowOperator.cpp"), true }; ClangBackEnd::FileContainer noDotArrowCorrectionForDotDotFileContainer{ Utf8StringLiteral(TESTDATA_DIR"/complete_withNoDotArrowCorrectionForDotDot.cpp"), {includePathArgument}, + {}, readFileContent("/complete_withNoDotArrowCorrectionForDotDot.cpp"), true }; ClangBackEnd::FileContainer noDotArrowCorrectionForArrowDotFileContainer{ Utf8StringLiteral(TESTDATA_DIR"/complete_withNoDotArrowCorrectionForArrowDot.cpp"), {includePathArgument}, + {}, readFileContent("/complete_withNoDotArrowCorrectionForArrowDot.cpp"), true }; ClangBackEnd::FileContainer noDotArrowCorrectionForOnlyDotFileContainer{ Utf8StringLiteral(TESTDATA_DIR"/complete_withNoDotArrowCorrectionForOnlyDot.cpp"), {includePathArgument}, + {}, readFileContent("/complete_withNoDotArrowCorrectionForOnlyDot.cpp"), true }; ClangBackEnd::FileContainer noDotArrowCorrectionForColonColonFileContainer{ Utf8StringLiteral(TESTDATA_DIR"/complete_withNoDotArrowCorrectionForColonColon.cpp"), {includePathArgument}, + {}, readFileContent("/complete_withNoDotArrowCorrectionForColonColon.cpp"), true }; ClangBackEnd::FileContainer dotArrowCorrectionForForwardDeclaredClassPointer{ Utf8StringLiteral(TESTDATA_DIR"/complete_withDotArrowCorrectionForForwardDeclaredClassPointer.cpp"), {includePathArgument}, + {}, readFileContent("/complete_withDotArrowCorrectionForForwardDeclaredClassPointer.cpp"), true }; ClangBackEnd::FileContainer globalCompletionAfterForwardDeclaredClassPointer{ Utf8StringLiteral(TESTDATA_DIR"/complete_withGlobalCompletionAfterForwardDeclaredClassPointer.cpp"), {includePathArgument}, + {}, readFileContent("/complete_withGlobalCompletionAfterForwardDeclaredClassPointer.cpp"), true }; ClangBackEnd::FileContainer smartPointerCompletion{ Utf8StringLiteral(TESTDATA_DIR"/complete_smartpointer.cpp"), {includePathArgument}, + {}, readFileContent("/complete_smartpointer.cpp"), true }; ClangBackEnd::FileContainer completionsOrder{ Utf8StringLiteral(TESTDATA_DIR"/completions_order.cpp"), {includePathArgument}, + {}, readFileContent("/completions_order.cpp"), true }; diff --git a/tests/unit/unittest/codecompletionsextractor-test.cpp b/tests/unit/unittest/codecompletionsextractor-test.cpp index 7907ef87371..3e493ab44b2 100644 --- a/tests/unit/unittest/codecompletionsextractor-test.cpp +++ b/tests/unit/unittest/codecompletionsextractor-test.cpp @@ -149,14 +149,14 @@ protected: ClangBackEnd::UnsavedFiles unsavedFiles; ClangBackEnd::Documents documents{unsavedFiles}; Utf8StringVector compilationArguments{TestEnvironment::addPlatformArguments()}; - Document functionDocument{Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_function.cpp"), compilationArguments, documents}; - Document functionOverloadDocument{Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_functionoverload.cpp"), compilationArguments, documents}; - Document variableDocument{Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_variable.cpp"), compilationArguments, documents}; - Document classDocument{Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_class.cpp"), compilationArguments, documents}; - Document namespaceDocument{Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_namespace.cpp"), compilationArguments, documents}; - Document enumerationDocument{Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_enumeration.cpp"), compilationArguments, documents}; - Document constructorDocument{Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_constructor.cpp"), compilationArguments, documents}; - Document briefCommentDocument{Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_brief_comment.cpp"), compilationArguments, documents}; + Document functionDocument{Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_function.cpp"), compilationArguments, {}, documents}; + Document functionOverloadDocument{Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_functionoverload.cpp"), compilationArguments, {}, documents}; + Document variableDocument{Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_variable.cpp"), compilationArguments, {}, documents}; + Document classDocument{Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_class.cpp"), compilationArguments, {}, documents}; + Document namespaceDocument{Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_namespace.cpp"), compilationArguments, {}, documents}; + Document enumerationDocument{Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_enumeration.cpp"), compilationArguments, {}, documents}; + Document constructorDocument{Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_constructor.cpp"), compilationArguments, {}, documents}; + Document briefCommentDocument{Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_brief_comment.cpp"), compilationArguments, {}, documents}; }; using CodeCompletionsExtractorSlowTest = CodeCompletionsExtractor; @@ -610,6 +610,7 @@ TEST_F(CodeCompletionsExtractorSlowTest, UnsavedFile) { Document document(Utf8String::fromUtf8(TESTDATA_DIR "/complete_extractor_function.cpp"), compilationArguments, + {}, documents); unsavedFiles.createOrUpdate( {unsavedDataFileContainer(TESTDATA_DIR "/complete_extractor_function.cpp", @@ -629,6 +630,7 @@ TEST_F(CodeCompletionsExtractorSlowTest, ChangeUnsavedFile) { Document document(Utf8String::fromUtf8(TESTDATA_DIR "/complete_extractor_function.cpp"), compilationArguments, + {}, documents); unsavedFiles.createOrUpdate( {unsavedDataFileContainer(TESTDATA_DIR "/complete_extractor_function.cpp", @@ -652,6 +654,7 @@ TEST_F(CodeCompletionsExtractorSlowTest, ArgumentDefinition) Document variableDocument{Utf8StringLiteral(TESTDATA_DIR "/complete_extractor_variable.cpp"), {Utf8StringLiteral("-DArgumentDefinition"), Utf8StringLiteral("-std=gnu++14")}, + {}, documents}; ClangCodeCompleteResults completeResults(getResults(variableDocument, 35)); @@ -668,6 +671,7 @@ TEST_F(CodeCompletionsExtractorSlowTest, NoArgumentDefinition) { Document variableDocument{Utf8StringLiteral(TESTDATA_DIR "/complete_extractor_variable.cpp"), {Utf8StringLiteral("-std=gnu++14")}, + {}, documents}; ClangCodeCompleteResults completeResults(getResults(variableDocument, 35)); diff --git a/tests/unit/unittest/cursor-test.cpp b/tests/unit/unittest/cursor-test.cpp index 20e985043b4..06a8af99652 100644 --- a/tests/unit/unittest/cursor-test.cpp +++ b/tests/unit/unittest/cursor-test.cpp @@ -64,6 +64,7 @@ struct Data { Utf8String filePath{Utf8StringLiteral(TESTDATA_DIR"/cursor.cpp")}; Document document{filePath, TestEnvironment::addPlatformArguments({Utf8StringLiteral("-std=c++11")}), + {}, documents}; TranslationUnit translationUnit{filePath, filePath, diff --git a/tests/unit/unittest/data/translationunits.cpp b/tests/unit/unittest/data/translationunits.cpp index d1165e73da4..8ab60b10e17 100644 --- a/tests/unit/unittest/data/translationunits.cpp +++ b/tests/unit/unittest/data/translationunits.cpp @@ -1,4 +1,5 @@ #include "translationunits.h" +#include "some/unresolved/file.h" void function() { diff --git a/tests/unit/unittest/data/uicmain.cpp b/tests/unit/unittest/data/uicmain.cpp new file mode 100644 index 00000000000..7739b1027b2 --- /dev/null +++ b/tests/unit/unittest/data/uicmain.cpp @@ -0,0 +1,3 @@ +#include "uicheader.h" + +static UicObject o; diff --git a/tests/unit/unittest/diagnostic-test.cpp b/tests/unit/unittest/diagnostic-test.cpp index be9f9f7f83f..fac44162cd0 100644 --- a/tests/unit/unittest/diagnostic-test.cpp +++ b/tests/unit/unittest/diagnostic-test.cpp @@ -88,6 +88,7 @@ protected: ClangBackEnd::Documents documents{unsavedFiles}; Document document{Utf8StringLiteral(TESTDATA_DIR"/diagnostic_diagnostic.cpp"), TestEnvironment::addPlatformArguments({Utf8StringLiteral("-std=c++11")}), + {}, documents}; UnitTest::RunDocumentParse _1{document}; DiagnosticSet diagnosticSet{document.translationUnit().diagnostics()}; diff --git a/tests/unit/unittest/diagnosticset-test.cpp b/tests/unit/unittest/diagnosticset-test.cpp index 8c8d336747c..f37d00e13fb 100644 --- a/tests/unit/unittest/diagnosticset-test.cpp +++ b/tests/unit/unittest/diagnosticset-test.cpp @@ -67,9 +67,11 @@ protected: TestEnvironment::addPlatformArguments({Utf8StringLiteral("-pedantic")})}; Document document{Utf8StringLiteral(TESTDATA_DIR "/diagnostic_diagnosticset.cpp"), compilationArguments, + {}, documents}; Document documentMainFile{Utf8StringLiteral(TESTDATA_DIR"/diagnostic_diagnosticset_mainfile.cpp"), compilationArguments, + {}, documents}; protected: diff --git a/tests/unit/unittest/fixit-test.cpp b/tests/unit/unittest/fixit-test.cpp index 08c41766c1d..0063dc27fc2 100644 --- a/tests/unit/unittest/fixit-test.cpp +++ b/tests/unit/unittest/fixit-test.cpp @@ -70,7 +70,8 @@ struct Data ClangBackEnd::UnsavedFiles unsavedFiles; ClangBackEnd::Documents documents{unsavedFiles}; Document document{Utf8StringLiteral(TESTDATA_DIR"/diagnostic_semicolon_fixit.cpp"), - Utf8StringVector(), + {}, + {}, documents}; UnitTest::RunDocumentParse _1{document}; TranslationUnit translationUnit{document.translationUnit()}; diff --git a/tests/unit/unittest/highlightingresultreporter-test.cpp b/tests/unit/unittest/highlightingresultreporter-test.cpp index a9fa277ef3f..29803783b17 100644 --- a/tests/unit/unittest/highlightingresultreporter-test.cpp +++ b/tests/unit/unittest/highlightingresultreporter-test.cpp @@ -51,6 +51,7 @@ struct Data { Documents documents{unsavedFiles}; Document document{Utf8StringLiteral(TESTDATA_DIR "/highlightingmarks.cpp"), TestEnvironment::addPlatformArguments({Utf8StringLiteral("-std=c++14")}), + Utf8StringVector(), documents}; }; diff --git a/tests/unit/unittest/skippedsourceranges-test.cpp b/tests/unit/unittest/skippedsourceranges-test.cpp index 396e0eec06e..083f795ec95 100644 --- a/tests/unit/unittest/skippedsourceranges-test.cpp +++ b/tests/unit/unittest/skippedsourceranges-test.cpp @@ -90,8 +90,8 @@ struct Data { ClangBackEnd::Documents documents{unsavedFiles}; Utf8String filePath = Utf8StringLiteral(TESTDATA_DIR"/skippedsourceranges.cpp"); Utf8StringVector compilationArguments{TestEnvironment::addPlatformArguments( - {Utf8StringLiteral("-std=c++11"), Utf8StringLiteral("-DBLAH")})}; - Document document{filePath, compilationArguments, documents}; + {Utf8StringLiteral("-std=c++11"), {}, Utf8StringLiteral("-DBLAH")})}; + Document document{filePath, compilationArguments, {}, documents}; TranslationUnit translationUnit{filePath, filePath, document.translationUnit().cxIndex(), diff --git a/tests/unit/unittest/sourcelocation-test.cpp b/tests/unit/unittest/sourcelocation-test.cpp index f2e8c908682..101ba2d6c87 100644 --- a/tests/unit/unittest/sourcelocation-test.cpp +++ b/tests/unit/unittest/sourcelocation-test.cpp @@ -51,7 +51,8 @@ struct Data { ClangBackEnd::UnsavedFiles unsavedFiles; ClangBackEnd::Documents documents{unsavedFiles}; Document document{Utf8StringLiteral(TESTDATA_DIR"/diagnostic_source_location.cpp"), - Utf8StringVector(), + {}, + {}, documents}; UnitTest::RunDocumentParse _1{document}; DiagnosticSet diagnosticSet{document.translationUnit().diagnostics()}; diff --git a/tests/unit/unittest/sourcerange-test.cpp b/tests/unit/unittest/sourcerange-test.cpp index daa3fa49947..c66b9854dbc 100644 --- a/tests/unit/unittest/sourcerange-test.cpp +++ b/tests/unit/unittest/sourcerange-test.cpp @@ -76,6 +76,7 @@ struct Data { Utf8String filePath{Utf8StringLiteral(TESTDATA_DIR"/diagnostic_source_range.cpp")}; Document document{filePath, {TestEnvironment::addPlatformArguments({Utf8StringLiteral("-pedantic")})}, + {}, documents}; UnitTest::RunDocumentParse _1{document}; TranslationUnit translationUnit{filePath, diff --git a/tests/unit/unittest/token-test.cpp b/tests/unit/unittest/token-test.cpp index 6dd30cadf45..3f7c39ea5f3 100644 --- a/tests/unit/unittest/token-test.cpp +++ b/tests/unit/unittest/token-test.cpp @@ -56,7 +56,7 @@ struct Data { Utf8String filePath{Utf8StringLiteral(TESTDATA_DIR"/token.cpp")}; Utf8StringVector compilationArguments{ TestEnvironment::addPlatformArguments({Utf8StringLiteral("-std=c++11")})}; - Document document{filePath, compilationArguments, documents}; + Document document{filePath, compilationArguments, {}, documents}; TranslationUnit translationUnit{filePath, filePath, document.translationUnit().cxIndex(), diff --git a/tests/unit/unittest/tokenprocessor-test.cpp b/tests/unit/unittest/tokenprocessor-test.cpp index a9cc385a24b..2935a853814 100644 --- a/tests/unit/unittest/tokenprocessor-test.cpp +++ b/tests/unit/unittest/tokenprocessor-test.cpp @@ -131,6 +131,7 @@ struct Data { TestEnvironment::addPlatformArguments( {Utf8StringLiteral("-std=c++14"), Utf8StringLiteral("-I" TESTDATA_DIR)}), + {}, documents}; TranslationUnit translationUnit{filePath, filePath,