diff options
Diffstat (limited to 'src')
13 files changed, 148 insertions, 60 deletions
diff --git a/src/plugins/autotest/quick/quicktest_utils.cpp b/src/plugins/autotest/quick/quicktest_utils.cpp index c25009a1ff..68147dbb3f 100644 --- a/src/plugins/autotest/quick/quicktest_utils.cpp +++ b/src/plugins/autotest/quick/quicktest_utils.cpp @@ -35,11 +35,10 @@ namespace Autotest { namespace Internal { namespace QuickTestUtils { -static const QByteArrayList valid = {"QUICK_TEST_MAIN", "QUICK_TEST_OPENGL_MAIN", - "QUICK_TEST_MAIN_WITH_SETUP"}; - bool isQuickTestMacro(const QByteArray ¯o) { + static const QByteArrayList valid = {"QUICK_TEST_MAIN", "QUICK_TEST_OPENGL_MAIN", + "QUICK_TEST_MAIN_WITH_SETUP"}; return valid.contains(macro); } diff --git a/src/plugins/autotest/quick/quicktestparser.cpp b/src/plugins/autotest/quick/quicktestparser.cpp index f35a390e3f..20e9da84c7 100644 --- a/src/plugins/autotest/quick/quicktestparser.cpp +++ b/src/plugins/autotest/quick/quicktestparser.cpp @@ -126,7 +126,7 @@ QString QuickTestParser::quickTestName(const CPlusPlus::Document::Ptr &doc) cons const Utils::FilePath filePath = Utils::FilePath::fromString(doc->fileName()); for (const CPlusPlus::Document::MacroUse ¯o : macros) { - if (!macro.isFunctionLike()) + if (!macro.isFunctionLike() || macro.arguments().isEmpty()) continue; const QByteArray name = macro.macro().name(); if (QuickTestUtils::isQuickTestMacro(name)) { @@ -137,7 +137,7 @@ QString QuickTestParser::quickTestName(const CPlusPlus::Document::Ptr &doc) cons } - const QByteArray &fileContent = getFileContent(filePath); + const QByteArray fileContent = getFileContent(filePath); // check for using quick_test_main() directly CPlusPlus::Document::Ptr document = m_cppSnapshot.preprocessedDocument(fileContent, filePath); if (document.isNull()) diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index e4bcf9d63f..73a517466e 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -651,6 +651,14 @@ DiagnosticManager *ClangdClient::createDiagnosticManager() return diagnosticManager; } +bool ClangdClient::referencesShadowFile(const TextEditor::TextDocument *doc, + const Utils::FilePath &candidate) +{ + const QRegularExpression includeRex("#include.*" + candidate.fileName() + R"([>"])"); + const QTextCursor includePos = doc->document()->find(includeRex); + return !includePos.isNull(); +} + RefactoringChangesData *ClangdClient::createRefactoringChangesBackend() const { return new CppEditor::CppRefactoringChangesData( diff --git a/src/plugins/clangcodemodel/clangdclient.h b/src/plugins/clangcodemodel/clangdclient.h index 5f2329b594..9c7ec12e03 100644 --- a/src/plugins/clangcodemodel/clangdclient.h +++ b/src/plugins/clangcodemodel/clangdclient.h @@ -145,6 +145,8 @@ private: const CustomInspectorTabs createCustomInspectorTabs() override; TextEditor::RefactoringChangesData *createRefactoringChangesBackend() const override; LanguageClient::DiagnosticManager *createDiagnosticManager() override; + bool referencesShadowFile(const TextEditor::TextDocument *doc, + const Utils::FilePath &candidate) override; class Private; class VirtualFunctionAssistProcessor; diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp index 9f811281e5..f6a9d112f0 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp @@ -418,16 +418,18 @@ void ClangModelManagerSupport::updateLanguageClient( bool hasDocuments = false; const ClangdSettings settings(ClangdProjectSettings(project).settings()); for (TextEditor::TextDocument * const doc : allCppDocuments()) { - const Client * const currentClient = LanguageClientManager::clientForDocument(doc); + Client * const currentClient = LanguageClientManager::clientForDocument(doc); if (!settings.sizeIsOkay(doc->filePath())) continue; + const Project * const docProject = SessionManager::projectForFile(doc->filePath()); if (currentClient && currentClient->project() - && currentClient->project() != project) { + && currentClient->project() != project + && currentClient->project() == docProject) { continue; } - if (const Project * const docProject - = SessionManager::projectForFile(doc->filePath()); - !docProject || docProject == project) { + if (!docProject || docProject == project) { + if (currentClient) + currentClient->closeDocument(doc); LanguageClientManager::openDocumentWithClient(doc, client); hasDocuments = true; } @@ -532,15 +534,18 @@ void ClangModelManagerSupport::claimNonProjectSources(ClangdClient *client) if (!client) return; for (TextEditor::TextDocument * const doc : allCppDocuments()) { - if (Client * const currentClient = LanguageClientManager::clientForDocument(doc); - currentClient && currentClient->state() == Client::Initialized + Client * const currentClient = LanguageClientManager::clientForDocument(doc); + if (currentClient && currentClient->state() == Client::Initialized && (currentClient == client || currentClient->project())) { continue; } if (!ClangdSettings::instance().sizeIsOkay(doc->filePath())) continue; - if (!ProjectExplorer::SessionManager::projectForFile(doc->filePath())) + if (!ProjectExplorer::SessionManager::projectForFile(doc->filePath())) { + if (currentClient) + currentClient->closeDocument(doc); LanguageClientManager::openDocumentWithClient(doc, client); + } } } diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdatabasetests.cpp b/src/plugins/compilationdatabaseprojectmanager/compilationdatabasetests.cpp index 15651214bd..d5fdc2dd17 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdatabasetests.cpp +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdatabasetests.cpp @@ -136,7 +136,7 @@ void CompilationDatabaseTests::testFilterEmptyFlags() void CompilationDatabaseTests::testFilterFromFilename() { - QCOMPARE(filterFromFileName(QStringList{"-o", "foo.o"}, "foo"), QStringList{"-o"}); + QCOMPARE(filterFromFileName(QStringList{"-o", "foo.o"}, "foo.c"), QStringList()); } void CompilationDatabaseTests::testFilterArguments() @@ -169,8 +169,10 @@ void CompilationDatabaseTests::testFilterArguments() "c++", QString("--sysroot=") + (HostOsInfo::isWindowsHost() ? "C:\\sysroot\\embedded" : "/opt/sysroot/embedded"), - "C:\\qt-creator\\src\\plugins\\cpptools\\compileroptionsbuilder.cpp"}, - "compileroptionsbuilder"); + QLatin1String(HostOsInfo::isWindowsHost() + ? "C:\\qt-creator\\src\\plugins\\cpptools\\compileroptionsbuilder.cpp" + : "/opt/qt-creator/src/plugins/cpptools/compileroptionsbuilder.cpp")}, + "compileroptionsbuilder.cpp"); testData.getFilteredFlags(); @@ -241,7 +243,7 @@ void CompilationDatabaseTests::testFilterCommand() testData.fileName = "SemaCodeComplete.cpp"; testData.workingDir = "C:/build-qt_llvm-msvc2017_64bit-Debug"; testData.flags = filterFromFileName(testData.getSplitCommandLine(kCmakeCommand), - "SemaCodeComplete"); + "SemaCodeComplete.cpp"); testData.getFilteredFlags(); if (Utils::HostOsInfo::isWindowsHost()) { @@ -278,7 +280,7 @@ void CompilationDatabaseTests::testFileKindDifferentFromExtension2() void CompilationDatabaseTests::testSkipOutputFiles() { CompilationDatabaseUtilsTestData testData; - testData.flags = filterFromFileName(QStringList{"-o", "foo.o"}, "foo"); + testData.flags = filterFromFileName(QStringList{"-o", "foo.o"}, "foo.cpp"); QVERIFY(testData.getFilteredFlags().isEmpty()); } diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.cpp b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.cpp index a60d2ed914..03b5d59079 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.cpp +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.cpp @@ -84,14 +84,24 @@ static CppEditor::ProjectFile::Kind fileKindFromString(QString flag) return ProjectFile::Unclassified; } -QStringList filterFromFileName(const QStringList &flags, QString baseName) +QStringList filterFromFileName(const QStringList &flags, QString fileName) { - baseName.append('.'); // to match name.c, name.o, etc. QStringList result; result.reserve(flags.size()); - for (const QString &flag : flags) { - if (!flag.contains(baseName)) - result.push_back(flag); + bool skipNext = false; + for (int i = 0; i < flags.size(); ++i) { + const QString &flag = flags.at(i); + if (skipNext) { + skipNext = false; + continue; + } + if (FilePath::fromUserInput(flag).fileName() == fileName) + continue; + if (flag == "-o" || flag.startsWith("/Fo")) { + skipNext = true; + continue; + } + result.push_back(flag); } return result; diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.cpp b/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.cpp index 21605c321c..c244eebb2b 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.cpp +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.cpp @@ -177,7 +177,7 @@ static QStringList jsonObjectFlags(const QJsonObject &object, QSet<QString> &fla return flags; } -static FilePath jsonObjectFilename(const QJsonObject &object) +static FilePath jsonObjectFilePath(const QJsonObject &object) { const QString workingDir = QDir::cleanPath(object["directory"].toString()); FilePath fileName = FilePath::fromString(QDir::cleanPath(object["file"].toString())); @@ -204,10 +204,10 @@ std::vector<DbEntry> CompilationDbParser::readJsonObjects() const } const QJsonObject object = document.object(); - const Utils::FilePath fileName = jsonObjectFilename(object); + const Utils::FilePath filePath = jsonObjectFilePath(object); const QStringList flags = filterFromFileName(jsonObjectFlags(object, flagsCache), - fileName.baseName()); - result.push_back({flags, fileName, object["directory"].toString()}); + filePath.fileName()); + result.push_back({flags, filePath, object["directory"].toString()}); objectStart = m_projectFileContents.indexOf('{', objectEnd + 1); objectEnd = m_projectFileContents.indexOf('}', objectStart + 1); diff --git a/src/plugins/coreplugin/editormanager/documentmodel.cpp b/src/plugins/coreplugin/editormanager/documentmodel.cpp index 20712a9d79..f3ff09161c 100644 --- a/src/plugins/coreplugin/editormanager/documentmodel.cpp +++ b/src/plugins/coreplugin/editormanager/documentmodel.cpp @@ -485,10 +485,15 @@ void DocumentModelPrivate::removeAllSuspendedEntries(PinnedFileRemovalPolicy pin if (pinnedFileRemovalPolicy == DoNotRemovePinnedFiles && entry->pinned) continue; + const FilePath fixedPath = DocumentManager::filePathKey(entry->fileName(), + DocumentManager::ResolveLinks); int row = i + 1/*<no document>*/; d->beginRemoveRows(QModelIndex(), row, row); delete d->m_entries.takeAt(i); d->endRemoveRows(); + + if (!fixedPath.isEmpty()) + d->m_entryByFixedPath.remove(fixedPath); } QSet<QString> displayNames; for (DocumentModel::Entry *entry : qAsConst(d->m_entries)) { diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp index 3408e08194..e57700133d 100644 --- a/src/plugins/languageclient/client.cpp +++ b/src/plugins/languageclient/client.cpp @@ -263,6 +263,12 @@ public: void sendOpenNotification(const FilePath &filePath, const QString &mimeType, const QString &content, int version); void sendCloseNotification(const FilePath &filePath); + void openRequiredShadowDocuments(const TextEditor::TextDocument *doc); + void closeRequiredShadowDocuments(const TextEditor::TextDocument *doc); + + using ShadowDocIterator = QMap<FilePath, QPair<QString, QList<const TextEditor::TextDocument *>>>::iterator; + void openShadowDocument(const TextEditor::TextDocument *requringDoc, ShadowDocIterator shadowIt); + void closeShadowDocument(ShadowDocIterator docIt); bool reset(); @@ -276,7 +282,9 @@ public: // Used for build system artifacts (e.g. UI headers) that Qt Creator "live-generates" ahead of // the build. - QMap<FilePath, QString> m_shadowDocuments; + // The Value is the file content + the documents that require the shadow file to be open + // (empty <=> shadow document is not open). + QMap<FilePath, QPair<QString, QList<const TextEditor::TextDocument *>>> m_shadowDocuments; QSet<TextEditor::TextDocument *> m_postponedDocuments; QMap<Utils::FilePath, int> m_documentVersions; @@ -577,10 +585,12 @@ void Client::openDocument(TextEditor::TextDocument *document) } const FilePath &filePath = document->filePath(); - if (d->m_shadowDocuments.contains(filePath)) { - d->sendCloseNotification(filePath); + const auto shadowIt = d->m_shadowDocuments.find(filePath); + if (shadowIt != d->m_shadowDocuments.end()) { + d->closeShadowDocument(shadowIt); emit shadowDocumentSwitched(filePath); } + d->openRequiredShadowDocuments(document); const QString method(DidOpenTextDocumentNotification::methodName); if (Utils::optional<bool> registered = d->m_dynamicCapabilities.isRegistered(method)) { @@ -647,6 +657,7 @@ void Client::closeDocument(TextEditor::TextDocument *document) { deactivateDocument(document); d->m_postponedDocuments.remove(document); + d->m_documentsToUpdate.erase(document); if (d->m_openedDocument.remove(document) != 0) { handleDocumentClosed(document); if (d->m_state == Initialized) @@ -655,12 +666,20 @@ void Client::closeDocument(TextEditor::TextDocument *document) if (d->m_state != Initialized) return; - const auto shadowIt = d->m_shadowDocuments.constFind(document->filePath()); + d->closeRequiredShadowDocuments(document); + const auto shadowIt = d->m_shadowDocuments.find(document->filePath()); if (shadowIt == d->m_shadowDocuments.constEnd()) return; - d->sendOpenNotification(document->filePath(), document->mimeType(), shadowIt.value(), - ++d->m_documentVersions[document->filePath()]); - emit shadowDocumentSwitched(document->filePath()); + QTC_CHECK(shadowIt.value().second.isEmpty()); + bool isReferenced = false; + for (auto it = d->m_openedDocument.cbegin(); it != d->m_openedDocument.cend(); ++it) { + if (referencesShadowFile(it.key(), shadowIt.key())) { + d->openShadowDocument(it.key(), shadowIt); + isReferenced = true; + } + } + if (isReferenced) + emit shadowDocumentSwitched(document->filePath()); } void ClientPrivate::updateCompletionProvider(TextEditor::TextDocument *document) @@ -870,6 +889,22 @@ void ClientPrivate::sendCloseNotification(const FilePath &filePath) Client::SendDocUpdates::Ignore); } +void ClientPrivate::openRequiredShadowDocuments(const TextEditor::TextDocument *doc) +{ + for (auto it = m_shadowDocuments.begin(); it != m_shadowDocuments.end(); ++it) { + if (!it.value().second.contains(doc) && q->referencesShadowFile(doc, it.key())) + openShadowDocument(doc, it); + } +} + +void ClientPrivate::closeRequiredShadowDocuments(const TextEditor::TextDocument *doc) +{ + for (auto it = m_shadowDocuments.begin(); it != m_shadowDocuments.end(); ++it) { + if (it.value().second.removeOne(doc) && it.value().second.isEmpty()) + closeShadowDocument(it); + } +} + bool Client::documentOpen(const TextEditor::TextDocument *document) const { return d->m_openedDocument.contains(const_cast<TextEditor::TextDocument *>(document)); @@ -887,24 +922,25 @@ TextEditor::TextDocument *Client::documentForFilePath(const Utils::FilePath &fil void Client::setShadowDocument(const Utils::FilePath &filePath, const QString &content) { QTC_ASSERT(reachable(), return); - const auto it = d->m_shadowDocuments.find(filePath); - const bool isNew = it == d->m_shadowDocuments.end(); - if (isNew) - d->m_shadowDocuments.insert(filePath, content); - else - it.value() = content; + auto shadowIt = d->m_shadowDocuments.find(filePath); + if (shadowIt == d->m_shadowDocuments.end()) { + shadowIt = d->m_shadowDocuments.insert(filePath, {content, {}}); + } else { + shadowIt.value().first = content; + if (!shadowIt.value().second.isEmpty()) { + VersionedTextDocumentIdentifier docId(DocumentUri::fromFilePath(filePath)); + docId.setVersion(++d->m_documentVersions[filePath]); + const DidChangeTextDocumentParams params(docId, content); + sendMessage(DidChangeTextDocumentNotification(params), SendDocUpdates::Ignore); + return; + } + } if (documentForFilePath(filePath)) return; - const auto uri = DocumentUri::fromFilePath(filePath); - if (isNew) { - const QString mimeType = mimeTypeForFile(filePath, MimeMatchMode::MatchExtension).name(); - d->sendOpenNotification(filePath, mimeType, content, 0); + for (auto docIt = d->m_openedDocument.cbegin(); docIt != d->m_openedDocument.cend(); ++docIt) { + if (referencesShadowFile(docIt.key(), filePath)) + d->openShadowDocument(docIt.key(), shadowIt); } - - VersionedTextDocumentIdentifier docId(uri); - docId.setVersion(++d->m_documentVersions[filePath]); - const DidChangeTextDocumentParams params(docId, content); - sendMessage(DidChangeTextDocumentNotification(params), SendDocUpdates::Ignore); } void Client::removeShadowDocument(const Utils::FilePath &filePath) @@ -912,10 +948,27 @@ void Client::removeShadowDocument(const Utils::FilePath &filePath) const auto it = d->m_shadowDocuments.find(filePath); if (it == d->m_shadowDocuments.end()) return; + if (!it.value().second.isEmpty()) + d->closeShadowDocument(it); d->m_shadowDocuments.erase(it); - if (documentForFilePath(filePath)) +} + +void ClientPrivate::openShadowDocument(const TextEditor::TextDocument *requringDoc, + ShadowDocIterator shadowIt) +{ + shadowIt.value().second << requringDoc; + if (shadowIt.value().second.size() > 1) return; - d->sendCloseNotification(filePath); + const auto uri = DocumentUri::fromFilePath(shadowIt.key()); + const QString mimeType = mimeTypeForFile(shadowIt.key(), MimeMatchMode::MatchExtension).name(); + sendOpenNotification(shadowIt.key(), mimeType, shadowIt.value().first, + ++m_documentVersions[shadowIt.key()]); +} + +void ClientPrivate::closeShadowDocument(ShadowDocIterator shadowIt) +{ + sendCloseNotification(shadowIt.key()); + shadowIt.value().second.clear(); } void Client::documentContentsSaved(TextEditor::TextDocument *document) @@ -947,6 +1000,7 @@ void Client::documentContentsSaved(TextEditor::TextDocument *document) return; DidSaveTextDocumentParams params( TextDocumentIdentifier(DocumentUri::fromFilePath(document->filePath()))); + d->openRequiredShadowDocuments(document); if (includeText) params.setText(document->plainText()); sendMessage(DidSaveTextDocumentNotification(params), SendDocUpdates::Send, Schedule::Now); @@ -1970,6 +2024,14 @@ QTextCursor Client::adjustedCursorForHighlighting(const QTextCursor &cursor, return cursor; } +bool Client::referencesShadowFile(const TextEditor::TextDocument *doc, + const Utils::FilePath &candidate) +{ + Q_UNUSED(doc) + Q_UNUSED(candidate) + return false; +} + } // namespace LanguageClient #include <client.moc> diff --git a/src/plugins/languageclient/client.h b/src/plugins/languageclient/client.h index 6fcc4d5a98..d718012e49 100644 --- a/src/plugins/languageclient/client.h +++ b/src/plugins/languageclient/client.h @@ -226,6 +226,8 @@ private: virtual void handleDocumentOpened(TextEditor::TextDocument *) {} virtual QTextCursor adjustedCursorForHighlighting(const QTextCursor &cursor, TextEditor::TextDocument *doc); + virtual bool referencesShadowFile(const TextEditor::TextDocument *doc, + const Utils::FilePath &candidate); }; } // namespace LanguageClient diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp index 45ea3d137f..08aa1f420c 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp @@ -138,6 +138,8 @@ bool MaterialBrowserView::isMaterial(const ModelNode &node) const void MaterialBrowserView::modelAboutToBeDetached(Model *model) { + m_widget->materialBrowserModel()->setMaterials({}, m_hasQuick3DImport); + AbstractView::modelAboutToBeDetached(model); } diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelineform.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelineform.cpp index db9e8a8ef6..e3bcef3942 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/timelineform.cpp +++ b/src/plugins/qmldesigner/components/timelineeditor/timelineform.cpp @@ -50,16 +50,7 @@ TimelineForm::TimelineForm(QWidget *parent) connect(ui->expressionBindingLineEdit, &QLineEdit::editingFinished, [this]() { QTC_ASSERT(m_timeline.isValid(), return ); - - static QString lastString; - const QString bindingText = ui->expressionBindingLineEdit->text(); - - if (bindingText == lastString) - return; - - lastString = bindingText; - if (bindingText.isEmpty()) { ui->animation->setChecked(true); try { |