diff options
author | Christian Kandeler <christian.kandeler@qt.io> | 2021-08-30 10:58:08 +0200 |
---|---|---|
committer | Christian Kandeler <christian.kandeler@qt.io> | 2021-09-01 14:53:58 +0000 |
commit | 284817fae6514701902ccdb834c2faa46462f2e8 (patch) | |
tree | 44a8c7d9813dc110b61c4639036366c7696bd7e9 /src/plugins/cpptools/cppmodelmanager.cpp | |
parent | 3e1fa0f170d523971d2c3c12da15a6e291f56511 (diff) | |
download | qt-creator-284817fae6514701902ccdb834c2faa46462f2e8.tar.gz |
Merge CppTools into CppEditor
There was no proper separation of responsibilities between these
plugins. In particular, CppTools had lots of editor-related
functionality, so it's not clear why it was separated out in the first
place.
In fact, for a lot of code, it seemed quite arbitrary where it was put
(just one example: switchHeaderSource() was in CppTools, wheras
switchDeclarationDefinition() was in CppEditor).
Merging the plugins will enable us to get rid of various convoluted
pseudo-abstractions that were only introduced to keep up the artificial
separation.
Change-Id: Iafc3bce625b4794f6d4aa03df6cddc7f2d26716a
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Diffstat (limited to 'src/plugins/cpptools/cppmodelmanager.cpp')
-rw-r--r-- | src/plugins/cpptools/cppmodelmanager.cpp | 1720 |
1 files changed, 0 insertions, 1720 deletions
diff --git a/src/plugins/cpptools/cppmodelmanager.cpp b/src/plugins/cpptools/cppmodelmanager.cpp deleted file mode 100644 index 8f67110937..0000000000 --- a/src/plugins/cpptools/cppmodelmanager.cpp +++ /dev/null @@ -1,1720 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "cppmodelmanager.h" - -#include "abstracteditorsupport.h" -#include "abstractoverviewmodel.h" -#include "baseeditordocumentprocessor.h" -#include "builtinindexingsupport.h" -#include "cppclassesfilter.h" -#include "cppcodemodelinspectordumper.h" -#include "cppcurrentdocumentfilter.h" -#include "cppfindreferences.h" -#include "cppfunctionsfilter.h" -#include "cppincludesfilter.h" -#include "cppindexingsupport.h" -#include "cpplocatordata.h" -#include "cpplocatorfilter.h" -#include "cppbuiltinmodelmanagersupport.h" -#include "cpprefactoringchanges.h" -#include "cpprefactoringengine.h" -#include "cppsourceprocessor.h" -#include "cpptoolsjsextension.h" -#include "cpptoolsplugin.h" -#include "cpptoolsconstants.h" -#include "cpptoolsreuse.h" -#include "editordocumenthandle.h" -#include "stringtable.h" -#include "symbolfinder.h" -#include "symbolsfindfilter.h" -#include "followsymbolinterface.h" - -#include <coreplugin/documentmanager.h> -#include <coreplugin/editormanager/editormanager.h> -#include <coreplugin/icore.h> -#include <coreplugin/jsexpander.h> -#include <coreplugin/progressmanager/progressmanager.h> -#include <coreplugin/vcsmanager.h> -#include <cplusplus/ASTPath.h> -#include <cplusplus/TypeOfExpression.h> -#include <extensionsystem/pluginmanager.h> -#include <projectexplorer/kitinformation.h> -#include <projectexplorer/kitmanager.h> -#include <projectexplorer/project.h> -#include <projectexplorer/projectexplorer.h> -#include <projectexplorer/projectmacro.h> -#include <projectexplorer/session.h> -#include <texteditor/textdocument.h> -#include <utils/fileutils.h> -#include <utils/hostosinfo.h> -#include <utils/qtcassert.h> - -#include <QCoreApplication> -#include <QDebug> -#include <QDir> -#include <QFutureWatcher> -#include <QMutexLocker> -#include <QReadLocker> -#include <QReadWriteLock> -#include <QTextBlock> -#include <QThreadPool> -#include <QTimer> -#include <QWriteLocker> - -#if defined(QTCREATOR_WITH_DUMP_AST) && defined(Q_CC_GNU) -#define WITH_AST_DUMP -#include <iostream> -#include <sstream> -#endif - -static const bool DumpProjectInfo = qgetenv("QTC_DUMP_PROJECT_INFO") == "1"; - -using namespace CppTools; -using namespace CppTools::Internal; -using namespace CPlusPlus; -using namespace ProjectExplorer; - -#ifdef QTCREATOR_WITH_DUMP_AST - -#include <cxxabi.h> - -class DumpAST: protected ASTVisitor -{ -public: - int depth; - - explicit DumpAST(Control *control) - : ASTVisitor(control), depth(0) - { } - - void operator()(AST *ast) - { accept(ast); } - -protected: - virtual bool preVisit(AST *ast) - { - std::ostringstream s; - PrettyPrinter pp(control(), s); - pp(ast); - QString code = QString::fromStdString(s.str()); - code.replace('\n', ' '); - code.replace(QRegularExpression("\\s+"), " "); - - const char *name = abi::__cxa_demangle(typeid(*ast).name(), 0, 0, 0) + 11; - - QByteArray ind(depth, ' '); - ind += name; - - printf("%-40s %s\n", ind.constData(), qPrintable(code)); - ++depth; - return true; - } - - virtual void postVisit(AST *) - { --depth; } -}; - -#endif // QTCREATOR_WITH_DUMP_AST - -namespace CppTools { - -using REType = RefactoringEngineType; - -namespace Internal { - -static CppModelManager *m_instance; - -class ProjectData -{ -public: - ProjectInfo::ConstPtr projectInfo; - QFutureWatcher<void> *indexer = nullptr; - bool fullyIndexed = false; -}; - -class CppModelManagerPrivate -{ -public: - void setupWatcher(const QFuture<void> &future, ProjectExplorer::Project *project, - ProjectData *projectData, CppModelManager *q); - - // Snapshot - mutable QMutex m_snapshotMutex; - Snapshot m_snapshot; - - // Project integration - QReadWriteLock m_projectLock; - QHash<ProjectExplorer::Project *, ProjectData> m_projectData; - QMap<Utils::FilePath, QList<ProjectPart::ConstPtr> > m_fileToProjectParts; - QMap<QString, ProjectPart::ConstPtr> m_projectPartIdToProjectProjectPart; - - // The members below are cached/(re)calculated from the projects and/or their project parts - bool m_dirty; - QStringList m_projectFiles; - ProjectExplorer::HeaderPaths m_headerPaths; - ProjectExplorer::Macros m_definedMacros; - - // Editor integration - mutable QMutex m_cppEditorDocumentsMutex; - QMap<QString, CppEditorDocumentHandle *> m_cppEditorDocuments; - QSet<AbstractEditorSupport *> m_extraEditorSupports; - - // Model Manager Supports for e.g. completion and highlighting - ModelManagerSupport::Ptr m_builtinModelManagerSupport; - ModelManagerSupport::Ptr m_activeModelManagerSupport; - - // Indexing - CppIndexingSupport *m_internalIndexingSupport; - bool m_indexerEnabled; - - QMutex m_fallbackProjectPartMutex; - ProjectPart::ConstPtr m_fallbackProjectPart; - - CppFindReferences *m_findReferences; - - SymbolFinder m_symbolFinder; - QThreadPool m_threadPool; - - bool m_enableGC; - QTimer m_delayedGcTimer; - - // Refactoring - using REHash = QMap<REType, RefactoringEngineInterface *>; - REHash m_refactoringEngines; - - CppLocatorData m_locatorData; - std::unique_ptr<Core::ILocatorFilter> m_locatorFilter; - std::unique_ptr<Core::ILocatorFilter> m_classesFilter; - std::unique_ptr<Core::ILocatorFilter> m_includesFilter; - std::unique_ptr<Core::ILocatorFilter> m_functionsFilter; - std::unique_ptr<Core::IFindFilter> m_symbolsFindFilter; - std::unique_ptr<Core::ILocatorFilter> m_currentDocumentFilter; -}; - -} // namespace Internal - -const char pp_configuration[] = - "# 1 \"<configuration>\"\n" - "#define Q_CREATOR_RUN 1\n" - "#define __cplusplus 1\n" - "#define __extension__\n" - "#define __context__\n" - "#define __range__\n" - "#define restrict\n" - "#define __restrict\n" - "#define __restrict__\n" - - "#define __complex__\n" - "#define __imag__\n" - "#define __real__\n" - - "#define __builtin_va_arg(a,b) ((b)0)\n" - - "#define _Pragma(x)\n" // C99 _Pragma operator - - "#define __func__ \"\"\n" - - // ### add macros for gcc - "#define __PRETTY_FUNCTION__ \"\"\n" - "#define __FUNCTION__ \"\"\n" - - // ### add macros for win32 - "#define __cdecl\n" - "#define __stdcall\n" - "#define __thiscall\n" - "#define QT_WA(x) x\n" - "#define CALLBACK\n" - "#define STDMETHODCALLTYPE\n" - "#define __RPC_FAR\n" - "#define __declspec(a)\n" - "#define STDMETHOD(method) virtual HRESULT STDMETHODCALLTYPE method\n" - "#define __try try\n" - "#define __except catch\n" - "#define __finally\n" - "#define __inline inline\n" - "#define __forceinline inline\n" - "#define __pragma(x)\n" - "#define __w64\n" - "#define __int64 long long\n" - "#define __int32 long\n" - "#define __int16 short\n" - "#define __int8 char\n" - "#define __ptr32\n" - "#define __ptr64\n"; - -QSet<QString> CppModelManager::timeStampModifiedFiles(const QList<Document::Ptr> &documentsToCheck) -{ - QSet<QString> sourceFiles; - - foreach (const Document::Ptr doc, documentsToCheck) { - const QDateTime lastModified = doc->lastModified(); - - if (!lastModified.isNull()) { - QFileInfo fileInfo(doc->fileName()); - - if (fileInfo.exists() && fileInfo.lastModified() != lastModified) - sourceFiles.insert(doc->fileName()); - } - } - - return sourceFiles; -} - -/*! - * \brief createSourceProcessor Create a new source processor, which will signal the - * model manager when a document has been processed. - * - * Indexed file is truncated version of fully parsed document: copy of source - * code and full AST will be dropped when indexing is done. - * - * \return a new source processor object, which the caller needs to delete when finished. - */ -CppSourceProcessor *CppModelManager::createSourceProcessor() -{ - CppModelManager *that = instance(); - return new CppSourceProcessor(that->snapshot(), [that](const Document::Ptr &doc) { - const Document::Ptr previousDocument = that->document(doc->fileName()); - const unsigned newRevision = previousDocument.isNull() - ? 1U - : previousDocument->revision() + 1; - doc->setRevision(newRevision); - that->emitDocumentUpdated(doc); - doc->releaseSourceAndAST(); - }); -} - -QString CppModelManager::editorConfigurationFileName() -{ - return QLatin1String("<per-editor-defines>"); -} - -static RefactoringEngineInterface *getRefactoringEngine(CppModelManagerPrivate::REHash &engines) -{ - QTC_ASSERT(!engines.empty(), return nullptr;); - RefactoringEngineInterface *currentEngine = engines[REType::BuiltIn]; - if (engines.find(REType::ClangCodeModel) != engines.end()) { - currentEngine = engines[REType::ClangCodeModel]; - } else if (engines.find(REType::ClangRefactoring) != engines.end()) { - RefactoringEngineInterface *engine = engines[REType::ClangRefactoring]; - if (engine->isRefactoringEngineAvailable()) - currentEngine = engine; - } - return currentEngine; -} - -void CppModelManager::startLocalRenaming(const CursorInEditor &data, - const CppTools::ProjectPart *projectPart, - RenameCallback &&renameSymbolsCallback) -{ - RefactoringEngineInterface *engine = getRefactoringEngine(d->m_refactoringEngines); - QTC_ASSERT(engine, return;); - engine->startLocalRenaming(data, projectPart, std::move(renameSymbolsCallback)); -} - -void CppModelManager::globalRename(const CursorInEditor &data, UsagesCallback &&renameCallback, - const QString &replacement) -{ - RefactoringEngineInterface *engine = getRefactoringEngine(d->m_refactoringEngines); - QTC_ASSERT(engine, return;); - engine->globalRename(data, std::move(renameCallback), replacement); -} - -void CppModelManager::findUsages(const CppTools::CursorInEditor &data, - UsagesCallback &&showUsagesCallback) const -{ - RefactoringEngineInterface *engine = getRefactoringEngine(d->m_refactoringEngines); - QTC_ASSERT(engine, return;); - engine->findUsages(data, std::move(showUsagesCallback)); -} - -void CppModelManager::globalFollowSymbol( - const CursorInEditor &data, - Utils::ProcessLinkCallback &&processLinkCallback, - const CPlusPlus::Snapshot &snapshot, - const CPlusPlus::Document::Ptr &documentFromSemanticInfo, - SymbolFinder *symbolFinder, - bool inNextSplit) const -{ - RefactoringEngineInterface *engine = getRefactoringEngine(d->m_refactoringEngines); - QTC_ASSERT(engine, return;); - engine->globalFollowSymbol(data, std::move(processLinkCallback), snapshot, documentFromSemanticInfo, - symbolFinder, inNextSplit); -} - -bool CppModelManager::positionRequiresSignal(const QString &filePath, const QByteArray &content, - int position) const -{ - if (content.isEmpty()) - return false; - - // Insert a dummy prefix if we don't have a real one. Otherwise the AST path will not contain - // anything after the CallAST. - QByteArray fixedContent = content; - if (position > 2 && content.mid(position - 2, 2) == "::") - fixedContent.insert(position, 'x'); - - const Snapshot snapshot = this->snapshot(); - const Document::Ptr document = snapshot.preprocessedDocument(fixedContent, - Utils::FilePath::fromString(filePath)); - document->check(); - QTextDocument textDocument(QString::fromUtf8(fixedContent)); - QTextCursor cursor(&textDocument); - cursor.setPosition(position); - - // Are we at the second argument of a function call? - const QList<AST *> path = ASTPath(document)(cursor); - if (path.isEmpty() || !path.last()->asSimpleName()) - return false; - const CallAST *callAst = nullptr; - for (auto it = path.crbegin(); it != path.crend(); ++it) { - if ((callAst = (*it)->asCall())) - break; - } - if (!callAst) - return false; - if (!callAst->expression_list || !callAst->expression_list->next) - return false; - const ExpressionAST * const secondArg = callAst->expression_list->next->value; - if (secondArg->firstToken() > path.last()->firstToken() - || secondArg->lastToken() < path.last()->lastToken()) { - return false; - } - - // Is the function called "connect" or "disconnect"? - if (!callAst->base_expression) - return false; - Scope *scope = document->globalNamespace(); - for (auto it = path.crbegin(); it != path.crend(); ++it) { - if (const CompoundStatementAST * const stmtAst = (*it)->asCompoundStatement()) { - scope = stmtAst->symbol; - break; - } - } - const NameAST *nameAst = nullptr; - const LookupContext context(document, snapshot); - if (const IdExpressionAST * const idAst = callAst->base_expression->asIdExpression()) { - nameAst = idAst->name; - } else if (const MemberAccessAST * const ast = callAst->base_expression->asMemberAccess()) { - nameAst = ast->member_name; - TypeOfExpression exprType; - exprType.setExpandTemplates(true); - exprType.init(document, snapshot); - const QList<LookupItem> typeMatches = exprType(ast->base_expression, document, scope); - if (typeMatches.isEmpty()) - return false; - const std::function<const NamedType *(const FullySpecifiedType &)> getNamedType - = [&getNamedType](const FullySpecifiedType &type ) -> const NamedType * { - Type * const t = type.type(); - if (const auto namedType = t->asNamedType()) - return namedType; - if (const auto pointerType = t->asPointerType()) - return getNamedType(pointerType->elementType()); - if (const auto refType = t->asReferenceType()) - return getNamedType(refType->elementType()); - return nullptr; - }; - const NamedType *namedType = getNamedType(typeMatches.first().type()); - if (!namedType && typeMatches.first().declaration()) - namedType = getNamedType(typeMatches.first().declaration()->type()); - if (!namedType) - return false; - const ClassOrNamespace * const result = context.lookupType(namedType->name(), scope); - if (!result) - return false; - scope = result->rootClass(); - if (!scope) - return false; - } - if (!nameAst || !nameAst->name) - return false; - const Identifier * const id = nameAst->name->identifier(); - if (!id) - return false; - const QString funcName = QString::fromUtf8(id->chars(), id->size()); - if (funcName != "connect" && funcName != "disconnect") - return false; - - // Is the function a member function of QObject? - const QList<LookupItem> matches = context.lookup(nameAst->name, scope); - for (const LookupItem &match : matches) { - if (!match.scope()) - continue; - const Class *klass = match.scope()->asClass(); - if (!klass || !klass->name()) - continue; - const Identifier * const classId = klass->name()->identifier(); - if (classId && QString::fromUtf8(classId->chars(), classId->size()) == "QObject") - return true; - } - - return false; -} - -void CppModelManager::addRefactoringEngine(RefactoringEngineType type, - RefactoringEngineInterface *refactoringEngine) -{ - instance()->d->m_refactoringEngines[type] = refactoringEngine; -} - -void CppModelManager::removeRefactoringEngine(RefactoringEngineType type) -{ - instance()->d->m_refactoringEngines.remove(type); -} - -RefactoringEngineInterface *CppModelManager::builtinRefactoringEngine() -{ - return instance()->d->m_refactoringEngines.value(RefactoringEngineType::BuiltIn); -} - -FollowSymbolInterface &CppModelManager::builtinFollowSymbol() -{ - return instance()->d->m_builtinModelManagerSupport->followSymbolInterface(); -} - -template<class FilterClass> -static void setFilter(std::unique_ptr<FilterClass> &filter, - std::unique_ptr<FilterClass> &&newFilter) -{ - QTC_ASSERT(newFilter, return;); - filter = std::move(newFilter); -} - -void CppModelManager::setLocatorFilter(std::unique_ptr<Core::ILocatorFilter> &&filter) -{ - setFilter(d->m_locatorFilter, std::move(filter)); -} - -void CppModelManager::setClassesFilter(std::unique_ptr<Core::ILocatorFilter> &&filter) -{ - setFilter(d->m_classesFilter, std::move(filter)); -} - -void CppModelManager::setIncludesFilter(std::unique_ptr<Core::ILocatorFilter> &&filter) -{ - setFilter(d->m_includesFilter, std::move(filter)); -} - -void CppModelManager::setFunctionsFilter(std::unique_ptr<Core::ILocatorFilter> &&filter) -{ - setFilter(d->m_functionsFilter, std::move(filter)); -} - -void CppModelManager::setSymbolsFindFilter(std::unique_ptr<Core::IFindFilter> &&filter) -{ - setFilter(d->m_symbolsFindFilter, std::move(filter)); -} - -void CppModelManager::setCurrentDocumentFilter(std::unique_ptr<Core::ILocatorFilter> &&filter) -{ - setFilter(d->m_currentDocumentFilter, std::move(filter)); -} - -Core::ILocatorFilter *CppModelManager::locatorFilter() const -{ - return d->m_locatorFilter.get(); -} - -Core::ILocatorFilter *CppModelManager::classesFilter() const -{ - return d->m_classesFilter.get(); -} - -Core::ILocatorFilter *CppModelManager::includesFilter() const -{ - return d->m_includesFilter.get(); -} - -Core::ILocatorFilter *CppModelManager::functionsFilter() const -{ - return d->m_functionsFilter.get(); -} - -Core::IFindFilter *CppModelManager::symbolsFindFilter() const -{ - return d->m_symbolsFindFilter.get(); -} - -Core::ILocatorFilter *CppModelManager::currentDocumentFilter() const -{ - return d->m_currentDocumentFilter.get(); -} - -FollowSymbolInterface &CppModelManager::followSymbolInterface() const -{ - return d->m_activeModelManagerSupport->followSymbolInterface(); -} - -std::unique_ptr<AbstractOverviewModel> CppModelManager::createOverviewModel() const -{ - return d->m_activeModelManagerSupport->createOverviewModel(); -} - -QString CppModelManager::configurationFileName() -{ - return Preprocessor::configurationFileName(); -} - -void CppModelManager::updateModifiedSourceFiles() -{ - const Snapshot snapshot = this->snapshot(); - QList<Document::Ptr> documentsToCheck; - foreach (const Document::Ptr document, snapshot) - documentsToCheck << document; - - updateSourceFiles(timeStampModifiedFiles(documentsToCheck)); -} - -/*! - \class CppTools::CppModelManager - \brief The CppModelManager keeps tracks of the source files the code model is aware of. - - The CppModelManager manages the source files in a Snapshot object. - - The snapshot is updated in case e.g. - * New files are opened/edited (Editor integration) - * A project manager pushes updated project information (Project integration) - * Files are garbage collected -*/ - -CppModelManager *CppModelManager::instance() -{ - QTC_ASSERT(m_instance, return nullptr;); - return m_instance; -} - -void CppModelManager::registerJsExtension() -{ - Core::JsExpander::registerGlobalObject("Cpp", [this] { - return new CppToolsJsExtension(&d->m_locatorData); - }); -} - -void CppModelManager::initCppTools() -{ - // Objects - connect(Core::VcsManager::instance(), &Core::VcsManager::repositoryChanged, - this, &CppModelManager::updateModifiedSourceFiles); - connect(Core::DocumentManager::instance(), &Core::DocumentManager::filesChangedInternally, - [this](const Utils::FilePaths &filePaths) { - updateSourceFiles(Utils::transform<QSet>(filePaths, &Utils::FilePath::toString)); - }); - - connect(this, &CppModelManager::documentUpdated, - &d->m_locatorData, &CppLocatorData::onDocumentUpdated); - - connect(this, &CppModelManager::aboutToRemoveFiles, - &d->m_locatorData, &CppLocatorData::onAboutToRemoveFiles); - - // Set up builtin filters - setLocatorFilter(std::make_unique<CppLocatorFilter>(&d->m_locatorData)); - setClassesFilter(std::make_unique<CppClassesFilter>(&d->m_locatorData)); - setIncludesFilter(std::make_unique<CppIncludesFilter>()); - setFunctionsFilter(std::make_unique<CppFunctionsFilter>(&d->m_locatorData)); - setSymbolsFindFilter(std::make_unique<SymbolsFindFilter>(this)); - setCurrentDocumentFilter( - std::make_unique<Internal::CppCurrentDocumentFilter>(this)); -} - -void CppModelManager::initializeBuiltinModelManagerSupport() -{ - d->m_builtinModelManagerSupport - = BuiltinModelManagerSupportProvider().createModelManagerSupport(); - d->m_activeModelManagerSupport = d->m_builtinModelManagerSupport; - d->m_refactoringEngines[RefactoringEngineType::BuiltIn] = - &d->m_activeModelManagerSupport->refactoringEngineInterface(); -} - -CppModelManager::CppModelManager() - : CppModelManagerBase(nullptr) - , d(new CppModelManagerPrivate) -{ - m_instance = this; - - // Used for weak dependency in VcsBaseSubmitEditor - setObjectName("CppModelManager"); - ExtensionSystem::PluginManager::addObject(this); - - d->m_enableGC = true; - - // Visual C++ has 1MiB, macOSX has 512KiB - if (Utils::HostOsInfo::isWindowsHost() || Utils::HostOsInfo::isMacHost()) - d->m_threadPool.setStackSize(2 * 1024 * 1024); - - qRegisterMetaType<QSet<QString> >(); - connect(this, &CppModelManager::sourceFilesRefreshed, - this, &CppModelManager::onSourceFilesRefreshed); - - d->m_findReferences = new CppFindReferences(this); - d->m_indexerEnabled = qgetenv("QTC_NO_CODE_INDEXER") != "1"; - - d->m_dirty = true; - - d->m_delayedGcTimer.setObjectName(QLatin1String("CppModelManager::m_delayedGcTimer")); - d->m_delayedGcTimer.setSingleShot(true); - connect(&d->m_delayedGcTimer, &QTimer::timeout, this, &CppModelManager::GC); - - auto sessionManager = ProjectExplorer::SessionManager::instance(); - connect(sessionManager, &ProjectExplorer::SessionManager::projectAdded, - this, &CppModelManager::onProjectAdded); - connect(sessionManager, &ProjectExplorer::SessionManager::aboutToRemoveProject, - this, &CppModelManager::onAboutToRemoveProject); - connect(sessionManager, &ProjectExplorer::SessionManager::aboutToLoadSession, - this, &CppModelManager::onAboutToLoadSession); - connect(sessionManager, &ProjectExplorer::SessionManager::startupProjectChanged, - this, &CppModelManager::onActiveProjectChanged); - - connect(Core::EditorManager::instance(), &Core::EditorManager::currentEditorChanged, - this, &CppModelManager::onCurrentEditorChanged); - - connect(Core::DocumentManager::instance(), &Core::DocumentManager::allDocumentsRenamed, - this, &CppModelManager::renameIncludes); - - connect(Core::ICore::instance(), &Core::ICore::coreAboutToClose, - this, &CppModelManager::onCoreAboutToClose); - - connect(KitManager::instance(), &KitManager::kitsChanged, this, - &CppModelManager::setupFallbackProjectPart); - setupFallbackProjectPart(); - - qRegisterMetaType<CPlusPlus::Document::Ptr>("CPlusPlus::Document::Ptr"); - qRegisterMetaType<QList<Document::DiagnosticMessage>>( - "QList<CPlusPlus::Document::DiagnosticMessage>"); - - initializeBuiltinModelManagerSupport(); - - d->m_internalIndexingSupport = new BuiltinIndexingSupport; - - initCppTools(); -} - -CppModelManager::~CppModelManager() -{ - ExtensionSystem::PluginManager::removeObject(this); - - delete d->m_internalIndexingSupport; - delete d; -} - -Snapshot CppModelManager::snapshot() const -{ - QMutexLocker locker(&d->m_snapshotMutex); - return d->m_snapshot; -} - -Document::Ptr CppModelManager::document(const QString &fileName) const -{ - QMutexLocker locker(&d->m_snapshotMutex); - return d->m_snapshot.document(fileName); -} - -/// Replace the document in the snapshot. -/// -/// \returns true if successful, false if the new document is out-dated. -bool CppModelManager::replaceDocument(Document::Ptr newDoc) -{ - QMutexLocker locker(&d->m_snapshotMutex); - - Document::Ptr previous = d->m_snapshot.document(newDoc->fileName()); - if (previous && (newDoc->revision() != 0 && newDoc->revision() < previous->revision())) - // the new document is outdated - return false; - - d->m_snapshot.insert(newDoc); - return true; -} - -/// Make sure that m_projectLock is locked for writing when calling this. -void CppModelManager::ensureUpdated() -{ - if (!d->m_dirty) - return; - - d->m_projectFiles = internalProjectFiles(); - d->m_headerPaths = internalHeaderPaths(); - d->m_definedMacros = internalDefinedMacros(); - d->m_dirty = false; -} - -QStringList CppModelManager::internalProjectFiles() const -{ - QStringList files; - for (const ProjectData &projectData : qAsConst(d->m_projectData)) { - for (const ProjectPart::ConstPtr &part : projectData.projectInfo->projectParts()) { - for (const ProjectFile &file : part->files) - files += file.path; - } - } - files.removeDuplicates(); - return files; -} - -ProjectExplorer::HeaderPaths CppModelManager::internalHeaderPaths() const -{ - ProjectExplorer::HeaderPaths headerPaths; - for (const ProjectData &projectData: qAsConst(d->m_projectData)) { - for (const ProjectPart::ConstPtr &part : projectData.projectInfo->projectParts()) { - for (const ProjectExplorer::HeaderPath &path : part->headerPaths) { - ProjectExplorer::HeaderPath hp(QDir::cleanPath(path.path), path.type); - if (!headerPaths.contains(hp)) - headerPaths.push_back(std::move(hp)); - } - } - } - return headerPaths; -} - -static void addUnique(const ProjectExplorer::Macros &newMacros, - ProjectExplorer::Macros ¯os, - QSet<ProjectExplorer::Macro> &alreadyIn) -{ - for (const ProjectExplorer::Macro ¯o : newMacros) { - if (!alreadyIn.contains(macro)) { - macros += macro; - alreadyIn.insert(macro); - } - } -} - -ProjectExplorer::Macros CppModelManager::internalDefinedMacros() const -{ - ProjectExplorer::Macros macros; - QSet<ProjectExplorer::Macro> alreadyIn; - for (const ProjectData &projectData : qAsConst(d->m_projectData)) { - for (const ProjectPart::ConstPtr &part : projectData.projectInfo->projectParts()) { - addUnique(part->toolChainMacros, macros, alreadyIn); - addUnique(part->projectMacros, macros, alreadyIn); - } - } - return macros; -} - -/// This function will acquire mutexes! -void CppModelManager::dumpModelManagerConfiguration(const QString &logFileId) -{ - const Snapshot globalSnapshot = snapshot(); - const QString globalSnapshotTitle - = QString::fromLatin1("Global/Indexing Snapshot (%1 Documents)").arg(globalSnapshot.size()); - - CppCodeModelInspector::Dumper dumper(globalSnapshot, logFileId); - dumper.dumpProjectInfos(projectInfos()); - dumper.dumpSnapshot(globalSnapshot, globalSnapshotTitle, /*isGlobalSnapshot=*/ true); - dumper.dumpWorkingCopy(workingCopy()); - dumper.dumpMergedEntities(headerPaths(), - ProjectExplorer:: Macro::toByteArray(definedMacros())); -} - -QSet<AbstractEditorSupport *> CppModelManager::abstractEditorSupports() const -{ - return d->m_extraEditorSupports; -} - -void CppModelManager::addExtraEditorSupport(AbstractEditorSupport *editorSupport) -{ - d->m_extraEditorSupports.insert(editorSupport); -} - -void CppModelManager::removeExtraEditorSupport(AbstractEditorSupport *editorSupport) -{ - d->m_extraEditorSupports.remove(editorSupport); -} - -CppEditorDocumentHandle *CppModelManager::cppEditorDocument(const QString &filePath) const -{ - if (filePath.isEmpty()) - return nullptr; - - QMutexLocker locker(&d->m_cppEditorDocumentsMutex); - return d->m_cppEditorDocuments.value(filePath, 0); -} - -void CppModelManager::registerCppEditorDocument(CppEditorDocumentHandle *editorDocument) -{ - QTC_ASSERT(editorDocument, return); - const QString filePath = editorDocument->filePath(); - QTC_ASSERT(!filePath.isEmpty(), return); - - QMutexLocker locker(&d->m_cppEditorDocumentsMutex); - QTC_ASSERT(d->m_cppEditorDocuments.value(filePath, 0) == 0, return); - d->m_cppEditorDocuments.insert(filePath, editorDocument); -} - -void CppModelManager::unregisterCppEditorDocument(const QString &filePath) -{ - QTC_ASSERT(!filePath.isEmpty(), return); - - static short closedCppDocuments = 0; - int openCppDocuments = 0; - - { - QMutexLocker locker(&d->m_cppEditorDocumentsMutex); - QTC_ASSERT(d->m_cppEditorDocuments.value(filePath, 0), return); - QTC_CHECK(d->m_cppEditorDocuments.remove(filePath) == 1); - openCppDocuments = d->m_cppEditorDocuments.size(); - } - - ++closedCppDocuments; - if (openCppDocuments == 0 || closedCppDocuments == 5) { - closedCppDocuments = 0; - delayedGC(); - } -} - -QList<int> CppModelManager::references(Symbol *symbol, const LookupContext &context) -{ - return d->m_findReferences->references(symbol, context); -} - -void CppModelManager::findUsages(Symbol *symbol, const LookupContext &context) -{ - if (symbol->identifier()) - d->m_findReferences->findUsages(symbol, context); -} - -void CppModelManager::renameUsages(Symbol *symbol, - const LookupContext &context, - const QString &replacement) -{ - if (symbol->identifier()) - d->m_findReferences->renameUsages(symbol, context, replacement); -} - -void CppModelManager::findMacroUsages(const CPlusPlus::Macro ¯o) -{ - d->m_findReferences->findMacroUses(macro); -} - -void CppModelManager::renameMacroUsages(const CPlusPlus::Macro ¯o, const QString &replacement) -{ - d->m_findReferences->renameMacroUses(macro, replacement); -} - -void CppModelManager::replaceSnapshot(const Snapshot &newSnapshot) -{ - QMutexLocker snapshotLocker(&d->m_snapshotMutex); - d->m_snapshot = newSnapshot; -} - -WorkingCopy CppModelManager::buildWorkingCopyList() -{ - WorkingCopy workingCopy; - - foreach (const CppEditorDocumentHandle *cppEditorDocument, cppEditorDocuments()) { - workingCopy.insert(cppEditorDocument->filePath(), - cppEditorDocument->contents(), - cppEditorDocument->revision()); - } - - for (AbstractEditorSupport *es : qAsConst(d->m_extraEditorSupports)) - workingCopy.insert(es->fileName(), es->contents(), es->revision()); - - // Add the project configuration file - QByteArray conf = codeModelConfiguration(); - conf += ProjectExplorer::Macro::toByteArray(definedMacros()); - workingCopy.insert(configurationFileName(), conf); - - return workingCopy; -} - -WorkingCopy CppModelManager::workingCopy() const -{ - return const_cast<CppModelManager *>(this)->buildWorkingCopyList(); -} - -QByteArray CppModelManager::codeModelConfiguration() const -{ - return QByteArray::fromRawData(pp_configuration, qstrlen(pp_configuration)); -} - -CppLocatorData *CppModelManager::locatorData() const -{ - return &d->m_locatorData; -} - -static QSet<QString> tooBigFilesRemoved(const QSet<QString> &files, int fileSizeLimitInMb) -{ - if (fileSizeLimitInMb <= 0) - return files; - - QSet<QString> result; - QFileInfo fileInfo; - - for (const QString &filePath : files) { - fileInfo.setFile(filePath); - if (fileSizeExceedsLimit(fileInfo, fileSizeLimitInMb)) - continue; - - result << filePath; - } - - return result; -} - -QFuture<void> CppModelManager::updateSourceFiles(const QSet<QString> &sourceFiles, - ProgressNotificationMode mode) -{ - if (sourceFiles.isEmpty() || !d->m_indexerEnabled) - return QFuture<void>(); - - const QSet<QString> filteredFiles = tooBigFilesRemoved(sourceFiles, indexerFileSizeLimitInMb()); - - return d->m_internalIndexingSupport->refreshSourceFiles(filteredFiles, mode); -} - -QList<ProjectInfo::ConstPtr> CppModelManager::projectInfos() const -{ - QReadLocker locker(&d->m_projectLock); - return Utils::transform<QList<ProjectInfo::ConstPtr>>(d->m_projectData, - [](const ProjectData &d) { return d.projectInfo; }); -} - -ProjectInfo::ConstPtr CppModelManager::projectInfo(ProjectExplorer::Project *project) const -{ - QReadLocker locker(&d->m_projectLock); - return d->m_projectData.value(project).projectInfo; -} - -/// \brief Remove all files and their includes (recursively) of given ProjectInfo from the snapshot. -void CppModelManager::removeProjectInfoFilesAndIncludesFromSnapshot(const ProjectInfo &projectInfo) -{ - QMutexLocker snapshotLocker(&d->m_snapshotMutex); - foreach (const ProjectPart::ConstPtr &projectPart, projectInfo.projectParts()) { - foreach (const ProjectFile &cxxFile, projectPart->files) { - foreach (const QString &fileName, d->m_snapshot.allIncludesForDocument(cxxFile.path)) - d->m_snapshot.remove(fileName); - d->m_snapshot.remove(cxxFile.path); - } - } -} - -QList<CppEditorDocumentHandle *> CppModelManager::cppEditorDocuments() const -{ - QMutexLocker locker(&d->m_cppEditorDocumentsMutex); - return d->m_cppEditorDocuments.values(); -} - -/// \brief Remove all given files from the snapshot. -void CppModelManager::removeFilesFromSnapshot(const QSet<QString> &filesToRemove) -{ - QMutexLocker snapshotLocker(&d->m_snapshotMutex); - for (const QString &file : filesToRemove) - d->m_snapshot.remove(file); -} - -class ProjectInfoComparer -{ -public: - ProjectInfoComparer(const ProjectInfo &oldProjectInfo, - const ProjectInfo &newProjectInfo) - : m_old(oldProjectInfo) - , m_oldSourceFiles(oldProjectInfo.sourceFiles()) - , m_new(newProjectInfo) - , m_newSourceFiles(newProjectInfo.sourceFiles()) - {} - - bool definesChanged() const { return m_new.definesChanged(m_old); } - bool configurationChanged() const { return m_new.configurationChanged(m_old); } - bool configurationOrFilesChanged() const { return m_new.configurationOrFilesChanged(m_old); } - - QSet<QString> addedFiles() const - { - QSet<QString> addedFilesSet = m_newSourceFiles; - addedFilesSet.subtract(m_oldSourceFiles); - return addedFilesSet; - } - - QSet<QString> removedFiles() const - { - QSet<QString> removedFilesSet = m_oldSourceFiles; - removedFilesSet.subtract(m_newSourceFiles); - return removedFilesSet; - } - - QStringList removedProjectParts() - { - QSet<QString> removed = projectPartIds(m_old.projectParts()); - removed.subtract(projectPartIds(m_new.projectParts())); - return Utils::toList(removed); - } - - /// Returns a list of common files that have a changed timestamp. - QSet<QString> timeStampModifiedFiles(const Snapshot &snapshot) const - { - QSet<QString> commonSourceFiles = m_newSourceFiles; - commonSourceFiles.intersect(m_oldSourceFiles); - - QList<Document::Ptr> documentsToCheck; - for (const QString &file : commonSourceFiles) { - if (Document::Ptr document = snapshot.document(file)) - documentsToCheck << document; - } - - return CppModelManager::timeStampModifiedFiles(documentsToCheck); - } - -private: - static QSet<QString> projectPartIds(const QVector<ProjectPart::ConstPtr> &projectParts) - { - QSet<QString> ids; - - foreach (const ProjectPart::ConstPtr &projectPart, projectParts) - ids.insert(projectPart->id()); - - return ids; - } - -private: - const ProjectInfo &m_old; - const QSet<QString> m_oldSourceFiles; - - const ProjectInfo &m_new; - const QSet<QString> m_newSourceFiles; -}; - -/// Make sure that m_projectLock is locked for writing when calling this. -void CppModelManager::recalculateProjectPartMappings() -{ - d->m_projectPartIdToProjectProjectPart.clear(); - d->m_fileToProjectParts.clear(); - for (const ProjectData &projectData : qAsConst(d->m_projectData)) { - for (const ProjectPart::ConstPtr &projectPart : projectData.projectInfo->projectParts()) { - d->m_projectPartIdToProjectProjectPart[projectPart->id()] = projectPart; - for (const ProjectFile &cxxFile : projectPart->files) - d->m_fileToProjectParts[Utils::FilePath::fromString(cxxFile.path)].append( - projectPart); - } - } - - d->m_symbolFinder.clearCache(); -} - -void CppModelManagerPrivate::setupWatcher(const QFuture<void> &future, - ProjectExplorer::Project *project, - ProjectData *projectData, CppModelManager *q) -{ - projectData->indexer = new QFutureWatcher<void>(q); - const auto handleFinished = [this, project, watcher = projectData->indexer, q] { - if (const auto it = m_projectData.find(project); - it != m_projectData.end() && it->indexer == watcher) { - it->indexer = nullptr; - it->fullyIndexed = !watcher->isCanceled(); - } - watcher->disconnect(q); - watcher->deleteLater(); - }; - q->connect(projectData->indexer, &QFutureWatcher<void>::canceled, q, handleFinished); - q->connect(projectData->indexer, &QFutureWatcher<void>::finished, q, handleFinished); - projectData->indexer->setFuture(future); -} - -void CppModelManager::updateCppEditorDocuments(bool projectsUpdated) const -{ - // Refresh visible documents - QSet<Core::IDocument *> visibleCppEditorDocuments; - foreach (Core::IEditor *editor, Core::EditorManager::visibleEditors()) { - if (Core::IDocument *document = editor->document()) { - const QString filePath = document->filePath().toString(); - if (CppEditorDocumentHandle *theCppEditorDocument = cppEditorDocument(filePath)) { - visibleCppEditorDocuments.insert(document); - theCppEditorDocument->processor()->run(projectsUpdated); - } - } - } - - // Mark invisible documents dirty - QSet<Core::IDocument *> invisibleCppEditorDocuments - = Utils::toSet(Core::DocumentModel::openedDocuments()); - invisibleCppEditorDocuments.subtract(visibleCppEditorDocuments); - foreach (Core::IDocument *document, invisibleCppEditorDocuments) { - const QString filePath = document->filePath().toString(); - if (CppEditorDocumentHandle *theCppEditorDocument = cppEditorDocument(filePath)) { - const CppEditorDocumentHandle::RefreshReason refreshReason = projectsUpdated - ? CppEditorDocumentHandle::ProjectUpdate - : CppEditorDocumentHandle::Other; - theCppEditorDocument->setRefreshReason(refreshReason); - } - } -} - -QFuture<void> CppModelManager::updateProjectInfo(const ProjectInfo::ConstPtr &newProjectInfo, - const QSet<QString> &additionalFiles) -{ - if (!newProjectInfo) - return {}; - - QSet<QString> filesToReindex; - QStringList removedProjectParts; - bool filesRemoved = false; - - ProjectExplorer::Project * const project = projectForProjectInfo(*newProjectInfo); - if (!project) - return {}; - - ProjectData *projectData = nullptr; - { // Only hold the lock for a limited scope, so the dumping afterwards does not deadlock. - QWriteLocker projectLocker(&d->m_projectLock); - - const QSet<QString> newSourceFiles = newProjectInfo->sourceFiles(); - - // Check if we can avoid a full reindexing - const auto it = d->m_projectData.find(project); - if (it != d->m_projectData.end() && it->projectInfo && it->fullyIndexed) { - ProjectInfoComparer comparer(*it->projectInfo, *newProjectInfo); - if (comparer.configurationOrFilesChanged()) { - d->m_dirty = true; - - // If the project configuration changed, do a full reindexing - if (comparer.configurationChanged()) { - removeProjectInfoFilesAndIncludesFromSnapshot(*it->projectInfo); - filesToReindex.unite(newSourceFiles); - - // The "configuration file" includes all defines and therefore should be updated - if (comparer.definesChanged()) { - QMutexLocker snapshotLocker(&d->m_snapshotMutex); - d->m_snapshot.remove(configurationFileName()); - } - - // Otherwise check for added and modified files - } else { - const QSet<QString> addedFiles = comparer.addedFiles(); - filesToReindex.unite(addedFiles); - - const QSet<QString> modifiedFiles = comparer.timeStampModifiedFiles(snapshot()); - filesToReindex.unite(modifiedFiles); - } - - // Announce and purge the removed files from the snapshot - const QSet<QString> removedFiles = comparer.removedFiles(); - if (!removedFiles.isEmpty()) { - filesRemoved = true; - emit aboutToRemoveFiles(Utils::toList(removedFiles)); - removeFilesFromSnapshot(removedFiles); - } - } - - removedProjectParts = comparer.removedProjectParts(); - - // A new project was opened/created, do a full indexing - } else { - d->m_dirty = true; - filesToReindex.unite(newSourceFiles); - } - - // Update Project/ProjectInfo and File/ProjectPart table - if (it != d->m_projectData.end()) { - if (it->indexer) - it->indexer->cancel(); - it->projectInfo = newProjectInfo; - it->fullyIndexed = false; - } - projectData = it == d->m_projectData.end() - ? &(d->m_projectData[project] = ProjectData{newProjectInfo, nullptr, false}) - : &(*it); - recalculateProjectPartMappings(); - } // Locker scope - - // If requested, dump everything we got - if (DumpProjectInfo) - dumpModelManagerConfiguration(QLatin1String("updateProjectInfo")); - - // Remove files from snapshot that are not reachable any more - if (filesRemoved) - GC(); - - // Announce removed project parts - if (!removedProjectParts.isEmpty()) - emit projectPartsRemoved(removedProjectParts); - - // Announce added project parts - emit projectPartsUpdated(project); - - // Ideally, we would update all the editor documents that depend on the 'filesToReindex'. - // However, on e.g. a session restore first the editor documents are created and then the - // project updates come in. That is, there are no reasonable dependency tables based on - // resolved includes that we could rely on. - updateCppEditorDocuments(/*projectsUpdated = */ true); - - filesToReindex.unite(additionalFiles); - // Trigger reindexing - const QFuture<void> indexingFuture = updateSourceFiles(filesToReindex, - ForcedProgressNotification); - - // It's safe to do this here, as only the UI thread writes to the map and no other thread - // uses the indexer value. - d->setupWatcher(indexingFuture, project, projectData, this); - - return indexingFuture; -} - -ProjectPart::ConstPtr CppModelManager::projectPartForId(const QString &projectPartId) const -{ - QReadLocker locker(&d->m_projectLock); - return d->m_projectPartIdToProjectProjectPart.value(projectPartId); -} - -QList<ProjectPart::ConstPtr> CppModelManager::projectPart(const Utils::FilePath &fileName) const -{ - QReadLocker locker(&d->m_projectLock); - return d->m_fileToProjectParts.value(fileName); -} - -QList<ProjectPart::ConstPtr> CppModelManager::projectPartFromDependencies( - const Utils::FilePath &fileName) const -{ - QSet<ProjectPart::ConstPtr> parts; - const Utils::FilePaths deps = snapshot().filesDependingOn(fileName); - - QReadLocker locker(&d->m_projectLock); - for (const Utils::FilePath &dep : deps) - parts.unite(Utils::toSet(d->m_fileToProjectParts.value(dep))); - - return parts.values(); -} - -ProjectPart::ConstPtr CppModelManager::fallbackProjectPart() -{ - QMutexLocker locker(&d->m_fallbackProjectPartMutex); - return d->m_fallbackProjectPart; -} - -bool CppModelManager::isCppEditor(Core::IEditor *editor) -{ - return editor->context().contains(ProjectExplorer::Constants::CXX_LANGUAGE_ID); -} - -bool CppModelManager::supportsOutline(const TextEditor::TextDocument *document) -{ - return instance()->d->m_activeModelManagerSupport->supportsOutline(document); -} - -bool CppModelManager::isClangCodeModelActive() const -{ - return d->m_activeModelManagerSupport != d->m_builtinModelManagerSupport; -} - -void CppModelManager::emitDocumentUpdated(Document::Ptr doc) -{ - if (replaceDocument(doc)) - emit documentUpdated(doc); -} - -void CppModelManager::emitAbstractEditorSupportContentsUpdated(const QString &filePath, - const QString &sourcePath, - const QByteArray &contents) -{ - emit abstractEditorSupportContentsUpdated(filePath, sourcePath, contents); -} - -void CppModelManager::emitAbstractEditorSupportRemoved(const QString &filePath) -{ - emit abstractEditorSupportRemoved(filePath); -} - -void CppModelManager::onProjectAdded(ProjectExplorer::Project *) -{ - QWriteLocker locker(&d->m_projectLock); - d->m_dirty = true; -} - -void CppModelManager::delayedGC() -{ - if (d->m_enableGC) - d->m_delayedGcTimer.start(500); -} - -static QStringList removedProjectParts(const QStringList &before, const QStringList &after) -{ - QSet<QString> b = Utils::toSet(before); - b.subtract(Utils::toSet(after)); - - return Utils::toList(b); -} - -void CppModelManager::onAboutToRemoveProject(ProjectExplorer::Project *project) -{ - QStringList idsOfRemovedProjectParts; - - { - QWriteLocker locker(&d->m_projectLock); - d->m_dirty = true; - const QStringList projectPartsIdsBefore = d->m_projectPartIdToProjectProjectPart.keys(); - - d->m_projectData.remove(project); - recalculateProjectPartMappings(); - - const QStringList projectPartsIdsAfter = d->m_projectPartIdToProjectProjectPart.keys(); - idsOfRemovedProjectParts = removedProjectParts(projectPartsIdsBefore, projectPartsIdsAfter); - } - - if (!idsOfRemovedProjectParts.isEmpty()) - emit projectPartsRemoved(idsOfRemovedProjectParts); - - delayedGC(); -} - -void CppModelManager::onActiveProjectChanged(ProjectExplorer::Project *project) -{ - if (!project) - return; // Last project closed. - - { - QReadLocker locker(&d->m_projectLock); - if (!d->m_projectData.contains(project)) - return; // Not yet known to us. - } - - updateCppEditorDocuments(); -} - -void CppModelManager::onSourceFilesRefreshed() const -{ - if (BuiltinIndexingSupport::isFindErrorsIndexingActive()) { - QTimer::singleShot(1, QCoreApplication::instance(), &QCoreApplication::quit); - qDebug("FindErrorsIndexing: Done, requesting Qt Creator to quit."); - } -} - -void CppModelManager::onCurrentEditorChanged(Core::IEditor *editor) -{ - if (!editor || !editor->document()) - return; - - const QString filePath = editor->document()->filePath().toString(); - if (CppEditorDocumentHandle *theCppEditorDocument = cppEditorDocument(filePath)) { - const CppEditorDocumentHandle::RefreshReason refreshReason - = theCppEditorDocument->refreshReason(); - if (refreshReason != CppEditorDocumentHandle::None) { - const bool projectsChanged = refreshReason == CppEditorDocumentHandle::ProjectUpdate; - theCppEditorDocument->setRefreshReason(CppEditorDocumentHandle::None); - theCppEditorDocument->processor()->run(projectsChanged); - } - } -} - -void CppModelManager::onAboutToLoadSession() -{ - if (d->m_delayedGcTimer.isActive()) - d->m_delayedGcTimer.stop(); - GC(); -} - -QSet<QString> CppModelManager::dependingInternalTargets(const Utils::FilePath &file) const -{ - QSet<QString> result; - const Snapshot snapshot = this->snapshot(); - QTC_ASSERT(snapshot.contains(file), return result); - bool wasHeader; - const QString correspondingFile - = correspondingHeaderOrSource(file.toString(), &wasHeader, CacheUsage::ReadOnly); - const Utils::FilePaths dependingFiles = snapshot.filesDependingOn( - wasHeader ? file : Utils::FilePath::fromString(correspondingFile)); - for (const Utils::FilePath &fn : qAsConst(dependingFiles)) { - for (const ProjectPart::ConstPtr &part : projectPart(fn)) - result.insert(part->buildSystemTarget); - } - return result; -} - -QSet<QString> CppModelManager::internalTargets(const Utils::FilePath &filePath) const -{ - const QList<ProjectPart::ConstPtr> projectParts = projectPart(filePath); - // if we have no project parts it's most likely a header with declarations only and CMake based - if (projectParts.isEmpty()) - return dependingInternalTargets(filePath); - QSet<QString> targets; - for (const ProjectPart::ConstPtr &part : projectParts) { - targets.insert(part->buildSystemTarget); - if (part->buildTargetType != ProjectExplorer::BuildTargetType::Executable) - targets.unite(dependingInternalTargets(filePath)); - } - return targets; -} - -void CppModelManager::renameIncludes(const Utils::FilePath &oldFilePath, - const Utils::FilePath &newFilePath) -{ - if (oldFilePath.isEmpty() || newFilePath.isEmpty()) - return; - - // We just want to handle renamings so return when the file was actually moved. - if (oldFilePath.absolutePath() != newFilePath.absolutePath()) - return; - - const TextEditor::RefactoringChanges changes; - - foreach (Snapshot::IncludeLocation loc, - snapshot().includeLocationsOfDocument(oldFilePath.toString())) { - TextEditor::RefactoringFilePtr file = changes.file( - Utils::FilePath::fromString(loc.first->fileName())); - const QTextBlock &block = file->document()->findBlockByNumber(loc.second - 1); - const int replaceStart = block.text().indexOf(oldFilePath.fileName()); - if (replaceStart > -1) { - Utils::ChangeSet changeSet; - changeSet.replace(block.position() + replaceStart, - block.position() + replaceStart + oldFilePath.fileName().length(), - newFilePath.fileName()); - file->setChangeSet(changeSet); - file->apply(); - } - } -} - -// Return the class name which function belongs to -static const char *belongingClassName(const Function *function) -{ - if (!function) - return nullptr; - - if (auto funcName = function->name()) { - if (auto qualifiedNameId = funcName->asQualifiedNameId()) { - if (const Name *funcBaseName = qualifiedNameId->base()) { - if (auto identifier = funcBaseName->identifier()) - return identifier->chars(); - } - } - } - - return nullptr; -} - -QSet<QString> CppModelManager::symbolsInFiles(const QSet<Utils::FilePath> &files) const -{ - QSet<QString> uniqueSymbols; - const Snapshot cppSnapShot = snapshot(); - - // Iterate over the files and get interesting symbols - for (const Utils::FilePath &file : files) { - // Add symbols from the C++ code model - const CPlusPlus::Document::Ptr doc = cppSnapShot.document(file); - if (!doc.isNull() && doc->control()) { - const CPlusPlus::Control *ctrl = doc->control(); - CPlusPlus::Symbol **symPtr = ctrl->firstSymbol(); // Read-only - while (symPtr != ctrl->lastSymbol()) { - const CPlusPlus::Symbol *sym = *symPtr; - - const CPlusPlus::Identifier *symId = sym->identifier(); - // Add any class, function or namespace identifiers - if ((sym->isClass() || sym->isFunction() || sym->isNamespace()) && symId - && symId->chars()) { - uniqueSymbols.insert(QString::fromUtf8(symId->chars())); - } - - // Handle specific case : get "Foo" in "void Foo::function() {}" - if (sym->isFunction() && !sym->asFunction()->isDeclaration()) { - const char *className = belongingClassName(sym->asFunction()); - if (className) - uniqueSymbols.insert(QString::fromUtf8(className)); - } - - ++symPtr; - } - } - } - return uniqueSymbols; -} - -void CppModelManager::onCoreAboutToClose() -{ - Core::ProgressManager::cancelTasks(CppTools::Constants::TASK_INDEX); - d->m_enableGC = false; -} - -void CppModelManager::setupFallbackProjectPart() -{ - ToolChainInfo tcInfo; - RawProjectPart rpp; - rpp.setMacros(definedMacros()); - rpp.setHeaderPaths(headerPaths()); - rpp.setQtVersion(Utils::QtVersion::Qt5); - - // Do not activate ObjectiveCExtensions since this will lead to the - // "objective-c++" language option for a project-less *.cpp file. - Utils::LanguageExtensions langExtensions = Utils::LanguageExtension::All; - langExtensions &= ~Utils::LanguageExtensions(Utils::LanguageExtension::ObjectiveC); - - // TODO: Use different fallback toolchain for different kinds of files? - const Kit * const defaultKit = KitManager::isLoaded() ? KitManager::defaultKit() : nullptr; - const ToolChain * const defaultTc = defaultKit - ? ToolChainKitAspect::cxxToolChain(defaultKit) : nullptr; - if (defaultKit && defaultTc) { - Utils::FilePath sysroot = SysRootKitAspect::sysRoot(defaultKit); - if (sysroot.isEmpty()) - sysroot = Utils::FilePath::fromString(defaultTc->sysRoot()); - Utils::Environment env = defaultKit->buildEnvironment(); - tcInfo = ToolChainInfo(defaultTc, sysroot.toString(), env); - const auto macroInspectionWrapper = [runner = tcInfo.macroInspectionRunner]( - const QStringList &flags) { - ToolChain::MacroInspectionReport report = runner(flags); - report.languageVersion = Utils::LanguageVersion::LatestCxx; - return report; - }; - tcInfo.macroInspectionRunner = macroInspectionWrapper; - } - - const auto part = ProjectPart::create({}, rpp, {}, {}, {}, langExtensions, {}, tcInfo); - QMutexLocker locker(&d->m_fallbackProjectPartMutex); - d->m_fallbackProjectPart = part; -} - -void CppModelManager::GC() -{ - if (!d->m_enableGC) - return; - - // Collect files of opened editors and editor supports (e.g. ui code model) - QStringList filesInEditorSupports; - foreach (const CppEditorDocumentHandle *editorDocument, cppEditorDocuments()) - filesInEditorSupports << editorDocument->filePath(); - - foreach (AbstractEditorSupport *abstractEditorSupport, abstractEditorSupports()) - filesInEditorSupports << abstractEditorSupport->fileName(); - - Snapshot currentSnapshot = snapshot(); - QSet<Utils::FilePath> reachableFiles; - // The configuration file is part of the project files, which is just fine. - // If single files are open, without any project, then there is no need to - // keep the configuration file around. - QStringList todo = filesInEditorSupports + projectFiles(); - - // Collect all files that are reachable from the project files - while (!todo.isEmpty()) { - const QString file = todo.last(); - todo.removeLast(); - - const Utils::FilePath fileName = Utils::FilePath::fromString(file); - if (reachableFiles.contains(fileName)) - continue; - reachableFiles.insert(fileName); - - if (Document::Ptr doc = currentSnapshot.document(file)) - todo += doc->includedFiles(); - } - - // Find out the files in the current snapshot that are not reachable from the project files - QStringList notReachableFiles; - Snapshot newSnapshot; - for (Snapshot::const_iterator it = currentSnapshot.begin(); it != currentSnapshot.end(); ++it) { - const Utils::FilePath &fileName = it.key(); - - if (reachableFiles.contains(fileName)) - newSnapshot.insert(it.value()); - else - notReachableFiles.append(fileName.toString()); - } - - // Announce removing files and replace the snapshot - emit aboutToRemoveFiles(notReachableFiles); - replaceSnapshot(newSnapshot); - emit gcFinished(); -} - -void CppModelManager::finishedRefreshingSourceFiles(const QSet<QString> &files) -{ - emit sourceFilesRefreshed(files); -} - -void CppModelManager::activateClangCodeModel( - ModelManagerSupportProvider *modelManagerSupportProvider) -{ - QTC_ASSERT(modelManagerSupportProvider, return); - - d->m_activeModelManagerSupport = modelManagerSupportProvider->createModelManagerSupport(); - d->m_refactoringEngines[RefactoringEngineType::ClangCodeModel] = - &d->m_activeModelManagerSupport->refactoringEngineInterface(); -} - -CppCompletionAssistProvider *CppModelManager::completionAssistProvider() const -{ - return d->m_activeModelManagerSupport->completionAssistProvider(); -} - -CppCompletionAssistProvider *CppModelManager::functionHintAssistProvider() const -{ - return d->m_activeModelManagerSupport->functionHintAssistProvider(); -} - -TextEditor::BaseHoverHandler *CppModelManager::createHoverHandler() const -{ - return d->m_activeModelManagerSupport->createHoverHandler(); -} - -BaseEditorDocumentProcessor *CppModelManager::createEditorDocumentProcessor( - TextEditor::TextDocument *baseTextDocument) const -{ - return d->m_activeModelManagerSupport->createEditorDocumentProcessor(baseTextDocument); -} - -CppIndexingSupport *CppModelManager::indexingSupport() -{ - return d->m_internalIndexingSupport; -} - -QStringList CppModelManager::projectFiles() -{ - QWriteLocker locker(&d->m_projectLock); - ensureUpdated(); - - return d->m_projectFiles; -} - -ProjectExplorer::HeaderPaths CppModelManager::headerPaths() -{ - QWriteLocker locker(&d->m_projectLock); - ensureUpdated(); - - return d->m_headerPaths; -} - -void CppModelManager::setHeaderPaths(const ProjectExplorer::HeaderPaths &headerPaths) -{ - QWriteLocker locker(&d->m_projectLock); - d->m_headerPaths = headerPaths; -} - -ProjectExplorer::Macros CppModelManager::definedMacros() -{ - QWriteLocker locker(&d->m_projectLock); - ensureUpdated(); - - return d->m_definedMacros; -} - -void CppModelManager::enableGarbageCollector(bool enable) -{ - d->m_delayedGcTimer.stop(); - d->m_enableGC = enable; -} - -SymbolFinder *CppModelManager::symbolFinder() -{ - return &d->m_symbolFinder; -} - -QThreadPool *CppModelManager::sharedThreadPool() -{ - return &d->m_threadPool; -} - -} // namespace CppTools |