From 91c497b1aebaf4b24ac1e5b884940820c6a0a88c Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Tue, 7 Jul 2015 15:17:58 +0200 Subject: [PATCH 01/70] CppTools: Make updateProjectPart() const ...and rename to "determineProjectPart". This is in preparation for a follow-up change. determineProjectPart() should not set any state. Change-Id: Iad7be8638fd97a79a4227a944896ac9af0a36862 Reviewed-by: Erik Verbruggen --- .../clangeditordocumentparser.cpp | 2 +- .../cpptools/baseeditordocumentparser.cpp | 26 ++++++++++--------- .../cpptools/baseeditordocumentparser.h | 4 +-- .../cpptools/builtineditordocumentparser.cpp | 2 +- 4 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/plugins/clangcodemodel/clangeditordocumentparser.cpp b/src/plugins/clangcodemodel/clangeditordocumentparser.cpp index e12833ca9a1..9b342bd7d1a 100644 --- a/src/plugins/clangcodemodel/clangeditordocumentparser.cpp +++ b/src/plugins/clangcodemodel/clangeditordocumentparser.cpp @@ -94,7 +94,7 @@ void ClangEditorDocumentParser::update(CppTools::WorkingCopy workingCopy) QMutexLocker lock(m_marker->mutex()); QMutexLocker lock2(&m_mutex); - updateProjectPart(); + m_projectPart = determineProjectPart(); const QStringList options = createOptions(filePath(), projectPart(), true); qCDebug(log, "Reparse options (cmd line equivalent): %s", diff --git a/src/plugins/cpptools/baseeditordocumentparser.cpp b/src/plugins/cpptools/baseeditordocumentparser.cpp index 7f1e74785b1..d24e341b1f2 100644 --- a/src/plugins/cpptools/baseeditordocumentparser.cpp +++ b/src/plugins/cpptools/baseeditordocumentparser.cpp @@ -45,7 +45,7 @@ namespace CppTools { the "best" project part for a file. Derived classes are expected to implement update() by using the protected - mutex, updateProjectPart() and by respecting the options set by the client. + mutex, determineProjectPart() and by respecting the options set by the client. */ BaseEditorDocumentParser::BaseEditorDocumentParser(const QString &filePath) @@ -115,33 +115,35 @@ BaseEditorDocumentParser *BaseEditorDocumentParser::get(const QString &filePath) return 0; } -void BaseEditorDocumentParser::updateProjectPart() +ProjectPart::Ptr BaseEditorDocumentParser::determineProjectPart() const { - if (m_manuallySetProjectPart) { - m_projectPart = m_manuallySetProjectPart; - return; - } + if (m_manuallySetProjectPart) + return m_manuallySetProjectPart; + + ProjectPart::Ptr projectPart = m_projectPart; CppModelManager *cmm = CppModelManager::instance(); QList projectParts = cmm->projectPart(m_filePath); if (projectParts.isEmpty()) { - if (m_projectPart) + if (projectPart) // File is not directly part of any project, but we got one before. We will re-use it, // because re-calculating this can be expensive when the dependency table is big. - return; + return projectPart; // Fall-back step 1: Get some parts through the dependency table: projectParts = cmm->projectPartFromDependencies(Utils::FileName::fromString(m_filePath)); if (projectParts.isEmpty()) // Fall-back step 2: Use fall-back part from the model manager: - m_projectPart = cmm->fallbackProjectPart(); + projectPart = cmm->fallbackProjectPart(); else - m_projectPart = projectParts.first(); + projectPart = projectParts.first(); } else { - if (!projectParts.contains(m_projectPart)) + if (!projectParts.contains(projectPart)) // Apparently the project file changed, so update our project part. - m_projectPart = projectParts.first(); + projectPart = projectParts.first(); } + + return projectPart; } bool BaseEditorDocumentParser::editorDefinesChanged() const diff --git a/src/plugins/cpptools/baseeditordocumentparser.h b/src/plugins/cpptools/baseeditordocumentparser.h index ddd12fbb0aa..c8f5704a9dc 100644 --- a/src/plugins/cpptools/baseeditordocumentparser.h +++ b/src/plugins/cpptools/baseeditordocumentparser.h @@ -63,18 +63,18 @@ public: static BaseEditorDocumentParser *get(const QString &filePath); protected: - void updateProjectPart(); + ProjectPart::Ptr determineProjectPart() const; bool editorDefinesChanged() const; void resetEditorDefinesChanged(); protected: mutable QMutex m_mutex; + ProjectPart::Ptr m_projectPart; private: const QString m_filePath; - ProjectPart::Ptr m_projectPart; ProjectPart::Ptr m_manuallySetProjectPart; bool m_usePrecompiledHeaders; diff --git a/src/plugins/cpptools/builtineditordocumentparser.cpp b/src/plugins/cpptools/builtineditordocumentparser.cpp index 24ae027bfc4..8c2232f1422 100644 --- a/src/plugins/cpptools/builtineditordocumentparser.cpp +++ b/src/plugins/cpptools/builtineditordocumentparser.cpp @@ -62,7 +62,7 @@ void BuiltinEditorDocumentParser::update(WorkingCopy workingCopy) QString projectConfigFile; LanguageFeatures features = LanguageFeatures::defaultFeatures(); - updateProjectPart(); + m_projectPart = determineProjectPart(); if (m_forceSnapshotInvalidation) { invalidateSnapshot = true; From 442bdbded2b2268efcb3be1a969d432533023366 Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Tue, 7 Jul 2015 15:02:14 +0200 Subject: [PATCH 02/70] CppTools: Avoid unnecessary blocking of main thread Among others, BaseEditorDocumentParser::projectPart() was a blocking operation in case the parser was running. This led to noticeable GUI freezes for the ClangCodeModel since the function was called from the main thread. Rework *EditorDocumentParser to clearly separate the configuration data (input) from the actual object state. Querying/setting configuration or (last) state does not block anymore. update() is supposed to get the necessary configuration and the last state at the beginning and to set the new state at end. Change-Id: Ib4b534fa6ff373c3059826726b3f10ece95acc21 Reviewed-by: Erik Verbruggen --- .../clangeditordocumentparser.cpp | 16 +- src/plugins/cppeditor/cppeditordocument.cpp | 8 +- .../cpptools/baseeditordocumentparser.cpp | 101 +++++------- .../cpptools/baseeditordocumentparser.h | 48 +++--- .../cpptools/builtineditordocumentparser.cpp | 155 ++++++++++-------- .../cpptools/builtineditordocumentparser.h | 33 ++-- .../builtineditordocumentprocessor.cpp | 5 +- src/plugins/cpptools/cppmodelmanager_test.cpp | 46 +++--- .../cpptools/cppsourceprocessor_test.cpp | 1 + src/plugins/cpptools/cpptoolstestcase.cpp | 29 ++++ src/plugins/cpptools/cpptoolstestcase.h | 2 + 11 files changed, 253 insertions(+), 191 deletions(-) diff --git a/src/plugins/clangcodemodel/clangeditordocumentparser.cpp b/src/plugins/clangcodemodel/clangeditordocumentparser.cpp index 9b342bd7d1a..fd2c60dbaee 100644 --- a/src/plugins/clangcodemodel/clangeditordocumentparser.cpp +++ b/src/plugins/clangcodemodel/clangeditordocumentparser.cpp @@ -91,21 +91,25 @@ ClangEditorDocumentParser::ClangEditorDocumentParser(const QString &filePath) void ClangEditorDocumentParser::update(CppTools::WorkingCopy workingCopy) { QTC_ASSERT(m_marker, return); - QMutexLocker lock(m_marker->mutex()); - QMutexLocker lock2(&m_mutex); + QMutexLocker locker(&m_updateIsRunning); - m_projectPart = determineProjectPart(); - const QStringList options = createOptions(filePath(), projectPart(), true); + // Determine project part + State state_ = state(); + state_.projectPart = determineProjectPart(filePath(), configuration(), state_); + setState(state_); + // Determine command line arguments + const QStringList options = createOptions(filePath(), state_.projectPart, true); qCDebug(log, "Reparse options (cmd line equivalent): %s", commandLine(options, filePath()).toUtf8().constData()); - QTime t; t.start(); + // Run + QTime t; t.start(); + QMutexLocker lock(m_marker->mutex()); m_marker->setFileName(filePath()); m_marker->setCompilationOptions(options); const Internal::UnsavedFiles unsavedFiles = Utils::createUnsavedFiles(workingCopy); m_marker->reparse(unsavedFiles); - qCDebug(log) << "Reparse took" << t.elapsed() << "ms."; } diff --git a/src/plugins/cppeditor/cppeditordocument.cpp b/src/plugins/cppeditor/cppeditordocument.cpp index 77bffc7338c..2746303cf0e 100644 --- a/src/plugins/cppeditor/cppeditordocument.cpp +++ b/src/plugins/cppeditor/cppeditordocument.cpp @@ -268,9 +268,11 @@ void CppEditorDocument::setPreprocessorSettings(const CppTools::ProjectPart::Ptr { CppTools::BaseEditorDocumentParser *parser = processor()->parser(); QTC_ASSERT(parser, return); - if (parser->projectPart() != projectPart || parser->editorDefines() != defines) { - parser->setProjectPart(projectPart); - parser->setEditorDefines(defines); + if (parser->projectPart() != projectPart || parser->configuration().editorDefines != defines) { + CppTools::BaseEditorDocumentParser::Configuration config = parser->configuration(); + config.manuallySetProjectPart = projectPart; + config.editorDefines = defines; + parser->setConfiguration(config); emit preprocessorSettingsChanged(!defines.trimmed().isEmpty()); } diff --git a/src/plugins/cpptools/baseeditordocumentparser.cpp b/src/plugins/cpptools/baseeditordocumentparser.cpp index d24e341b1f2..31d08bd4317 100644 --- a/src/plugins/cpptools/baseeditordocumentparser.cpp +++ b/src/plugins/cpptools/baseeditordocumentparser.cpp @@ -44,15 +44,19 @@ namespace CppTools { It's meant to be used in the C++ editor to get precise results by using the "best" project part for a file. - Derived classes are expected to implement update() by using the protected - mutex, determineProjectPart() and by respecting the options set by the client. + Derived classes are expected to implement update() this way: + + \list + \li Get a copy of the configuration and the last state. + \li Acquire the protected m_updateIsRunning for the duration of update(). + \li Work on the data and do whatever is necessary. At least, update + the project part with the help of determineProjectPart(). + \li Ensure the new state is set before update() returns. + \endlist */ BaseEditorDocumentParser::BaseEditorDocumentParser(const QString &filePath) - : m_mutex(QMutex::Recursive) - , m_filePath(filePath) - , m_usePrecompiledHeaders(false) - , m_editorDefinesChangedSinceLastUpdate(false) + : m_filePath(filePath) { } @@ -65,44 +69,33 @@ QString BaseEditorDocumentParser::filePath() const return m_filePath; } +BaseEditorDocumentParser::Configuration BaseEditorDocumentParser::configuration() const +{ + QMutexLocker locker(&m_stateAndConfigurationMutex); + return m_configuration; +} + +void BaseEditorDocumentParser::setConfiguration(const Configuration &configuration) +{ + QMutexLocker locker(&m_stateAndConfigurationMutex); + m_configuration = configuration; +} + +BaseEditorDocumentParser::State BaseEditorDocumentParser::state() const +{ + QMutexLocker locker(&m_stateAndConfigurationMutex); + return m_state; +} + +void BaseEditorDocumentParser::setState(const State &state) +{ + QMutexLocker locker(&m_stateAndConfigurationMutex); + m_state = state; +} + ProjectPart::Ptr BaseEditorDocumentParser::projectPart() const { - QMutexLocker locker(&m_mutex); - return m_projectPart; -} - -void BaseEditorDocumentParser::setProjectPart(ProjectPart::Ptr projectPart) -{ - QMutexLocker locker(&m_mutex); - m_manuallySetProjectPart = projectPart; -} - -bool BaseEditorDocumentParser::usePrecompiledHeaders() const -{ - QMutexLocker locker(&m_mutex); - return m_usePrecompiledHeaders; -} - -void BaseEditorDocumentParser::setUsePrecompiledHeaders(bool usePrecompiledHeaders) -{ - QMutexLocker locker(&m_mutex); - m_usePrecompiledHeaders = usePrecompiledHeaders; -} - -QByteArray BaseEditorDocumentParser::editorDefines() const -{ - QMutexLocker locker(&m_mutex); - return m_editorDefines; -} - -void BaseEditorDocumentParser::setEditorDefines(const QByteArray &editorDefines) -{ - QMutexLocker locker(&m_mutex); - - if (editorDefines != m_editorDefines) { - m_editorDefines = editorDefines; - m_editorDefinesChangedSinceLastUpdate = true; - } + return state().projectPart; } BaseEditorDocumentParser *BaseEditorDocumentParser::get(const QString &filePath) @@ -115,15 +108,17 @@ BaseEditorDocumentParser *BaseEditorDocumentParser::get(const QString &filePath) return 0; } -ProjectPart::Ptr BaseEditorDocumentParser::determineProjectPart() const +ProjectPart::Ptr BaseEditorDocumentParser::determineProjectPart(const QString &filePath, + const Configuration &config, + const State &state) { - if (m_manuallySetProjectPart) - return m_manuallySetProjectPart; + if (config.manuallySetProjectPart) + return config.manuallySetProjectPart; - ProjectPart::Ptr projectPart = m_projectPart; + ProjectPart::Ptr projectPart = state.projectPart; CppModelManager *cmm = CppModelManager::instance(); - QList projectParts = cmm->projectPart(m_filePath); + QList projectParts = cmm->projectPart(filePath); if (projectParts.isEmpty()) { if (projectPart) // File is not directly part of any project, but we got one before. We will re-use it, @@ -131,7 +126,7 @@ ProjectPart::Ptr BaseEditorDocumentParser::determineProjectPart() const return projectPart; // Fall-back step 1: Get some parts through the dependency table: - projectParts = cmm->projectPartFromDependencies(Utils::FileName::fromString(m_filePath)); + projectParts = cmm->projectPartFromDependencies(Utils::FileName::fromString(filePath)); if (projectParts.isEmpty()) // Fall-back step 2: Use fall-back part from the model manager: projectPart = cmm->fallbackProjectPart(); @@ -146,14 +141,4 @@ ProjectPart::Ptr BaseEditorDocumentParser::determineProjectPart() const return projectPart; } -bool BaseEditorDocumentParser::editorDefinesChanged() const -{ - return m_editorDefinesChangedSinceLastUpdate; -} - -void BaseEditorDocumentParser::resetEditorDefinesChanged() -{ - m_editorDefinesChangedSinceLastUpdate = false; -} - } // namespace CppTools diff --git a/src/plugins/cpptools/baseeditordocumentparser.h b/src/plugins/cpptools/baseeditordocumentparser.h index c8f5704a9dc..42ce6c12b33 100644 --- a/src/plugins/cpptools/baseeditordocumentparser.h +++ b/src/plugins/cpptools/baseeditordocumentparser.h @@ -42,45 +42,49 @@ class CPPTOOLS_EXPORT BaseEditorDocumentParser : public QObject { Q_OBJECT +public: + static BaseEditorDocumentParser *get(const QString &filePath); + + struct Configuration { + bool usePrecompiledHeaders = false; + QByteArray editorDefines; + ProjectPart::Ptr manuallySetProjectPart; + }; + public: BaseEditorDocumentParser(const QString &filePath); virtual ~BaseEditorDocumentParser(); QString filePath() const; + Configuration configuration() const; + void setConfiguration(const Configuration &configuration); + virtual void update(WorkingCopy workingCopy) = 0; ProjectPart::Ptr projectPart() const; - void setProjectPart(ProjectPart::Ptr projectPart); - - bool usePrecompiledHeaders() const; - void setUsePrecompiledHeaders(bool usePrecompiledHeaders); - - QByteArray editorDefines() const; - void setEditorDefines(const QByteArray &editorDefines); - -public: - static BaseEditorDocumentParser *get(const QString &filePath); protected: - ProjectPart::Ptr determineProjectPart() const; + struct State { + QByteArray editorDefines; + ProjectPart::Ptr projectPart; + }; - bool editorDefinesChanged() const; - void resetEditorDefinesChanged(); + State state() const; + void setState(const State &state); -protected: - mutable QMutex m_mutex; - ProjectPart::Ptr m_projectPart; + static ProjectPart::Ptr determineProjectPart(const QString &filePath, + const Configuration &config, + const State &state); + + mutable QMutex m_updateIsRunning; + mutable QMutex m_stateAndConfigurationMutex; private: const QString m_filePath; - ProjectPart::Ptr m_manuallySetProjectPart; - - bool m_usePrecompiledHeaders; - - QByteArray m_editorDefines; - bool m_editorDefinesChangedSinceLastUpdate; + Configuration m_configuration; + State m_state; }; } // namespace CppTools diff --git a/src/plugins/cpptools/builtineditordocumentparser.cpp b/src/plugins/cpptools/builtineditordocumentparser.cpp index 8c2232f1422..3871cb2bb0b 100644 --- a/src/plugins/cpptools/builtineditordocumentparser.cpp +++ b/src/plugins/cpptools/builtineditordocumentparser.cpp @@ -40,15 +40,19 @@ using namespace CppTools::Internal; BuiltinEditorDocumentParser::BuiltinEditorDocumentParser(const QString &filePath) : BaseEditorDocumentParser(filePath) - , m_forceSnapshotInvalidation(false) - , m_releaseSourceAndAST(true) { qRegisterMetaType("CPlusPlus::Snapshot"); } void BuiltinEditorDocumentParser::update(WorkingCopy workingCopy) { - QMutexLocker locker(&m_mutex); + QMutexLocker locker(&m_updateIsRunning); + + const Configuration baseConfig = configuration(); + const bool releaseSourceAndAST_ = releaseSourceAndAST(); + + State baseState = state(); + ExtraState state = extraState(); if (filePath().isEmpty()) return; @@ -62,52 +66,52 @@ void BuiltinEditorDocumentParser::update(WorkingCopy workingCopy) QString projectConfigFile; LanguageFeatures features = LanguageFeatures::defaultFeatures(); - m_projectPart = determineProjectPart(); + baseState.projectPart = determineProjectPart(filePath(), baseConfig, baseState); - if (m_forceSnapshotInvalidation) { + if (state.forceSnapshotInvalidation) { invalidateSnapshot = true; - m_forceSnapshotInvalidation = false; + state.forceSnapshotInvalidation = false; } - if (const ProjectPart::Ptr part = projectPart()) { + if (const ProjectPart::Ptr part = baseState.projectPart) { configFile += part->toolchainDefines; configFile += part->projectDefines; headerPaths = part->headerPaths; projectConfigFile = part->projectConfigFile; - if (usePrecompiledHeaders()) + if (baseConfig.usePrecompiledHeaders) precompiledHeaders = part->precompiledHeaders; features = part->languageFeatures; } - if (configFile != m_configFile) { - m_configFile = configFile; + if (configFile != state.configFile) { + state.configFile = configFile; invalidateSnapshot = true; invalidateConfig = true; } - if (editorDefinesChanged()) { + if (baseConfig.editorDefines != baseState.editorDefines) { + baseState.editorDefines = baseConfig.editorDefines; invalidateSnapshot = true; editorDefinesChanged_ = true; - resetEditorDefinesChanged(); } - if (headerPaths != m_headerPaths) { - m_headerPaths = headerPaths; + if (headerPaths != state.headerPaths) { + state.headerPaths = headerPaths; invalidateSnapshot = true; } - if (projectConfigFile != m_projectConfigFile) { - m_projectConfigFile = projectConfigFile; + if (projectConfigFile != state.projectConfigFile) { + state.projectConfigFile = projectConfigFile; invalidateSnapshot = true; } - if (precompiledHeaders != m_precompiledHeaders) { - m_precompiledHeaders = precompiledHeaders; + if (precompiledHeaders != state.precompiledHeaders) { + state.precompiledHeaders = precompiledHeaders; invalidateSnapshot = true; } unsigned rev = 0; - if (Document::Ptr doc = document()) + if (Document::Ptr doc = state.snapshot.document(filePath())) rev = doc->revision(); else invalidateSnapshot = true; @@ -115,26 +119,26 @@ void BuiltinEditorDocumentParser::update(WorkingCopy workingCopy) Snapshot globalSnapshot = modelManager->snapshot(); if (invalidateSnapshot) { - m_snapshot = Snapshot(); + state.snapshot = Snapshot(); } else { // Remove changed files from the snapshot QSet toRemove; - foreach (const Document::Ptr &doc, m_snapshot) { + foreach (const Document::Ptr &doc, state.snapshot) { const Utils::FileName fileName = Utils::FileName::fromString(doc->fileName()); if (workingCopy.contains(fileName)) { if (workingCopy.get(fileName).second != doc->editorRevision()) - addFileAndDependencies(&toRemove, fileName); + addFileAndDependencies(&state.snapshot, &toRemove, fileName); continue; } Document::Ptr otherDoc = globalSnapshot.document(fileName); if (!otherDoc.isNull() && otherDoc->revision() != doc->revision()) - addFileAndDependencies(&toRemove, fileName); + addFileAndDependencies(&state.snapshot, &toRemove, fileName); } if (!toRemove.isEmpty()) { invalidateSnapshot = true; foreach (const Utils::FileName &fileName, toRemove) - m_snapshot.remove(fileName); + state.snapshot.remove(fileName); } } @@ -142,19 +146,19 @@ void BuiltinEditorDocumentParser::update(WorkingCopy workingCopy) if (invalidateSnapshot) { const QString configurationFileName = modelManager->configurationFileName(); if (invalidateConfig) - m_snapshot.remove(configurationFileName); - if (!m_snapshot.contains(configurationFileName)) - workingCopy.insert(configurationFileName, m_configFile); - m_snapshot.remove(filePath()); + state.snapshot.remove(configurationFileName); + if (!state.snapshot.contains(configurationFileName)) + workingCopy.insert(configurationFileName, state.configFile); + state.snapshot.remove(filePath()); static const QString editorDefinesFileName = CppModelManager::editorConfigurationFileName(); if (editorDefinesChanged_) { - m_snapshot.remove(editorDefinesFileName); - workingCopy.insert(editorDefinesFileName, editorDefines()); + state.snapshot.remove(editorDefinesFileName); + workingCopy.insert(editorDefinesFileName, baseState.editorDefines); } - CppSourceProcessor sourceProcessor(m_snapshot, [&](const Document::Ptr &doc) { + CppSourceProcessor sourceProcessor(state.snapshot, [&](const Document::Ptr &doc) { const QString fileName = doc->fileName(); const bool isInEditor = fileName == filePath(); Document::Ptr otherDoc = modelManager->document(fileName); @@ -163,68 +167,64 @@ void BuiltinEditorDocumentParser::update(WorkingCopy workingCopy) newRev = qMax(rev + 1, newRev); doc->setRevision(newRev); modelManager->emitDocumentUpdated(doc); - if (m_releaseSourceAndAST) + if (releaseSourceAndAST_) doc->releaseSourceAndAST(); }); Snapshot globalSnapshot = modelManager->snapshot(); globalSnapshot.remove(filePath()); sourceProcessor.setGlobalSnapshot(globalSnapshot); sourceProcessor.setWorkingCopy(workingCopy); - sourceProcessor.setHeaderPaths(m_headerPaths); + sourceProcessor.setHeaderPaths(state.headerPaths); sourceProcessor.setLanguageFeatures(features); sourceProcessor.run(configurationFileName); - if (!m_projectConfigFile.isEmpty()) - sourceProcessor.run(m_projectConfigFile); - if (usePrecompiledHeaders()) { - foreach (const QString &precompiledHeader, m_precompiledHeaders) + if (!state.projectConfigFile.isEmpty()) + sourceProcessor.run(state.projectConfigFile); + if (baseConfig.usePrecompiledHeaders) { + foreach (const QString &precompiledHeader, state.precompiledHeaders) sourceProcessor.run(precompiledHeader); } - if (!editorDefines().isEmpty()) + if (!baseState.editorDefines.isEmpty()) sourceProcessor.run(editorDefinesFileName); - sourceProcessor.run(filePath(), usePrecompiledHeaders() ? m_precompiledHeaders - : QStringList()); - m_snapshot = sourceProcessor.snapshot(); - Snapshot newSnapshot = m_snapshot.simplified(document()); - for (Snapshot::const_iterator i = m_snapshot.begin(), ei = m_snapshot.end(); i != ei; ++i) { + sourceProcessor.run(filePath(), baseConfig.usePrecompiledHeaders ? state.precompiledHeaders + : QStringList()); + state.snapshot = sourceProcessor.snapshot(); + Snapshot newSnapshot = state.snapshot.simplified(state.snapshot.document(filePath())); + for (Snapshot::const_iterator i = state.snapshot.begin(), ei = state.snapshot.end(); i != ei; ++i) { if (Client::isInjectedFile(i.key().toString())) newSnapshot.insert(i.value()); } - m_snapshot = newSnapshot; - m_snapshot.updateDependencyTable(); - - emit finished(document(), m_snapshot); + state.snapshot = newSnapshot; + state.snapshot.updateDependencyTable(); } + + setState(baseState); + setExtraState(state); + + if (invalidateSnapshot) + emit finished(state.snapshot.document(filePath()), state.snapshot); } void BuiltinEditorDocumentParser::releaseResources() { - QMutexLocker locker(&m_mutex); - m_snapshot = Snapshot(); - m_forceSnapshotInvalidation = true; + ExtraState s = extraState(); + s.snapshot = Snapshot(); + s.forceSnapshotInvalidation = true; + setExtraState(s); } Document::Ptr BuiltinEditorDocumentParser::document() const { - QMutexLocker locker(&m_mutex); - return m_snapshot.document(filePath()); + return extraState().snapshot.document(filePath()); } Snapshot BuiltinEditorDocumentParser::snapshot() const { - QMutexLocker locker(&m_mutex); - return m_snapshot; + return extraState().snapshot; } ProjectPart::HeaderPaths BuiltinEditorDocumentParser::headerPaths() const { - QMutexLocker locker(&m_mutex); - return m_headerPaths; -} - -void BuiltinEditorDocumentParser::setReleaseSourceAndAST(bool onoff) -{ - QMutexLocker locker(&m_mutex); - m_releaseSourceAndAST = onoff; + return extraState().headerPaths; } BuiltinEditorDocumentParser *BuiltinEditorDocumentParser::get(const QString &filePath) @@ -234,12 +234,39 @@ BuiltinEditorDocumentParser *BuiltinEditorDocumentParser::get(const QString &fil return 0; } -void BuiltinEditorDocumentParser::addFileAndDependencies(QSet *toRemove, +void BuiltinEditorDocumentParser::addFileAndDependencies(Snapshot *snapshot, + QSet *toRemove, const Utils::FileName &fileName) const { + QTC_ASSERT(snapshot, return); + toRemove->insert(fileName); if (fileName != Utils::FileName::fromString(filePath())) { - Utils::FileNameList deps = m_snapshot.filesDependingOn(fileName); + Utils::FileNameList deps = snapshot->filesDependingOn(fileName); toRemove->unite(QSet::fromList(deps)); } } + +BuiltinEditorDocumentParser::ExtraState BuiltinEditorDocumentParser::extraState() const +{ + QMutexLocker locker(&m_stateAndConfigurationMutex); + return m_extraState; +} + +void BuiltinEditorDocumentParser::setExtraState(const ExtraState &extraState) +{ + QMutexLocker locker(&m_stateAndConfigurationMutex); + m_extraState = extraState; +} + +bool BuiltinEditorDocumentParser::releaseSourceAndAST() const +{ + QMutexLocker locker(&m_stateAndConfigurationMutex); + return m_releaseSourceAndAST; +} + +void BuiltinEditorDocumentParser::setReleaseSourceAndAST(bool release) +{ + QMutexLocker locker(&m_stateAndConfigurationMutex); + m_releaseSourceAndAST = release; +} diff --git a/src/plugins/cpptools/builtineditordocumentparser.h b/src/plugins/cpptools/builtineditordocumentparser.h index ebd8cc28fd5..a495be4787a 100644 --- a/src/plugins/cpptools/builtineditordocumentparser.h +++ b/src/plugins/cpptools/builtineditordocumentparser.h @@ -37,7 +37,6 @@ #include -#include #include namespace CppTools { @@ -49,14 +48,16 @@ class CPPTOOLS_EXPORT BuiltinEditorDocumentParser : public BaseEditorDocumentPar public: BuiltinEditorDocumentParser(const QString &filePath); + bool releaseSourceAndAST() const; + void setReleaseSourceAndAST(bool release); + void update(WorkingCopy workingCopy) override; - void releaseResources(); CPlusPlus::Document::Ptr document() const; CPlusPlus::Snapshot snapshot() const; ProjectPart::HeaderPaths headerPaths() const; - void setReleaseSourceAndAST(bool onoff); + void releaseResources(); signals: void finished(CPlusPlus::Document::Ptr document, CPlusPlus::Snapshot snapshot); @@ -65,18 +66,26 @@ public: static BuiltinEditorDocumentParser *get(const QString &filePath); private: - void addFileAndDependencies(QSet *toRemove, const Utils::FileName &fileName) const; + void addFileAndDependencies(CPlusPlus::Snapshot *snapshot, + QSet *toRemove, + const Utils::FileName &fileName) const; -private: - QByteArray m_configFile; + struct ExtraState { + QByteArray configFile; - ProjectPart::HeaderPaths m_headerPaths; - QString m_projectConfigFile; - QStringList m_precompiledHeaders; + ProjectPart::HeaderPaths headerPaths; + QString projectConfigFile; + QStringList precompiledHeaders; - CPlusPlus::Snapshot m_snapshot; - bool m_forceSnapshotInvalidation; - bool m_releaseSourceAndAST; + CPlusPlus::Snapshot snapshot; + bool forceSnapshotInvalidation = false; + }; + + ExtraState extraState() const; + void setExtraState(const ExtraState &extraState); + + bool m_releaseSourceAndAST = true; + ExtraState m_extraState; }; } // namespace CppTools diff --git a/src/plugins/cpptools/builtineditordocumentprocessor.cpp b/src/plugins/cpptools/builtineditordocumentprocessor.cpp index 12bfe1531c3..518fe1a6f6e 100644 --- a/src/plugins/cpptools/builtineditordocumentprocessor.cpp +++ b/src/plugins/cpptools/builtineditordocumentprocessor.cpp @@ -134,7 +134,10 @@ BuiltinEditorDocumentProcessor::BuiltinEditorDocumentProcessor( using namespace Internal; QSharedPointer cms = CppToolsPlugin::instance()->codeModelSettings(); - m_parser.setUsePrecompiledHeaders(cms->pchUsage() != CppCodeModelSettings::PchUse_None); + + BaseEditorDocumentParser::Configuration config = m_parser.configuration(); + config.usePrecompiledHeaders = cms->pchUsage() != CppCodeModelSettings::PchUse_None; + m_parser.setConfiguration(config); if (m_semanticHighlighter) { m_semanticHighlighter->setHighlightingRunner( diff --git a/src/plugins/cpptools/cppmodelmanager_test.cpp b/src/plugins/cpptools/cppmodelmanager_test.cpp index 7140ffecc25..79d70056f74 100644 --- a/src/plugins/cpptools/cppmodelmanager_test.cpp +++ b/src/plugins/cpptools/cppmodelmanager_test.cpp @@ -167,13 +167,11 @@ private: const QString &m_filePath; }; -void waitForProcessedEditorDocument(const QString &filePath) +ProjectPart::Ptr projectPartOfEditorDocument(const QString &filePath) { - CppEditorDocumentHandle *editorDocument - = CppModelManager::instance()->cppEditorDocument(filePath); - QVERIFY(editorDocument); - while (editorDocument->processor()->isParserRunning()) - QCoreApplication::processEvents(); + auto *editorDocument = CppModelManager::instance()->cppEditorDocument(filePath); + QTC_ASSERT(editorDocument, return ProjectPart::Ptr()); + return editorDocument->processor()->parser()->projectPart(); } } // anonymous namespace @@ -914,7 +912,9 @@ void CppToolsPlugin::test_modelmanager_precompiled_headers() auto *parser = BuiltinEditorDocumentParser::get(fileName); QVERIFY(parser); - parser->setUsePrecompiledHeaders(true); + BaseEditorDocumentParser::Configuration config = parser->configuration(); + config.usePrecompiledHeaders = true; + parser->setConfiguration(config); parser->update(mm->workingCopy()); // Check if defines from pch are considered @@ -995,7 +995,10 @@ void CppToolsPlugin::test_modelmanager_defines_per_editor() const QString filePath = editor->document()->filePath().toString(); BaseEditorDocumentParser *parser = BaseEditorDocumentParser::get(filePath); - parser->setEditorDefines(editorDefines.toUtf8()); + BaseEditorDocumentParser::Configuration config = parser->configuration(); + config.editorDefines = editorDefines.toUtf8(); + parser->setConfiguration(config); + parser->update(mm->workingCopy()); Document::Ptr doc = mm->document(main1File); @@ -1006,7 +1009,6 @@ void CppToolsPlugin::test_modelmanager_defines_per_editor() void CppToolsPlugin::test_modelmanager_updateEditorsAfterProjectUpdate() { ModelManagerTestHelper helper; - CppModelManager *mm = CppModelManager::instance(); MyTestDataDir testDataDirectory(_("testdata_defines")); const QString fileA = testDataDirectory.file(_("main1.cpp")); // content not relevant @@ -1017,10 +1019,8 @@ void CppToolsPlugin::test_modelmanager_updateEditorsAfterProjectUpdate() QVERIFY(editorA); EditorCloser closerA(editorA); QCOMPARE(Core::DocumentModel::openedDocuments().size(), 1); - - CppEditorDocumentHandle *editorDocumentA = mm->cppEditorDocument(fileA); - QVERIFY(editorDocumentA); - ProjectPart::Ptr documentAProjectPart = editorDocumentA->processor()->parser()->projectPart(); + QVERIFY(TestCase::waitForProcessedEditorDocument(fileA)); + ProjectPart::Ptr documentAProjectPart = projectPartOfEditorDocument(fileA); QVERIFY(!documentAProjectPart->project); // Open file B in editor @@ -1028,10 +1028,8 @@ void CppToolsPlugin::test_modelmanager_updateEditorsAfterProjectUpdate() QVERIFY(editorB); EditorCloser closerB(editorB); QCOMPARE(Core::DocumentModel::openedDocuments().size(), 2); - - CppEditorDocumentHandle *editorDocumentB = mm->cppEditorDocument(fileB); - QVERIFY(editorDocumentB); - ProjectPart::Ptr documentBProjectPart = editorDocumentB->processor()->parser()->projectPart(); + QVERIFY(TestCase::waitForProcessedEditorDocument(fileB)); + ProjectPart::Ptr documentBProjectPart = projectPartOfEditorDocument(fileB); QVERIFY(!documentBProjectPart->project); // Switch back to document A @@ -1053,16 +1051,14 @@ void CppToolsPlugin::test_modelmanager_updateEditorsAfterProjectUpdate() helper.updateProjectInfo(pi); // ... and check for updated editor document A - while (editorDocumentA->processor()->isParserRunning()) - QCoreApplication::processEvents(); - documentAProjectPart = editorDocumentA->processor()->parser()->projectPart(); + QVERIFY(TestCase::waitForProcessedEditorDocument(fileA)); + documentAProjectPart = projectPartOfEditorDocument(fileA); QCOMPARE(documentAProjectPart->project, project); // Switch back to document B and check if that's updated, too Core::EditorManager::activateEditor(editorB); - while (editorDocumentB->processor()->isParserRunning()) - QCoreApplication::processEvents(); - documentBProjectPart = editorDocumentB->processor()->parser()->projectPart(); + QVERIFY(TestCase::waitForProcessedEditorDocument(fileB)); + documentBProjectPart = projectPartOfEditorDocument(fileB); QCOMPARE(documentBProjectPart->project, project); } @@ -1131,7 +1127,7 @@ void CppToolsPlugin::test_modelmanager_documentsAndRevisions() TextEditor::BaseTextEditor *editor1; QVERIFY(helper.openBaseTextEditor(filePath1, &editor1)); helper.closeEditorAtEndOfTestCase(editor1); - waitForProcessedEditorDocument(filePath1); + QVERIFY(TestCase::waitForProcessedEditorDocument(filePath1)); VERIFY_DOCUMENT_REVISION(modelManager->document(filePath1), 2U); VERIFY_DOCUMENT_REVISION(modelManager->document(filePath2), 1U); @@ -1144,7 +1140,7 @@ void CppToolsPlugin::test_modelmanager_documentsAndRevisions() TextEditor::BaseTextEditor *editor2; QVERIFY(helper.openBaseTextEditor(filePath2, &editor2)); helper.closeEditorAtEndOfTestCase(editor2); - waitForProcessedEditorDocument(filePath2); + QVERIFY(TestCase::waitForProcessedEditorDocument(filePath2)); VERIFY_DOCUMENT_REVISION(modelManager->document(filePath1), 3U); VERIFY_DOCUMENT_REVISION(modelManager->document(filePath2), 3U); diff --git a/src/plugins/cpptools/cppsourceprocessor_test.cpp b/src/plugins/cpptools/cppsourceprocessor_test.cpp index 378d1ae4134..518eece2262 100644 --- a/src/plugins/cpptools/cppsourceprocessor_test.cpp +++ b/src/plugins/cpptools/cppsourceprocessor_test.cpp @@ -137,6 +137,7 @@ void CppToolsPlugin::test_cppsourceprocessor_includes_cyclic() const QString filePath = editor->document()->filePath().toString(); auto *processor = BaseEditorDocumentProcessor::get(filePath); QVERIFY(processor); + QVERIFY(TestCase::waitForProcessedEditorDocument(filePath)); Snapshot snapshot = processor->snapshot(); QCOMPARE(snapshot.size(), 3); // Configuration file included diff --git a/src/plugins/cpptools/cpptoolstestcase.cpp b/src/plugins/cpptools/cpptoolstestcase.cpp index 8d2a3684a0c..8cd7953320e 100644 --- a/src/plugins/cpptools/cpptoolstestcase.cpp +++ b/src/plugins/cpptools/cpptoolstestcase.cpp @@ -29,6 +29,10 @@ ****************************************************************************/ #include "cpptoolstestcase.h" + +#include "baseeditordocumentparser.h" +#include "baseeditordocumentprocessor.h" +#include "editordocumenthandle.h" #include "cppmodelmanager.h" #include "cppworkingcopy.h" @@ -140,6 +144,31 @@ bool TestCase::garbageCollectGlobalSnapshot() return globalSnapshot().isEmpty(); } +static bool waitForProcessedEditorDocument_internal(CppEditorDocumentHandle *editorDocument, + int timeOutInMs) +{ + QTC_ASSERT(editorDocument, return false); + + QTime timer; + timer.start(); + + forever { + if (!editorDocument->processor()->isParserRunning()) + return true; + if (timer.elapsed() > timeOutInMs) + return false; + + QCoreApplication::processEvents(); + QThread::msleep(20); + } +} + +bool TestCase::waitForProcessedEditorDocument(const QString &filePath, int timeOutInMs) +{ + auto *editorDocument = CppModelManager::instance()->cppEditorDocument(filePath); + return waitForProcessedEditorDocument_internal(editorDocument, timeOutInMs); +} + bool TestCase::parseFiles(const QSet &filePaths) { CppModelManager::instance()->updateSourceFiles(filePaths).waitForFinished(); diff --git a/src/plugins/cpptools/cpptoolstestcase.h b/src/plugins/cpptools/cpptoolstestcase.h index 5a95952365d..d35e93c3b4c 100644 --- a/src/plugins/cpptools/cpptoolstestcase.h +++ b/src/plugins/cpptools/cpptoolstestcase.h @@ -95,6 +95,8 @@ public: static CPlusPlus::Snapshot globalSnapshot(); static bool garbageCollectGlobalSnapshot(); + static bool waitForProcessedEditorDocument(const QString &filePath, int timeOutInMs = 5000); + enum { defaultTimeOutInMs = 30 * 1000 /*= 30 secs*/ }; static bool waitUntilCppModelManagerIsAwareOf( ProjectExplorer::Project *project, From 5902a622985158eda3f47bc98d8c4d4c80426eba Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Fri, 10 Jul 2015 12:34:40 +0200 Subject: [PATCH 03/70] CppTools: Let BaseEditorDocumentParser acquire the mutex ...so derived classes are freed from doing this. Change-Id: I73f3eca54be14cfd6542a466f0e9c024457bef07 Reviewed-by: Erik Verbruggen --- .../clangcodemodel/clangeditordocumentparser.cpp | 3 +-- .../clangcodemodel/clangeditordocumentparser.h | 4 ++-- src/plugins/cpptools/baseeditordocumentparser.cpp | 12 +++++++++--- src/plugins/cpptools/baseeditordocumentparser.h | 9 ++++----- src/plugins/cpptools/builtineditordocumentparser.cpp | 4 +--- src/plugins/cpptools/builtineditordocumentparser.h | 4 +--- 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/plugins/clangcodemodel/clangeditordocumentparser.cpp b/src/plugins/clangcodemodel/clangeditordocumentparser.cpp index fd2c60dbaee..1f7d100fb63 100644 --- a/src/plugins/clangcodemodel/clangeditordocumentparser.cpp +++ b/src/plugins/clangcodemodel/clangeditordocumentparser.cpp @@ -88,10 +88,9 @@ ClangEditorDocumentParser::ClangEditorDocumentParser(const QString &filePath) { } -void ClangEditorDocumentParser::update(CppTools::WorkingCopy workingCopy) +void ClangEditorDocumentParser::updateHelper(CppTools::WorkingCopy workingCopy) { QTC_ASSERT(m_marker, return); - QMutexLocker locker(&m_updateIsRunning); // Determine project part State state_ = state(); diff --git a/src/plugins/clangcodemodel/clangeditordocumentparser.h b/src/plugins/clangcodemodel/clangeditordocumentparser.h index e86cf50f949..37039eb5399 100644 --- a/src/plugins/clangcodemodel/clangeditordocumentparser.h +++ b/src/plugins/clangcodemodel/clangeditordocumentparser.h @@ -46,13 +46,13 @@ class ClangEditorDocumentParser : public CppTools::BaseEditorDocumentParser public: ClangEditorDocumentParser(const QString &filePath); - void update(CppTools::WorkingCopy workingCopy) override; - QList diagnostics() const; QList ifdefedOutBlocks() const; SemanticMarker::Ptr semanticMarker() const; private: + void updateHelper(CppTools::WorkingCopy workingCopy) override; + SemanticMarker::Ptr m_marker; }; diff --git a/src/plugins/cpptools/baseeditordocumentparser.cpp b/src/plugins/cpptools/baseeditordocumentparser.cpp index 31d08bd4317..d075a86622a 100644 --- a/src/plugins/cpptools/baseeditordocumentparser.cpp +++ b/src/plugins/cpptools/baseeditordocumentparser.cpp @@ -31,6 +31,7 @@ #include "baseeditordocumentparser.h" #include "baseeditordocumentprocessor.h" +#include "cppworkingcopy.h" #include "editordocumenthandle.h" namespace CppTools { @@ -44,14 +45,13 @@ namespace CppTools { It's meant to be used in the C++ editor to get precise results by using the "best" project part for a file. - Derived classes are expected to implement update() this way: + Derived classes are expected to implement updateHelper() this way: \list \li Get a copy of the configuration and the last state. - \li Acquire the protected m_updateIsRunning for the duration of update(). \li Work on the data and do whatever is necessary. At least, update the project part with the help of determineProjectPart(). - \li Ensure the new state is set before update() returns. + \li Ensure the new state is set before updateHelper() returns. \endlist */ @@ -81,6 +81,12 @@ void BaseEditorDocumentParser::setConfiguration(const Configuration &configurati m_configuration = configuration; } +void BaseEditorDocumentParser::update(WorkingCopy workingCopy) +{ + QMutexLocker locker(&m_updateIsRunning); + updateHelper(workingCopy); +} + BaseEditorDocumentParser::State BaseEditorDocumentParser::state() const { QMutexLocker locker(&m_stateAndConfigurationMutex); diff --git a/src/plugins/cpptools/baseeditordocumentparser.h b/src/plugins/cpptools/baseeditordocumentparser.h index 42ce6c12b33..c5a19748118 100644 --- a/src/plugins/cpptools/baseeditordocumentparser.h +++ b/src/plugins/cpptools/baseeditordocumentparser.h @@ -56,11 +56,10 @@ public: virtual ~BaseEditorDocumentParser(); QString filePath() const; - Configuration configuration() const; void setConfiguration(const Configuration &configuration); - virtual void update(WorkingCopy workingCopy) = 0; + void update(WorkingCopy workingCopy); ProjectPart::Ptr projectPart() const; @@ -69,7 +68,6 @@ protected: QByteArray editorDefines; ProjectPart::Ptr projectPart; }; - State state() const; void setState(const State &state); @@ -77,14 +75,15 @@ protected: const Configuration &config, const State &state); - mutable QMutex m_updateIsRunning; mutable QMutex m_stateAndConfigurationMutex; private: - const QString m_filePath; + virtual void updateHelper(WorkingCopy workingCopy) = 0; + const QString m_filePath; Configuration m_configuration; State m_state; + mutable QMutex m_updateIsRunning; }; } // namespace CppTools diff --git a/src/plugins/cpptools/builtineditordocumentparser.cpp b/src/plugins/cpptools/builtineditordocumentparser.cpp index 3871cb2bb0b..f244595fde0 100644 --- a/src/plugins/cpptools/builtineditordocumentparser.cpp +++ b/src/plugins/cpptools/builtineditordocumentparser.cpp @@ -44,10 +44,8 @@ BuiltinEditorDocumentParser::BuiltinEditorDocumentParser(const QString &filePath qRegisterMetaType("CPlusPlus::Snapshot"); } -void BuiltinEditorDocumentParser::update(WorkingCopy workingCopy) +void BuiltinEditorDocumentParser::updateHelper(WorkingCopy workingCopy) { - QMutexLocker locker(&m_updateIsRunning); - const Configuration baseConfig = configuration(); const bool releaseSourceAndAST_ = releaseSourceAndAST(); diff --git a/src/plugins/cpptools/builtineditordocumentparser.h b/src/plugins/cpptools/builtineditordocumentparser.h index a495be4787a..fee17882eb7 100644 --- a/src/plugins/cpptools/builtineditordocumentparser.h +++ b/src/plugins/cpptools/builtineditordocumentparser.h @@ -51,8 +51,6 @@ public: bool releaseSourceAndAST() const; void setReleaseSourceAndAST(bool release); - void update(WorkingCopy workingCopy) override; - CPlusPlus::Document::Ptr document() const; CPlusPlus::Snapshot snapshot() const; ProjectPart::HeaderPaths headerPaths() const; @@ -66,6 +64,7 @@ public: static BuiltinEditorDocumentParser *get(const QString &filePath); private: + void updateHelper(WorkingCopy workingCopy) override; void addFileAndDependencies(CPlusPlus::Snapshot *snapshot, QSet *toRemove, const Utils::FileName &fileName) const; @@ -80,7 +79,6 @@ private: CPlusPlus::Snapshot snapshot; bool forceSnapshotInvalidation = false; }; - ExtraState extraState() const; void setExtraState(const ExtraState &extraState); From 418fc32f6a11a042ca6de2c6befea4ecb32a3381 Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Fri, 10 Jul 2015 14:57:42 +0200 Subject: [PATCH 04/70] Clang: Do not call DocumentManager::modifiedDocuments() from worker thread This is unsafe. Change-Id: I8ac075a7289afa0d84785e37b1325d186a153000 Reviewed-by: Erik Verbruggen --- .../clangcompletionassistinterface.cpp | 5 ++++- .../clangcodemodel/clangeditordocumentparser.cpp | 5 +++-- .../clangcodemodel/clangeditordocumentparser.h | 2 +- .../clangcodemodel/clangeditordocumentprocessor.cpp | 7 +++---- src/plugins/clangcodemodel/clangutils.cpp | 11 ++--------- src/plugins/clangcodemodel/clangutils.h | 4 +++- src/plugins/cpptools/baseeditordocumentparser.cpp | 13 ++++++++++--- src/plugins/cpptools/baseeditordocumentparser.h | 11 +++++++++-- .../cpptools/baseeditordocumentprocessor.cpp | 5 +++-- src/plugins/cpptools/baseeditordocumentprocessor.h | 2 +- .../cpptools/builtineditordocumentparser.cpp | 9 +++++---- src/plugins/cpptools/builtineditordocumentparser.h | 2 +- .../cpptools/builtineditordocumentprocessor.cpp | 6 ++++-- src/plugins/cpptools/builtinindexingsupport.cpp | 2 +- src/plugins/cpptools/cppcompletionassist.cpp | 2 +- src/plugins/cpptools/cppmodelmanager_test.cpp | 5 ++--- src/plugins/cpptools/cpptoolsreuse.cpp | 10 ++++++++++ src/plugins/cpptools/cpptoolsreuse.h | 6 ++++++ 18 files changed, 69 insertions(+), 38 deletions(-) diff --git a/src/plugins/clangcodemodel/clangcompletionassistinterface.cpp b/src/plugins/clangcodemodel/clangcompletionassistinterface.cpp index 5c7a2a2d0e8..ec46846ccba 100644 --- a/src/plugins/clangcodemodel/clangcompletionassistinterface.cpp +++ b/src/plugins/clangcodemodel/clangcompletionassistinterface.cpp @@ -33,6 +33,7 @@ #include "clangutils.h" #include +#include #include #include @@ -58,7 +59,9 @@ ClangCompletionAssistInterface::ClangCompletionAssistInterface( , m_languageFeatures(features) , m_textEditorWidget(textEditorWidget) { - m_unsavedFiles = Utils::createUnsavedFiles(CppTools::CppModelManager::instance()->workingCopy()); + m_unsavedFiles = Utils::createUnsavedFiles( + CppTools::CppModelManager::instance()->workingCopy(), + CppTools::modifiedFiles()); } bool ClangCompletionAssistInterface::objcEnabled() const diff --git a/src/plugins/clangcodemodel/clangeditordocumentparser.cpp b/src/plugins/clangcodemodel/clangeditordocumentparser.cpp index 1f7d100fb63..c4897befbcb 100644 --- a/src/plugins/clangcodemodel/clangeditordocumentparser.cpp +++ b/src/plugins/clangcodemodel/clangeditordocumentparser.cpp @@ -88,7 +88,7 @@ ClangEditorDocumentParser::ClangEditorDocumentParser(const QString &filePath) { } -void ClangEditorDocumentParser::updateHelper(CppTools::WorkingCopy workingCopy) +void ClangEditorDocumentParser::updateHelper(const BaseEditorDocumentParser::InMemoryInfo &info) { QTC_ASSERT(m_marker, return); @@ -107,7 +107,8 @@ void ClangEditorDocumentParser::updateHelper(CppTools::WorkingCopy workingCopy) QMutexLocker lock(m_marker->mutex()); m_marker->setFileName(filePath()); m_marker->setCompilationOptions(options); - const Internal::UnsavedFiles unsavedFiles = Utils::createUnsavedFiles(workingCopy); + const Internal::UnsavedFiles unsavedFiles = Utils::createUnsavedFiles(info.workingCopy, + info.modifiedFiles); m_marker->reparse(unsavedFiles); qCDebug(log) << "Reparse took" << t.elapsed() << "ms."; } diff --git a/src/plugins/clangcodemodel/clangeditordocumentparser.h b/src/plugins/clangcodemodel/clangeditordocumentparser.h index 37039eb5399..4784d51672c 100644 --- a/src/plugins/clangcodemodel/clangeditordocumentparser.h +++ b/src/plugins/clangcodemodel/clangeditordocumentparser.h @@ -51,7 +51,7 @@ public: SemanticMarker::Ptr semanticMarker() const; private: - void updateHelper(CppTools::WorkingCopy workingCopy) override; + void updateHelper(const BaseEditorDocumentParser::InMemoryInfo &info) override; SemanticMarker::Ptr m_marker; }; diff --git a/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp b/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp index 090a0cf06de..5ca055b0a14 100644 --- a/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp +++ b/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp @@ -144,9 +144,6 @@ ClangEditorDocumentProcessor::~ClangEditorDocumentProcessor() void ClangEditorDocumentProcessor::run() { // Run clang parser - const CppTools::WorkingCopy workingCopy - = CppTools::CppModelManager::instance()->workingCopy(); - disconnect(&m_parserWatcher, &QFutureWatcher::finished, this, &ClangEditorDocumentProcessor::onParserFinished); m_parserWatcher.cancel(); @@ -155,7 +152,9 @@ void ClangEditorDocumentProcessor::run() m_parserRevision = revision(); connect(&m_parserWatcher, &QFutureWatcher::finished, this, &ClangEditorDocumentProcessor::onParserFinished); - const QFuture future = QtConcurrent::run(&runParser, parser(), workingCopy); + const QFuture future = QtConcurrent::run(&runParser, + parser(), + ClangEditorDocumentParser::InMemoryInfo(true)); m_parserWatcher.setFuture(future); // Run builtin processor diff --git a/src/plugins/clangcodemodel/clangutils.cpp b/src/plugins/clangcodemodel/clangutils.cpp index 582ed43d782..257d3c966e5 100644 --- a/src/plugins/clangcodemodel/clangutils.cpp +++ b/src/plugins/clangcodemodel/clangutils.cpp @@ -32,7 +32,6 @@ #include -#include #include #include @@ -58,15 +57,9 @@ namespace Utils { Q_LOGGING_CATEGORY(verboseRunLog, "qtc.clangcodemodel.verboserun") -UnsavedFiles createUnsavedFiles(WorkingCopy workingCopy) +UnsavedFiles createUnsavedFiles(const WorkingCopy &workingCopy, + const ::Utils::FileNameList &modifiedFiles) { - // TODO: change the modelmanager to hold one working copy, and amend it every time we ask for one. - // TODO: Reason: the UnsavedFile needs a QByteArray. - - QSet< ::Utils::FileName> modifiedFiles; - foreach (IDocument *doc, DocumentManager::modifiedDocuments()) - modifiedFiles.insert(doc->filePath()); - UnsavedFiles result; QHashIterator< ::Utils::FileName, QPair > wcIter = workingCopy.iterator(); while (wcIter.hasNext()) { diff --git a/src/plugins/clangcodemodel/clangutils.h b/src/plugins/clangcodemodel/clangutils.h index 65322d86ad1..d3a78cc45b7 100644 --- a/src/plugins/clangcodemodel/clangutils.h +++ b/src/plugins/clangcodemodel/clangutils.h @@ -43,7 +43,9 @@ namespace Utils { Q_DECLARE_LOGGING_CATEGORY(verboseRunLog) -ClangCodeModel::Internal::UnsavedFiles createUnsavedFiles(CppTools::WorkingCopy workingCopy); +ClangCodeModel::Internal::UnsavedFiles createUnsavedFiles( + const CppTools::WorkingCopy &workingCopy, + const ::Utils::FileNameList &modifiedFiles); QStringList createClangOptions(const CppTools::ProjectPart::Ptr &pPart, CppTools::ProjectFile::Kind fileKind); diff --git a/src/plugins/cpptools/baseeditordocumentparser.cpp b/src/plugins/cpptools/baseeditordocumentparser.cpp index d075a86622a..52fd64e1135 100644 --- a/src/plugins/cpptools/baseeditordocumentparser.cpp +++ b/src/plugins/cpptools/baseeditordocumentparser.cpp @@ -31,7 +31,7 @@ #include "baseeditordocumentparser.h" #include "baseeditordocumentprocessor.h" -#include "cppworkingcopy.h" +#include "cpptoolsreuse.h" #include "editordocumenthandle.h" namespace CppTools { @@ -81,10 +81,10 @@ void BaseEditorDocumentParser::setConfiguration(const Configuration &configurati m_configuration = configuration; } -void BaseEditorDocumentParser::update(WorkingCopy workingCopy) +void BaseEditorDocumentParser::update(const InMemoryInfo &info) { QMutexLocker locker(&m_updateIsRunning); - updateHelper(workingCopy); + updateHelper(info); } BaseEditorDocumentParser::State BaseEditorDocumentParser::state() const @@ -147,4 +147,11 @@ ProjectPart::Ptr BaseEditorDocumentParser::determineProjectPart(const QString &f return projectPart; } +BaseEditorDocumentParser::InMemoryInfo::InMemoryInfo(bool withModifiedFiles) + : workingCopy(CppTools::CppModelManager::instance()->workingCopy()) +{ + if (withModifiedFiles) + modifiedFiles = CppTools::modifiedFiles(); +} + } // namespace CppTools diff --git a/src/plugins/cpptools/baseeditordocumentparser.h b/src/plugins/cpptools/baseeditordocumentparser.h index c5a19748118..b9c8ecaadcd 100644 --- a/src/plugins/cpptools/baseeditordocumentparser.h +++ b/src/plugins/cpptools/baseeditordocumentparser.h @@ -33,6 +33,7 @@ #include "cppmodelmanager.h" #include "cpptools_global.h" +#include "cppworkingcopy.h" #include @@ -59,7 +60,13 @@ public: Configuration configuration() const; void setConfiguration(const Configuration &configuration); - void update(WorkingCopy workingCopy); + struct CPPTOOLS_EXPORT InMemoryInfo { + InMemoryInfo(bool withModifiedFiles); + + WorkingCopy workingCopy; + Utils::FileNameList modifiedFiles; + }; + void update(const InMemoryInfo &info); ProjectPart::Ptr projectPart() const; @@ -78,7 +85,7 @@ protected: mutable QMutex m_stateAndConfigurationMutex; private: - virtual void updateHelper(WorkingCopy workingCopy) = 0; + virtual void updateHelper(const InMemoryInfo &inMemoryInfo) = 0; const QString m_filePath; Configuration m_configuration; diff --git a/src/plugins/cpptools/baseeditordocumentprocessor.cpp b/src/plugins/cpptools/baseeditordocumentprocessor.cpp index 373624a9ea5..d627ab3cb76 100644 --- a/src/plugins/cpptools/baseeditordocumentprocessor.cpp +++ b/src/plugins/cpptools/baseeditordocumentprocessor.cpp @@ -31,6 +31,7 @@ #include "baseeditordocumentprocessor.h" #include "cppworkingcopy.h" +#include "cpptoolsreuse.h" #include "editordocumenthandle.h" #include @@ -118,7 +119,7 @@ QList BaseEditorDocumentProcessor::toTextEditorSelect void BaseEditorDocumentProcessor::runParser(QFutureInterface &future, BaseEditorDocumentParser *parser, - WorkingCopy workingCopy) + BaseEditorDocumentParser::InMemoryInfo info) { future.setProgressRange(0, 1); if (future.isCanceled()) { @@ -126,7 +127,7 @@ void BaseEditorDocumentProcessor::runParser(QFutureInterface &future, return; } - parser->update(workingCopy); + parser->update(info); CppModelManager::instance() ->finishedRefreshingSourceFiles(QSet() << parser->filePath()); diff --git a/src/plugins/cpptools/baseeditordocumentprocessor.h b/src/plugins/cpptools/baseeditordocumentprocessor.h index 4f30a519e33..76c6c057eaa 100644 --- a/src/plugins/cpptools/baseeditordocumentprocessor.h +++ b/src/plugins/cpptools/baseeditordocumentprocessor.h @@ -86,7 +86,7 @@ protected: static void runParser(QFutureInterface &future, CppTools::BaseEditorDocumentParser *parser, - CppTools::WorkingCopy workingCopy); + BaseEditorDocumentParser::InMemoryInfo info); // Convenience QString filePath() const { return m_baseTextDocument->filePath().toString(); } diff --git a/src/plugins/cpptools/builtineditordocumentparser.cpp b/src/plugins/cpptools/builtineditordocumentparser.cpp index f244595fde0..41035333f60 100644 --- a/src/plugins/cpptools/builtineditordocumentparser.cpp +++ b/src/plugins/cpptools/builtineditordocumentparser.cpp @@ -44,16 +44,17 @@ BuiltinEditorDocumentParser::BuiltinEditorDocumentParser(const QString &filePath qRegisterMetaType("CPlusPlus::Snapshot"); } -void BuiltinEditorDocumentParser::updateHelper(WorkingCopy workingCopy) +void BuiltinEditorDocumentParser::updateHelper(const InMemoryInfo &info) { + if (filePath().isEmpty()) + return; + const Configuration baseConfig = configuration(); const bool releaseSourceAndAST_ = releaseSourceAndAST(); State baseState = state(); ExtraState state = extraState(); - - if (filePath().isEmpty()) - return; + WorkingCopy workingCopy = info.workingCopy; bool invalidateSnapshot = false, invalidateConfig = false, editorDefinesChanged_ = false; diff --git a/src/plugins/cpptools/builtineditordocumentparser.h b/src/plugins/cpptools/builtineditordocumentparser.h index fee17882eb7..c27b3366227 100644 --- a/src/plugins/cpptools/builtineditordocumentparser.h +++ b/src/plugins/cpptools/builtineditordocumentparser.h @@ -64,7 +64,7 @@ public: static BuiltinEditorDocumentParser *get(const QString &filePath); private: - void updateHelper(WorkingCopy workingCopy) override; + void updateHelper(const InMemoryInfo &info) override; void addFileAndDependencies(CPlusPlus::Snapshot *snapshot, QSet *toRemove, const Utils::FileName &fileName) const; diff --git a/src/plugins/cpptools/builtineditordocumentprocessor.cpp b/src/plugins/cpptools/builtineditordocumentprocessor.cpp index 518fe1a6f6e..b61f698ab46 100644 --- a/src/plugins/cpptools/builtineditordocumentprocessor.cpp +++ b/src/plugins/cpptools/builtineditordocumentprocessor.cpp @@ -43,8 +43,8 @@ #include #include -#include #include +#include #include @@ -166,7 +166,9 @@ BuiltinEditorDocumentProcessor::~BuiltinEditorDocumentProcessor() void BuiltinEditorDocumentProcessor::run() { - m_parserFuture = QtConcurrent::run(&runParser, parser(), CppTools::CppModelManager::instance()->workingCopy()); + m_parserFuture = QtConcurrent::run(&runParser, + parser(), + BuiltinEditorDocumentParser::InMemoryInfo(false)); } BaseEditorDocumentParser *BuiltinEditorDocumentProcessor::parser() diff --git a/src/plugins/cpptools/builtinindexingsupport.cpp b/src/plugins/cpptools/builtinindexingsupport.cpp index fc06b95024b..ef03f75c58d 100644 --- a/src/plugins/cpptools/builtinindexingsupport.cpp +++ b/src/plugins/cpptools/builtinindexingsupport.cpp @@ -162,7 +162,7 @@ void indexFindErrors(QFutureInterface &future, const ParseParams params) // Parse the file as precisely as possible BuiltinEditorDocumentParser parser(file); parser.setReleaseSourceAndAST(false); - parser.update(params.workingCopy); + parser.update(BuiltinEditorDocumentParser::InMemoryInfo(false)); CPlusPlus::Document::Ptr document = parser.document(); QTC_ASSERT(document, return); diff --git a/src/plugins/cpptools/cppcompletionassist.cpp b/src/plugins/cpptools/cppcompletionassist.cpp index 8f9ab8a456c..96f6a6efb2b 100644 --- a/src/plugins/cpptools/cppcompletionassist.cpp +++ b/src/plugins/cpptools/cppcompletionassist.cpp @@ -2188,7 +2188,7 @@ void CppCompletionAssistInterface::getCppSpecifics() const m_gotCppSpecifics = true; if (BuiltinEditorDocumentParser *parser = BuiltinEditorDocumentParser::get(fileName())) { - parser->update(m_workingCopy); + parser->update(BuiltinEditorDocumentParser::InMemoryInfo(false)); m_snapshot = parser->snapshot(); m_headerPaths = parser->headerPaths(); if (Document::Ptr document = parser->document()) diff --git a/src/plugins/cpptools/cppmodelmanager_test.cpp b/src/plugins/cpptools/cppmodelmanager_test.cpp index 79d70056f74..7aa40b357b7 100644 --- a/src/plugins/cpptools/cppmodelmanager_test.cpp +++ b/src/plugins/cpptools/cppmodelmanager_test.cpp @@ -915,7 +915,7 @@ void CppToolsPlugin::test_modelmanager_precompiled_headers() BaseEditorDocumentParser::Configuration config = parser->configuration(); config.usePrecompiledHeaders = true; parser->setConfiguration(config); - parser->update(mm->workingCopy()); + parser->update(BuiltinEditorDocumentParser::InMemoryInfo(false)); // Check if defines from pch are considered Document::Ptr document = mm->document(fileName); @@ -998,8 +998,7 @@ void CppToolsPlugin::test_modelmanager_defines_per_editor() BaseEditorDocumentParser::Configuration config = parser->configuration(); config.editorDefines = editorDefines.toUtf8(); parser->setConfiguration(config); - - parser->update(mm->workingCopy()); + parser->update(BuiltinEditorDocumentParser::InMemoryInfo(false)); Document::Ptr doc = mm->document(main1File); QCOMPARE(nameOfFirstDeclaration(doc), firstDeclarationName); diff --git a/src/plugins/cpptools/cpptoolsreuse.cpp b/src/plugins/cpptools/cpptoolsreuse.cpp index 1478d34a6fa..8c4962ef344 100644 --- a/src/plugins/cpptools/cpptoolsreuse.cpp +++ b/src/plugins/cpptools/cpptoolsreuse.cpp @@ -32,6 +32,7 @@ #include "cpptoolsplugin.h" +#include #include #include #include @@ -287,4 +288,13 @@ bool skipFileDueToSizeLimit(const QFileInfo &fileInfo, int limitInMB) return false; } +Utils::FileNameList modifiedFiles() +{ + Utils::FileNameList files; + foreach (Core::IDocument *doc, Core::DocumentManager::modifiedDocuments()) + files.append(doc->filePath()); + files.removeDuplicates(); + return files; +} + } // CppTools diff --git a/src/plugins/cpptools/cpptoolsreuse.h b/src/plugins/cpptools/cpptoolsreuse.h index 62d0df71ccf..cb6e0246e68 100644 --- a/src/plugins/cpptools/cpptoolsreuse.h +++ b/src/plugins/cpptools/cpptoolsreuse.h @@ -44,6 +44,10 @@ class QStringRef; class QTextCursor; QT_END_NAMESPACE +namespace Utils { +class FileNameList; +} // namespace Utils + namespace CPlusPlus { class Macro; class Symbol; @@ -52,6 +56,8 @@ class LookupContext; namespace CppTools { +Utils::FileNameList CPPTOOLS_EXPORT modifiedFiles(); + void CPPTOOLS_EXPORT moveCursorToEndOfIdentifier(QTextCursor *tc); void CPPTOOLS_EXPORT moveCursorToStartOfIdentifier(QTextCursor *tc); From e44b5d57e317cb812f1424512eceb6d3803482f0 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Fri, 10 Jul 2015 15:31:08 +0200 Subject: [PATCH 05/70] Doc: fixed a typo in the 3.5.0 changes file Change-Id: Ibe340fedc8ca2e7e79af3dc4637f42ba2fd6f1b4 Reviewed-by: Eike Ziller --- dist/changes-3.5.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dist/changes-3.5.0.md b/dist/changes-3.5.0.md index a8d94d9ae40..04d7e8bca1d 100644 --- a/dist/changes-3.5.0.md +++ b/dist/changes-3.5.0.md @@ -127,7 +127,7 @@ FakeVim Todo -* Added option to excluding file patterns from parsing +* Added option to exclude file patterns from parsing Beautifier From f5b9a2f4ef7d060cd3da12975cc6f0a358aea091 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Mon, 29 Jun 2015 13:15:54 +0200 Subject: [PATCH 06/70] Squish: Fix tst_simple_debug Change-Id: I8d90c0279d73a1902627d76388a5fa5497fb520d Reviewed-by: Robert Loehning --- tests/system/suite_debugger/tst_simple_debug/test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/system/suite_debugger/tst_simple_debug/test.py b/tests/system/suite_debugger/tst_simple_debug/test.py index 97e25f5e70c..c5723aced48 100644 --- a/tests/system/suite_debugger/tst_simple_debug/test.py +++ b/tests/system/suite_debugger/tst_simple_debug/test.py @@ -50,12 +50,12 @@ def main(): invokeMenuItem("File", "Save All") filesAndLines = [ { "%s.Resources.qml\.qrc./.main\\.qml" % projectName : 'onTriggered.*' }, - { "%s.Sources.main\\.cpp" % projectName : "viewer.setOrientation\\(.+\\);" } + { "%s.Sources.main\\.cpp" % projectName : "QQmlApplicationEngine engine;" } ] test.log("Setting breakpoints") result = setBreakpointsForCurrentProject(filesAndLines) if result: - expectedBreakpointsOrder = [{os.path.join(workingDir, projectName, "main.cpp"):10}, + expectedBreakpointsOrder = [{os.path.join(workingDir, projectName, "main.cpp"):8}, {os.path.join(workingDir, projectName, "main.qml"):10}] # Only use 4.7.4 to work around QTBUG-25187 availableConfigs = iterateBuildConfigs(len(checkedTargets), "Debug") From 90985d18c0c20fafe29ed452888b2c87189048e5 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Sat, 11 Jul 2015 21:53:18 +0300 Subject: [PATCH 07/70] Debugger: Exclude lldb-gdbserver-* from autodetection Change-Id: If7b887188d3a94ae741c3fcf9a1dbce063a04bd6 Reviewed-by: hjk --- src/plugins/debugger/debuggeritemmanager.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/debugger/debuggeritemmanager.cpp b/src/plugins/debugger/debuggeritemmanager.cpp index b4736f23280..0c3abc30320 100644 --- a/src/plugins/debugger/debuggeritemmanager.cpp +++ b/src/plugins/debugger/debuggeritemmanager.cpp @@ -252,8 +252,10 @@ void DebuggerItemManager::autoDetectGdbOrLldbDebuggers() foreach (const QString &base, path) { dir.setPath(base); foreach (const QString &entry, dir.entryList()) { - if (entry.startsWith(QLatin1String("lldb-platform-"))) + if (entry.startsWith(QLatin1String("lldb-platform-")) + || entry.startsWith(QLatin1String("lldb-gdbserver-"))) { continue; + } suspects.append(FileName::fromString(dir.absoluteFilePath(entry))); } } From 92f4ea3f796a50bdd5433df34ca9e1eff70b8c91 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 10 Jul 2015 11:06:27 +0200 Subject: [PATCH 08/70] Debugger: Use DebuggerCommand in QML engine ... instead of manually set up JSON. It's more concise, and paves the way to use per-command callbacks as in the other engines. Change-Id: Ib5cf9c9b882ec0ec87acd7c1ceb938d3ee60346b Reviewed-by: Christian Stenger --- src/plugins/debugger/debuggerprotocol.cpp | 18 ++ src/plugins/debugger/debuggerprotocol.h | 4 + src/plugins/debugger/qml/qmlengine.cpp | 270 ++++++++-------------- 3 files changed, 116 insertions(+), 176 deletions(-) diff --git a/src/plugins/debugger/debuggerprotocol.cpp b/src/plugins/debugger/debuggerprotocol.cpp index f3515afe3a5..5be634c83f8 100644 --- a/src/plugins/debugger/debuggerprotocol.cpp +++ b/src/plugins/debugger/debuggerprotocol.cpp @@ -782,6 +782,16 @@ void DebuggerCommand::arg(const char *name, const char *value) args.append("\","); } +void DebuggerCommand::arg(const char *name, const QList &list) +{ + beginList(name); + foreach (int item, list) { + args.append(QByteArray::number(item)); + args.append(','); + } + endList(); +} + void DebuggerCommand::arg(const char *value) { args.append("\""); @@ -823,5 +833,13 @@ void DebuggerCommand::endGroup() args += "},"; } +QByteArray DebuggerCommand::arguments() const +{ + QByteArray result = args; + if (result.endsWith(',')) + result.chop(1); + return result; +} + } // namespace Internal } // namespace Debugger diff --git a/src/plugins/debugger/debuggerprotocol.h b/src/plugins/debugger/debuggerprotocol.h index 7bccb4356ba..eac5c03da28 100644 --- a/src/plugins/debugger/debuggerprotocol.h +++ b/src/plugins/debugger/debuggerprotocol.h @@ -32,6 +32,7 @@ #define DEBUGGER_PROTOCOL_H #include +#include #include #include @@ -64,10 +65,13 @@ public: void arg(const char *name, const QString &value); void arg(const char *name, const QByteArray &value); void arg(const char *name, const char *value); + void arg(const char *name, const QList &list); + void beginList(const char *name = 0); void endList(); void beginGroup(const char *name = 0); void endGroup(); + QByteArray arguments() const; QByteArray function; QByteArray args; diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp index 46e2796446b..3a834ff8ffe 100644 --- a/src/plugins/debugger/qml/qmlengine.cpp +++ b/src/plugins/debugger/qml/qmlengine.cpp @@ -139,8 +139,8 @@ public: int frame = -1, bool addContext = false); void lookup(const QList handles, bool includeSource = false); void backtrace(int fromFrame = -1, int toFrame = -1, bool bottom = false); - void frame(int number = -1); - void scope(int number = -1, int frameNumber = -1); + void frame(int number); + void scope(int number, int frameNumber = -1); void scripts(int types = 4, const QList ids = QList(), bool includeSource = false, const QVariant filter = QVariant()); @@ -150,13 +150,9 @@ public: void clearBreakpoint(int breakpoint); void setExceptionBreak(Exceptions type, bool enabled = false); - void version(); void clearCache(); - void sendAndLogV8Request(const QJsonObject &request); - QByteArray packMessage(const QByteArray &type, const QByteArray &message = QByteArray()); - QJsonObject initObject(); void expandObject(const QByteArray &iname, quint64 objectId); void flushSendBuffer(); @@ -170,6 +166,7 @@ public: bool canEvaluateScript(const QString &script); void updateScriptSource(const QString &fileName, int lineOffset, int columnOffset, const QString &source); + void runCommand(const DebuggerCommand &command); public: int sequence = -1; @@ -1322,7 +1319,11 @@ void QmlEnginePrivate::disconnect() // "type" : "request", // "command" : "disconnect", // } - QJsonObject jsonVal = initObject(); + QJsonObject jsonVal = { + {_(SEQ), ++sequence}, + {_(TYPE), _(REQUEST)} + }; + jsonVal.insert(_(COMMAND), _(DISCONNECT)); const QByteArray msg = QJsonDocument(jsonVal).toJson(QJsonDocument::Compact); @@ -1339,27 +1340,18 @@ void QmlEnginePrivate::continueDebugging(StepAction action) // "stepcount" : // } // } - QJsonObject jsonVal = initObject(); - jsonVal.insert(_(COMMAND), _(CONTINEDEBUGGING)); - if (action != Continue) { - QJsonObject args; - switch (action) { - case StepIn: - args.insert(_(STEPACTION), _(IN)); - break; - case StepOut: - args.insert(_(STEPACTION), _(OUT)); - break; - case Next: - args.insert(_(STEPACTION), _(NEXT)); - break; - default:break; - } + DebuggerCommand cmd(CONTINEDEBUGGING); + + if (action == StepIn) + cmd.arg(STEPACTION, IN); + else if (action == StepOut) + cmd.arg(STEPACTION, OUT); + else if (action == Next) + cmd.arg(STEPACTION, NEXT); + + runCommand(cmd); - jsonVal.insert(_(ARGUMENTS), args); - } - sendAndLogV8Request(jsonVal); previousStepAction = action; } @@ -1380,45 +1372,37 @@ void QmlEnginePrivate::evaluate(const QString expr, bool global, // ] // } // } - QJsonObject jsonVal = initObject(); - jsonVal.insert(_(COMMAND), _(EVALUATE)); - QJsonObject args { - { _(EXPRESSION), expr } - }; + DebuggerCommand cmd(EVALUATE); + + cmd.arg(EXPRESSION, expr); if (frame != -1) - args.insert(_(FRAME), frame); + cmd.arg(FRAME, frame); if (global) - args.insert(_(GLOBAL), global); + cmd.arg(GLOBAL, global); if (disableBreak) - args.insert(_(DISABLE_BREAK), disableBreak); + cmd.arg(DISABLE_BREAK, disableBreak); if (addContext) { WatchHandler *watchHandler = engine->watchHandler(); QAbstractItemModel *watchModel = watchHandler->model(); int rowCount = watchModel->rowCount(); - QJsonArray ctxtList; - while (rowCount) { - QModelIndex index = watchModel->index(--rowCount, 0); + cmd.beginList(ADDITIONAL_CONTEXT); + for (int row = 0; row < rowCount; ++row) { + QModelIndex index = watchModel->index(row, 0); // FIXME: This looks wrong. const WatchData *data = watchHandler->watchItem(index); - const QJsonObject ctxt { - { _(NAME), data->name }, - { _(HANDLE), int(data->id) } - }; - - ctxtList.push_front(ctxt); + cmd.beginGroup(); + cmd.arg(NAME, data->name); + cmd.arg(HANDLE, int(data->id)); + cmd.endGroup(); } - - args.insert(_(ADDITIONAL_CONTEXT), ctxtList); } - jsonVal.insert(_(ARGUMENTS), args); - - sendAndLogV8Request(jsonVal); + runCommand(cmd); } void QmlEnginePrivate::lookup(QList handles, bool includeSource) @@ -1432,22 +1416,15 @@ void QmlEnginePrivate::lookup(QList handles, bool includeSource) // script objects are returned>, // } // } - QJsonObject jsonVal = initObject(); - jsonVal.insert(_(COMMAND), _(LOOKUP)); - QJsonObject args; + DebuggerCommand cmd(LOOKUP); - QJsonArray array; - foreach (int handle, handles) - array.push_back(handle); - args.insert(_(HANDLES), array); + cmd.arg(HANDLES, handles); if (includeSource) - args.insert(_(INCLUDESOURCE), includeSource); + cmd.arg(INCLUDESOURCE, includeSource); - jsonVal.insert(_(ARGUMENTS), args); - - sendAndLogV8Request(jsonVal); + runCommand(cmd); } void QmlEnginePrivate::backtrace(int fromFrame, int toFrame, bool bottom) @@ -1461,23 +1438,19 @@ void QmlEnginePrivate::backtrace(int fromFrame, int toFrame, bool bottom) // stack is requested> // } // } - QJsonObject jsonVal = initObject(); - jsonVal.insert(_(COMMAND), _(BACKTRACE)); - QJsonObject args; + DebuggerCommand cmd(BACKTRACE); if (fromFrame != -1) - args.insert(_(FROMFRAME), fromFrame); + cmd.arg(FROMFRAME, fromFrame); if (toFrame != -1) - args.insert(_(TOFRAME), toFrame); + cmd.arg(TOFRAME, toFrame); if (bottom) - args.insert(_(BOTTOM), bottom); + cmd.arg(BOTTOM, bottom); - jsonVal.insert(_(ARGUMENTS), args); - - sendAndLogV8Request(jsonVal); + runCommand(cmd); } void QmlEnginePrivate::frame(int number) @@ -1488,18 +1461,12 @@ void QmlEnginePrivate::frame(int number) // "arguments" : { "number" : // } // } - QJsonObject jsonVal = initObject(); - jsonVal.insert(_(COMMAND), _(FRAME)); - if (number != -1) { - const QJsonObject args { - { _(NUMBER), number } - }; + DebuggerCommand cmd(FRAME); + if (number != -1) + cmd.arg(NUMBER, number); - jsonVal.insert(_(ARGUMENTS), args); - } - - sendAndLogV8Request(jsonVal); + runCommand(cmd); } void QmlEnginePrivate::scope(int number, int frameNumber) @@ -1512,21 +1479,13 @@ void QmlEnginePrivate::scope(int number, int frameNumber) // frame if missing> // } // } - QJsonObject jsonVal = initObject(); - jsonVal.insert(_(COMMAND), _(SCOPE)); - if (number != -1) { - QJsonObject args { - { _(NUMBER), number } - }; + DebuggerCommand cmd(SCOPE); + cmd.arg(NUMBER, number); + if (frameNumber != -1) + cmd.arg(FRAMENUMBER, frameNumber); - if (frameNumber != -1) - args.insert(_(FRAMENUMBER), frameNumber); - - jsonVal.insert(_(ARGUMENTS), args); - } - - sendAndLogV8Request(jsonVal); + runCommand(cmd); } void QmlEnginePrivate::scripts(int types, const QList ids, bool includeSource, @@ -1547,37 +1506,24 @@ void QmlEnginePrivate::scripts(int types, const QList ids, bool includeSour // If a string is specified, then only scripts whose names contain the filter string will be retrieved.> // } // } - QJsonObject jsonVal = initObject(); - jsonVal.insert(_(COMMAND), _(SCRIPTS)); - QJsonObject args { - { _(TYPES), types } - }; + DebuggerCommand cmd(SCRIPTS); + cmd.arg(TYPES, types); - if (ids.count()) { - QJsonArray array; - foreach (int id, ids) { - array.push_back(id); - } - args.insert(_(IDS), array); - } + if (ids.count()) + cmd.arg(IDS, ids); if (includeSource) - args.insert(_(INCLUDESOURCE), includeSource); + cmd.arg(INCLUDESOURCE, includeSource); - QJsonValue filterValue; if (filter.type() == QVariant::String) - filterValue = filter.toString(); + cmd.arg(FILTER, filter.toString()); else if (filter.type() == QVariant::Int) - filterValue = filter.toInt(); + cmd.arg(FILTER, filter.toInt()); else QTC_CHECK(!filter.isValid()); - args.insert(_(FILTER), filterValue); - - jsonVal.insert(_(ARGUMENTS), args); - - sendAndLogV8Request(jsonVal); + runCommand(cmd); } void QmlEnginePrivate::setBreakpoint(const QString type, const QString target, @@ -1604,33 +1550,25 @@ void QmlEnginePrivate::setBreakpoint(const QString type, const QString target, sendMessage(packMessage(BREAKONSIGNAL, params)); } else { - QJsonObject jsonVal = initObject(); - jsonVal.insert(_(COMMAND), _(SETBREAKPOINT)); + DebuggerCommand cmd(SETBREAKPOINT); + cmd.arg(TYPE, type); + cmd.arg(ENABLED, enabled); - QJsonObject args { - { _(TYPE), type }, - { _(ENABLED), enabled } - }; if (type == _(SCRIPTREGEXP)) - args.insert(_(TARGET), Utils::FileName::fromString(target).fileName()); + cmd.arg(TARGET, Utils::FileName::fromString(target).fileName()); else - args.insert(_(TARGET), target); + cmd.arg(TARGET, target); if (line) - args.insert(_(LINE), line - 1); - + cmd.arg(LINE, line - 1); if (column) - args.insert(_(COLUMN), column - 1); - + cmd.arg(COLUMN, column - 1); if (!condition.isEmpty()) - args.insert(_(CONDITION), condition); - + cmd.arg(CONDITION, condition); if (ignoreCount != -1) - args.insert(_(IGNORECOUNT), ignoreCount); + cmd.arg(IGNORECOUNT, ignoreCount); - jsonVal.insert(_(ARGUMENTS), args); - - sendAndLogV8Request(jsonVal); + runCommand(cmd); } } @@ -1642,16 +1580,10 @@ void QmlEnginePrivate::clearBreakpoint(int breakpoint) // "arguments" : { "breakpoint" : // } // } - QJsonObject jsonVal = initObject(); - jsonVal.insert(_(COMMAND), _(CLEARBREAKPOINT)); - QJsonObject args { - { _(BREAKPOINT), breakpoint } - }; - - jsonVal.insert(_(ARGUMENTS), args); - - sendAndLogV8Request(jsonVal); + DebuggerCommand cmd(CLEARBREAKPOINT); + cmd.arg(BREAKPOINT, breakpoint); + runCommand(cmd); } void QmlEnginePrivate::setExceptionBreak(Exceptions type, bool enabled) @@ -1663,35 +1595,19 @@ void QmlEnginePrivate::setExceptionBreak(Exceptions type, bool enabled) // "enabled" : // } // } - QJsonObject jsonVal = initObject(); - jsonVal.insert(_(COMMAND), _(SETEXCEPTIONBREAK)); - - QJsonObject args; + DebuggerCommand cmd(SETEXCEPTIONBREAK); if (type == AllExceptions) - args.insert(_(TYPE), _(ALL)); - //Not Supported - // else if (type == UncaughtExceptions) - // args.setProperty(_(TYPE),QScriptValue(_(UNCAUGHT))); + cmd.arg(TYPE, ALL); + + //Not Supported: + // else if (type == UncaughtExceptions) + // cmd.args(TYPE, UNCAUGHT); if (enabled) - args.insert(_(ENABLED), enabled); + cmd.arg(ENABLED, enabled); - jsonVal.insert(_(ARGUMENTS), args); - - sendAndLogV8Request(jsonVal); -} - -void QmlEnginePrivate::version() -{ - // { "seq" : , - // "type" : "request", - // "command" : "version", - // } - QJsonObject jsonVal = initObject(); - jsonVal.insert(_(COMMAND), _(VERSION)); - - sendAndLogV8Request(jsonVal); + runCommand(cmd); } QVariant valueFromRef(int handle, const QVariant &refsVal, bool *success) @@ -1837,19 +1753,22 @@ QByteArray QmlEnginePrivate::packMessage(const QByteArray &type, const QByteArra return request; } -QJsonObject QmlEnginePrivate::initObject() +void QmlEnginePrivate::runCommand(const DebuggerCommand &command) { - return QJsonObject { - {_(SEQ), ++sequence}, - {_(TYPE), _(REQUEST)} - }; -} + // Leave items as variables, serialization depends on it. + QByteArray cmd = V8DEBUG; + QByteArray type = V8REQUEST; + QByteArray msg = "{\"seq\":" + QByteArray::number(++sequence) + "," + + "\"type\":\"request\"," + + "\"command\":\"" + command.function + "\"," + + "\"arguments\":{" + command.arguments() + "}}"; -void QmlEnginePrivate::sendAndLogV8Request(const QJsonObject &request) -{ - const QByteArray msg = QJsonDocument(request).toJson(QJsonDocument::Compact); engine->showMessage(QString::fromLatin1("%1 %2").arg(_(V8REQUEST), QString::fromUtf8(msg)), LogInput); - sendMessage(packMessage(V8REQUEST, msg)); + + QByteArray request; + QmlDebugStream rs(&request, QIODevice::WriteOnly); + rs << cmd << type << msg; + sendMessage(request); } void QmlEnginePrivate::expandObject(const QByteArray &iname, quint64 objectId) @@ -2643,9 +2562,8 @@ void QmlEnginePrivate::stateChanged(State state) /// Start session. flushSendBuffer(); connect(); - //Query for the V8 version. This is - //only for logging to the debuggerlog - version(); + // Query for the V8 version. This is only for logging to the log. + runCommand(VERSION); } } From 4363e3e9e471ac4943f0db6631ac15d875669bd6 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 3 Jul 2015 08:33:09 +0200 Subject: [PATCH 09/70] TreeModel: Remove TreeItem::setModel from interface This should not be accessible to client code, as the property is effectively managed by the owning model and manually changing it on an item breaks that. Change-Id: Ie04451be3c0e51e7c796dcd64d400600f035fa08 Reviewed-by: Christian Stenger --- src/libs/utils/treemodel.cpp | 14 ++++---------- src/libs/utils/treemodel.h | 1 - 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/src/libs/utils/treemodel.cpp b/src/libs/utils/treemodel.cpp index 424bc49a246..4a34181d2b5 100644 --- a/src/libs/utils/treemodel.cpp +++ b/src/libs/utils/treemodel.cpp @@ -770,15 +770,6 @@ QModelIndex TreeItem::index() const return m_model->indexForItem(this); } -void TreeItem::setModel(TreeModel *model) -{ - if (m_model == model) - return; - m_model = model; - foreach (TreeItem *item, m_children) - item->setModel(model); -} - void TreeItem::walkTree(TreeItemVisitor *visitor) { if (visitor->preVisit(this)) { @@ -972,6 +963,9 @@ int TreeModel::topLevelItemCount() const void TreeModel::setRootItem(TreeItem *item) { + QTC_ASSERT(item, return); + QTC_ASSERT(item->m_model == 0, return); + QTC_ASSERT(item->m_parent == 0, return); QTC_CHECK(m_root); if (m_root) { QTC_CHECK(m_root->m_parent == 0); @@ -980,7 +974,7 @@ void TreeModel::setRootItem(TreeItem *item) delete m_root; } m_root = item; - item->setModel(this); + item->propagateModel(this); emit layoutChanged(); } diff --git a/src/libs/utils/treemodel.h b/src/libs/utils/treemodel.h index e33be6ec785..c151fe1509d 100644 --- a/src/libs/utils/treemodel.h +++ b/src/libs/utils/treemodel.h @@ -101,7 +101,6 @@ public: QModelIndex index() const; TreeModel *model() const { return m_model; } - void setModel(TreeModel *model); void walkTree(TreeItemVisitor *visitor); void walkTree(std::function f); From bb549770a82aebafb0dc9dadf36ca69b9dff4d4d Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Thu, 9 Jul 2015 17:22:10 +0200 Subject: [PATCH 10/70] Clang: Remove unused function Change-Id: Iee4a6a4e8197db9520ad188fa872840305bca1b1 Reviewed-by: Nikolai Kosjar --- src/plugins/clangcodemodel/clangassistproposalmodel.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/plugins/clangcodemodel/clangassistproposalmodel.cpp b/src/plugins/clangcodemodel/clangassistproposalmodel.cpp index 3f11eee6311..b07b2eb42e4 100644 --- a/src/plugins/clangcodemodel/clangassistproposalmodel.cpp +++ b/src/plugins/clangcodemodel/clangassistproposalmodel.cpp @@ -39,15 +39,6 @@ namespace ClangCodeModel { namespace Internal { -namespace { - -const ClangAssistProposalItem &toClangAssistProposalItem(TextEditor::AssistProposalItem *assistProposalItem) -{ - return *static_cast(assistProposalItem); -} - -} - bool ClangAssistProposalModel::replaceDotForArrow(TextEditor::IAssistProposalModel *model) { auto clangAssistProposalModel = static_cast(model); From 0f00e08422d452440660a7fa2bbccab1f8299939 Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Mon, 13 Jul 2015 12:00:49 +0200 Subject: [PATCH 11/70] C++: Fix null pointer access for invalid code The code snippet provided in the bug report could not be parsed properly, thus Bind did not generate all expected symbols/names. The chunk in onConnectOrDisconnectCall() fixes the crash. The other chunks address triggered QTC_ASSERTs. Change-Id: Idf508b91b70659d38e59064d4922600f7b31daf8 Task-number: QTCREATORBUG-14709 Reviewed-by: Marco Bubke --- src/plugins/cppeditor/cppquickfixes.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp index 082c45feb97..736638ef921 100644 --- a/src/plugins/cppeditor/cppquickfixes.cpp +++ b/src/plugins/cppeditor/cppquickfixes.cpp @@ -1832,7 +1832,7 @@ NameAST *nameUnderCursor(const QList &path) bool canLookupDefinition(const CppQuickFixInterface &interface, const NameAST *nameAst) { - QTC_ASSERT(nameAst, return false); + QTC_ASSERT(nameAst && nameAst->name, return false); // Find the enclosing scope unsigned line, column; @@ -1909,7 +1909,7 @@ void AddIncludeForUndefinedIdentifier::match(const CppQuickFixInterface &interfa QuickFixOperations &result) { const NameAST *nameAst = nameUnderCursor(interface.path()); - if (!nameAst) + if (!nameAst || !nameAst->name) return; if (canLookupDefinition(interface, nameAst)) @@ -5852,7 +5852,7 @@ bool onConnectOrDisconnectCall(AST *ast, const ExpressionListAST **arguments) return false; const IdExpressionAST *idExpr = call->base_expression->asIdExpression(); - if (!idExpr) + if (!idExpr || !idExpr->name || !idExpr->name->name) return false; const ExpressionListAST *args = call->expression_list; From 65c867db3b3fd0ac962af08f0113a02253ea460d Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Thu, 9 Jul 2015 17:23:11 +0200 Subject: [PATCH 12/70] Clang: Remove option for code completion Completion should be faster and the test are still running. Change-Id: If663e80ce349547b0948412e52b9bf4f76cbb011 Reviewed-by: Nikolai Kosjar --- src/tools/clangbackend/ipcsource/translationunit.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/tools/clangbackend/ipcsource/translationunit.cpp b/src/tools/clangbackend/ipcsource/translationunit.cpp index 02b43e77ce2..f44d6989819 100644 --- a/src/tools/clangbackend/ipcsource/translationunit.cpp +++ b/src/tools/clangbackend/ipcsource/translationunit.cpp @@ -163,8 +163,7 @@ void TranslationUnit::removeOutdatedTranslationUnit() const void TranslationUnit::createTranslationUnitIfNeeded() const { - const auto options = CXTranslationUnit_DetailedPreprocessingRecord - | CXTranslationUnit_CacheCompletionResults + const auto options = CXTranslationUnit_CacheCompletionResults | CXTranslationUnit_PrecompiledPreamble | CXTranslationUnit_SkipFunctionBodies; From 2e256e5223167a99c06ed91c5e6a3a6a5b12e9c9 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 10 Jul 2015 13:06:00 +0200 Subject: [PATCH 13/70] Debugger: Remove remaining direct uses of QmlEngine::sendMessage Ready to introduce callbacks. Change-Id: If26566ed71ce1283f9f42b62e75a1c793a21ef32 Reviewed-by: Christian Stenger --- src/plugins/debugger/qml/qmlengine.cpp | 68 +++++++------------------- 1 file changed, 19 insertions(+), 49 deletions(-) diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp index 3a834ff8ffe..89e3c6c862d 100644 --- a/src/plugins/debugger/qml/qmlengine.cpp +++ b/src/plugins/debugger/qml/qmlengine.cpp @@ -130,9 +130,6 @@ public: void messageReceived(const QByteArray &data); void stateChanged(State state); - void connect(); - void disconnect(); - void continueDebugging(StepAction stepAction); void evaluate(const QString expr, bool global = false, bool disableBreak = false, @@ -152,8 +149,6 @@ public: void clearCache(); - QByteArray packMessage(const QByteArray &type, const QByteArray &message = QByteArray()); - void expandObject(const QByteArray &iname, quint64 objectId); void flushSendBuffer(); @@ -166,7 +161,9 @@ public: bool canEvaluateScript(const QString &script); void updateScriptSource(const QString &fileName, int lineOffset, int columnOffset, const QString &source); + void runCommand(const DebuggerCommand &command); + void runDirectCommand(const QByteArray &type, const QByteArray &msg = QByteArray()); public: int sequence = -1; @@ -604,7 +601,11 @@ void QmlEngine::notifyEngineRemoteServerRunning(const QByteArray &serverChannel, void QmlEngine::shutdownInferior() { // End session. - d->disconnect(); + // { "seq" : , + // "type" : "request", + // "command" : "disconnect", + // } + d->runCommand(DISCONNECT); if (isSlaveEngine()) resetLocation(); @@ -661,7 +662,7 @@ void QmlEngine::continueInferior() void QmlEngine::interruptInferior() { showMessage(_(INTERRUPT), LogInput); - d->sendMessage(d->packMessage(INTERRUPT)); + d->runDirectCommand(INTERRUPT); notifyInferiorStopOk(); } @@ -1307,30 +1308,6 @@ void QmlEngine::logServiceActivity(const QString &service, const QString &logMes showMessage(service + QLatin1Char(' ') + logMessage, LogDebug); } -void QmlEnginePrivate::connect() -{ - engine->showMessage(_(CONNECT), LogInput); - sendMessage(packMessage(CONNECT)); -} - -void QmlEnginePrivate::disconnect() -{ - // { "seq" : , - // "type" : "request", - // "command" : "disconnect", - // } - QJsonObject jsonVal = { - {_(SEQ), ++sequence}, - {_(TYPE), _(REQUEST)} - }; - - jsonVal.insert(_(COMMAND), _(DISCONNECT)); - - const QByteArray msg = QJsonDocument(jsonVal).toJson(QJsonDocument::Compact); - engine->showMessage(QString::fromUtf8(msg), LogInput); - sendMessage(packMessage(DISCONNECT, msg)); -} - void QmlEnginePrivate::continueDebugging(StepAction action) { // { "seq" : , @@ -1547,7 +1524,7 @@ void QmlEnginePrivate::setBreakpoint(const QString type, const QString target, QmlDebugStream rs(¶ms, QIODevice::WriteOnly); rs << target.toUtf8() << enabled; engine->showMessage(QString(_("%1 %2 %3")).arg(_(BREAKONSIGNAL), target, enabled ? _("enabled") : _("disabled")), LogInput); - sendMessage(packMessage(BREAKONSIGNAL, params)); + runDirectCommand(BREAKONSIGNAL, params); } else { DebuggerCommand cmd(SETBREAKPOINT); @@ -1743,27 +1720,21 @@ void QmlEnginePrivate::clearCache() updateLocalsAndWatchers.clear(); } -QByteArray QmlEnginePrivate::packMessage(const QByteArray &type, const QByteArray &message) -{ - SDEBUG(message); - QByteArray request; - QmlDebugStream rs(&request, QIODevice::WriteOnly); - QByteArray cmd = V8DEBUG; - rs << cmd << type << message; - return request; -} - void QmlEnginePrivate::runCommand(const DebuggerCommand &command) { - // Leave items as variables, serialization depends on it. - QByteArray cmd = V8DEBUG; - QByteArray type = V8REQUEST; QByteArray msg = "{\"seq\":" + QByteArray::number(++sequence) + "," + "\"type\":\"request\"," + "\"command\":\"" + command.function + "\"," + "\"arguments\":{" + command.arguments() + "}}"; + runDirectCommand(V8REQUEST, msg); +} - engine->showMessage(QString::fromLatin1("%1 %2").arg(_(V8REQUEST), QString::fromUtf8(msg)), LogInput); +void QmlEnginePrivate::runDirectCommand(const QByteArray &type, const QByteArray &msg) +{ + // Leave item as variable, serialization depends on it. + QByteArray cmd = V8DEBUG; + + engine->showMessage(QString::fromLatin1("%1 %2").arg(_(type), _(msg)), LogInput); QByteArray request; QmlDebugStream rs(&request, QIODevice::WriteOnly); @@ -2561,9 +2532,8 @@ void QmlEnginePrivate::stateChanged(State state) if (state == QmlDebugClient::Enabled) { /// Start session. flushSendBuffer(); - connect(); - // Query for the V8 version. This is only for logging to the log. - runCommand(VERSION); + runDirectCommand(CONNECT); + runCommand(VERSION); // Only used for logging. } } From 6a7df3eede24b71a2ed4df309bcb7c25e25ef359 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Mon, 13 Jul 2015 17:12:56 +0300 Subject: [PATCH 14/70] Sdktool: Add missing space in usage message Change-Id: I3dba922f138b9e8d404fde256171e76de06574e0 Reviewed-by: Tobias Hunger --- src/tools/sdktool/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/sdktool/main.cpp b/src/tools/sdktool/main.cpp index b3b69ae4665..51cc49ac864 100644 --- a/src/tools/sdktool/main.cpp +++ b/src/tools/sdktool/main.cpp @@ -66,7 +66,7 @@ void printHelp(const Operation *op) void printHelp(const QList &operations) { std::cout << "Qt Creator SDK setup tool." << std::endl; - std::cout << " Usage:" << qPrintable(qApp->arguments().at(0)) + std::cout << " Usage: " << qPrintable(qApp->arguments().at(0)) << " " << std::endl << std::endl; std::cout << "ARGS:" << std::endl; std::cout << " --help|-h Print this help text" << std::endl; From f54b7d63ccd3651245d87746964a3d3da1d86e23 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Mon, 29 Jun 2015 14:36:26 +0200 Subject: [PATCH 15/70] Squish: Fix tst_simple_analyze Change-Id: Iac334d37a1cf6a85d4f85d09165503f9bca8ce91 Reviewed-by: Robert Loehning --- tests/system/objects.map | 1 - .../suite_debugger/tst_simple_analyze/test.py | 38 ++++++------------- .../testdata/events_qt48.tsv | 8 ---- .../testdata/events_qt48_nonOptimized.tsv | 9 ----- .../testdata/events_qt5.tsv | 15 ++++++++ .../testdata/events_qt50.tsv | 8 ---- .../testdata/events_qt50_nonOptimized.tsv | 9 ----- 7 files changed, 26 insertions(+), 62 deletions(-) delete mode 100644 tests/system/suite_debugger/tst_simple_analyze/testdata/events_qt48.tsv delete mode 100644 tests/system/suite_debugger/tst_simple_analyze/testdata/events_qt48_nonOptimized.tsv create mode 100644 tests/system/suite_debugger/tst_simple_analyze/testdata/events_qt5.tsv delete mode 100644 tests/system/suite_debugger/tst_simple_analyze/testdata/events_qt50.tsv delete mode 100644 tests/system/suite_debugger/tst_simple_analyze/testdata/events_qt50_nonOptimized.tsv diff --git a/tests/system/objects.map b/tests/system/objects.map index e96b9ea1c1b..791fe94ae73 100644 --- a/tests/system/objects.map +++ b/tests/system/objects.map @@ -104,7 +104,6 @@ :Help Widget_Help::Internal::HelpWidget {type='Help::Internal::HelpWidget' unnamed='1' visible='1' windowTitle?='Help -*'} :Hits_QCLuceneResultWidget {aboveWidget=':Hits_QLabel' type='QCLuceneResultWidget' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} :Hits_QLabel {text~='\\\\d+ - \\\\d+ of \\\\d+ Hits' type='QLabel' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} -:JavaScript.QmlProfilerEventsTable_QmlProfiler::Internal::QV8ProfilerEventsMainView {container=':*Qt Creator.JavaScript_QDockWidget' name='QmlProfilerEventsTable' type='QmlProfiler::Internal::QV8ProfilerEventsMainView' visible='1'} :Kits_QtVersion_QComboBox {container=':qt_tabwidget_stackedwidget_QWidget' leftWidget=':QtVersionLabel_KitPage' type='QComboBox' unnamed='1' visible='1'} :Locals and Expressions_Debugger::Internal::WatchTreeView {container=':DebugModeWidget.Locals and Expressions_QDockWidget' name='WatchWindow' type='Debugger::Internal::WatchTreeView' visible='1' windowTitle='Locals and Expressions'} :Minimal required Qt version:_QLabel {text='Minimal required Qt version:' type='QLabel' unnamed='1' visible='1' window=':New Text File_ProjectExplorer::JsonWizard'} diff --git a/tests/system/suite_debugger/tst_simple_analyze/test.py b/tests/system/suite_debugger/tst_simple_analyze/test.py index dddff7d5e87..f5b926794f5 100644 --- a/tests/system/suite_debugger/tst_simple_analyze/test.py +++ b/tests/system/suite_debugger/tst_simple_analyze/test.py @@ -36,10 +36,10 @@ def main(): return # using a temporary directory won't mess up a potentially existing workingDir = tempDir() - # we need a Qt >= 4.8 - analyzerTargets = Targets.desktopTargetClasses() & ~Targets.DESKTOP_474_GCC + # we need a Qt >= 5.3 - we use checkedTargets, so we should get only valid targets + analyzerTargets = Targets.desktopTargetClasses() if platform.system() in ('Windows', 'Microsoft') and JIRA.isBugStillOpen(14307): - analyzerTargets &= ~Targets.DESKTOP_480_DEFAULT & ~Targets.DESKTOP_541_GCC + analyzerTargets &= ~Targets.DESKTOP_541_GCC checkedTargets, projectName = createNewQtQuickApplication(workingDir, targets=analyzerTargets) editor = waitForObject(":Qt Creator_QmlJSEditor::QmlJSTextEditorWidget") if placeCursorToLine(editor, "MouseArea.*", True): @@ -59,13 +59,12 @@ def main(): invokeMenuItem("File", "Save All") availableConfigs = iterateBuildConfigs(len(checkedTargets), "Debug") if not availableConfigs: - test.fatal("Haven't found a suitable Qt version (need Qt 4.8) - leaving without debugging.") + test.fatal("Haven't found a suitable Qt version (need Qt 5.3+) - leaving without debugging.") else: - performTest(workingDir, projectName, len(checkedTargets), availableConfigs, False) - performTest(workingDir, projectName, len(checkedTargets), availableConfigs, True) + performTest(workingDir, projectName, len(checkedTargets), availableConfigs) invokeMenuItem("File", "Exit") -def performTest(workingDir, projectName, targetCount, availableConfigs, disableOptimizer): +def performTest(workingDir, projectName, targetCount, availableConfigs): def __elapsedTime__(elapsedTimeLabelText): return float(re.search("Elapsed:\s+(-?\d+\.\d+) s", elapsedTimeLabelText).group(1)) @@ -75,9 +74,6 @@ def performTest(workingDir, projectName, targetCount, availableConfigs, disableO invokeMenuItem('Build', 'Clean Project "%s"' % projectName) qtVersion = verifyBuildConfig(targetCount, kit, config, True, enableQmlDebug=True)[0] test.log("Selected kit using Qt %s" % qtVersion) - if disableOptimizer: - batchEditRunEnvironment(targetCount, kit, ["QML_DISABLE_OPTIMIZER=1"]) - switchViewTo(ViewConstants.EDIT) # explicitly build before start debugging for adding the executable as allowed program to WinFW invokeMenuItem("Build", "Rebuild All") waitForCompile() @@ -106,30 +102,18 @@ def performTest(workingDir, projectName, targetCount, availableConfigs, disableO "Elapsed time should be positive in string '%s'" % str(elapsedLabel.text)) except: test.fatal("Could not read elapsed time from '%s'" % str(elapsedLabel.text)) - if safeClickTab("V8"): - model = findObject(":JavaScript.QmlProfilerEventsTable_QmlProfiler::" - "Internal::QV8ProfilerEventsMainView").model() - test.compare(model.rowCount(), 0) if safeClickTab("Events"): colPercent, colTotal, colCalls, colMean, colMedian, colLongest, colShortest = range(2, 9) model = waitForObject(":Events.QmlProfilerEventsTable_QmlProfiler::" "Internal::QmlProfilerEventsMainView").model() - if qtVersion.startswith("5."): - if disableOptimizer: - compareEventsTab(model, "events_qt50_nonOptimized.tsv") - else: - compareEventsTab(model, "events_qt50.tsv") - numberOfMsRows = 3 - else: - if disableOptimizer: - compareEventsTab(model, "events_qt48_nonOptimized.tsv") - else: - compareEventsTab(model, "events_qt48.tsv") - numberOfMsRows = 2 + compareEventsTab(model, "events_qt5.tsv") + numberOfMsRows = 3 test.compare(dumpItems(model, column=colPercent)[0], '100.00 %') - for i in [colTotal, colMean, colMedian, colLongest, colShortest]: + # cannot run following test on colShortest (unstable) + for i in [colTotal, colMean, colMedian, colLongest]: for item in dumpItems(model, column=i)[:numberOfMsRows]: test.verify(item.endswith(' ms'), "Verify that '%s' ends with ' ms'" % item) + for i in [colTotal, colMean, colMedian, colLongest, colShortest]: for item in dumpItems(model, column=i): test.verify(not item.startswith('0.000 '), "Check for implausible durations (QTCREATORBUG-8996): %s" % item) diff --git a/tests/system/suite_debugger/tst_simple_analyze/testdata/events_qt48.tsv b/tests/system/suite_debugger/tst_simple_analyze/testdata/events_qt48.tsv deleted file mode 100644 index 443e686825b..00000000000 --- a/tests/system/suite_debugger/tst_simple_analyze/testdata/events_qt48.tsv +++ /dev/null @@ -1,8 +0,0 @@ -"0" "1" "4" "9" -"" "" "1" "Main Program" -"main.qml:12" "Signal" "2" "triggered(): { runCount += 1; var i; for (i = 1; i < 2500; ++i) { var j = i * i; console.log(j); } }" -"main.qml:1" "Create" "1" "main.qml" -"main.qml:1" "Compile" "1" "main.qml" -"main.qml:31" "Binding" "1" "text: qsTr(""Hello World"")" -"" "Binding" "2" "Source code not available" -"main.qml:11" "Binding" "3" "running: runCount < 2" diff --git a/tests/system/suite_debugger/tst_simple_analyze/testdata/events_qt48_nonOptimized.tsv b/tests/system/suite_debugger/tst_simple_analyze/testdata/events_qt48_nonOptimized.tsv deleted file mode 100644 index 661b87864f3..00000000000 --- a/tests/system/suite_debugger/tst_simple_analyze/testdata/events_qt48_nonOptimized.tsv +++ /dev/null @@ -1,9 +0,0 @@ -"0" "1" "4" "9" -"" "" "1" "Main Program" -"main.qml:12" "Signal" "2" "triggered(): { runCount += 1; var i; for (i = 1; i < 2500; ++i) { var j = i * i; console.log(j); } }" -"main.qml:1" "Create" "1" "main.qml" -"main.qml:1" "Compile" "1" "main.qml" -"main.qml:31" "Binding" "1" "text: qsTr(""Hello World"")" -"main.qml:11" "Binding" "3" "running: runCount < 2" -"main.qml:32" "Binding" "1" "centerIn: parent" -"main.qml:24" "Binding" "1" "fill: parent" diff --git a/tests/system/suite_debugger/tst_simple_analyze/testdata/events_qt5.tsv b/tests/system/suite_debugger/tst_simple_analyze/testdata/events_qt5.tsv new file mode 100644 index 00000000000..8b8833faeb8 --- /dev/null +++ b/tests/system/suite_debugger/tst_simple_analyze/testdata/events_qt5.tsv @@ -0,0 +1,15 @@ +"0" "1" "4" "9" +"" "" "1" "Main Program" +"main.qml:4" "Create" "2" "QtQuick.Window/Window" +"main.qml:12" "Signal" "2" "onTriggered: { runCount += 1; var i; for (i = 1; i < 2500; ++i) { var j = i * i; console.log(j); } }" +"main.qml:12" "JavaScript" "2" "onTriggered" +"main.qml:30" "Create" "2" "QtQuick/Text" +"main.qml:1" "Compile" "1" "main.qml" +"main.qml:7" "Create" "2" "QtQuick/Timer" +"main.qml:32" "Binding" "1" "anchors.centerIn: parent" +"main.qml:23" "Create" "2" "QtQuick/MouseArea" +"main.qml:11" "Binding" "3" "running: runCount < 2" +"main.qml:32" "JavaScript" "1" "expression for centerIn" +"main.qml:24" "Binding" "1" "anchors.fill: parent" +"main.qml:11" "JavaScript" "3" "expression for running" +"main.qml:24" "JavaScript" "1" "expression for fill" diff --git a/tests/system/suite_debugger/tst_simple_analyze/testdata/events_qt50.tsv b/tests/system/suite_debugger/tst_simple_analyze/testdata/events_qt50.tsv deleted file mode 100644 index c9027ef163e..00000000000 --- a/tests/system/suite_debugger/tst_simple_analyze/testdata/events_qt50.tsv +++ /dev/null @@ -1,8 +0,0 @@ -"0" "1" "4" "9" -"" "" "1" "Main Program" -"main.qml:1" "Create" "1" "main.qml" -"main.qml:12" "Signal" "2" "triggered(): { runCount += 1; var i; for (i = 1; i < 2500; ++i) { var j = i * i; console.log(j); } }" -"main.qml:1" "Compile" "1" "main.qml" -"main.qml:31" "Binding" "1" "text: qsTr(""Hello World"")" -"" "Binding" "2" "Source code not available" -"main.qml:11" "Binding" "3" "running: runCount < 2" diff --git a/tests/system/suite_debugger/tst_simple_analyze/testdata/events_qt50_nonOptimized.tsv b/tests/system/suite_debugger/tst_simple_analyze/testdata/events_qt50_nonOptimized.tsv deleted file mode 100644 index 9b1f613781b..00000000000 --- a/tests/system/suite_debugger/tst_simple_analyze/testdata/events_qt50_nonOptimized.tsv +++ /dev/null @@ -1,9 +0,0 @@ -"0" "1" "4" "9" -"" "" "1" "Main Program" -"main.qml:1" "Create" "1" "main.qml" -"main.qml:12" "Signal" "2" "triggered(): { runCount += 1; var i; for (i = 1; i < 2500; ++i) { var j = i * i; console.log(j); } }" -"main.qml:1" "Compile" "1" "main.qml" -"main.qml:31" "Binding" "1" "text: qsTr(""Hello World"")" -"main.qml:11" "Binding" "3" "running: runCount < 2" -"main.qml:32" "Binding" "1" "centerIn: parent" -"main.qml:24" "Binding" "1" "fill: parent" From 5f9d991062d497c9eddf2671ed8bf3be6040c79e Mon Sep 17 00:00:00 2001 From: Daniel Teske Date: Mon, 13 Jul 2015 13:09:45 +0200 Subject: [PATCH 16/70] Add QtVersionManager::unsortedVersions() To sort the list, we need to know the version number of all qt versions. That requires running the qmake. Since in most cases we don't need the sorted list at startup, add a method for that and use it. This prevents almost all calls to queryQmake for me, except for a few for Android Qt Versions. Change-Id: I6db89f214d68d07fee4b4dd15ee14c10d1248565 Reviewed-by: Orgad Shaneh Reviewed-by: Tobias Hunger --- src/plugins/android/androidconfigurations.cpp | 2 +- src/plugins/qtsupport/qtkitinformation.cpp | 4 ++-- src/plugins/qtsupport/qtversionmanager.cpp | 9 ++++++++- src/plugins/qtsupport/qtversionmanager.h | 3 +++ 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index eb9f0609e24..c15d0d8d96a 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -1302,7 +1302,7 @@ void AndroidConfigurations::updateAutomaticKitList() } QHash > qtVersionsForArch; - foreach (QtSupport::BaseQtVersion *qtVersion, QtSupport::QtVersionManager::versions()) { + foreach (QtSupport::BaseQtVersion *qtVersion, QtSupport::QtVersionManager::unsortedVersions()) { if (qtVersion->type() != QLatin1String(Constants::ANDROIDQT)) continue; QList qtAbis = qtVersion->qtAbis(); diff --git a/src/plugins/qtsupport/qtkitinformation.cpp b/src/plugins/qtsupport/qtkitinformation.cpp index c9a04cad215..c893b8ccf27 100644 --- a/src/plugins/qtsupport/qtkitinformation.cpp +++ b/src/plugins/qtsupport/qtkitinformation.cpp @@ -60,7 +60,7 @@ QVariant QtKitInformation::defaultValue(ProjectExplorer::Kit *k) const Q_UNUSED(k); // find "Qt in PATH": - QList versionList = QtVersionManager::versions(); + QList versionList = QtVersionManager::unsortedVersions(); BaseQtVersion *result = findOrDefault(versionList, [](const BaseQtVersion *v) { return v->autodetectionSource() == QLatin1String("PATH"); }); @@ -174,7 +174,7 @@ int QtKitInformation::qtVersionId(const ProjectExplorer::Kit *k) id = -1; } else { QString source = data.toString(); - foreach (BaseQtVersion *v, QtVersionManager::versions()) { + foreach (BaseQtVersion *v, QtVersionManager::unsortedVersions()) { if (v->autodetectionSource() != source) continue; id = v->uniqueId(); diff --git a/src/plugins/qtsupport/qtversionmanager.cpp b/src/plugins/qtsupport/qtversionmanager.cpp index 7298eb319e8..3a44f6861db 100644 --- a/src/plugins/qtsupport/qtversionmanager.cpp +++ b/src/plugins/qtsupport/qtversionmanager.cpp @@ -354,7 +354,7 @@ void QtVersionManager::updateFromInstaller(bool emitSignal) qDebug() << ""; } } - foreach (BaseQtVersion *qtVersion, QtVersionManager::versions()) { + foreach (BaseQtVersion *qtVersion, m_versions) { if (qtVersion->autodetectionSource().startsWith(QLatin1String("SDK."))) { if (!sdkVersions.contains(qtVersion->autodetectionSource())) { if (debug) @@ -515,6 +515,13 @@ int QtVersionManager::getUniqueId() return m_idcount++; } +QList QtVersionManager::unsortedVersions() +{ + QList versions; + QTC_ASSERT(isLoaded(), return versions); + return m_versions.values(); +} + QList QtVersionManager::versions() { QList versions; diff --git a/src/plugins/qtsupport/qtversionmanager.h b/src/plugins/qtsupport/qtversionmanager.h index 0754a566757..b99bb3e42d0 100644 --- a/src/plugins/qtsupport/qtversionmanager.h +++ b/src/plugins/qtsupport/qtversionmanager.h @@ -56,6 +56,9 @@ public: static QList versions(); static QList validVersions(); + // Sorting is slow due to needing to potentially run qmake --query for each version + static QList unsortedVersions(); + // Note: DO NOT STORE THIS POINTER! // The QtVersionManager will delete it at random times and you will // need to get a new pointer by calling this function again! From 16ab843f95b2563ac1bae7d80cc2a899dbb1cfc9 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Mon, 13 Jul 2015 15:24:03 +0200 Subject: [PATCH 17/70] Clang: Add qt.widgets and qt.gui to unittests Change-Id: I52d1a5dce514daaf3de1262e3368addda7588d81 Reviewed-by: Nikolai Kosjar --- tests/unit/unittest/unittest.pro | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro index e765da89d7a..826bf52f8c1 100644 --- a/tests/unit/unittest/unittest.pro +++ b/tests/unit/unittest/unittest.pro @@ -1,5 +1,4 @@ -QT += core network testlib -QT -= gui +QT += core network testlib widgets TARGET = unittest CONFIG += console c++14 testcase From 9f29762d345b5f61321bc0fbb740bd9a89a0c658 Mon Sep 17 00:00:00 2001 From: Andrey Pokrovskiy Date: Sat, 11 Jul 2015 23:35:49 -0700 Subject: [PATCH 18/70] ANSI: Crash in AnsiEscapeCodeHandler::parseText MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Qt creator crashes when capturing output from a program that can output unfinished control sequence. For example: "\x1b". Task-number: QTCREATORBUG-14720 Change-Id: I7535e509a192685aece63aea79234d88153fcb56 Reviewed-by: Tobias Hunger Reviewed-by: André Hartmann Reviewed-by: wonder.mice --- src/libs/utils/ansiescapecodehandler.cpp | 83 ++++++++++++------- src/libs/utils/ansiescapecodehandler.h | 1 + .../tst_ansiescapecodehandler.cpp | 49 +++++++++++ 3 files changed, 101 insertions(+), 32 deletions(-) diff --git a/src/libs/utils/ansiescapecodehandler.cpp b/src/libs/utils/ansiescapecodehandler.cpp index bc7e6dcb1a4..d956c90f416 100644 --- a/src/libs/utils/ansiescapecodehandler.cpp +++ b/src/libs/utils/ansiescapecodehandler.cpp @@ -86,53 +86,83 @@ QList AnsiEscapeCodeHandler::parseText(const FormattedText &input DefaultBackgroundColor = 49 }; - QList outputData; - - QTextCharFormat charFormat = m_previousFormatClosed ? input.format : m_previousFormat; - const QString escape = QLatin1String("\x1b["); - const int escapePos = input.text.indexOf(escape); - if (escapePos < 0) { - outputData << FormattedText(input.text, charFormat); - return outputData; - } else if (escapePos != 0) { - outputData << FormattedText(input.text.left(escapePos), charFormat); - } - const QChar semicolon = QLatin1Char(';'); const QChar colorTerminator = QLatin1Char('m'); const QChar eraseToEol = QLatin1Char('K'); - // strippedText always starts with "\e[" - QString strippedText = input.text.mid(escapePos); + + QList outputData; + QTextCharFormat charFormat = m_previousFormatClosed ? input.format : m_previousFormat; + QString strippedText; + if (m_pendingText.isEmpty()) { + strippedText = input.text; + } else { + strippedText = m_pendingText.append(input.text); + m_pendingText.clear(); + } + while (!strippedText.isEmpty()) { - while (strippedText.startsWith(escape)) { - strippedText.remove(0, 2); + QTC_ASSERT(m_pendingText.isEmpty(), break); + const int escapePos = strippedText.indexOf(escape[0]); + if (escapePos < 0) { + outputData << FormattedText(strippedText, charFormat); + break; + } else if (escapePos != 0) { + outputData << FormattedText(strippedText.left(escapePos), charFormat); + strippedText.remove(0, escapePos); + } + QTC_ASSERT(strippedText[0] == escape[0], break); + + while (!strippedText.isEmpty() && escape[0] == strippedText[0]) { + if (escape.startsWith(strippedText)) { + // control secquence is not complete + m_pendingText += strippedText; + strippedText.clear(); + break; + } + if (!strippedText.startsWith(escape)) { + // not a control sequence + m_pendingText.clear(); + outputData << FormattedText(strippedText.left(1), charFormat); + strippedText.remove(0, 1); + continue; + } + m_pendingText += strippedText.mid(0, escape.length()); + strippedText.remove(0, escape.length()); // \e[K is not supported. Just strip it. if (strippedText.startsWith(eraseToEol)) { + m_pendingText.clear(); strippedText.remove(0, 1); continue; } // get the number QString strNumber; QStringList numbers; - while (strippedText.at(0).isDigit() || strippedText.at(0) == semicolon) { + while (!strippedText.isEmpty()) { if (strippedText.at(0).isDigit()) { strNumber += strippedText.at(0); } else { - numbers << strNumber; + if (!strNumber.isEmpty()) + numbers << strNumber; + if (strNumber.isEmpty() || strippedText.at(0) != semicolon) + break; strNumber.clear(); } + m_pendingText += strippedText.mid(0, 1); strippedText.remove(0, 1); } - if (!strNumber.isEmpty()) - numbers << strNumber; + if (strippedText.isEmpty()) + break; // remove terminating char if (!strippedText.startsWith(colorTerminator)) { + m_pendingText.clear(); strippedText.remove(0, 1); - continue; + break; } + // got consistent control sequence, ok to clear pending text + m_pendingText.clear(); strippedText.remove(0, 1); if (numbers.isEmpty()) { @@ -224,17 +254,6 @@ QList AnsiEscapeCodeHandler::parseText(const FormattedText &input } } } - - if (strippedText.isEmpty()) - break; - int index = strippedText.indexOf(escape); - if (index > 0) { - outputData << FormattedText(strippedText.left(index), charFormat); - strippedText.remove(0, index); - } else if (index == -1) { - outputData << FormattedText(strippedText, charFormat); - break; - } } return outputData; } diff --git a/src/libs/utils/ansiescapecodehandler.h b/src/libs/utils/ansiescapecodehandler.h index f1f75817859..34d7593f060 100644 --- a/src/libs/utils/ansiescapecodehandler.h +++ b/src/libs/utils/ansiescapecodehandler.h @@ -62,6 +62,7 @@ private: bool m_previousFormatClosed; QTextCharFormat m_previousFormat; + QString m_pendingText; }; } // namespace Utils diff --git a/tests/auto/utils/ansiescapecodehandler/tst_ansiescapecodehandler.cpp b/tests/auto/utils/ansiescapecodehandler/tst_ansiescapecodehandler.cpp index 16675bb885b..9825758cfed 100644 --- a/tests/auto/utils/ansiescapecodehandler/tst_ansiescapecodehandler.cpp +++ b/tests/auto/utils/ansiescapecodehandler/tst_ansiescapecodehandler.cpp @@ -57,6 +57,7 @@ private Q_SLOTS: void testSimpleFormat(); void testSimpleFormat_data(); void testLineOverlappingFormat(); + void testSplitControlSequence(); private: const QString red; @@ -225,6 +226,31 @@ void tst_AnsiEscapeCodeHandler::testSimpleFormat_data() << (FormattedTextList() << FormattedText("All text after this is ", defaultFormat) << FormattedText("not deleted", defaultFormat)); + + QTest::newRow("Unfinished control sequence \\x1b") + << QString("A text before \x1b") << QTextCharFormat() + << (FormattedTextList() + << FormattedText("A text before ", defaultFormat)); + + QTest::newRow("Unfinished control sequence \\x1b[") + << QString("A text before \x1b[") << QTextCharFormat() + << (FormattedTextList() + << FormattedText("A text before ", defaultFormat)); + + QTest::newRow("Unfinished control sequence \\x1b[3") + << QString("A text before \x1b[3") << QTextCharFormat() + << (FormattedTextList() + << FormattedText("A text before ", defaultFormat)); + + QTest::newRow("Unfinished control sequence \\x1b[31") + << QString("A text before \x1b[31") << QTextCharFormat() + << (FormattedTextList() + << FormattedText("A text before ", defaultFormat)); + + QTest::newRow("Unfinished control sequence \\x1b[31,") + << QString("A text before \x1b[31,") << QTextCharFormat() + << (FormattedTextList() + << FormattedText("A text before ", defaultFormat)); } void tst_AnsiEscapeCodeHandler::testLineOverlappingFormat() @@ -254,6 +280,29 @@ void tst_AnsiEscapeCodeHandler::testLineOverlappingFormat() QCOMPARE(result[3].format, defaultFormat); } +void tst_AnsiEscapeCodeHandler::testSplitControlSequence() +{ + // Test line-overlapping formats + const QString line1 = "Normal line \x1b"; + const QString line2 = "[1m bold line"; + + QTextCharFormat defaultFormat; + + AnsiEscapeCodeHandler handler; + FormattedTextList result; + result.append(handler.parseText(FormattedText(line1, defaultFormat))); + result.append(handler.parseText(FormattedText(line2, defaultFormat))); + + QTextCharFormat boldFormat; + boldFormat.setFontWeight(QFont::Bold); + + QCOMPARE(result.size(), 2); + QCOMPARE(result[0].text, QLatin1String("Normal line ")); + QCOMPARE(result[0].format, defaultFormat); + QCOMPARE(result[1].text, QLatin1String(" bold line")); + QCOMPARE(result[1].format, boldFormat); +} + QTEST_APPLESS_MAIN(tst_AnsiEscapeCodeHandler) #include "tst_ansiescapecodehandler.moc" From e34148ba75e2e6c527f63070bf6846e2b6c02922 Mon Sep 17 00:00:00 2001 From: Robert Loehning Date: Mon, 13 Jul 2015 16:16:18 +0200 Subject: [PATCH 19/70] Squish: Update tst_git_local Change-Id: I26a0e497382a602e99811e77a7f1b5cebc57a946 Reviewed-by: Christian Stenger --- tests/system/suite_tools/tst_git_local/test.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/system/suite_tools/tst_git_local/test.py b/tests/system/suite_tools/tst_git_local/test.py index 121c286b82d..7e6021e8f26 100644 --- a/tests/system/suite_tools/tst_git_local/test.py +++ b/tests/system/suite_tools/tst_git_local/test.py @@ -109,9 +109,11 @@ def __clickCommit__(count): description = waitForObject(":Qt Creator_DiffEditor::Internal::DescriptionEditorWidget") waitFor('len(str(description.plainText)) != 0', 5000) show = str(description.plainText) + id = "Nobody " + time = "\w{3} \w{3} \d{1,2} \d{2}:\d{2}:\d{2} \d{4}.* seconds ago\)" expected = [{"commit %s" % commit:False}, - {"Author: Nobody ": False}, - {"Date:\s+\w{3} \w{3} \d{1,2} \d{2}:\d{2}:\d{2} \d{4}.*":True}] + {"Author: %s, %s" % (id, time): True}, + {"Committer: %s, %s" % (id, time): True}] for line, exp in zip(show.splitlines(), expected): expLine = exp.keys()[0] isRegex = exp.values()[0] From 4816ad212590d15ae32099eaa21975bf61eb214b Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 13 Jul 2015 13:36:28 +0200 Subject: [PATCH 20/70] Debugger: Cache handle->value pair in QmlEngine Needed in preparation to determine the time of a needed watchHandler()->notifyUpdateFinished() deterministically which in turn is needed to get the update cycle of evaluated expressions right. This will also save roundtrips later. Change-Id: Id90101df8f2b0f5e31c6a18af7cac165d060c5fe Reviewed-by: Christian Stenger --- src/plugins/debugger/qml/qmlengine.cpp | 128 +++++++++++++------------ 1 file changed, 65 insertions(+), 63 deletions(-) diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp index 89e3c6c862d..07f8d28ce0f 100644 --- a/src/plugins/debugger/qml/qmlengine.cpp +++ b/src/plugins/debugger/qml/qmlengine.cpp @@ -152,12 +152,12 @@ public: void expandObject(const QByteArray &iname, quint64 objectId); void flushSendBuffer(); - void handleBacktrace(const QVariant &bodyVal, const QVariant &refsVal); - void handleLookup(const QVariant &bodyVal, const QVariant &refsVal); - void handleEvaluate(int sequence, bool success, const QVariant &bodyVal, const QVariant &refsVal); - void handleFrame(const QVariant &bodyVal, const QVariant &refsVal); - void handleScope(const QVariant &bodyVal, const QVariant &refsVal); - StackFrame extractStackFrame(const QVariant &bodyVal, const QVariant &refsVal); + void handleBacktrace(const QVariant &bodyVal); + void handleLookup(const QVariant &bodyVal); + void handleEvaluate(int sequence, bool success, const QVariant &bodyVal); + void handleFrame(const QVariant &bodyVal); + void handleScope(const QVariant &bodyVal); + StackFrame extractStackFrame(const QVariant &bodyVal); bool canEvaluateScript(const QString &script); void updateScriptSource(const QString &fileName, int lineOffset, int columnOffset, const QString &source); @@ -165,7 +165,14 @@ public: void runCommand(const DebuggerCommand &command); void runDirectCommand(const QByteArray &type, const QByteArray &msg = QByteArray()); + void clearRefs() { refVals.clear(); } + void memorizeRefs(const QVariant &refs); + QmlV8ObjectData extractData(const QVariant &data) const; + void insertSubItems(WatchItem *parent, const QVariantList &properties); + ConsoleItem *constructLogItemTree(ConsoleItem *parent, const QmlV8ObjectData &objectData); + public: + QHash refVals; // The mapping of target object handles to retrieved values. int sequence = -1; QmlEngine *engine; QHash breakpoints; @@ -1587,23 +1594,7 @@ void QmlEnginePrivate::setExceptionBreak(Exceptions type, bool enabled) runCommand(cmd); } -QVariant valueFromRef(int handle, const QVariant &refsVal, bool *success) -{ - *success = false; - QVariant variant; - const QVariantList refs = refsVal.toList(); - foreach (const QVariant &ref, refs) { - const QVariantMap refData = ref.toMap(); - if (refData.value(_(HANDLE)).toInt() == handle) { - variant = refData; - *success = true; - break; - } - } - return variant; -} - -QmlV8ObjectData extractData(const QVariant &data, const QVariant &refsVal) +QmlV8ObjectData QmlEnginePrivate::extractData(const QVariant &data) const { // { "handle" : , // "type" : <"undefined", "null", "boolean", "number", "string", "object", "function" or "frame"> @@ -1663,10 +1654,8 @@ QmlV8ObjectData extractData(const QVariant &data, const QVariant &refsVal) if (dataMap.contains(_(REF))) { objectData.handle = dataMap.value(_(REF)).toInt(); - bool success; - QVariant dataFromRef = valueFromRef(objectData.handle, refsVal, &success); - if (success) { - QmlV8ObjectData data = extractData(dataFromRef, refsVal); + if (refVals.contains(objectData.handle)) { + QmlV8ObjectData data = extractData(refVals.value(objectData.handle)); objectData.type = data.type; objectData.value = data.value; objectData.properties = data.properties; @@ -1760,6 +1749,17 @@ void QmlEnginePrivate::expandObject(const QByteArray &iname, quint64 objectId) lookup(QList() << objectId); } +void QmlEnginePrivate::memorizeRefs(const QVariant &refs) +{ + if (refs.isValid()) { + foreach (const QVariant &ref, refs.toList()) { + const QVariantMap refData = ref.toMap(); + int handle = refData.value(_(HANDLE)).toInt(); + refVals[handle] = refData; + } + } +} + void QmlEnginePrivate::messageReceived(const QByteArray &data) { QmlDebugStream ds(data); @@ -1793,6 +1793,8 @@ void QmlEnginePrivate::messageReceived(const QByteArray &data) if (type == _("response")) { + memorizeRefs(resp.value(_(REFS))); + bool success = resp.value(_("success")).toBool(); if (!success) { SDEBUG("Request was unsuccessful"); @@ -1808,21 +1810,21 @@ void QmlEnginePrivate::messageReceived(const QByteArray &data) } else if (debugCommand == _(BACKTRACE)) { if (success) - handleBacktrace(resp.value(_(BODY)), resp.value(_(REFS))); + handleBacktrace(resp.value(_(BODY))); } else if (debugCommand == _(LOOKUP)) { if (success) - handleLookup(resp.value(_(BODY)), resp.value(_(REFS))); + handleLookup(resp.value(_(BODY))); } else if (debugCommand == _(EVALUATE)) { int seq = resp.value(_("request_seq")).toInt(); if (success) { - handleEvaluate(seq, success, resp.value(_(BODY)), resp.value(_(REFS))); + handleEvaluate(seq, success, resp.value(_(BODY))); } else { QVariantMap map; map.insert(_(TYPE), QVariant(_("string"))); map.insert(_(VALUE), resp.value(_("message"))); - handleEvaluate(seq, success, QVariant(map), QVariant()); + handleEvaluate(seq, success, QVariant(map)); } } else if (debugCommand == _(SETBREAKPOINT)) { @@ -1886,11 +1888,11 @@ void QmlEnginePrivate::messageReceived(const QByteArray &data) } else if (debugCommand == _(FRAME)) { if (success) - handleFrame(resp.value(_(BODY)), resp.value(_(REFS))); + handleFrame(resp.value(_(BODY))); } else if (debugCommand == _(SCOPE)) { if (success) - handleScope(resp.value(_(BODY)), resp.value(_(REFS))); + handleScope(resp.value(_(BODY))); } else if (debugCommand == _(SCRIPTS)) { // { "seq" : , @@ -1962,6 +1964,8 @@ void QmlEnginePrivate::messageReceived(const QByteArray &data) const QString eventType(resp.value(_(EVENT)).toString()); if (eventType == _("break")) { + + clearRefs(); const QVariantMap breakData = resp.value(_(BODY)).toMap(); const QString invocationText = breakData.value(_("invocationText")).toString(); const QString scriptUrl = breakData.value(_("script")).toMap().value(_("name")).toString(); @@ -2085,7 +2089,7 @@ void QmlEnginePrivate::messageReceived(const QByteArray &data) map.insert(_(VALUE), resp.value(_("message"))); //Since there is no sequence value, best estimate is //last sequence value - handleEvaluate(sequence, success, QVariant(map), QVariant()); + handleEvaluate(sequence, success, QVariant(map)); } } //EVENT @@ -2096,7 +2100,7 @@ void QmlEnginePrivate::messageReceived(const QByteArray &data) } } -void QmlEnginePrivate::handleBacktrace(const QVariant &bodyVal, const QVariant &refsVal) +void QmlEnginePrivate::handleBacktrace(const QVariant &bodyVal) { // { "seq" : , // "type" : "response", @@ -2123,7 +2127,7 @@ void QmlEnginePrivate::handleBacktrace(const QVariant &bodyVal, const QVariant & int i = 0; stackIndexLookup.clear(); foreach (const QVariant &frame, frames) { - StackFrame stackFrame = extractStackFrame(frame, refsVal); + StackFrame stackFrame = extractStackFrame(frame); if (stackFrame.level < 0) continue; stackIndexLookup.insert(i, stackFrame.level); @@ -2137,10 +2141,10 @@ void QmlEnginePrivate::handleBacktrace(const QVariant &bodyVal, const QVariant & //Update all Locals visible in current scope //Traverse the scope chain and store the local properties //in a list and show them in the Locals Window. - handleFrame(frames.value(0), refsVal); + handleFrame(frames.value(0)); } -StackFrame QmlEnginePrivate::extractStackFrame(const QVariant &bodyVal, const QVariant &refsVal) +StackFrame QmlEnginePrivate::extractStackFrame(const QVariant &bodyVal) { // { "seq" : , // "type" : "response", @@ -2183,17 +2187,17 @@ StackFrame QmlEnginePrivate::extractStackFrame(const QVariant &bodyVal, const QV return stackFrame; } - QmlV8ObjectData objectData = extractData(body.value(_("func")), refsVal); + QmlV8ObjectData objectData = extractData(body.value(_("func"))); QString functionName = objectData.value.toString(); if (functionName.isEmpty()) functionName = tr("Anonymous Function"); stackFrame.function = functionName; - objectData = extractData(body.value(_("script")), refsVal); + objectData = extractData(body.value(_("script"))); stackFrame.file = engine->toFileInProject(objectData.value.toString()); stackFrame.usable = QFileInfo(stackFrame.file).isReadable(); - objectData = extractData(body.value(_("receiver")), refsVal); + objectData = extractData(body.value(_("receiver"))); stackFrame.to = objectData.value.toString(); stackFrame.line = body.value(_("line")).toInt() + 1; @@ -2201,7 +2205,7 @@ StackFrame QmlEnginePrivate::extractStackFrame(const QVariant &bodyVal, const QV return stackFrame; } -void QmlEnginePrivate::handleFrame(const QVariant &bodyVal, const QVariant &refsVal) +void QmlEnginePrivate::handleFrame(const QVariant &bodyVal) { // { "seq" : , // "type" : "response", @@ -2258,7 +2262,7 @@ void QmlEnginePrivate::handleFrame(const QVariant &bodyVal, const QVariant &refs //Set "this" variable { auto item = new WatchItem("local.this", QLatin1String("this")); - QmlV8ObjectData objectData = extractData(currentFrame.value(_("receiver")), refsVal); + QmlV8ObjectData objectData = extractData(currentFrame.value(_("receiver"))); item->id = objectData.handle; item->type = objectData.type; item->value = objectData.value.toString(); @@ -2291,7 +2295,7 @@ void QmlEnginePrivate::handleFrame(const QVariant &bodyVal, const QVariant &refs engine->stackFrameCompleted(); } -void QmlEnginePrivate::handleScope(const QVariant &bodyVal, const QVariant &refsVal) +void QmlEnginePrivate::handleScope(const QVariant &bodyVal) { // { "seq" : , // "type" : "response", @@ -2321,11 +2325,11 @@ void QmlEnginePrivate::handleScope(const QVariant &bodyVal, const QVariant &refs if (bodyMap.value(_("frameIndex")).toInt() != stackHandler->currentIndex()) return; - QmlV8ObjectData objectData = extractData(bodyMap.value(_("object")), refsVal); + QmlV8ObjectData objectData = extractData(bodyMap.value(_("object"))); QList handlesToLookup; foreach (const QVariant &property, objectData.properties) { - QmlV8ObjectData localData = extractData(property, refsVal); + QmlV8ObjectData localData = extractData(property); auto item = new WatchItem; item->exp = localData.name; //Check for v8 specific local data @@ -2354,9 +2358,8 @@ void QmlEnginePrivate::handleScope(const QVariant &bodyVal, const QVariant &refs engine->watchHandler()->notifyUpdateFinished(); } -ConsoleItem *constructLogItemTree(ConsoleItem *parent, - const QmlV8ObjectData &objectData, - const QVariant &refsVal) +ConsoleItem *QmlEnginePrivate::constructLogItemTree(ConsoleItem *parent, + const QmlV8ObjectData &objectData) { bool sorted = boolSetting(SortStructMembers); if (!objectData.value.isValid()) @@ -2373,10 +2376,10 @@ ConsoleItem *constructLogItemTree(ConsoleItem *parent, QSet childrenFetched; foreach (const QVariant &property, objectData.properties) { - const QmlV8ObjectData childObjectData = extractData(property, refsVal); + const QmlV8ObjectData childObjectData = extractData(property); if (childObjectData.handle == objectData.handle) continue; - ConsoleItem *child = constructLogItemTree(item, childObjectData, refsVal); + ConsoleItem *child = constructLogItemTree(item, childObjectData); if (child) { const QString text = child->text(); if (childrenFetched.contains(text)) @@ -2389,11 +2392,11 @@ ConsoleItem *constructLogItemTree(ConsoleItem *parent, return item; } -static void insertSubItems(WatchItem *parent, const QVariantList &properties, const QVariant &refsVal) +void QmlEnginePrivate::insertSubItems(WatchItem *parent, const QVariantList &properties) { QTC_ASSERT(parent, return); foreach (const QVariant &property, properties) { - QmlV8ObjectData propertyData = extractData(property, refsVal); + QmlV8ObjectData propertyData = extractData(property); auto item = new WatchItem; item->name = QString::fromUtf8(propertyData.name); @@ -2418,8 +2421,7 @@ static void insertSubItems(WatchItem *parent, const QVariantList &properties, co } } -void QmlEnginePrivate::handleEvaluate(int sequence, bool success, - const QVariant &bodyVal, const QVariant &refsVal) +void QmlEnginePrivate::handleEvaluate(int sequence, bool success, const QVariant &bodyVal) { // { "seq" : , // "type" : "response", @@ -2443,9 +2445,9 @@ void QmlEnginePrivate::handleEvaluate(int sequence, bool success, } else if (debuggerCommands.contains(sequence)) { updateLocalsAndWatchers.removeOne(sequence); - QmlV8ObjectData body = extractData(bodyVal, refsVal); + QmlV8ObjectData body = extractData(bodyVal); if (auto consoleManager = ConsoleManagerInterface::instance()) { - if (ConsoleItem *item = constructLogItemTree(consoleManager->rootItem(), body, refsVal)) + if (ConsoleItem *item = constructLogItemTree(consoleManager->rootItem(), body)) consoleManager->printToConsolePane(item); } //Update the locals @@ -2453,13 +2455,13 @@ void QmlEnginePrivate::handleEvaluate(int sequence, bool success, scope(index); } else { - QmlV8ObjectData body = extractData(bodyVal, refsVal); + QmlV8ObjectData body = extractData(bodyVal); if (evaluatingExpression.contains(sequence)) { QString exp = evaluatingExpression.take(sequence); //Do we have request to evaluate a local? if (exp.startsWith(QLatin1String("local."))) { WatchItem *item = watchHandler->findItem(exp.toLatin1()); - insertSubItems(item, body.properties, refsVal); + insertSubItems(item, body.properties); } else { QByteArray iname = watchHandler->watcherName(exp.toLatin1()); SDEBUG(QString(iname)); @@ -2476,14 +2478,14 @@ void QmlEnginePrivate::handleEvaluate(int sequence, bool success, item->setError(body.value.toString()); } watchHandler->insertItem(item); - insertSubItems(item, body.properties, refsVal); + insertSubItems(item, body.properties); } //Insert the newly evaluated expression to the Watchers Window } } } -void QmlEnginePrivate::handleLookup(const QVariant &bodyVal, const QVariant &refsVal) +void QmlEnginePrivate::handleLookup(const QVariant &bodyVal) { // { "seq" : , // "type" : "response", @@ -2498,14 +2500,14 @@ void QmlEnginePrivate::handleLookup(const QVariant &bodyVal, const QVariant &ref QStringList handlesList = body.keys(); WatchHandler *watchHandler = engine->watchHandler(); foreach (const QString &handle, handlesList) { - QmlV8ObjectData bodyObjectData = extractData(body.value(handle), refsVal); + QmlV8ObjectData bodyObjectData = extractData(body.value(handle)); QByteArray prepend = localsAndWatchers.take(handle.toInt()); if (prepend.startsWith("local.") || prepend.startsWith("watch.")) { // Data for expanded local/watch. // Could be an object or function. WatchItem *parent = watchHandler->findItem(prepend); - insertSubItems(parent, bodyObjectData.properties, refsVal); + insertSubItems(parent, bodyObjectData.properties); } else { //rest auto item = new WatchItem; From 447f42d0e217f05c5122d3f65e0e5b8f88f55449 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 10 Jul 2015 14:30:04 +0200 Subject: [PATCH 21/70] OS X: There is no qml(1)puppet anymore, so don't try to deploy it Change-Id: Ic3f3150e3295529082ca621ec27792b2d08caed1 Reviewed-by: Alessandro Portale Reviewed-by: Tim Jenssen --- scripts/deployqtHelper_mac.sh | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/scripts/deployqtHelper_mac.sh b/scripts/deployqtHelper_mac.sh index be7929a5ff8..8ac00fbab32 100755 --- a/scripts/deployqtHelper_mac.sh +++ b/scripts/deployqtHelper_mac.sh @@ -82,11 +82,6 @@ fi if [ ! -d "$1/Contents/Frameworks/QtCore.framework" ]; then - qmlpuppetapp="$1/Contents/MacOS/qmlpuppet" - if [ -f "$qmlpuppetapp" ]; then - qmlpuppetArgument="-executable=$qmlpuppetapp" - fi - qml2puppetapp="$1/Contents/MacOS/qml2puppet" if [ -f "$qml2puppetapp" ]; then qml2puppetArgument="-executable=$qml2puppetapp" @@ -111,6 +106,6 @@ if [ ! -d "$1/Contents/Frameworks/QtCore.framework" ]; then "-executable=$qbsapp-setup-android" \ "-executable=$qbsapp-setup-qt" \ "-executable=$qbsapp-setup-toolchains" \ - "$qmlpuppetArgument" "$qml2puppetArgument" "$clangbackendArgument" || exit 1 + "$qml2puppetArgument" "$clangbackendArgument" || exit 1 fi From 231aeafd1d039b3be4c94fbd9a905f1c06f9056b Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 10 Jul 2015 11:28:06 +0200 Subject: [PATCH 22/70] Fix that locator filters weren't accepting column numbers There was some adaption of locator filter code missing in 44e7eca55942589e1cc3da4790bc2e38550f2791 . Also remove some duplication of logic. Change-Id: I0a4b0920ea57472c922f1110b51b7eb8bad509b3 Reviewed-by: hjk --- .../editormanager/editormanager.cpp | 30 +++++++------------ .../coreplugin/editormanager/editormanager.h | 2 +- .../coreplugin/locator/basefilefilter.cpp | 2 +- .../coreplugin/locator/filesystemfilter.cpp | 2 +- .../locator/opendocumentsfilter.cpp | 2 +- 5 files changed, 15 insertions(+), 23 deletions(-) diff --git a/src/plugins/coreplugin/editormanager/editormanager.cpp b/src/plugins/coreplugin/editormanager/editormanager.cpp index 60c51bbc5ac..ed58364530f 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.cpp +++ b/src/plugins/coreplugin/editormanager/editormanager.cpp @@ -180,7 +180,7 @@ void EditorManagerPlaceHolder::currentModeChanged(IMode *mode) static EditorManager *m_instance = 0; static EditorManagerPrivate *d; -static int extractNumericSuffix(QString *fileName) +static int extractNumericSuffix(QString *fileName, QString *postfix = 0) { int i = fileName->length() - 1; for (; i >= 0; --i) { @@ -195,6 +195,8 @@ static int extractNumericSuffix(QString *fileName) const QString suffix = fileName->mid(i + 1); const int result = suffix.toInt(&ok); if (suffix.isEmpty() || ok) { + if (postfix) + *postfix = fileName->mid(i); fileName->truncate(i); return result; } @@ -2552,25 +2554,15 @@ IEditor *EditorManager::openEditorAt(const QString &fileName, int line, int colu fileName, line, column, editorId, flags, newEditor); } -// Extract line number suffix. Return the suffix (e.g. ":132") and truncates the filename accordingly. -QString EditorManager::splitLineNumber(QString *fileName) +// Extract line and column number suffix. Return the suffix (e.g. ":132") and truncates the filename accordingly. +QString EditorManager::splitLineAndColumnNumber(QString *fileName) { - int i = fileName->length() - 1; - for (; i >= 0; --i) { - if (!fileName->at(i).isNumber()) - break; - } - if (i == -1) - return QString(); - const QChar c = fileName->at(i); - if (c == QLatin1Char(':') || c == QLatin1Char('+')) { - const QString result = fileName->mid(i + 1); - bool ok; - result.toInt(&ok); - if (result.isEmpty() || ok) { - fileName->truncate(i); - return QString(c) + result; - } + QString postfix; + if (extractNumericSuffix(fileName, &postfix)) { + QString previousPostfix; + if (extractNumericSuffix(fileName, &previousPostfix)) + postfix.prepend(previousPostfix); + return postfix; } return QString(); } diff --git a/src/plugins/coreplugin/editormanager/editormanager.h b/src/plugins/coreplugin/editormanager/editormanager.h index f475e1e5ddb..b6b97fd35a9 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.h +++ b/src/plugins/coreplugin/editormanager/editormanager.h @@ -109,7 +109,7 @@ public: }; Q_DECLARE_FLAGS(OpenEditorFlags, OpenEditorFlag) - static QString splitLineNumber(QString *fileName); + static QString splitLineAndColumnNumber(QString *fileName); static IEditor *openEditor(const QString &fileName, Id editorId = Id(), OpenEditorFlags flags = NoFlags, bool *newEditor = 0); static IEditor *openEditorAt(const QString &fileName, int line, int column = 0, diff --git a/src/plugins/coreplugin/locator/basefilefilter.cpp b/src/plugins/coreplugin/locator/basefilefilter.cpp index b505ccfaad6..d7519a43f26 100644 --- a/src/plugins/coreplugin/locator/basefilefilter.cpp +++ b/src/plugins/coreplugin/locator/basefilefilter.cpp @@ -103,7 +103,7 @@ QList BaseFileFilter::matchesFor(QFutureInterface betterEntries; QList goodEntries; QString needle = trimWildcards(QDir::fromNativeSeparators(origEntry)); - const QString lineNoSuffix = EditorManager::splitLineNumber(&needle); + const QString lineNoSuffix = EditorManager::splitLineAndColumnNumber(&needle); QStringMatcher matcher(needle, Qt::CaseInsensitive); const QChar asterisk = QLatin1Char('*'); QRegExp regexp(asterisk + needle+ asterisk, Qt::CaseInsensitive, QRegExp::Wildcard); diff --git a/src/plugins/coreplugin/locator/filesystemfilter.cpp b/src/plugins/coreplugin/locator/filesystemfilter.cpp index 22144f51a18..df9df7ffb10 100644 --- a/src/plugins/coreplugin/locator/filesystemfilter.cpp +++ b/src/plugins/coreplugin/locator/filesystemfilter.cpp @@ -119,7 +119,7 @@ QList FileSystemFilter::matchesFor(QFutureInterface OpenDocumentsFilter::matchesFor(QFutureInterface goodEntries; QList betterEntries; QString entry = entry_; - const QString lineNoSuffix = EditorManager::splitLineNumber(&entry); + const QString lineNoSuffix = EditorManager::splitLineAndColumnNumber(&entry); const QChar asterisk = QLatin1Char('*'); QString pattern = QString(asterisk); pattern += entry; From 83d1aa0d7220720c28b83c2d6932959cb33ca3a8 Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Tue, 14 Jul 2015 10:15:52 +0200 Subject: [PATCH 23/70] Clang: Avoid heap-use-after-free in IpcCommunicator ...on shutdown. Now the slot will be disconnected on destruction. Change-Id: Ie511bf5400c41eee3245879ea355293e7bb5c7cd Reviewed-by: Marco Bubke --- .../clangcodemodel/clangbackendipcintegration.cpp | 11 +++++++---- .../clangcodemodel/clangbackendipcintegration.h | 1 + 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/plugins/clangcodemodel/clangbackendipcintegration.cpp b/src/plugins/clangcodemodel/clangbackendipcintegration.cpp index 4c41104f467..8100b9cf4a5 100644 --- a/src/plugins/clangcodemodel/clangbackendipcintegration.cpp +++ b/src/plugins/clangcodemodel/clangbackendipcintegration.cpp @@ -223,10 +223,8 @@ IpcCommunicator::IpcCommunicator() connect(Core::EditorManager::instance(), &Core::EditorManager::editorAboutToClose, this, &IpcCommunicator::onEditorAboutToClose); - - connect(Core::ICore::instance(), &Core::ICore::coreAboutToClose, [this]() { - m_sendMode = IgnoreSendRequests; - }); + connect(Core::ICore::instance(), &Core::ICore::coreAboutToClose, + this, &IpcCommunicator::onCoreAboutToClose); initializeBackend(); } @@ -376,6 +374,11 @@ void IpcCommunicator::onEditorAboutToClose(Core::IEditor *editor) m_ipcReceiver.deleteProcessorsOfEditorWidget(textEditor->editorWidget()); } +void IpcCommunicator::onCoreAboutToClose() +{ + m_sendMode = IgnoreSendRequests; +} + void IpcCommunicator::initializeBackendWithCurrentData() { registerEmptyProjectForProjectLessFiles(); diff --git a/src/plugins/clangcodemodel/clangbackendipcintegration.h b/src/plugins/clangcodemodel/clangbackendipcintegration.h index 365654fd921..4a4ca40ab0f 100644 --- a/src/plugins/clangcodemodel/clangbackendipcintegration.h +++ b/src/plugins/clangcodemodel/clangbackendipcintegration.h @@ -143,6 +143,7 @@ private: void onBackendRestarted(); void onEditorAboutToClose(Core::IEditor *editor); + void onCoreAboutToClose(); IpcReceiver m_ipcReceiver; ClangBackEnd::ConnectionClient m_connection; From 6dfd03596f0962315a806448a1c922dc0759b25e Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Tue, 14 Jul 2015 12:06:07 +0200 Subject: [PATCH 24/70] QmlDesigner.QmlPuppet: Fix compile for Qt 5.6 Change-Id: I231bcf61e813db14c0958565cf76dd4df56b4e99 Reviewed-by: Tim Jenssen --- .../qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp | 2 +- .../instances/qt5informationnodeinstanceserver.cpp | 2 +- .../qml2puppet/instances/qt5nodeinstanceclientproxy.cpp | 2 +- .../qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp | 2 +- .../qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.h | 2 +- .../qml2puppet/instances/qt5previewnodeinstanceserver.cpp | 2 +- .../qml2puppet/instances/qt5rendernodeinstanceserver.cpp | 2 +- .../qml2puppet/instances/qt5testnodeinstanceserver.cpp | 2 +- .../qmlpuppet/qml2puppet/instances/quickitemnodeinstance.h | 2 +- .../qml/qmlpuppet/qmlprivategate/designersupportdelegate.h | 5 +++++ .../qml/qmlpuppet/qmlprivategate/qmlprivategate.cpp | 2 +- 11 files changed, 15 insertions(+), 10 deletions(-) create mode 100644 share/qtcreator/qml/qmlpuppet/qmlprivategate/designersupportdelegate.h diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp index ac193363dbb..27b5a1b0b23 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp @@ -83,7 +83,7 @@ #include #include -#include +#include namespace { diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp index b548668a16f..3b2d2a0f6c3 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp @@ -63,7 +63,7 @@ #include "dummycontextobject.h" -#include +#include namespace QmlDesigner { diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceclientproxy.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceclientproxy.cpp index e7547e49489..8f535c89003 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceclientproxy.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceclientproxy.cpp @@ -37,7 +37,7 @@ #include "qt5rendernodeinstanceserver.h" #include "qt5testnodeinstanceserver.h" -#include +#include #if defined(Q_OS_UNIX) #include diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp index 20bc738a3d0..85533d6e9f3 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp @@ -34,7 +34,7 @@ #include #include -#include +#include #include #include #include diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.h index b6836404aa3..0aa0dcc3395 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.h @@ -34,7 +34,7 @@ #include #include "nodeinstanceserver.h" -#include "designersupport.h" +#include QT_BEGIN_NAMESPACE class QQuickItem; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5previewnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5previewnodeinstanceserver.cpp index e9f587b7efd..b550e61a12d 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5previewnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5previewnodeinstanceserver.cpp @@ -36,7 +36,7 @@ #include "removesharedmemorycommand.h" #include #include -#include +#include namespace QmlDesigner { diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5rendernodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5rendernodeinstanceserver.cpp index 98efd1f0576..6a53f4d9e9c 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5rendernodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5rendernodeinstanceserver.cpp @@ -63,7 +63,7 @@ #include "dummycontextobject.h" -#include +#include namespace QmlDesigner { diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5testnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5testnodeinstanceserver.cpp index 063fb9c2876..d80abae6fb8 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5testnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5testnodeinstanceserver.cpp @@ -65,7 +65,7 @@ #include "dummycontextobject.h" -#include +#include namespace QmlDesigner { diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.h index 22d2d06e8e4..4c96c18be0e 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.h @@ -36,7 +36,7 @@ #include "objectnodeinstance.h" #include -#include +#include namespace QmlDesigner { namespace Internal { diff --git a/share/qtcreator/qml/qmlpuppet/qmlprivategate/designersupportdelegate.h b/share/qtcreator/qml/qmlpuppet/qmlprivategate/designersupportdelegate.h new file mode 100644 index 00000000000..05ed2ec5b76 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/qmlprivategate/designersupportdelegate.h @@ -0,0 +1,5 @@ +#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) +#include +#else +#include +#endif diff --git a/share/qtcreator/qml/qmlpuppet/qmlprivategate/qmlprivategate.cpp b/share/qtcreator/qml/qmlpuppet/qmlprivategate/qmlprivategate.cpp index 2ed682ae986..5c972767f95 100644 --- a/share/qtcreator/qml/qmlpuppet/qmlprivategate/qmlprivategate.cpp +++ b/share/qtcreator/qml/qmlpuppet/qmlprivategate/qmlprivategate.cpp @@ -57,7 +57,7 @@ #include -#include +#include namespace QmlDesigner { From b2ba98d988eba49470bc13d47fd189ec6ddaea7a Mon Sep 17 00:00:00 2001 From: Robert Loehning Date: Mon, 13 Jul 2015 17:07:39 +0200 Subject: [PATCH 25/70] Squish: Remove BlackBerry Change-Id: If79d09f44f682e8fa7ee7b71e265696ecc998337 Reviewed-by: Christian Stenger --- tests/system/shared/project.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/system/shared/project.py b/tests/system/shared/project.py index 7df1631dd78..b782607fffb 100644 --- a/tests/system/shared/project.py +++ b/tests/system/shared/project.py @@ -634,7 +634,7 @@ def __getSupportedPlatforms__(text, templateName, getAsStrings=False): result.extend([Targets.DESKTOP_521_DEFAULT, Targets.DESKTOP_531_DEFAULT]) if platform.system() != 'Darwin': result.append(Targets.DESKTOP_541_GCC) - if not ("BlackBerry" in templateName or re.search("custom Qt Creator plugin", text)) and (version == None or version < "5.0"): + if not templateName == "Qt Creator Plugin" and (version == None or version < "5.0"): result.append(Targets.SIMULATOR) elif 'Platform independent' in text: result = list(Targets.ALL_TARGETS) From f1af0c4f39e8af7f76c7a343dede38c1854227bb Mon Sep 17 00:00:00 2001 From: Robert Loehning Date: Tue, 14 Jul 2015 12:43:40 +0200 Subject: [PATCH 26/70] Squish: Tiny update to tst_cli_output_console Change-Id: I26409008831afb70031591a599e0fa3d47d05f38 Reviewed-by: Christian Stenger --- tests/system/suite_debugger/tst_cli_output_console/test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/system/suite_debugger/tst_cli_output_console/test.py b/tests/system/suite_debugger/tst_cli_output_console/test.py index 24671749844..4a1386d089b 100644 --- a/tests/system/suite_debugger/tst_cli_output_console/test.py +++ b/tests/system/suite_debugger/tst_cli_output_console/test.py @@ -57,7 +57,7 @@ def main(): invokeMenuItem("File", "Save All") openDocument(project + "." + project + "\\.pro") proEditor = waitForObject(":Qt Creator_TextEditor::TextEditorWidget") - test.verify("CONFIG += console" in str(proEditor.plainText), "Verifying that program is configured with console") + test.verify("CONFIG += console" in str(proEditor.plainText), "Verifying that program is configured with console") availableConfigs = iterateBuildConfigs(len(checkedTargets)) if not availableConfigs: From 029b83b8dc1c9aa269f85d4909b5e88a604ee730 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 25 Jun 2015 16:06:48 +0200 Subject: [PATCH 27/70] Squish: Fix suite_general Change-Id: I4e1458555a971d21e42a071e2fc0b135b0b1e91c Reviewed-by: Robert Loehning --- tests/system/shared/project.py | 2 +- tests/system/shared/utils.py | 2 +- .../tst_create_proj_wizard/test.py | 83 ++++++++++++++----- .../tst_save_before_build/test.py | 2 +- 4 files changed, 66 insertions(+), 23 deletions(-) diff --git a/tests/system/shared/project.py b/tests/system/shared/project.py index b782607fffb..951ed4645bd 100644 --- a/tests/system/shared/project.py +++ b/tests/system/shared/project.py @@ -644,7 +644,7 @@ def __getSupportedPlatforms__(text, templateName, getAsStrings=False): else: test.warning("Returning None (__getSupportedPlatforms__())", "Parsed text: '%s'" % text) - return None, None + return [], None if getAsStrings: result = Targets.getTargetsAsStrings(result) return result, version diff --git a/tests/system/shared/utils.py b/tests/system/shared/utils.py index 08e36005031..1cd77662b95 100644 --- a/tests/system/shared/utils.py +++ b/tests/system/shared/utils.py @@ -380,7 +380,7 @@ def getConfiguredKits(): iterateKits(True, True, __setQtVersionForKit__, kitsWithQtVersionName) # merge defined target names with their configured Qt versions and devices for kit, qtVersion in kitsWithQtVersionName.iteritems(): - if kit in ('Fremantle', 'Harmattan'): + if kit in ('Fremantle', 'Harmattan', 'Qt Simulator'): test.verify(qtVersion == 'None', "The outdated kit '%s' should not have a Qt version" % kit) elif qtVersion in qtVersionNames: diff --git a/tests/system/suite_general/tst_create_proj_wizard/test.py b/tests/system/suite_general/tst_create_proj_wizard/test.py index 8d0de10b226..da9fa6d4b29 100644 --- a/tests/system/suite_general/tst_create_proj_wizard/test.py +++ b/tests/system/suite_general/tst_create_proj_wizard/test.py @@ -30,12 +30,17 @@ source("../../shared/qtcreator.py") -import re - def main(): global tmpSettingsDir - quickCombinations = ["1.1", "2.1", "2.2", "2.3", "2.4", - "Controls 1.0", "Controls 1.1", "Controls 1.2", "Controls 1.3"] + qtVersionsForQuick = ["5.3"] + availableBuildSystems = ["qmake", "Qbs"] + if platform.system() != 'Darwin': + qtVersionsForQuick.append("5.4") + if which("cmake"): + availableBuildSystems.append("CMake") + else: + test.warning("Could not find cmake in PATH - several tests won't run without.") + startApplication("qtcreator" + SettingsPath) if not startedWithoutPluginError(): return @@ -50,8 +55,11 @@ def main(): comboBox = findObject(":New.comboBox_QComboBox") targets = zip(*kits.values())[0] test.verify(comboBox.enabled, "Verifying whether combobox is enabled.") - test.compare(comboBox.currentText, "Desktop Templates") - selectFromCombo(comboBox, "All Templates") + test.compare(comboBox.currentText, "All Templates") + try: + selectFromCombo(comboBox, "All Templates") + except: + test.warning("Could not explicitly select 'All Templates' from combobox.") for category in [item.replace(".", "\\.") for item in dumpItems(catModel, projects)]: # skip non-configurable if "Import" in category: @@ -62,27 +70,39 @@ def main(): for template in dumpItems(templatesView.model(), templatesView.rootIndex()): template = template.replace(".", "\\.") # skip non-configurable - if (template != "Qt Quick UI" and "(CMake Build)" not in template - and "(Qbs Build)" not in template): + if not template in ["Qt Quick UI", "Qt Quick Controls UI", "Qt Canvas 3D Application"]: availableProjectTypes.append({category:template}) - clickButton(waitForObject("{text='Cancel' type='QPushButton' unnamed='1' visible='1'}")) + safeClickButton("Cancel") for current in availableProjectTypes: category = current.keys()[0] template = current.values()[0] displayedPlatforms = __createProject__(category, template) - if template == "Qt Quick Application": - for counter, qComb in enumerate(quickCombinations): - requiredQtVersion = __createProjectHandleQtQuickSelection__(qComb) + if template == "Qt Quick Application" or template == "Qt Quick Controls Application": + for counter, qtVersion in enumerate(qtVersionsForQuick): + requiredQtVersion = __createProjectHandleQtQuickSelection__(qtVersion) __modifyAvailableTargets__(displayedPlatforms, requiredQtVersion, True) verifyKitCheckboxes(kits, displayedPlatforms) # FIXME: if QTBUG-35203 is fixed replace by triggering the shortcut for Back - clickButton(waitForObject("{type='QPushButton' text='Cancel' visible='1'}")) + safeClickButton("Cancel") # are there more Quick combinations - then recreate this project - if counter < len(quickCombinations) - 1: + if counter < len(qtVersionsForQuick) - 1: displayedPlatforms = __createProject__(category, template) continue + elif template.startswith("Plain C"): + for counter, buildSystem in enumerate(availableBuildSystems): + combo = "{name='BuildSystem' type='Utils::TextFieldComboBox' visible='1'}" + selectFromCombo(combo, buildSystem) + clickButton(waitForObject(":Next_QPushButton")) + verifyKitCheckboxes(kits, displayedPlatforms) + # FIXME: if QTBUG-35203 is fixed replace by triggering the shortcut for Back + safeClickButton("Cancel") + if counter < len(availableBuildSystems) - 1: + displayedPlatforms = __createProject__(category, template) + continue + verifyKitCheckboxes(kits, displayedPlatforms) - clickButton(waitForObject("{type='QPushButton' text='Cancel' visible='1'}")) + safeClickButton("Cancel") + invokeMenuItem("File", "Exit") def verifyKitCheckboxes(kits, displayedPlatforms): @@ -106,18 +126,41 @@ def verifyKitCheckboxes(kits, displayedPlatforms): % str(availableCheckboxes)) def __createProject__(category, template): + def safeGetTextBrowserText(): + try: + return str(waitForObject(":frame.templateDescription_QTextBrowser", 500).plainText) + except: + return "" + invokeMenuItem("File", "New File or Project...") selectFromCombo(waitForObject(":New.comboBox_QComboBox"), "All Templates") categoriesView = waitForObject(":New.templateCategoryView_QTreeView") clickItem(categoriesView, "Projects." + category, 5, 5, 0, Qt.LeftButton) templatesView = waitForObject("{name='templatesView' type='QListView' visible='1'}") + test.log("Verifying '%s' -> '%s'" % (category.replace("\\.", "."), template.replace("\\.", "."))) - textBrowser = findObject(":frame.templateDescription_QTextBrowser") - origTxt = str(textBrowser.plainText) + origTxt = safeGetTextBrowserText() clickItem(templatesView, template, 5, 5, 0, Qt.LeftButton) - waitFor("origTxt != str(textBrowser.plainText)", 2000) - displayedPlatforms = __getSupportedPlatforms__(str(textBrowser.plainText), template, True)[0] - clickButton(waitForObject("{text='Choose...' type='QPushButton' unnamed='1' visible='1'}")) + waitFor("origTxt != safeGetTextBrowserText() != ''", 2000) + displayedPlatforms = __getSupportedPlatforms__(safeGetTextBrowserText(), template, True)[0] + safeClickButton("Choose...") # don't check because project could exist __createProjectSetNameAndPath__(os.path.expanduser("~"), 'untitled', False) return displayedPlatforms + +def safeClickButton(buttonLabel): + buttonString = "{type='QPushButton' text='%s' visible='1' unnamed='1'}" + for _ in range(5): + try: + clickButton(buttonString % buttonLabel) + return + except: + if buttonLabel == "Cancel": + try: + clickButton("{name='qt_wizard_cancel' type='QPushButton' text='Cancel' " + "visible='1'}") + return + except: + pass + snooze(1) + test.fatal("Even safeClickButton failed...") diff --git a/tests/system/suite_general/tst_save_before_build/test.py b/tests/system/suite_general/tst_save_before_build/test.py index 4b4bb3a7e80..4601b4a6518 100644 --- a/tests/system/suite_general/tst_save_before_build/test.py +++ b/tests/system/suite_general/tst_save_before_build/test.py @@ -48,7 +48,7 @@ def main(): return ensureSaveBeforeBuildChecked(False) # create qt quick application - createNewQtQuickApplication(tempDir(), "SampleApp", qtQuickVersion="2.2") + createNewQtQuickApplication(tempDir(), "SampleApp") for expectDialog in [True, False]: files = ["SampleApp.SampleApp\\.pro", "SampleApp.deployment.deployment\\.pri", From 6f38873a3c768d14b26c834ae0d73eb9c7981fec Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 14 Jul 2015 12:39:53 +0200 Subject: [PATCH 28/70] Debugger: Fix compiler warning Losing precision in case of 64 bit ints is ok in readNumericVectorHelper, as the result is only used to plot data. Change-Id: I7f0e4c332ee8302b0bb774a7eca2ff5823c37eac Reviewed-by: Kai Koehne --- src/plugins/debugger/watchdata.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/plugins/debugger/watchdata.cpp b/src/plugins/debugger/watchdata.cpp index 9f33111cd8a..265d0bbc1be 100644 --- a/src/plugins/debugger/watchdata.cpp +++ b/src/plugins/debugger/watchdata.cpp @@ -645,7 +645,12 @@ template void readNumericVectorHelper(std::vector *v, const QByteArray &ba) { const T *p = (const T *) ba.data(); - std::copy(p, p + ba.size() / sizeof(T), std::back_insert_iterator >(*v)); + const int n = ba.size() / sizeof(T); + v->resize(n); + // Losing precision in case of 64 bit ints is ok here, as the result + // is only used to plot data. + for (int i = 0; i != n; ++i) + (*v)[i] = static_cast(p[i]); } void readNumericVector(std::vector *v, const QByteArray &rawData, DebuggerEncoding encoding) From 967aad78de6c91b66546aa95b1768262b96d21d1 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 13 Jul 2015 13:36:28 +0200 Subject: [PATCH 29/70] Debugger: Store parsed data in QmlEngine's refVals cache No need to re-do it each time the reference is used. Change-Id: Ie90101df8f2b0f5e31c6a18af7cac165d060c5fe Reviewed-by: Christian Stenger --- src/plugins/debugger/qml/qmlengine.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp index 07f8d28ce0f..388b484a4be 100644 --- a/src/plugins/debugger/qml/qmlengine.cpp +++ b/src/plugins/debugger/qml/qmlengine.cpp @@ -172,7 +172,7 @@ public: ConsoleItem *constructLogItemTree(ConsoleItem *parent, const QmlV8ObjectData &objectData); public: - QHash refVals; // The mapping of target object handles to retrieved values. + QHash refVals; // The mapping of target object handles to retrieved values. int sequence = -1; QmlEngine *engine; QHash breakpoints; @@ -1655,7 +1655,7 @@ QmlV8ObjectData QmlEnginePrivate::extractData(const QVariant &data) const if (dataMap.contains(_(REF))) { objectData.handle = dataMap.value(_(REF)).toInt(); if (refVals.contains(objectData.handle)) { - QmlV8ObjectData data = extractData(refVals.value(objectData.handle)); + QmlV8ObjectData data = refVals.value(objectData.handle); objectData.type = data.type; objectData.value = data.value; objectData.properties = data.properties; @@ -1755,7 +1755,7 @@ void QmlEnginePrivate::memorizeRefs(const QVariant &refs) foreach (const QVariant &ref, refs.toList()) { const QVariantMap refData = ref.toMap(); int handle = refData.value(_(HANDLE)).toInt(); - refVals[handle] = refData; + refVals[handle] = extractData(refData); } } } From 945c0fbc71d2b36d54340970b3197b0543806a51 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Tue, 14 Jul 2015 16:08:14 +0200 Subject: [PATCH 30/70] Clang: Add code completion for keyword snippets from clang Change-Id: I91f7af74d811769424928bce1c586a30b5794d6f Reviewed-by: Nikolai Kosjar --- .../clangassistproposalitem.cpp | 43 ++++- .../clangcompletionassistprocessor.cpp | 14 +- .../clangcodemodel/clangfunctionhintmodel.cpp | 2 +- .../completionchunkstotextconverter.cpp | 150 +++++++++++++++++- .../completionchunkstotextconverter.h | 30 +++- .../completionchunkstotextconvertertest.cpp | 101 +++++++++++- 6 files changed, 323 insertions(+), 17 deletions(-) diff --git a/src/plugins/clangcodemodel/clangassistproposalitem.cpp b/src/plugins/clangcodemodel/clangassistproposalitem.cpp index 697e5453bb6..41cb7702075 100644 --- a/src/plugins/clangcodemodel/clangassistproposalitem.cpp +++ b/src/plugins/clangcodemodel/clangassistproposalitem.cpp @@ -30,10 +30,13 @@ #include "clangassistproposalitem.h" +#include "completionchunkstotextconverter.h" + #include #include #include +#include #include #include @@ -64,6 +67,21 @@ bool ClangAssistProposalItem::prematurelyApplies(const QChar &typedChar) const return applies; } +static bool hasOnlyBlanksBeforeCursorInLine(QTextCursor textCursor) +{ + textCursor.movePosition(QTextCursor::StartOfLine, QTextCursor::KeepAnchor); + + const auto textBeforeCursor = textCursor.selectedText(); + + const auto nonSpace = std::find_if(textBeforeCursor.cbegin(), + textBeforeCursor.cend(), + [] (const QChar &signBeforeCursor) { + return !signBeforeCursor.isSpace(); + }); + + return nonSpace == textBeforeCursor.cend(); +} + void ClangAssistProposalItem::applyContextualContent(TextEditor::TextEditorWidget *editorWidget, int basePosition) const { @@ -86,6 +104,17 @@ void ClangAssistProposalItem::applyContextualContent(TextEditor::TextEditorWidge if (m_typedChar == QLatin1Char('/')) // Eat the slash m_typedChar = QChar(); } + } else if (ccr.completionKind() == CodeCompletion::KeywordCompletionKind) { + CompletionChunksToTextConverter converter; + converter.setAddPlaceHolderPositions(true); + converter.setAddSpaces(true); + converter.setAddExtraVerticalSpaceBetweenBraces(true); + + converter.parseChunks(ccr.chunks()); + + toInsert = converter.text(); + if (converter.hasPlaceholderPositions()) + cursorOffset = converter.placeholderPositions().at(0) - converter.text().size(); } else if (!ccr.text().isEmpty()) { const TextEditor::CompletionSettings &completionSettings = TextEditor::TextEditorSettings::instance()->completionSettings(); @@ -165,7 +194,7 @@ void ClangAssistProposalItem::applyContextualContent(TextEditor::TextEditorWidge const int endsPosition = editorWidget->position(TextEditor::EndOfLinePosition); const QString existingText = editorWidget->textAt(editorWidget->position(), endsPosition - editorWidget->position()); int existLength = 0; - if (!existingText.isEmpty()) { + if (!existingText.isEmpty() && ccr.completionKind() != CodeCompletion::KeywordCompletionKind) { // Calculate the exist length in front of the extra chars existLength = toInsert.length() - (editorWidget->position() - basePosition); while (!existingText.startsWith(toInsert.right(existLength))) { @@ -189,6 +218,18 @@ void ClangAssistProposalItem::applyContextualContent(TextEditor::TextEditorWidge editorWidget->replace(length, toInsert); if (cursorOffset) editorWidget->setCursorPosition(editorWidget->position() + cursorOffset); + + // indent the statement + if (ccr.completionKind() == CodeCompletion::KeywordCompletionKind) { + auto selectionCursor = editorWidget->textCursor(); + selectionCursor.setPosition(basePosition); + selectionCursor.setPosition(basePosition + toInsert.size(), QTextCursor::KeepAnchor); + + auto basePositionCursor = editorWidget->textCursor(); + basePositionCursor.setPosition(basePosition); + if (hasOnlyBlanksBeforeCursorInLine(basePositionCursor)) + editorWidget->textDocument()->autoIndent(selectionCursor); + } } void ClangAssistProposalItem::keepCompletionOperator(unsigned compOp) diff --git a/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp b/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp index 1062a3726b8..61c893601eb 100644 --- a/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp +++ b/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp @@ -37,6 +37,7 @@ #include "clangcompletioncontextanalyzer.h" #include "clangfunctionhintmodel.h" #include "clangutils.h" +#include "completionchunkstotextconverter.h" #include @@ -86,14 +87,19 @@ QList toAssistProposalItems(const CodeCompletions &complet if (slotCompletion && ccr.completionKind() != CodeCompletion::SlotCompletionKind) continue; - const QString txt(ccr.text().toString()); - ClangAssistProposalItem *item = items.value(txt, 0); + QString name; + if (ccr.completionKind() == CodeCompletion::KeywordCompletionKind) + name = CompletionChunksToTextConverter::convertToName(ccr.chunks()); + else + name = ccr.text().toString(); + + ClangAssistProposalItem *item = items.value(name, 0); if (item) { item->addOverload(ccr); } else { item = new ClangAssistProposalItem; - items.insert(txt, item); - item->setText(txt); + items.insert(name, item); + item->setText(name); item->setDetail(ccr.hint().toString()); item->setOrder(ccr.priority()); diff --git a/src/plugins/clangcodemodel/clangfunctionhintmodel.cpp b/src/plugins/clangcodemodel/clangfunctionhintmodel.cpp index 67e8048ee46..f950947448e 100644 --- a/src/plugins/clangcodemodel/clangfunctionhintmodel.cpp +++ b/src/plugins/clangcodemodel/clangfunctionhintmodel.cpp @@ -76,7 +76,7 @@ QString ClangFunctionHintModel::text(int index) const hintText += prettyMethod.mid(end).toHtmlEscaped()); return hintText; #endif - return CompletionChunksToTextConverter::convert(m_functionSymbols.at(index).chunks()); + return CompletionChunksToTextConverter::convertToFunctionSignature(m_functionSymbols.at(index).chunks()); } int ClangFunctionHintModel::activeArgument(const QString &prefix) const diff --git a/src/plugins/clangcodemodel/completionchunkstotextconverter.cpp b/src/plugins/clangcodemodel/completionchunkstotextconverter.cpp index 3027039603c..c9342bdccd4 100644 --- a/src/plugins/clangcodemodel/completionchunkstotextconverter.cpp +++ b/src/plugins/clangcodemodel/completionchunkstotextconverter.cpp @@ -30,15 +30,53 @@ #include "completionchunkstotextconverter.h" +#include +#include + namespace ClangCodeModel { namespace Internal { void CompletionChunksToTextConverter::parseChunks(const QVector &codeCompletionChunks) { m_text.clear(); + m_placeholderPositions.clear(); - for (const auto &codeCompletionChunk : codeCompletionChunks) - parse(codeCompletionChunk); + m_codeCompletionChunks = codeCompletionChunks; + + addExtraVerticalSpaceBetweenBraces(); + + std::for_each(m_codeCompletionChunks.cbegin(), + m_codeCompletionChunks.cend(), + [this] (const ClangBackEnd::CodeCompletionChunk &chunk) + { + parse(chunk); + m_previousCodeCompletionChunk = chunk; + }); +} + +void CompletionChunksToTextConverter::setAddPlaceHolderText(bool addPlaceHolderText) +{ + m_addPlaceHolderText = addPlaceHolderText; +} + +void CompletionChunksToTextConverter::setAddPlaceHolderPositions(bool addPlaceHolderPositions) +{ + m_addPlaceHolderPositions = addPlaceHolderPositions; +} + +void CompletionChunksToTextConverter::setAddResultType(bool addResultType) +{ + m_addResultType = addResultType; +} + +void CompletionChunksToTextConverter::setAddSpaces(bool addSpaces) +{ + m_addSpaces = addSpaces; +} + +void CompletionChunksToTextConverter::setAddExtraVerticalSpaceBetweenBraces(bool addExtraVerticalSpaceBetweenBraces) +{ + m_addExtraVerticalSpaceBetweenBraces = addExtraVerticalSpaceBetweenBraces; } const QString &CompletionChunksToTextConverter::text() const @@ -46,7 +84,28 @@ const QString &CompletionChunksToTextConverter::text() const return m_text; } -QString CompletionChunksToTextConverter::convert(const QVector &codeCompletionChunks) +const std::vector &CompletionChunksToTextConverter::placeholderPositions() const +{ + return m_placeholderPositions; +} + +bool CompletionChunksToTextConverter::hasPlaceholderPositions() const +{ + return m_placeholderPositions.size() > 0; +} + +QString CompletionChunksToTextConverter::convertToFunctionSignature(const QVector &codeCompletionChunks) +{ + CompletionChunksToTextConverter converter; + converter.setAddPlaceHolderText(true); + converter.setAddResultType(true); + + converter.parseChunks(codeCompletionChunks); + + return converter.text(); +} + +QString CompletionChunksToTextConverter::convertToName(const QVector &codeCompletionChunks) { CompletionChunksToTextConverter converter; @@ -62,17 +121,25 @@ void CompletionChunksToTextConverter::parse(const ClangBackEnd::CodeCompletionCh switch (codeCompletionChunk.kind()) { case CodeCompletionChunk::ResultType: parseResultType(codeCompletionChunk.text()); break; case CodeCompletionChunk::Optional: parseOptional(codeCompletionChunk); break; + case CodeCompletionChunk::Placeholder: parsePlaceHolder(codeCompletionChunk); break; + case CodeCompletionChunk::LeftParen: parseLeftParen(codeCompletionChunk); break; + case CodeCompletionChunk::LeftBrace: parseLeftBrace(codeCompletionChunk); break; default: parseText(codeCompletionChunk.text()); break; } } void CompletionChunksToTextConverter::parseResultType(const Utf8String &resultTypeText) { - m_text += resultTypeText.toString() + QChar(QChar::Space); + if (m_addResultType) + m_text += resultTypeText.toString() + QChar(QChar::Space); } void CompletionChunksToTextConverter::parseText(const Utf8String &text) { + if (m_addSpaces + && m_previousCodeCompletionChunk.kind() == ClangBackEnd::CodeCompletionChunk::RightBrace) + m_text += QChar(QChar::Space); + m_text += text.toString(); } @@ -80,11 +147,84 @@ void CompletionChunksToTextConverter::parseOptional(const ClangBackEnd::CodeComp { m_text += QStringLiteral(""); - m_text += convert(optionalCodeCompletionChunk.optionalChunks()); + m_text += convertToFunctionSignature(optionalCodeCompletionChunk.optionalChunks()); m_text += QStringLiteral(""); } +void CompletionChunksToTextConverter::parsePlaceHolder(const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk) +{ + if (m_addPlaceHolderText) + m_text += codeCompletionChunk.text().toString(); + + if (m_addPlaceHolderPositions) + m_placeholderPositions.push_back(m_text.size()); +} + +void CompletionChunksToTextConverter::parseLeftParen(const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk) +{ + if (m_addSpaces && m_previousCodeCompletionChunk.kind() != ClangBackEnd::CodeCompletionChunk::RightAngle) + m_text += QChar(QChar::Space); + + m_text += codeCompletionChunk.text().toString(); +} + +void CompletionChunksToTextConverter::parseLeftBrace(const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk) +{ + if (m_addSpaces) + m_text += QChar(QChar::Space); + + m_text += codeCompletionChunk.text().toString(); +} + +void CompletionChunksToTextConverter::addExtraVerticalSpaceBetweenBraces() +{ + if (m_addExtraVerticalSpaceBetweenBraces) + addExtraVerticalSpaceBetweenBraces(m_codeCompletionChunks.begin()); +} + +void CompletionChunksToTextConverter::addExtraVerticalSpaceBetweenBraces(const QVector::iterator &begin) +{ + using ClangBackEnd::CodeCompletionChunk; + + const auto leftBraceCompare = [] (const CodeCompletionChunk &chunk) { + return chunk.kind() == CodeCompletionChunk::LeftBrace; + }; + + const auto rightBraceCompare = [] (const CodeCompletionChunk &chunk) { + return chunk.kind() == CodeCompletionChunk::RightBrace; + }; + + const auto verticalSpaceCompare = [] (const CodeCompletionChunk &chunk) { + return chunk.kind() == CodeCompletionChunk::VerticalSpace; + }; + + auto leftBrace = std::find_if(begin, m_codeCompletionChunks.end(), leftBraceCompare); + + if (leftBrace != m_codeCompletionChunks.end()) { + auto rightBrace = std::find_if(leftBrace, m_codeCompletionChunks.end(), rightBraceCompare); + + if (rightBrace != m_codeCompletionChunks.end()) { + auto verticalSpaceCount = std::count_if(leftBrace, rightBrace, verticalSpaceCompare); + + if (verticalSpaceCount <= 1) { + auto distance = std::distance(leftBrace, rightBrace); + CodeCompletionChunk verticalSpaceChunck(CodeCompletionChunk::VerticalSpace, + Utf8StringLiteral("\n")); + auto verticalSpace = m_codeCompletionChunks.insert(std::next(leftBrace), + verticalSpaceChunck); + std::advance(verticalSpace, distance); + rightBrace = verticalSpace; + } + + auto begin = std::next(rightBrace); + + if (begin != m_codeCompletionChunks.end()) + addExtraVerticalSpaceBetweenBraces(begin); + } + } +} + } // namespace Internal } // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/completionchunkstotextconverter.h b/src/plugins/clangcodemodel/completionchunkstotextconverter.h index 20d4472b5ba..9e2f6d5c6d4 100644 --- a/src/plugins/clangcodemodel/completionchunkstotextconverter.h +++ b/src/plugins/clangcodemodel/completionchunkstotextconverter.h @@ -37,6 +37,8 @@ #include +#include + namespace ClangCodeModel { namespace Internal { @@ -45,18 +47,40 @@ class CompletionChunksToTextConverter public: void parseChunks(const QVector &codeCompletionChunks); - const QString &text() const; + void setAddPlaceHolderText(bool addPlaceHolderText); + void setAddPlaceHolderPositions(bool addPlaceHolderPositions); + void setAddResultType(bool addResultType); + void setAddSpaces(bool addSpaces); + void setAddExtraVerticalSpaceBetweenBraces(bool addExtraVerticalSpaceBetweenBraces); - static QString convert(const QVector &codeCompletionChunks); + const QString &text() const; + const std::vector &placeholderPositions() const; + bool hasPlaceholderPositions() const; + + static QString convertToFunctionSignature(const QVector &codeCompletionChunks); + static QString convertToName(const QVector &codeCompletionChunks); private: void parse(const ClangBackEnd::CodeCompletionChunk & codeCompletionChunk); void parseResultType(const Utf8String &text); void parseText(const Utf8String &text); - void parseOptional(const ClangBackEnd::CodeCompletionChunk & optionalCodeCompletionChunk); + void parseOptional(const ClangBackEnd::CodeCompletionChunk &optionalCodeCompletionChunk); + void parsePlaceHolder(const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk); + void parseLeftParen(const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk); + void parseLeftBrace(const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk); + void addExtraVerticalSpaceBetweenBraces(); + void addExtraVerticalSpaceBetweenBraces(const QVector::iterator &); private: + std::vector m_placeholderPositions; + QVector m_codeCompletionChunks; + ClangBackEnd::CodeCompletionChunk m_previousCodeCompletionChunk; QString m_text; + bool m_addPlaceHolderText = false; + bool m_addPlaceHolderPositions = false; + bool m_addResultType = false; + bool m_addSpaces = false; + bool m_addExtraVerticalSpaceBetweenBraces = false; }; } // namespace Internal diff --git a/tests/unit/unittest/completionchunkstotextconvertertest.cpp b/tests/unit/unittest/completionchunkstotextconvertertest.cpp index 97f017c0695..0e51d63c735 100644 --- a/tests/unit/unittest/completionchunkstotextconvertertest.cpp +++ b/tests/unit/unittest/completionchunkstotextconvertertest.cpp @@ -39,11 +39,15 @@ namespace { using ClangBackEnd::CodeCompletionChunk; +using Converter = ClangCodeModel::Internal::CompletionChunksToTextConverter; class CompletionChunksToTextConverter : public ::testing::Test { protected: - ClangCodeModel::Internal::CompletionChunksToTextConverter converter; + void setupConverterForKeywords(); + +protected: + Converter converter; CodeCompletionChunk integerResultType{CodeCompletionChunk::ResultType, Utf8StringLiteral("int")}; CodeCompletionChunk enumerationResultType{CodeCompletionChunk::ResultType, Utf8StringLiteral("Enumeration")}; CodeCompletionChunk functionName{CodeCompletionChunk::TypedText, Utf8StringLiteral("Function")}; @@ -52,18 +56,33 @@ protected: CodeCompletionChunk enumerationName{CodeCompletionChunk::TypedText, Utf8StringLiteral("Enumeration")}; CodeCompletionChunk className{CodeCompletionChunk::TypedText, Utf8StringLiteral("Class")}; CodeCompletionChunk leftParen{CodeCompletionChunk::LeftParen, Utf8StringLiteral("(")}; - CodeCompletionChunk rightParen{CodeCompletionChunk::LeftParen, Utf8StringLiteral(")")}; + CodeCompletionChunk rightParen{CodeCompletionChunk::RightParen, Utf8StringLiteral(")")}; CodeCompletionChunk comma{CodeCompletionChunk::Comma, Utf8StringLiteral(", ")}; + CodeCompletionChunk semicolon{CodeCompletionChunk::SemiColon, Utf8StringLiteral(";")}; CodeCompletionChunk functionArgumentX{CodeCompletionChunk::Placeholder, Utf8StringLiteral("char x")}; CodeCompletionChunk functionArgumentY{CodeCompletionChunk::Placeholder, Utf8StringLiteral("int y")}; CodeCompletionChunk functionArgumentZ{CodeCompletionChunk::Placeholder, Utf8StringLiteral("int z")}; + CodeCompletionChunk switchName{CodeCompletionChunk::TypedText, Utf8StringLiteral("switch")}; + CodeCompletionChunk condition{CodeCompletionChunk::Placeholder, Utf8StringLiteral("condition")}; + CodeCompletionChunk leftBrace{CodeCompletionChunk::LeftBrace, Utf8StringLiteral("{")}; + CodeCompletionChunk rightBrace{CodeCompletionChunk::RightBrace, Utf8StringLiteral("}")}; + CodeCompletionChunk verticalSpace{CodeCompletionChunk::VerticalSpace, Utf8StringLiteral("\n")}; + CodeCompletionChunk throwName{CodeCompletionChunk::TypedText, Utf8StringLiteral("throw")}; + CodeCompletionChunk voidResultType{CodeCompletionChunk::ResultType, Utf8StringLiteral("void")}; + CodeCompletionChunk forName{CodeCompletionChunk::TypedText, Utf8StringLiteral("for")}; + CodeCompletionChunk initStatement{CodeCompletionChunk::Placeholder, Utf8StringLiteral("init-statement")}; + CodeCompletionChunk initExpression{CodeCompletionChunk::Placeholder, Utf8StringLiteral("init-expression")}; + CodeCompletionChunk statements{CodeCompletionChunk::Placeholder, Utf8StringLiteral("statements")}; + CodeCompletionChunk constCastName{CodeCompletionChunk::TypedText, Utf8StringLiteral("const_cast")}; + CodeCompletionChunk leftAngle{CodeCompletionChunk::LeftAngle, Utf8StringLiteral("<")}; + CodeCompletionChunk rightAngle{CodeCompletionChunk::RightAngle, Utf8StringLiteral(">")}; CodeCompletionChunk optional{CodeCompletionChunk::Optional, Utf8String(), {comma, functionArgumentY, comma, functionArgumentZ}}; }; TEST_F(CompletionChunksToTextConverter, ParseIsClearingText) { QVector completionChunks({integerResultType, functionName, leftParen, rightParen}); - converter.parseChunks(completionChunks); + converter.setAddResultType(true); converter.parseChunks(completionChunks); @@ -73,6 +92,7 @@ TEST_F(CompletionChunksToTextConverter, ParseIsClearingText) TEST_F(CompletionChunksToTextConverter, ConvertFunction) { QVector completionChunks({integerResultType, functionName, leftParen, rightParen}); + converter.setAddResultType(true); converter.parseChunks(completionChunks); @@ -82,6 +102,8 @@ TEST_F(CompletionChunksToTextConverter, ConvertFunction) TEST_F(CompletionChunksToTextConverter, ConvertFunctionWithParameters) { QVector completionChunks({integerResultType, functionName, leftParen, functionArgumentX,rightParen}); + converter.setAddResultType(true); + converter.setAddPlaceHolderText(true); converter.parseChunks(completionChunks); @@ -91,6 +113,8 @@ TEST_F(CompletionChunksToTextConverter, ConvertFunctionWithParameters) TEST_F(CompletionChunksToTextConverter, ConvertFunctionWithOptionalParameter) { QVector completionChunks({integerResultType, functionName, leftParen, functionArgumentX, optional,rightParen}); + converter.setAddResultType(true); + converter.setAddPlaceHolderText(true); converter.parseChunks(completionChunks); @@ -100,6 +124,7 @@ TEST_F(CompletionChunksToTextConverter, ConvertFunctionWithOptionalParameter) TEST_F(CompletionChunksToTextConverter, ConvertVariable) { QVector completionChunks({integerResultType, variableName}); + converter.setAddResultType(true); converter.parseChunks(completionChunks); @@ -109,6 +134,7 @@ TEST_F(CompletionChunksToTextConverter, ConvertVariable) TEST_F(CompletionChunksToTextConverter, Enumerator) { QVector completionChunks({enumerationResultType, enumeratorName}); + converter.setAddResultType(true); converter.parseChunks(completionChunks); @@ -124,4 +150,73 @@ TEST_F(CompletionChunksToTextConverter, Enumeration) ASSERT_THAT(converter.text(), QStringLiteral("Class")); } +TEST_F(CompletionChunksToTextConverter, Switch) +{ + QVector completionChunks({switchName, + leftParen, + condition, + rightParen, + leftBrace, + verticalSpace, + rightBrace}); + setupConverterForKeywords(); + + converter.parseChunks(completionChunks); + + ASSERT_THAT(converter.text(), QStringLiteral("switch () {\n\n}")); + ASSERT_THAT(converter.placeholderPositions().at(0), 8); +} + +TEST_F(CompletionChunksToTextConverter, For) +{ + QVector completionChunks({forName, + leftParen, + initStatement, + semicolon, + initExpression, + semicolon, + condition, + rightParen, + leftBrace, + verticalSpace, + statements, + verticalSpace, + rightBrace}); + setupConverterForKeywords(); + + converter.parseChunks(completionChunks); + + ASSERT_THAT(converter.text(), QStringLiteral("for (;;) {\n\n}")); +} + +TEST_F(CompletionChunksToTextConverter, const_cast) +{ + QVector completionChunks({constCastName, + leftAngle, + rightAngle, + leftParen, + rightParen}); + setupConverterForKeywords(); + + converter.parseChunks(completionChunks); + + ASSERT_THAT(converter.text(), QStringLiteral("const_cast<>()")); + +} + +TEST_F(CompletionChunksToTextConverter, Throw) +{ + QVector completionChunks({voidResultType, throwName}); + + auto completionName = Converter::convertToName(completionChunks); + + ASSERT_THAT(completionName, QStringLiteral("throw")); +} + +void CompletionChunksToTextConverter::setupConverterForKeywords() +{ + converter.setAddPlaceHolderPositions(true); + converter.setAddSpaces(true); + converter.setAddExtraVerticalSpaceBetweenBraces(true); +} } From 2901b008ec6a56dd249f53b794b48ad7c074244e Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 14 Jul 2015 23:17:57 +0200 Subject: [PATCH 31/70] Debugger: Fix loading core files from the command line Make qtcreator -debug [exe,]core=/path/to/core work again. Change-Id: I16d1e388d74409d4deed2840dd768eab8c26cf40 Reviewed-by: Christian Stenger --- src/plugins/debugger/gdb/coregdbadapter.cpp | 2 -- src/plugins/debugger/gdb/coregdbadapter.h | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/plugins/debugger/gdb/coregdbadapter.cpp b/src/plugins/debugger/gdb/coregdbadapter.cpp index c81bef5a1b7..8b71bcb7077 100644 --- a/src/plugins/debugger/gdb/coregdbadapter.cpp +++ b/src/plugins/debugger/gdb/coregdbadapter.cpp @@ -130,7 +130,6 @@ GdbCoreEngine::readExecutableNameFromCore(const QString &debuggerCommand, const CoreInfo cinfo; #if 0 ElfReader reader(coreFile); - cinfo.isCore = false; cinfo.rawStringFromCore = QString::fromLocal8Bit(reader.readCoreName(&cinfo.isCore)); cinfo.foundExecutableName = findExecutableFromName(cinfo.rawStringFromCore, coreFile); #else @@ -161,7 +160,6 @@ GdbCoreEngine::readExecutableNameFromCore(const QString &debuggerCommand, const } } } - cinfo.isCore = false; #endif return cinfo; } diff --git a/src/plugins/debugger/gdb/coregdbadapter.h b/src/plugins/debugger/gdb/coregdbadapter.h index bd0ee88ee6d..03780b569b8 100644 --- a/src/plugins/debugger/gdb/coregdbadapter.h +++ b/src/plugins/debugger/gdb/coregdbadapter.h @@ -50,7 +50,7 @@ public: { QString rawStringFromCore; QString foundExecutableName; // empty if no corresponding exec could be found - bool isCore; + bool isCore = false; }; static CoreInfo readExecutableNameFromCore(const QString &debuggerCmd, const QString &coreFile); From 0f46ad4a552439a4b137bc8cab2d6c41edb5cbc0 Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Wed, 15 Jul 2015 10:38:15 +0300 Subject: [PATCH 32/70] Debugger: Set debuggee environment vars. Env vars should be set to debuggee not to debugger. Change-Id: I1ff877e295cb61f3a47c3aec5ffb43dea64df1cc Reviewed-by: hjk --- src/plugins/debugger/gdb/attachgdbadapter.cpp | 2 -- src/plugins/debugger/gdb/gdbengine.cpp | 10 +++++++++- src/plugins/debugger/gdb/gdbengine.h | 1 + src/plugins/debugger/gdb/gdbplainengine.cpp | 4 +--- src/plugins/debugger/gdb/remotegdbserveradapter.cpp | 4 ++-- src/plugins/debugger/lldb/lldbengine.cpp | 7 ++++++- 6 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/plugins/debugger/gdb/attachgdbadapter.cpp b/src/plugins/debugger/gdb/attachgdbadapter.cpp index 87f16d648af..c089e8f91c2 100644 --- a/src/plugins/debugger/gdb/attachgdbadapter.cpp +++ b/src/plugins/debugger/gdb/attachgdbadapter.cpp @@ -59,8 +59,6 @@ void GdbAttachEngine::setupEngine() if (!runParameters().workingDirectory.isEmpty()) m_gdbProc.setWorkingDirectory(runParameters().workingDirectory); - if (runParameters().environment.size()) - m_gdbProc.setEnvironment(runParameters().environment); startGdb(); } diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index e6924371fd7..16a2300247c 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -4260,6 +4260,14 @@ void GdbEngine::loadInitScript() } } +void GdbEngine::setEnvironmentVariables() +{ + if (runParameters().environment.size()) { + foreach (const QString &env, runParameters().environment.toStringList()) + postCommand("-gdb-set environment " + env.toUtf8()); + } +} + void GdbEngine::reloadDebuggingHelpers() { runCommand("reloadDumpers"); @@ -4570,7 +4578,7 @@ bool GdbEngine::prepareCommand() QtcProcess::SplitError perr; rp.processArgs = QtcProcess::prepareArgs(rp.processArgs, &perr, HostOsInfo::hostOs(), - &rp.environment, &rp.workingDirectory).toWindowsArgs(); + nullptr, &rp.workingDirectory).toWindowsArgs(); if (perr != QtcProcess::SplitOk) { // perr == BadQuoting is never returned on Windows // FIXME? QTCREATORBUG-2809 diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index b06cd67bcdc..d994a1cbbdd 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -103,6 +103,7 @@ protected: ////////// Gdb Process Management ////////// void handleGdbExit(const DebuggerResponse &response); void loadInitScript(); + void setEnvironmentVariables(); // Something went wrong with the adapter *before* adapterStarted() was emitted. // Make sure to clean up everything before emitting this signal. diff --git a/src/plugins/debugger/gdb/gdbplainengine.cpp b/src/plugins/debugger/gdb/gdbplainengine.cpp index 1980f9c32b5..b49bb315475 100644 --- a/src/plugins/debugger/gdb/gdbplainengine.cpp +++ b/src/plugins/debugger/gdb/gdbplainengine.cpp @@ -57,6 +57,7 @@ GdbPlainEngine::GdbPlainEngine(const DebuggerRunParameters &startParameters) void GdbPlainEngine::setupInferior() { QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state()); + setEnvironmentVariables(); if (!runParameters().processArgs.isEmpty()) { QString args = runParameters().processArgs; postCommand("-exec-arguments " + toLocalEncoding(args)); @@ -127,9 +128,6 @@ void GdbPlainEngine::setupEngine() if (!runParameters().workingDirectory.isEmpty()) m_gdbProc.setWorkingDirectory(runParameters().workingDirectory); - Utils::Environment env = runParameters().environment; - if (env.size()) - m_gdbProc.setEnvironment(env); startGdb(gdbArgs); } diff --git a/src/plugins/debugger/gdb/remotegdbserveradapter.cpp b/src/plugins/debugger/gdb/remotegdbserveradapter.cpp index 617f087791c..95f99d136a1 100644 --- a/src/plugins/debugger/gdb/remotegdbserveradapter.cpp +++ b/src/plugins/debugger/gdb/remotegdbserveradapter.cpp @@ -91,8 +91,6 @@ void GdbRemoteServerEngine::setupEngine() } if (!runParameters().workingDirectory.isEmpty()) m_gdbProc.setWorkingDirectory(runParameters().workingDirectory); - if (runParameters().environment.size()) - m_gdbProc.setEnvironment(runParameters().environment); if (runParameters().remoteSetupNeeded) notifyEngineRequestRemoteSetup(); @@ -186,6 +184,8 @@ void GdbRemoteServerEngine::setupInferior() if (!args.isEmpty()) postCommand("-exec-arguments " + args.toLocal8Bit()); + setEnvironmentVariables(); + // This has to be issued before 'target remote'. On pre-7.0 the // command is not present and will result in ' No symbol table is // loaded. Use the "file" command.' as gdb tries to set the diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp index 47037761924..753a483199f 100644 --- a/src/plugins/debugger/lldb/lldbengine.cpp +++ b/src/plugins/debugger/lldb/lldbengine.cpp @@ -182,7 +182,7 @@ bool LldbEngine::prepareCommand() QtcProcess::SplitError perr; rp.processArgs = QtcProcess::prepareArgs(rp.processArgs, &perr, HostOsInfo::hostOs(), - &rp.environment, &rp.workingDirectory).toWindowsArgs(); + nullptr, &rp.workingDirectory).toWindowsArgs(); if (perr != QtcProcess::SplitOk) { // perr == BadQuoting is never returned on Windows // FIXME? QTCREATORBUG-2809 @@ -290,6 +290,11 @@ void LldbEngine::startLldbStage2() void LldbEngine::setupInferior() { + if (runParameters().environment.size()) { + foreach (const QString &env, runParameters().environment.toStringList()) + runCommand("env " + env.toUtf8()); + } + const QString path = stringSetting(ExtraDumperFile); if (!path.isEmpty() && QFileInfo(path).isReadable()) { DebuggerCommand cmd("addDumperModule"); From 89bc1fc4c4d28dadbff282fb3e55ce84b51f3add Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Tue, 14 Jul 2015 18:22:06 +0200 Subject: [PATCH 33/70] Clang: Rename filePaths in ids UnregisterProjectPartsForCodeCompletionCommand is using them as ids and not as file paths. Change-Id: I13a82c1995c60bdb60c72f4fd794aa354fcbb4ef Reviewed-by: Nikolai Kosjar --- ...egisterprojectsforcodecompletioncommand.cpp | 18 +++++++++--------- ...nregisterprojectsforcodecompletioncommand.h | 6 +++--- .../test/clangcodecompletion_test.cpp | 2 +- .../clangbackend/ipcsource/clangipcserver.cpp | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/libs/clangbackendipc/cmbunregisterprojectsforcodecompletioncommand.cpp b/src/libs/clangbackendipc/cmbunregisterprojectsforcodecompletioncommand.cpp index 7c6743616c7..18e3eb3e347 100644 --- a/src/libs/clangbackendipc/cmbunregisterprojectsforcodecompletioncommand.cpp +++ b/src/libs/clangbackendipc/cmbunregisterprojectsforcodecompletioncommand.cpp @@ -42,44 +42,44 @@ namespace ClangBackEnd { UnregisterProjectPartsForCodeCompletionCommand::UnregisterProjectPartsForCodeCompletionCommand(const Utf8StringVector &filePaths) - : filePaths_(filePaths) + : projectPartIds_(filePaths) { } -const Utf8StringVector &UnregisterProjectPartsForCodeCompletionCommand::filePaths() const +const Utf8StringVector &UnregisterProjectPartsForCodeCompletionCommand::projectPartIds() const { - return filePaths_; + return projectPartIds_; } QDataStream &operator<<(QDataStream &out, const UnregisterProjectPartsForCodeCompletionCommand &command) { - out << command.filePaths_; + out << command.projectPartIds_; return out; } QDataStream &operator>>(QDataStream &in, UnregisterProjectPartsForCodeCompletionCommand &command) { - in >> command.filePaths_; + in >> command.projectPartIds_; return in; } bool operator==(const UnregisterProjectPartsForCodeCompletionCommand &first, const UnregisterProjectPartsForCodeCompletionCommand &second) { - return first.filePaths_ == second.filePaths_; + return first.projectPartIds_ == second.projectPartIds_; } bool operator<(const UnregisterProjectPartsForCodeCompletionCommand &first, const UnregisterProjectPartsForCodeCompletionCommand &second) { - return compareContainer(first.filePaths_, second.filePaths_); + return compareContainer(first.projectPartIds_, second.projectPartIds_); } QDebug operator<<(QDebug debug, const UnregisterProjectPartsForCodeCompletionCommand &command) { debug.nospace() << "UnregisterProjectPartsForCodeCompletionCommand("; - for (const Utf8String &fileNames_ : command.filePaths()) + for (const Utf8String &fileNames_ : command.projectPartIds()) debug.nospace() << fileNames_ << ", "; debug.nospace() << ")"; @@ -91,7 +91,7 @@ void PrintTo(const UnregisterProjectPartsForCodeCompletionCommand &command, ::st { *os << "UnregisterProjectPartsForCodeCompletionCommand("; - for (const Utf8String &fileNames_ : command.filePaths()) + for (const Utf8String &fileNames_ : command.projectPartIds()) *os << fileNames_.constData() << ", "; *os << ")"; diff --git a/src/libs/clangbackendipc/cmbunregisterprojectsforcodecompletioncommand.h b/src/libs/clangbackendipc/cmbunregisterprojectsforcodecompletioncommand.h index 59bf8ce5c58..592a5ae4ef2 100644 --- a/src/libs/clangbackendipc/cmbunregisterprojectsforcodecompletioncommand.h +++ b/src/libs/clangbackendipc/cmbunregisterprojectsforcodecompletioncommand.h @@ -49,12 +49,12 @@ class CMBIPC_EXPORT UnregisterProjectPartsForCodeCompletionCommand public: UnregisterProjectPartsForCodeCompletionCommand() = default; - UnregisterProjectPartsForCodeCompletionCommand(const Utf8StringVector &filePaths); + UnregisterProjectPartsForCodeCompletionCommand(const Utf8StringVector &projectPartIds); - const Utf8StringVector &filePaths() const; + const Utf8StringVector &projectPartIds() const; private: - Utf8StringVector filePaths_; + Utf8StringVector projectPartIds_; }; CMBIPC_EXPORT QDataStream &operator<<(QDataStream &out, const UnregisterProjectPartsForCodeCompletionCommand &command); diff --git a/src/plugins/clangcodemodel/test/clangcodecompletion_test.cpp b/src/plugins/clangcodemodel/test/clangcodecompletion_test.cpp index 95c43eeb200..9cbcaf92727 100644 --- a/src/plugins/clangcodemodel/test/clangcodecompletion_test.cpp +++ b/src/plugins/clangcodemodel/test/clangcodecompletion_test.cpp @@ -330,7 +330,7 @@ QString toString(const UnregisterProjectPartsForCodeCompletionCommand &command) QTextStream ts(&out); ts << "UnregisterProjectPartsForCodeCompletionCommand\n" - << command.filePaths().join(Utf8String::fromUtf8(",")).toByteArray() << "\n"; + << command.projectPartIds().join(Utf8String::fromUtf8(",")).toByteArray() << "\n"; return out; } diff --git a/src/tools/clangbackend/ipcsource/clangipcserver.cpp b/src/tools/clangbackend/ipcsource/clangipcserver.cpp index d192da2193f..e8b860520be 100644 --- a/src/tools/clangbackend/ipcsource/clangipcserver.cpp +++ b/src/tools/clangbackend/ipcsource/clangipcserver.cpp @@ -99,7 +99,7 @@ void ClangIpcServer::registerProjectPartsForCodeCompletion(const RegisterProject void ClangIpcServer::unregisterProjectPartsForCodeCompletion(const UnregisterProjectPartsForCodeCompletionCommand &command) { try { - projects.remove(command.filePaths()); + projects.remove(command.projectPartIds()); } catch (const ProjectPartDoNotExistException &exception) { client()->projectPartsDoNotExist(ProjectPartsDoNotExistCommand(exception.projectPartIds())); } catch (const std::exception &exception) { From dbe4e32201ebd10874c83c26493a94ba3ac0a215 Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Mon, 13 Jul 2015 12:13:18 +0200 Subject: [PATCH 34/70] QML wizards: Do not offer .ui.qml files for Qt 5.3 Qt 5.3 is the only version we are going to support that does not offer ui.qml file support. So just check for the QtQuick version shipped in Qt 5.3 to decide whether or not to display the checkbox. Task-number: QTCREATORBUG-14712 Change-Id: Ibb2204f2bcff819b749e1ed744c14a2e96769351 Reviewed-by: hjk Reviewed-by: Alessandro Portale --- .../projects/qmake/qtquickapplication/main.qml | 2 +- .../wizards/projects/qmake/qtquickapplication/qml.qrc | 2 +- .../projects/qmake/qtquickapplication/wizard.json | 11 +++++++---- .../qmake/qtquickcontrolsapplication/main.qml | 4 ++-- .../projects/qmake/qtquickcontrolsapplication/qml.qrc | 2 +- .../qmake/qtquickcontrolsapplication/wizard.json | 9 ++++++--- src/libs/utils/macroexpander.cpp | 2 +- 7 files changed, 19 insertions(+), 13 deletions(-) diff --git a/share/qtcreator/templates/wizards/projects/qmake/qtquickapplication/main.qml b/share/qtcreator/templates/wizards/projects/qmake/qtquickapplication/main.qml index 5ab93ecb205..8e8a45b4eed 100644 --- a/share/qtcreator/templates/wizards/projects/qmake/qtquickapplication/main.qml +++ b/share/qtcreator/templates/wizards/projects/qmake/qtquickapplication/main.qml @@ -4,7 +4,7 @@ import QtQuick.Window %{QtQuickWindowVersion} Window { visible: true -@if %{QmlUISplit} +@if %{IsUiFileInUse} MainForm { anchors.fill: parent mouseArea.onClicked: { diff --git a/share/qtcreator/templates/wizards/projects/qmake/qtquickapplication/qml.qrc b/share/qtcreator/templates/wizards/projects/qmake/qtquickapplication/qml.qrc index 068979cb030..b6165a029b7 100644 --- a/share/qtcreator/templates/wizards/projects/qmake/qtquickapplication/qml.qrc +++ b/share/qtcreator/templates/wizards/projects/qmake/qtquickapplication/qml.qrc @@ -1,7 +1,7 @@ main.qml -@if %{QmlUISplit} +@if %{IsUiFileInUse} MainForm.ui.qml @endif diff --git a/share/qtcreator/templates/wizards/projects/qmake/qtquickapplication/wizard.json b/share/qtcreator/templates/wizards/projects/qmake/qtquickapplication/wizard.json index ff84948f890..de3d358440a 100644 --- a/share/qtcreator/templates/wizards/projects/qmake/qtquickapplication/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qmake/qtquickapplication/wizard.json @@ -16,7 +16,9 @@ { "key": "MainCppFileName", "value": "%{JS: 'main.' + Util.preferredSuffix('text/x-c++src')}" }, { "key": "QtQuickVersion", "value": "%{JS: %{QtVersion}.qtQuickVersion}" }, { "key": "QtQuickWindowVersion", "value": "%{JS: %{QtVersion}.qtQuickWindowVersion}" }, - { "key": "QtQuickFeature", "value": "QtSupport.Wizards.FeatureQtQuick.%{QtQuickVersion}" } + { "key": "QtQuickFeature", "value": "QtSupport.Wizards.FeatureQtQuick.%{QtQuickVersion}" }, + { "key": "UiSupport", "value": "%{JS: '%{QtQuickVersion}' !== '2.3' }" }, + { "key": "IsUiFileInUse", "value": "%{JS: %{UiSupport} && %{QmlUiSplit} }" } ], "pages": @@ -69,12 +71,13 @@ } }, { - "name": "QmlUISplit", + "name": "QmlUiSplit", "trDisplayName": "With ui.qml file", "type": "CheckBox", + "visible": "%{UiSupport}", "data": { - "checked": false + "checked": true } } ] @@ -115,7 +118,7 @@ }, { "source": "MainForm.ui.qml", - "condition": "%{QmlUISplit}" + "condition": "%{IsUiFileInUse}" }, { "source": "qml.qrc" diff --git a/share/qtcreator/templates/wizards/projects/qmake/qtquickcontrolsapplication/main.qml b/share/qtcreator/templates/wizards/projects/qmake/qtquickcontrolsapplication/main.qml index f581c7c226c..3378f4f131b 100644 --- a/share/qtcreator/templates/wizards/projects/qmake/qtquickcontrolsapplication/main.qml +++ b/share/qtcreator/templates/wizards/projects/qmake/qtquickcontrolsapplication/main.qml @@ -1,6 +1,6 @@ import QtQuick %{QtQuickVersion} import QtQuick.Controls %{QtQuickControlsVersion} -@if %{QmlUISplit} +@if %{IsUiFileInUse} import QtQuick.Dialogs %{QtQuickDialogsVersion} @endif @@ -24,7 +24,7 @@ ApplicationWindow { } } -@if %{QmlUISplit} +@if %{IsUiFileInUse} MainForm { anchors.fill: parent button1.onClicked: messageDialog.show(qsTr("Button 1 pressed")) diff --git a/share/qtcreator/templates/wizards/projects/qmake/qtquickcontrolsapplication/qml.qrc b/share/qtcreator/templates/wizards/projects/qmake/qtquickcontrolsapplication/qml.qrc index 068979cb030..b6165a029b7 100644 --- a/share/qtcreator/templates/wizards/projects/qmake/qtquickcontrolsapplication/qml.qrc +++ b/share/qtcreator/templates/wizards/projects/qmake/qtquickcontrolsapplication/qml.qrc @@ -1,7 +1,7 @@ main.qml -@if %{QmlUISplit} +@if %{IsUiFileInUse} MainForm.ui.qml @endif diff --git a/share/qtcreator/templates/wizards/projects/qmake/qtquickcontrolsapplication/wizard.json b/share/qtcreator/templates/wizards/projects/qmake/qtquickcontrolsapplication/wizard.json index 0a57e21bf3b..fffd8650563 100644 --- a/share/qtcreator/templates/wizards/projects/qmake/qtquickcontrolsapplication/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qmake/qtquickcontrolsapplication/wizard.json @@ -18,7 +18,9 @@ { "key": "QtQuickControlsVersion", "value": "%{JS: %{QtVersion}.qtQuickControlsVersion}" }, { "key": "QtQuickDialogsVersion", "value": "%{JS: %{QtVersion}.qtQuickDialogsVersion}" }, { "key": "QtQuickLayoutsVersion", "value": "%{JS: %{QtVersion}.qtQuickLayoutsVersion}" }, - { "key": "QtQuickFeature", "value": "QtSupport.Wizards.FeatureQtQuick.%{QtQuickVersion}" } + { "key": "QtQuickFeature", "value": "QtSupport.Wizards.FeatureQtQuick.%{QtQuickVersion}" }, + { "key": "UiSupport", "value": "%{JS: '%{QtQuickVersion}' !== '2.3' }" }, + { "key": "IsUiFileInUse", "value": "%{JS: %{UiSupport} && %{QmlUiSplit} }" } ], "pages": @@ -77,9 +79,10 @@ } }, { - "name": "QmlUISplit", + "name": "QmlUiSplit", "trDisplayName": "With ui.qml file", "type": "CheckBox", + "visible": "%{UiSupport}", "data": { "checked": true @@ -132,7 +135,7 @@ }, { "source": "MainForm.ui.qml", - "condition": "%{QmlUISplit}" + "condition": "%{IsUiFileInUse}" }, { "source": "qml.qrc" diff --git a/src/libs/utils/macroexpander.cpp b/src/libs/utils/macroexpander.cpp index 0dc797406b2..159974d0d23 100644 --- a/src/libs/utils/macroexpander.cpp +++ b/src/libs/utils/macroexpander.cpp @@ -274,7 +274,7 @@ QString MacroExpander::expand(const QString &stringWithVariables) const if (d->m_lockDepth == 0) d->m_aborted = false; - if (d->m_lockDepth > 3) { // Limit recursion. + if (d->m_lockDepth > 10) { // Limit recursion. d->m_aborted = true; return QString(); } From f9899c2da8157376036148909575fb634007c0a5 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Wed, 15 Jul 2015 13:55:51 +0200 Subject: [PATCH 35/70] Clang: Little speedup for code completion ...by ensuring that the precompiled preamble is created. Change-Id: I80784b6a79c40a7e452530e8288783f33f881efc Reviewed-by: Nikolai Kosjar --- .../ipcsource/translationunit.cpp | 25 +++++++++++++++---- .../clangbackend/ipcsource/translationunit.h | 2 ++ 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/tools/clangbackend/ipcsource/translationunit.cpp b/src/tools/clangbackend/ipcsource/translationunit.cpp index f44d6989819..f74b555f383 100644 --- a/src/tools/clangbackend/ipcsource/translationunit.cpp +++ b/src/tools/clangbackend/ipcsource/translationunit.cpp @@ -163,10 +163,6 @@ void TranslationUnit::removeOutdatedTranslationUnit() const void TranslationUnit::createTranslationUnitIfNeeded() const { - const auto options = CXTranslationUnit_CacheCompletionResults - | CXTranslationUnit_PrecompiledPreamble - | CXTranslationUnit_SkipFunctionBodies; - if (!d->translationUnit) { d->translationUnit = CXTranslationUnit(); CXErrorCode errorCode = clang_parseTranslationUnit2(index(), @@ -175,11 +171,15 @@ void TranslationUnit::createTranslationUnitIfNeeded() const d->projectPart.argumentCount(), d->unsavedFiles.cxUnsavedFiles(), d->unsavedFiles.count(), - options, + defaultOptions(), &d->translationUnit); checkTranslationUnitErrorCode(errorCode); + // We need to reparse to create the precompiled preamble, which will speed up further calls, + // e.g. clang_codeCompleteAt() dramatically. + reparseTranslationUnit(); + updateLastChangeTimePoint(); } } @@ -192,6 +192,21 @@ void TranslationUnit::checkTranslationUnitErrorCode(CXErrorCode errorCode) const } } +void TranslationUnit::reparseTranslationUnit() const +{ + clang_reparseTranslationUnit(d->translationUnit, + d->unsavedFiles.count(), + d->unsavedFiles.cxUnsavedFiles(), + clang_defaultReparseOptions(d->translationUnit)); +} + +int TranslationUnit::defaultOptions() +{ + return CXTranslationUnit_CacheCompletionResults + | CXTranslationUnit_PrecompiledPreamble + | CXTranslationUnit_SkipFunctionBodies; +} + uint TranslationUnit::unsavedFilesCount() const { return d->unsavedFiles.count(); diff --git a/src/tools/clangbackend/ipcsource/translationunit.h b/src/tools/clangbackend/ipcsource/translationunit.h index 5383023869e..75dd39e8614 100644 --- a/src/tools/clangbackend/ipcsource/translationunit.h +++ b/src/tools/clangbackend/ipcsource/translationunit.h @@ -91,6 +91,8 @@ private: void removeOutdatedTranslationUnit() const; void createTranslationUnitIfNeeded() const; void checkTranslationUnitErrorCode(CXErrorCode errorCode) const; + void reparseTranslationUnit() const; + static int defaultOptions(); private: mutable std::shared_ptr d; From fbd549f213fdfbaf87f3bc1df0568e4237ee5023 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Wed, 15 Jul 2015 11:18:54 +0200 Subject: [PATCH 36/70] Clang: Prevent double spaces for clang snippets Change-Id: I62f9b9c217570dd6dafc45719e898cc2ac4d2937 Reviewed-by: Nikolai Kosjar --- .../completionchunkstotextconverter.cpp | 16 +++++++++---- .../completionchunkstotextconverter.h | 2 ++ .../completionchunkstotextconvertertest.cpp | 23 ++++++++++++++++++- 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/src/plugins/clangcodemodel/completionchunkstotextconverter.cpp b/src/plugins/clangcodemodel/completionchunkstotextconverter.cpp index c9342bdccd4..3c7c58c6a3c 100644 --- a/src/plugins/clangcodemodel/completionchunkstotextconverter.cpp +++ b/src/plugins/clangcodemodel/completionchunkstotextconverter.cpp @@ -136,9 +136,10 @@ void CompletionChunksToTextConverter::parseResultType(const Utf8String &resultTy void CompletionChunksToTextConverter::parseText(const Utf8String &text) { - if (m_addSpaces - && m_previousCodeCompletionChunk.kind() == ClangBackEnd::CodeCompletionChunk::RightBrace) + if (canAddSpace() + && m_previousCodeCompletionChunk.kind() == ClangBackEnd::CodeCompletionChunk::RightBrace) { m_text += QChar(QChar::Space); + } m_text += text.toString(); } @@ -163,7 +164,7 @@ void CompletionChunksToTextConverter::parsePlaceHolder(const ClangBackEnd::CodeC void CompletionChunksToTextConverter::parseLeftParen(const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk) { - if (m_addSpaces && m_previousCodeCompletionChunk.kind() != ClangBackEnd::CodeCompletionChunk::RightAngle) + if (canAddSpace()) m_text += QChar(QChar::Space); m_text += codeCompletionChunk.text().toString(); @@ -171,7 +172,7 @@ void CompletionChunksToTextConverter::parseLeftParen(const ClangBackEnd::CodeCom void CompletionChunksToTextConverter::parseLeftBrace(const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk) { - if (m_addSpaces) + if (canAddSpace()) m_text += QChar(QChar::Space); m_text += codeCompletionChunk.text().toString(); @@ -225,6 +226,13 @@ void CompletionChunksToTextConverter::addExtraVerticalSpaceBetweenBraces(const Q } } +bool CompletionChunksToTextConverter::canAddSpace() const +{ + return m_addSpaces + && m_previousCodeCompletionChunk.kind() != ClangBackEnd::CodeCompletionChunk::HorizontalSpace + && m_previousCodeCompletionChunk.kind() != ClangBackEnd::CodeCompletionChunk::RightAngle; +} + } // namespace Internal } // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/completionchunkstotextconverter.h b/src/plugins/clangcodemodel/completionchunkstotextconverter.h index 9e2f6d5c6d4..32a9a040989 100644 --- a/src/plugins/clangcodemodel/completionchunkstotextconverter.h +++ b/src/plugins/clangcodemodel/completionchunkstotextconverter.h @@ -71,6 +71,8 @@ private: void addExtraVerticalSpaceBetweenBraces(); void addExtraVerticalSpaceBetweenBraces(const QVector::iterator &); + bool canAddSpace() const; + private: std::vector m_placeholderPositions; QVector m_codeCompletionChunks; diff --git a/tests/unit/unittest/completionchunkstotextconvertertest.cpp b/tests/unit/unittest/completionchunkstotextconvertertest.cpp index 0e51d63c735..bc2bb4219a3 100644 --- a/tests/unit/unittest/completionchunkstotextconvertertest.cpp +++ b/tests/unit/unittest/completionchunkstotextconvertertest.cpp @@ -76,6 +76,9 @@ protected: CodeCompletionChunk constCastName{CodeCompletionChunk::TypedText, Utf8StringLiteral("const_cast")}; CodeCompletionChunk leftAngle{CodeCompletionChunk::LeftAngle, Utf8StringLiteral("<")}; CodeCompletionChunk rightAngle{CodeCompletionChunk::RightAngle, Utf8StringLiteral(">")}; + CodeCompletionChunk elseName{CodeCompletionChunk::TypedText, Utf8StringLiteral("else")}; + CodeCompletionChunk ifName{CodeCompletionChunk::TypedText, Utf8StringLiteral("if")}; + CodeCompletionChunk horizontalSpace{CodeCompletionChunk::HorizontalSpace, Utf8StringLiteral(" ")}; CodeCompletionChunk optional{CodeCompletionChunk::Optional, Utf8String(), {comma, functionArgumentY, comma, functionArgumentZ}}; }; @@ -201,7 +204,6 @@ TEST_F(CompletionChunksToTextConverter, const_cast) converter.parseChunks(completionChunks); ASSERT_THAT(converter.text(), QStringLiteral("const_cast<>()")); - } TEST_F(CompletionChunksToTextConverter, Throw) @@ -213,6 +215,25 @@ TEST_F(CompletionChunksToTextConverter, Throw) ASSERT_THAT(completionName, QStringLiteral("throw")); } +TEST_F(CompletionChunksToTextConverter, ElseIf) +{ + QVector completionChunks({elseName, + horizontalSpace, + ifName, + horizontalSpace, + leftBrace, + verticalSpace, + statements, + verticalSpace, + rightBrace}); + + setupConverterForKeywords(); + + converter.parseChunks(completionChunks); + + ASSERT_THAT(converter.text(), QStringLiteral("else if {\n\n}")); +} + void CompletionChunksToTextConverter::setupConverterForKeywords() { converter.setAddPlaceHolderPositions(true); From 9795a50fdd60d76c60d6fe988ab47e9b659f6b9b Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Wed, 15 Jul 2015 12:33:38 +0200 Subject: [PATCH 37/70] Clang: Reserve result vector in the CodeCompletionsExtractor To prevent re-allocations. Change-Id: I25f8d56bc8e55938e1888364414bc316da7fdf6c Reviewed-by: Nikolai Kosjar --- src/tools/clangbackend/ipcsource/codecompletionsextractor.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/clangbackend/ipcsource/codecompletionsextractor.cpp b/src/tools/clangbackend/ipcsource/codecompletionsextractor.cpp index e12c35fde98..c6a5febe76d 100644 --- a/src/tools/clangbackend/ipcsource/codecompletionsextractor.cpp +++ b/src/tools/clangbackend/ipcsource/codecompletionsextractor.cpp @@ -91,6 +91,7 @@ bool CodeCompletionsExtractor::peek(const Utf8String &name) QVector CodeCompletionsExtractor::extractAll() { QVector codeCompletions; + codeCompletions.reserve(cxCodeCompleteResults->NumResults); while (next()) codeCompletions.append(currentCodeCompletion_); From e9c2148806bf4a7c071fa464a3b9657681ebbb5a Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Wed, 15 Jul 2015 13:47:56 +0200 Subject: [PATCH 38/70] Clang: Reserve result vector in CodeCompletionChunkConverter Change-Id: If05c053afd0e422bb407e85bd2d403690084d637 Reviewed-by: Nikolai Kosjar --- .../clangbackend/ipcsource/codecompletionchunkconverter.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/clangbackend/ipcsource/codecompletionchunkconverter.cpp b/src/tools/clangbackend/ipcsource/codecompletionchunkconverter.cpp index 7fb2429c257..f58f6bda81e 100644 --- a/src/tools/clangbackend/ipcsource/codecompletionchunkconverter.cpp +++ b/src/tools/clangbackend/ipcsource/codecompletionchunkconverter.cpp @@ -37,6 +37,7 @@ namespace ClangBackEnd { void CodeCompletionChunkConverter::extractCompletionChunks(CXCompletionString completionString) { const uint completionChunkCount = clang_getNumCompletionChunks(completionString); + chunks.reserve(completionChunkCount); for (uint chunkIndex = 0; chunkIndex < completionChunkCount; ++chunkIndex) { const CodeCompletionChunk::Kind kind = chunkKind(completionString, chunkIndex); From 91d248c28fc7649094cea95391501b0401baa609 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 15 Jul 2015 15:57:51 +0200 Subject: [PATCH 39/70] Update qbs submodule. To HEAD of 1.4 branch. Change-Id: Id8b7ecc1dbcbe381c5766666e4cc91c75ad502f4 Reviewed-by: Joerg Bornemann --- src/shared/qbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/qbs b/src/shared/qbs index fc44e70c9db..d69b32061f2 160000 --- a/src/shared/qbs +++ b/src/shared/qbs @@ -1 +1 @@ -Subproject commit fc44e70c9db97048f67a36cd672ffe5e10972620 +Subproject commit d69b32061f2cc97892ba1a2f7d851e21f0787a8d From 1adbcc03f8c935937733b25c0bba800b607a93eb Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 14 Jul 2015 16:24:26 +0200 Subject: [PATCH 40/70] Debugger: Start using callbacks in QmlEngine commands Version, Backtrace, Frame, Scope and Lookup for now. Change-Id: I615c8f8c00484e9bb1742485f24bdfc537f83021 Reviewed-by: Christian Stenger --- src/plugins/debugger/qml/qmlengine.cpp | 111 +++++++++++-------------- 1 file changed, 50 insertions(+), 61 deletions(-) diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp index 388b484a4be..c90d89ff490 100644 --- a/src/plugins/debugger/qml/qmlengine.cpp +++ b/src/plugins/debugger/qml/qmlengine.cpp @@ -83,6 +83,8 @@ #endif # define XSDEBUG(s) qDebug() << s +#define CB(callback) [this](const QVariantMap &r) { callback(r); } + using namespace Core; using namespace ProjectExplorer; using namespace QmlDebug; @@ -116,6 +118,8 @@ struct QmlV8ObjectData QVariantList properties; }; +typedef std::function QmlCallback; + class QmlEnginePrivate : QmlDebugClient { public: @@ -134,8 +138,8 @@ public: void evaluate(const QString expr, bool global = false, bool disableBreak = false, int frame = -1, bool addContext = false); - void lookup(const QList handles, bool includeSource = false); - void backtrace(int fromFrame = -1, int toFrame = -1, bool bottom = false); + void lookup(const QList handles); + void backtrace(); void frame(int number); void scope(int number, int frameNumber = -1); void scripts(int types = 4, const QList ids = QList(), @@ -152,17 +156,19 @@ public: void expandObject(const QByteArray &iname, quint64 objectId); void flushSendBuffer(); - void handleBacktrace(const QVariant &bodyVal); - void handleLookup(const QVariant &bodyVal); + void handleBacktrace(const QVariantMap &response); + void handleLookup(const QVariantMap &response); void handleEvaluate(int sequence, bool success, const QVariant &bodyVal); - void handleFrame(const QVariant &bodyVal); - void handleScope(const QVariant &bodyVal); + void handleFrame(const QVariantMap &response); + void handleFrameHelper(const QVariantMap ¤tFrame); + void handleScope(const QVariantMap &response); + void handleVersion(const QVariantMap &response); StackFrame extractStackFrame(const QVariant &bodyVal); bool canEvaluateScript(const QString &script); void updateScriptSource(const QString &fileName, int lineOffset, int columnOffset, const QString &source); - void runCommand(const DebuggerCommand &command); + void runCommand(const DebuggerCommand &command, const QmlCallback &cb = QmlCallback()); void runDirectCommand(const QByteArray &type, const QByteArray &msg = QByteArray()); void clearRefs() { refVals.clear(); } @@ -208,6 +214,8 @@ public: QTimer connectionTimer; QmlDebug::QmlDebugConnection *connection; QmlDebug::QDebugMessageClient *msgClient = 0; + + QHash callbackForToken; }; static void updateDocument(IDocument *document, const QTextDocument *textDocument) @@ -1389,7 +1397,7 @@ void QmlEnginePrivate::evaluate(const QString expr, bool global, runCommand(cmd); } -void QmlEnginePrivate::lookup(QList handles, bool includeSource) +void QmlEnginePrivate::lookup(QList handles) { // { "seq" : , // "type" : "request", @@ -1402,16 +1410,11 @@ void QmlEnginePrivate::lookup(QList handles, bool includeSource) // } DebuggerCommand cmd(LOOKUP); - cmd.arg(HANDLES, handles); - - if (includeSource) - cmd.arg(INCLUDESOURCE, includeSource); - - runCommand(cmd); + runCommand(cmd, CB(handleLookup)); } -void QmlEnginePrivate::backtrace(int fromFrame, int toFrame, bool bottom) +void QmlEnginePrivate::backtrace() { // { "seq" : , // "type" : "request", @@ -1424,17 +1427,7 @@ void QmlEnginePrivate::backtrace(int fromFrame, int toFrame, bool bottom) // } DebuggerCommand cmd(BACKTRACE); - - if (fromFrame != -1) - cmd.arg(FROMFRAME, fromFrame); - - if (toFrame != -1) - cmd.arg(TOFRAME, toFrame); - - if (bottom) - cmd.arg(BOTTOM, bottom); - - runCommand(cmd); + runCommand(cmd, CB(handleBacktrace)); } void QmlEnginePrivate::frame(int number) @@ -1450,7 +1443,7 @@ void QmlEnginePrivate::frame(int number) if (number != -1) cmd.arg(NUMBER, number); - runCommand(cmd); + runCommand(cmd, CB(handleFrame)); } void QmlEnginePrivate::scope(int number, int frameNumber) @@ -1469,7 +1462,7 @@ void QmlEnginePrivate::scope(int number, int frameNumber) if (frameNumber != -1) cmd.arg(FRAMENUMBER, frameNumber); - runCommand(cmd); + runCommand(cmd, CB(handleScope)); } void QmlEnginePrivate::scripts(int types, const QList ids, bool includeSource, @@ -1709,12 +1702,15 @@ void QmlEnginePrivate::clearCache() updateLocalsAndWatchers.clear(); } -void QmlEnginePrivate::runCommand(const DebuggerCommand &command) +void QmlEnginePrivate::runCommand(const DebuggerCommand &command, const QmlCallback &cb) { QByteArray msg = "{\"seq\":" + QByteArray::number(++sequence) + "," + "\"type\":\"request\"," + "\"command\":\"" + command.function + "\"," + "\"arguments\":{" + command.arguments() + "}}"; + if (cb) + callbackForToken[sequence] = cb; + runDirectCommand(V8REQUEST, msg); } @@ -1793,6 +1789,8 @@ void QmlEnginePrivate::messageReceived(const QByteArray &data) if (type == _("response")) { + const QString debugCommand(resp.value(_(COMMAND)).toString()); + memorizeRefs(resp.value(_(REFS))); bool success = resp.value(_("success")).toBool(); @@ -1800,22 +1798,16 @@ void QmlEnginePrivate::messageReceived(const QByteArray &data) SDEBUG("Request was unsuccessful"); } - const QString debugCommand(resp.value(_(COMMAND)).toString()); + int requestSeq = resp.value(_("request_seq")).toInt(); + if (callbackForToken.contains(requestSeq)) { + callbackForToken[requestSeq](resp); - if (debugCommand == _(DISCONNECT)) { + } else if (debugCommand == _(DISCONNECT)) { //debugging session ended } else if (debugCommand == _(CONTINEDEBUGGING)) { //do nothing, wait for next break - } else if (debugCommand == _(BACKTRACE)) { - if (success) - handleBacktrace(resp.value(_(BODY))); - - } else if (debugCommand == _(LOOKUP)) { - if (success) - handleLookup(resp.value(_(BODY))); - } else if (debugCommand == _(EVALUATE)) { int seq = resp.value(_("request_seq")).toInt(); if (success) { @@ -1886,14 +1878,6 @@ void QmlEnginePrivate::messageReceived(const QByteArray &data) // } - } else if (debugCommand == _(FRAME)) { - if (success) - handleFrame(resp.value(_(BODY))); - - } else if (debugCommand == _(SCOPE)) { - if (success) - handleScope(resp.value(_(BODY))); - } else if (debugCommand == _(SCRIPTS)) { // { "seq" : , // "type" : "response", @@ -1951,11 +1935,6 @@ void QmlEnginePrivate::messageReceived(const QByteArray &data) engine->sourceFilesHandler()->setSourceFiles(files); //update open editors } - } else if (debugCommand == _(VERSION)) { - engine->showMessage(QString(_("Using V8 Version: %1")).arg( - resp.value(_(BODY)).toMap(). - value(_("V8Version")).toString()), LogOutput); - } else { // DO NOTHING } @@ -2100,7 +2079,7 @@ void QmlEnginePrivate::messageReceived(const QByteArray &data) } } -void QmlEnginePrivate::handleBacktrace(const QVariant &bodyVal) +void QmlEnginePrivate::handleBacktrace(const QVariantMap &response) { // { "seq" : , // "type" : "response", @@ -2115,7 +2094,7 @@ void QmlEnginePrivate::handleBacktrace(const QVariant &bodyVal) // "success" : true // } - const QVariantMap body = bodyVal.toMap(); + const QVariantMap body = response.value(_(BODY)).toMap(); const QVariantList frames = body.value(_("frames")).toList(); int fromFrameIndex = body.value(_("fromFrame")).toInt(); @@ -2141,7 +2120,7 @@ void QmlEnginePrivate::handleBacktrace(const QVariant &bodyVal) //Update all Locals visible in current scope //Traverse the scope chain and store the local properties //in a list and show them in the Locals Window. - handleFrame(frames.value(0)); + handleFrameHelper(frames.value(0).toMap()); } StackFrame QmlEnginePrivate::extractStackFrame(const QVariant &bodyVal) @@ -2205,7 +2184,7 @@ StackFrame QmlEnginePrivate::extractStackFrame(const QVariant &bodyVal) return stackFrame; } -void QmlEnginePrivate::handleFrame(const QVariant &bodyVal) +void QmlEnginePrivate::handleFrame(const QVariantMap &response) { // { "seq" : , // "type" : "response", @@ -2237,8 +2216,11 @@ void QmlEnginePrivate::handleFrame(const QVariant &bodyVal) // "running" : // "success" : true // } - QVariantMap currentFrame = bodyVal.toMap(); + handleFrameHelper(response.value(_(BODY)).toMap()); +} +void QmlEnginePrivate::handleFrameHelper(const QVariantMap ¤tFrame) +{ StackHandler *stackHandler = engine->stackHandler(); WatchHandler * watchHandler = engine->watchHandler(); watchHandler->notifyUpdateStarted(); @@ -2295,7 +2277,7 @@ void QmlEnginePrivate::handleFrame(const QVariant &bodyVal) engine->stackFrameCompleted(); } -void QmlEnginePrivate::handleScope(const QVariant &bodyVal) +void QmlEnginePrivate::handleScope(const QVariantMap &response) { // { "seq" : , // "type" : "response", @@ -2318,7 +2300,7 @@ void QmlEnginePrivate::handleScope(const QVariant &bodyVal) // "running" : // "success" : true // } - QVariantMap bodyMap = bodyVal.toMap(); + QVariantMap bodyMap = response.value(_(BODY)).toMap(); //Check if the frameIndex is same as current Stack Index StackHandler *stackHandler = engine->stackHandler(); @@ -2485,7 +2467,7 @@ void QmlEnginePrivate::handleEvaluate(int sequence, bool success, const QVariant } } -void QmlEnginePrivate::handleLookup(const QVariant &bodyVal) +void QmlEnginePrivate::handleLookup(const QVariantMap &response) { // { "seq" : , // "type" : "response", @@ -2495,7 +2477,7 @@ void QmlEnginePrivate::handleLookup(const QVariant &bodyVal) // "running" : // "success" : true // } - const QVariantMap body = bodyVal.toMap(); + const QVariantMap body = response.value(_(BODY)).toMap(); QStringList handlesList = body.keys(); WatchHandler *watchHandler = engine->watchHandler(); @@ -2539,6 +2521,13 @@ void QmlEnginePrivate::stateChanged(State state) } } +void QmlEnginePrivate::handleVersion(const QVariantMap &response) +{ + engine->showMessage(QString(_("Using V8 Version: %1")).arg( + response.value(_(BODY)).toMap(). + value(_("V8Version")).toString()), LogOutput); +} + void QmlEnginePrivate::sendMessage(const QByteArray &msg) { if (state() == Enabled) From 66964ac91c62603d7af8da957fca840962ee923d Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 14 Jul 2015 16:59:46 +0200 Subject: [PATCH 41/70] Debugger: Rework QmlEngine watcher expansion Use callbacks in QmlEnginePrivate::evaluate(). This separates the four code paths through the machinery into three separate handlers and one direct access to the console. This also fixes a bug where items were put into 'debuggerCommands' but attempted to be removed from 'updateLocalsAndWatchers'. Introduce a QmlEngine::updateLocals similar to what the other engines do. Let the frame() and assignValue() paths use it. Keep track of pending changes and call notifyUpdateFinished if and only if the pending lookup queues is empty. Finally, remove some dead code. Change-Id: I173a52911d0de994b849fc6ab4f52ef7f64a8ba5 Reviewed-by: Christian Stenger --- src/plugins/debugger/qml/qmlengine.cpp | 376 +++++++++---------------- src/plugins/debugger/qml/qmlengine.h | 2 - 2 files changed, 133 insertions(+), 245 deletions(-) diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp index c90d89ff490..aab9446c00a 100644 --- a/src/plugins/debugger/qml/qmlengine.cpp +++ b/src/plugins/debugger/qml/qmlengine.cpp @@ -120,6 +120,14 @@ struct QmlV8ObjectData typedef std::function QmlCallback; +struct LookupData +{ + QByteArray iname; + QString name; +}; + +typedef QMultiHash LookupItems; // id -> (iname, exp) + class QmlEnginePrivate : QmlDebugClient { public: @@ -136,11 +144,10 @@ public: void continueDebugging(StepAction stepAction); - void evaluate(const QString expr, bool global = false, bool disableBreak = false, - int frame = -1, bool addContext = false); - void lookup(const QList handles); + void evaluate(const QString expr, const QmlCallback &cb); + void lookup(const LookupItems &items); void backtrace(); - void frame(int number); + void updateLocals(); void scope(int number, int frameNumber = -1); void scripts(int types = 4, const QList ids = QList(), bool includeSource = false, const QVariant filter = QVariant()); @@ -151,16 +158,13 @@ public: void clearBreakpoint(int breakpoint); void setExceptionBreak(Exceptions type, bool enabled = false); - void clearCache(); - - void expandObject(const QByteArray &iname, quint64 objectId); void flushSendBuffer(); void handleBacktrace(const QVariantMap &response); void handleLookup(const QVariantMap &response); - void handleEvaluate(int sequence, bool success, const QVariant &bodyVal); + void handleExecuteDebuggerCommand(const QVariantMap &response); + void handleEvaluateWatcher(const QVariantMap &response, const QString &expr); void handleFrame(const QVariantMap &response); - void handleFrameHelper(const QVariantMap ¤tFrame); void handleScope(const QVariantMap &response); void handleVersion(const QVariantMap &response); StackFrame extractStackFrame(const QVariant &bodyVal); @@ -175,6 +179,7 @@ public: void memorizeRefs(const QVariant &refs); QmlV8ObjectData extractData(const QVariant &data) const; void insertSubItems(WatchItem *parent, const QVariantList &properties); + void checkForFinishedUpdate(); ConsoleItem *constructLogItemTree(ConsoleItem *parent, const QmlV8ObjectData &objectData); public: @@ -185,10 +190,7 @@ public: QHash breakpointsSync; QList breakpointsTemp; - QHash evaluatingExpression; - QHash localsAndWatchers; - QList updateLocalsAndWatchers; - QList debuggerCommands; + LookupItems currentlyLookingUp; // Id -> inames //Cache QList currentFrameScopes; @@ -344,11 +346,6 @@ void QmlEngine::connectionEstablished() { attemptBreakpointSynchronization(); - if (!watchHandler()->watcherNames().isEmpty()) - synchronizeWatchers(); - connect(watchModel(), &QAbstractItemModel::layoutChanged, - this, &QmlEngine::synchronizeWatchers); - if (state() == EngineRunRequested) notifyEngineRunAndInferiorRunOk(); } @@ -521,9 +518,6 @@ void QmlEngine::gotoLocation(const Location &location) void QmlEngine::closeConnection() { - disconnect(watchModel(), &QAbstractItemModel::layoutChanged, - this, &QmlEngine::synchronizeWatchers); - if (d->connectionTimer.isActive()) { d->connectionTimer.stop(); } else { @@ -755,11 +749,10 @@ void QmlEngine::activateFrame(int index) if (state() != InferiorStopOk && state() != InferiorUnrunnable) return; - if (index != stackHandler()->currentIndex()) - d->frame(d->stackIndexLookup.value(index)); - stackHandler()->setCurrentIndex(index); gotoLocation(stackHandler()->frames().value(index)); + + d->updateLocals(); } void QmlEngine::selectThread(ThreadId threadId) @@ -958,17 +951,16 @@ bool QmlEngine::canHandleToolTip(const DebuggerToolTipContext &) const } void QmlEngine::assignValueInDebugger(WatchItem *item, - const QString &expression, const QVariant &valueV) + const QString &expression, const QVariant &value) { if (!expression.isEmpty()) { if (item->isInspect() && d->inspectorAdapter.agent()) { - d->inspectorAdapter.agent()->assignValue(item, expression, valueV); + d->inspectorAdapter.agent()->assignValue(item, expression, value); } else { StackHandler *handler = stackHandler(); - QString expression = QString(_("%1 = %2;")).arg(expression).arg(valueV.toString()); + QString exp = QString(_("%1 = %2;")).arg(expression).arg(value.toString()); if (handler->isContentsValid() && handler->currentFrame().isUsable()) { - d->evaluate(expression, false, false, handler->currentIndex()); - d->updateLocalsAndWatchers.append(d->sequence); + d->evaluate(exp, [this](const QVariantMap &) { d->updateLocals(); }); } else { showMessage(QString(_("Cannot evaluate %1 in current stack frame")).arg( expression), ConsoleOutput); @@ -979,8 +971,6 @@ void QmlEngine::assignValueInDebugger(WatchItem *item, void QmlEngine::updateWatchData(const QByteArray &iname) { -// qDebug() << "UPDATE WATCH DATA" << data.toString(); - //showStatusMessage(tr("Stopped."), 5000); const WatchItem *item = watchHandler()->findItem(iname); // invalid expressions or out of scope variables if (!item) @@ -990,10 +980,12 @@ void QmlEngine::updateWatchData(const QByteArray &iname) d->inspectorAdapter.agent()->updateWatchData(*item); } else { if (!item->name.isEmpty()) { - if (item->isChildrenNeeded() && watchHandler()->isExpandedIName(item->iname)) - d->expandObject(item->iname, item->id); + if (item->isChildrenNeeded() && watchHandler()->isExpandedIName(item->iname)) { + LookupItems items; + items.insert(int(item->id), {item->iname, item->name}); + d->lookup(items); + } } - synchronizeWatchers(); } } @@ -1004,23 +996,6 @@ void QmlEngine::selectWatchData(const QByteArray &iname) d->inspectorAdapter.agent()->watchDataSelected(item->id); } -void QmlEngine::synchronizeWatchers() -{ - if (state() != InferiorStopOk) - return; - - QStringList watchers = watchHandler()->watchedExpressions(); - - // send watchers list - foreach (const QString &exp, watchers) { - StackHandler *handler = stackHandler(); - if (handler->isContentsValid() && handler->currentFrame().isUsable()) { - d->evaluate(exp, false, false, handler->currentIndex()); - d->evaluatingExpression.insert(d->sequence, exp); - } - } -} - static ConsoleItem *constructLogItemTree(ConsoleItem *parent, const QVariant &result, const QString &key = QString()) @@ -1136,8 +1111,6 @@ void QmlEngine::updateCurrentContext() context = grandParentData->name; } - synchronizeWatchers(); - if (auto consoleManager = ConsoleManagerInterface::instance()) consoleManager->setContext(tr("Context:") + QLatin1Char(' ') + context); } @@ -1149,8 +1122,7 @@ void QmlEngine::executeDebuggerCommand(const QString &command, DebuggerLanguages StackHandler *handler = stackHandler(); if (handler->isContentsValid() && handler->currentFrame().isUsable()) { - d->evaluate(command, false, false, handler->currentIndex()); - d->debuggerCommands.append(d->sequence); + d->evaluate(command, CB(d->handleExecuteDebuggerCommand)); } else { //Currently cannot evaluate if not in a javascript break d->engine->showMessage(QString(_("Cannot evaluate %1 in current stack frame")).arg( @@ -1347,8 +1319,7 @@ void QmlEnginePrivate::continueDebugging(StepAction action) previousStepAction = action; } -void QmlEnginePrivate::evaluate(const QString expr, bool global, - bool disableBreak, int frame, bool addContext) +void QmlEnginePrivate::evaluate(const QString expr, const QmlCallback &cb) { // { "seq" : , // "type" : "request", @@ -1368,36 +1339,45 @@ void QmlEnginePrivate::evaluate(const QString expr, bool global, DebuggerCommand cmd(EVALUATE); cmd.arg(EXPRESSION, expr); + cmd.arg(FRAME, engine->stackHandler()->currentIndex()); - if (frame != -1) - cmd.arg(FRAME, frame); - - if (global) - cmd.arg(GLOBAL, global); - - if (disableBreak) - cmd.arg(DISABLE_BREAK, disableBreak); - - if (addContext) { - WatchHandler *watchHandler = engine->watchHandler(); - QAbstractItemModel *watchModel = watchHandler->model(); - int rowCount = watchModel->rowCount(); - - cmd.beginList(ADDITIONAL_CONTEXT); - for (int row = 0; row < rowCount; ++row) { - QModelIndex index = watchModel->index(row, 0); // FIXME: This looks wrong. - const WatchData *data = watchHandler->watchItem(index); - cmd.beginGroup(); - cmd.arg(NAME, data->name); - cmd.arg(HANDLE, int(data->id)); - cmd.endGroup(); - } - } - - runCommand(cmd); + runCommand(cmd, cb); } -void QmlEnginePrivate::lookup(QList handles) +void QmlEnginePrivate::handleEvaluateWatcher(const QVariantMap &response, const QString &exp) +{ + // { "seq" : , + // "type" : "response", + // "request_seq" : , + // "command" : "evaluate", + // "body" : ... + // "running" : + // "success" : true + // } + + QVariant bodyVal = response.value(_(BODY)).toMap(); + QmlV8ObjectData body = extractData(bodyVal); + WatchHandler *watchHandler = engine->watchHandler(); + + QByteArray iname = watchHandler->watcherName(exp.toLatin1()); + + auto item = new WatchItem(iname, exp); + item->exp = exp.toLatin1(); + item->id = body.handle; + bool success = response.value(_("success")).toBool(); + if (success) { + item->type = body.type; + item->value = body.value.toString(); + item->wantsChildren = body.properties.count(); + } else { + //Do not set type since it is unknown + item->setError(body.value.toString()); + } + watchHandler->insertItem(item); + insertSubItems(item, body.properties); +} + +void QmlEnginePrivate::lookup(const LookupItems &items) { // { "seq" : , // "type" : "request", @@ -1409,6 +1389,12 @@ void QmlEnginePrivate::lookup(QList handles) // } // } + if (items.isEmpty()) + return; + + QList handles = items.keys(); + currentlyLookingUp += items; + DebuggerCommand cmd(LOOKUP); cmd.arg(HANDLES, handles); runCommand(cmd, CB(handleLookup)); @@ -1430,19 +1416,16 @@ void QmlEnginePrivate::backtrace() runCommand(cmd, CB(handleBacktrace)); } -void QmlEnginePrivate::frame(int number) +void QmlEnginePrivate::updateLocals() { // { "seq" : , // "type" : "request", // "command" : "frame", - // "arguments" : { "number" : - // } + // "arguments" : { "number" : } // } DebuggerCommand cmd(FRAME); - if (number != -1) - cmd.arg(NUMBER, number); - + cmd.arg(NUMBER, stackIndexLookup.value(engine->stackHandler()->currentIndex())); runCommand(cmd, CB(handleFrame)); } @@ -1696,12 +1679,6 @@ QmlV8ObjectData QmlEnginePrivate::extractData(const QVariant &data) const return objectData; } -void QmlEnginePrivate::clearCache() -{ - currentFrameScopes.clear(); - updateLocalsAndWatchers.clear(); -} - void QmlEnginePrivate::runCommand(const DebuggerCommand &command, const QmlCallback &cb) { QByteArray msg = "{\"seq\":" + QByteArray::number(++sequence) + "," @@ -1727,24 +1704,6 @@ void QmlEnginePrivate::runDirectCommand(const QByteArray &type, const QByteArray sendMessage(request); } -void QmlEnginePrivate::expandObject(const QByteArray &iname, quint64 objectId) -{ - if (objectId == 0) { - //We may have got the global object - const WatchItem *watch = engine->watchHandler()->findItem(iname); - if (watch->value == QLatin1String("global")) { - StackHandler *stackHandler = engine->stackHandler(); - if (stackHandler->isContentsValid() && stackHandler->currentFrame().isUsable()) { - evaluate(watch->name, false, false, stackHandler->currentIndex()); - evaluatingExpression.insert(sequence, QLatin1String(iname)); - } - return; - } - } - localsAndWatchers.insertMulti(objectId, iname); - lookup(QList() << objectId); -} - void QmlEnginePrivate::memorizeRefs(const QVariant &refs) { if (refs.isValid()) { @@ -1808,17 +1767,6 @@ void QmlEnginePrivate::messageReceived(const QByteArray &data) } else if (debugCommand == _(CONTINEDEBUGGING)) { //do nothing, wait for next break - } else if (debugCommand == _(EVALUATE)) { - int seq = resp.value(_("request_seq")).toInt(); - if (success) { - handleEvaluate(seq, success, resp.value(_(BODY))); - } else { - QVariantMap map; - map.insert(_(TYPE), QVariant(_("string"))); - map.insert(_(VALUE), resp.value(_("message"))); - handleEvaluate(seq, success, QVariant(map)); - } - } else if (debugCommand == _(SETBREAKPOINT)) { // { "seq" : , // "type" : "response", @@ -2062,13 +2010,13 @@ void QmlEnginePrivate::messageReceived(const QByteArray &data) //This is most probably due to a wrong eval expression. //Redirect output to console. if (eventType.isEmpty()) { - bool success = resp.value(_("success")).toBool(); - QVariantMap map; - map.insert(_(TYPE), QVariant(_("string"))); - map.insert(_(VALUE), resp.value(_("message"))); - //Since there is no sequence value, best estimate is - //last sequence value - handleEvaluate(sequence, success, QVariant(map)); + QmlV8ObjectData entry; + entry.type = "string"; + entry.value = resp.value(_("message")); + if (auto consoleManager = ConsoleManagerInterface::instance()) { + if (ConsoleItem *item = constructLogItemTree(consoleManager->rootItem(), entry)) + consoleManager->printToConsolePane(item); + } } } //EVENT @@ -2115,12 +2063,9 @@ void QmlEnginePrivate::handleBacktrace(const QVariantMap &response) i++; } stackHandler->setFrames(stackFrames); + stackHandler->setCurrentIndex(0); - //Populate locals and watchers wrt top frame - //Update all Locals visible in current scope - //Traverse the scope chain and store the local properties - //in a list and show them in the Locals Window. - handleFrameHelper(frames.value(0).toMap()); + updateLocals(); } StackFrame QmlEnginePrivate::extractStackFrame(const QVariant &bodyVal) @@ -2216,35 +2161,23 @@ void QmlEnginePrivate::handleFrame(const QVariantMap &response) // "running" : // "success" : true // } - handleFrameHelper(response.value(_(BODY)).toMap()); -} + QVariantMap body = response.value(_(BODY)).toMap(); -void QmlEnginePrivate::handleFrameHelper(const QVariantMap ¤tFrame) -{ StackHandler *stackHandler = engine->stackHandler(); WatchHandler * watchHandler = engine->watchHandler(); watchHandler->notifyUpdateStarted(); - clearCache(); const int frameIndex = stackHandler->currentIndex(); - QSet expandedInames = watchHandler->expandedINames(); - QHash handlesToLookup; - // Store handles of all expanded watch data - foreach (const QByteArray &iname, expandedInames) { - const WatchItem *item = watchHandler->findItem(iname); - if (item && item->isLocal()) - handlesToLookup.insert(item->id, iname); - } if (frameIndex < 0) return; const StackFrame frame = stackHandler->currentFrame(); if (!frame.isUsable()) return; - //Set "this" variable + // Always add a "this" variable { auto item = new WatchItem("local.this", QLatin1String("this")); - QmlV8ObjectData objectData = extractData(currentFrame.value(_("receiver"))); + QmlV8ObjectData objectData = extractData(body.value(_("receiver"))); item->id = objectData.handle; item->type = objectData.type; item->value = objectData.value.toString(); @@ -2258,7 +2191,8 @@ void QmlEnginePrivate::handleFrameHelper(const QVariantMap ¤tFrame) watchHandler->insertItem(item); } - const QVariantList scopes = currentFrame.value(_("scopes")).toList(); + currentFrameScopes.clear(); + const QVariantList scopes = body.value(_("scopes")).toList(); foreach (const QVariant &scope, scopes) { //Do not query for global types (0) //Showing global properties increases clutter. @@ -2270,11 +2204,24 @@ void QmlEnginePrivate::handleFrameHelper(const QVariantMap ¤tFrame) } engine->gotoLocation(stackHandler->currentFrame()); - // Expand watch data that were previously expanded - QHash::const_iterator itEnd = handlesToLookup.constEnd(); - for (QHash::const_iterator it = handlesToLookup.constBegin(); it != itEnd; ++it) - expandObject(it.value(), it.key()); - engine->stackFrameCompleted(); + // Send watchers list + if (stackHandler->isContentsValid() && stackHandler->currentFrame().isUsable()) { + QStringList watchers = watchHandler->watchedExpressions(); + foreach (const QString &exp, watchers) { + evaluate(exp, [this, exp](const QVariantMap &response) { + handleEvaluateWatcher(response, exp); + }); + } + } + + // Expand locals and watchers that were previously expanded + LookupItems itemsToLookup; + foreach (const QByteArray &iname, watchHandler->expandedINames()) { + const WatchItem *item = watchHandler->findItem(iname); + if (item && item->isLocal()) + itemsToLookup.insert(int(item->id), {item->iname, item->name}); + } + lookup(itemsToLookup); } void QmlEnginePrivate::handleScope(const QVariantMap &response) @@ -2309,7 +2256,7 @@ void QmlEnginePrivate::handleScope(const QVariantMap &response) QmlV8ObjectData objectData = extractData(bodyMap.value(_("object"))); - QList handlesToLookup; + LookupItems itemsToLookup; foreach (const QVariant &property, objectData.properties) { QmlV8ObjectData localData = extractData(property); auto item = new WatchItem; @@ -2320,23 +2267,24 @@ void QmlEnginePrivate::handleScope(const QVariantMap &response) item->name = QLatin1String(item->exp); item->iname = QByteArray("local.") + item->exp; + item->id = localData.handle; - int handle = localData.handle; if (localData.value.isValid()) { - item->id = handle; item->type = localData.type; item->value = localData.value.toString(); item->setHasChildren(localData.properties.count()); engine->watchHandler()->insertItem(item); } else { - handlesToLookup << handle; - localsAndWatchers.insertMulti(handle, item->exp); + itemsToLookup.insert(int(item->id), {item->iname, item->name}); } } + lookup(itemsToLookup); + checkForFinishedUpdate(); +} - if (!handlesToLookup.isEmpty()) - lookup(handlesToLookup); - else +void QmlEnginePrivate::checkForFinishedUpdate() +{ + if (currentlyLookingUp.isEmpty()) engine->watchHandler()->notifyUpdateFinished(); } @@ -2403,68 +2351,16 @@ void QmlEnginePrivate::insertSubItems(WatchItem *parent, const QVariantList &pro } } -void QmlEnginePrivate::handleEvaluate(int sequence, bool success, const QVariant &bodyVal) +void QmlEnginePrivate::handleExecuteDebuggerCommand(const QVariantMap &response) { - // { "seq" : , - // "type" : "response", - // "request_seq" : , - // "command" : "evaluate", - // "body" : ... - // "running" : - // "success" : true - // } - WatchHandler *watchHandler = engine->watchHandler(); - if (updateLocalsAndWatchers.contains(sequence)) { - updateLocalsAndWatchers.removeOne(sequence); - //Update the locals - foreach (int index, currentFrameScopes) - scope(index); - //Also update "this" - QByteArray iname("local.this"); - const WatchItem *parent = watchHandler->findItem(iname); - localsAndWatchers.insertMulti(parent->id, iname); - lookup(QList() << parent->id); - - } else if (debuggerCommands.contains(sequence)) { - updateLocalsAndWatchers.removeOne(sequence); - QmlV8ObjectData body = extractData(bodyVal); - if (auto consoleManager = ConsoleManagerInterface::instance()) { - if (ConsoleItem *item = constructLogItemTree(consoleManager->rootItem(), body)) - consoleManager->printToConsolePane(item); - } - //Update the locals - foreach (int index, currentFrameScopes) - scope(index); - - } else { - QmlV8ObjectData body = extractData(bodyVal); - if (evaluatingExpression.contains(sequence)) { - QString exp = evaluatingExpression.take(sequence); - //Do we have request to evaluate a local? - if (exp.startsWith(QLatin1String("local."))) { - WatchItem *item = watchHandler->findItem(exp.toLatin1()); - insertSubItems(item, body.properties); - } else { - QByteArray iname = watchHandler->watcherName(exp.toLatin1()); - SDEBUG(QString(iname)); - - auto item = new WatchItem(iname, exp); - item->exp = exp.toLatin1(); - item->id = body.handle; - if (success) { - item->type = body.type; - item->value = body.value.toString(); - item->wantsChildren = body.properties.count(); - } else { - //Do not set type since it is unknown - item->setError(body.value.toString()); - } - watchHandler->insertItem(item); - insertSubItems(item, body.properties); - } - //Insert the newly evaluated expression to the Watchers Window - } + QmlV8ObjectData body = extractData(response.value(_(BODY))); + if (auto consoleManager = ConsoleManagerInterface::instance()) { + if (ConsoleItem *item = constructLogItemTree(consoleManager->rootItem(), body)) + consoleManager->printToConsolePane(item); } + // Update the locals + foreach (int index, currentFrameScopes) + scope(index); } void QmlEnginePrivate::handleLookup(const QVariantMap &response) @@ -2480,33 +2376,27 @@ void QmlEnginePrivate::handleLookup(const QVariantMap &response) const QVariantMap body = response.value(_(BODY)).toMap(); QStringList handlesList = body.keys(); - WatchHandler *watchHandler = engine->watchHandler(); - foreach (const QString &handle, handlesList) { - QmlV8ObjectData bodyObjectData = extractData(body.value(handle)); - QByteArray prepend = localsAndWatchers.take(handle.toInt()); - - if (prepend.startsWith("local.") || prepend.startsWith("watch.")) { - // Data for expanded local/watch. - // Could be an object or function. - WatchItem *parent = watchHandler->findItem(prepend); - insertSubItems(parent, bodyObjectData.properties); - } else { - //rest + foreach (const QString &handleString, handlesList) { + int handle = handleString.toInt(); + QmlV8ObjectData bodyObjectData = extractData(body.value(handleString)); + QList vals = currentlyLookingUp.values(handle); + currentlyLookingUp.remove(handle); + foreach (const LookupData &res, vals) { auto item = new WatchItem; - item->exp = prepend; - item->name = QLatin1String(item->exp); - item->iname = QByteArray("local.") + item->exp; - item->id = handle.toInt(); + item->iname = res.iname; + item->name = res.name; + item->id = handle; item->type = bodyObjectData.type; item->value = bodyObjectData.value.toString(); item->setHasChildren(bodyObjectData.properties.count()); + insertSubItems(item, bodyObjectData.properties); engine->watchHandler()->insertItem(item); } } - engine->watchHandler()->notifyUpdateFinished(); + checkForFinishedUpdate(); } void QmlEnginePrivate::stateChanged(State state) diff --git a/src/plugins/debugger/qml/qmlengine.h b/src/plugins/debugger/qml/qmlengine.h index 2fe073aa498..bf51bf3ed42 100644 --- a/src/plugins/debugger/qml/qmlengine.h +++ b/src/plugins/debugger/qml/qmlengine.h @@ -77,8 +77,6 @@ private slots: void appStartupFailed(const QString &errorMessage); void appendMessage(const QString &msg, Utils::OutputFormat); - void synchronizeWatchers(); - private: void notifyEngineRemoteServerRunning(const QByteArray &, int pid); void notifyEngineRemoteSetupFinished(const RemoteSetupResult &result); From 63c5fc034bcab89f11895b6b8a68ab30accf8a31 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 15 Jul 2015 17:14:29 +0200 Subject: [PATCH 42/70] Debugger: Split updateWatchData() paths There are two cases that do not coincide in asynchronous engines such as the QmlEngine: Inserting a new watch item, and expanding the children of an existing item. Change-Id: Ic98a5f1e89aca37146039a241de737c407606e83 Reviewed-by: Christian Stenger --- src/plugins/debugger/debuggerengine.cpp | 7 ++++- src/plugins/debugger/debuggerengine.h | 3 ++- .../debugger/debuggertooltipmanager.cpp | 2 +- src/plugins/debugger/pdb/pdbengine.cpp | 2 +- src/plugins/debugger/pdb/pdbengine.h | 2 +- src/plugins/debugger/qml/qmlcppengine.cpp | 6 ++--- src/plugins/debugger/qml/qmlcppengine.h | 2 +- src/plugins/debugger/qml/qmlengine.cpp | 27 +++++++++++-------- src/plugins/debugger/qml/qmlengine.h | 3 ++- src/plugins/debugger/watchhandler.cpp | 10 +++---- 10 files changed, 38 insertions(+), 26 deletions(-) diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index f05e90d9851..25171f7dead 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -1976,13 +1976,18 @@ bool DebuggerEngine::canHandleToolTip(const DebuggerToolTipContext &context) con return state() == InferiorStopOk && context.isCppEditor; } -void DebuggerEngine::updateWatchData(const QByteArray &iname) +void DebuggerEngine::updateItem(const QByteArray &iname) { UpdateParameters params; params.partialVariable = iname; doUpdateLocals(params); } +void DebuggerEngine::expandItem(const QByteArray &iname) +{ + updateItem(iname); +} + } // namespace Internal } // namespace Debugger diff --git a/src/plugins/debugger/debuggerengine.h b/src/plugins/debugger/debuggerengine.h index eea8e4e7671..e7b1eb0deae 100644 --- a/src/plugins/debugger/debuggerengine.h +++ b/src/plugins/debugger/debuggerengine.h @@ -191,7 +191,8 @@ public: DebuggerRunParameters &runParameters(); virtual bool canHandleToolTip(const DebuggerToolTipContext &) const; - virtual void updateWatchData(const QByteArray &iname); + virtual void expandItem(const QByteArray &iname); // Called when item in tree gets expanded. + virtual void updateItem(const QByteArray &iname); // Called for fresh watch items. virtual void selectWatchData(const QByteArray &iname); virtual void startDebugger(DebuggerRunControl *runControl); diff --git a/src/plugins/debugger/debuggertooltipmanager.cpp b/src/plugins/debugger/debuggertooltipmanager.cpp index 07656201092..e498dcebde3 100644 --- a/src/plugins/debugger/debuggertooltipmanager.cpp +++ b/src/plugins/debugger/debuggertooltipmanager.cpp @@ -1222,7 +1222,7 @@ static void slotTooltipOverrideRequested m_tooltips.push_back(tooltip); tooltip->setState(PendingUnshown); if (engine->canHandleToolTip(context)) { - engine->updateWatchData(context.iname); + engine->updateItem(context.iname); } else { ToolTip::show(point, DebuggerToolTipManager::tr("Expression too complex"), Internal::mainWindow()); diff --git a/src/plugins/debugger/pdb/pdbengine.cpp b/src/plugins/debugger/pdb/pdbengine.cpp index 9c5666eed17..78435e0faa6 100644 --- a/src/plugins/debugger/pdb/pdbengine.cpp +++ b/src/plugins/debugger/pdb/pdbengine.cpp @@ -394,7 +394,7 @@ void PdbEngine::assignValueInDebugger(WatchItem *, const QString &expression, co updateLocals(); } -void PdbEngine::updateWatchData(const QByteArray &iname) +void PdbEngine::updateItem(const QByteArray &iname) { Q_UNUSED(iname); updateAll(); diff --git a/src/plugins/debugger/pdb/pdbengine.h b/src/plugins/debugger/pdb/pdbengine.h index bd16495fbcf..0d17912c879 100644 --- a/src/plugins/debugger/pdb/pdbengine.h +++ b/src/plugins/debugger/pdb/pdbengine.h @@ -96,7 +96,7 @@ private: bool supportsThreads() const { return true; } bool isSynchronous() const { return true; } - void updateWatchData(const QByteArray &iname); + void updateItem(const QByteArray &iname); QString mainPythonFile() const; QString pythonInterpreter() const; diff --git a/src/plugins/debugger/qml/qmlcppengine.cpp b/src/plugins/debugger/qml/qmlcppengine.cpp index 160720465ae..7248d7846c6 100644 --- a/src/plugins/debugger/qml/qmlcppengine.cpp +++ b/src/plugins/debugger/qml/qmlcppengine.cpp @@ -114,12 +114,12 @@ bool QmlCppEngine::canHandleToolTip(const DebuggerToolTipContext &ctx) const return success; } -void QmlCppEngine::updateWatchData(const QByteArray &iname) +void QmlCppEngine::updateItem(const QByteArray &iname) { if (iname.startsWith("inspect.")) - m_qmlEngine->updateWatchData(iname); + m_qmlEngine->updateItem(iname); else - m_activeEngine->updateWatchData(iname); + m_activeEngine->updateItem(iname); } void QmlCppEngine::selectWatchData(const QByteArray &iname) diff --git a/src/plugins/debugger/qml/qmlcppengine.h b/src/plugins/debugger/qml/qmlcppengine.h index 9985b747783..b0260a6d710 100644 --- a/src/plugins/debugger/qml/qmlcppengine.h +++ b/src/plugins/debugger/qml/qmlcppengine.h @@ -48,7 +48,7 @@ public: bool canDisplayTooltip() const; bool canHandleToolTip(const DebuggerToolTipContext &) const; - void updateWatchData(const QByteArray &iname); + void updateItem(const QByteArray &iname); void selectWatchData(const QByteArray &iname); void watchPoint(const QPoint &); diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp index aab9446c00a..6287a4a5b7e 100644 --- a/src/plugins/debugger/qml/qmlengine.cpp +++ b/src/plugins/debugger/qml/qmlengine.cpp @@ -969,26 +969,31 @@ void QmlEngine::assignValueInDebugger(WatchItem *item, } } -void QmlEngine::updateWatchData(const QByteArray &iname) +void QmlEngine::expandItem(const QByteArray &iname) { const WatchItem *item = watchHandler()->findItem(iname); - // invalid expressions or out of scope variables - if (!item) - return; + QTC_ASSERT(item, return); if (item->isInspect()) { d->inspectorAdapter.agent()->updateWatchData(*item); } else { - if (!item->name.isEmpty()) { - if (item->isChildrenNeeded() && watchHandler()->isExpandedIName(item->iname)) { - LookupItems items; - items.insert(int(item->id), {item->iname, item->name}); - d->lookup(items); - } - } + LookupItems items; + items.insert(int(item->id), {item->iname, item->name}); + d->lookup(items); } } +void QmlEngine::updateItem(const QByteArray &iname) +{ + const WatchItem *item = watchHandler()->findItem(iname); + QTC_ASSERT(item, return); + + QString exp = QString::fromUtf8(item->exp); + d->evaluate(exp, [this, exp](const QVariantMap &response) { + d->handleEvaluateWatcher(response, exp); + }); +} + void QmlEngine::selectWatchData(const QByteArray &iname) { const WatchItem *item = watchHandler()->findItem(iname); diff --git a/src/plugins/debugger/qml/qmlengine.h b/src/plugins/debugger/qml/qmlengine.h index bf51bf3ed42..26f6dd0b3af 100644 --- a/src/plugins/debugger/qml/qmlengine.h +++ b/src/plugins/debugger/qml/qmlengine.h @@ -129,7 +129,8 @@ private: void reloadSourceFiles(); void reloadFullStack() {} - void updateWatchData(const QByteArray &iname); + void updateItem(const QByteArray &iname); + void expandItem(const QByteArray &iname); void selectWatchData(const QByteArray &iname); void executeDebuggerCommand(const QString &command, DebuggerLanguages languages); bool evaluateScript(const QString &expression); diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index 6828971500a..8fbfaec3772 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -683,7 +683,7 @@ void WatchItem::fetchMore() model->m_fetchTriggered.insert(iname); if (children().isEmpty()) { setChildrenNeeded(); - model->m_engine->updateWatchData(iname); + model->m_engine->expandItem(iname); } } @@ -940,12 +940,12 @@ bool WatchModel::setData(const QModelIndex &idx, const QVariant &value, int role case LocalsTypeFormatRole: setTypeFormat(item->type, value.toInt()); - m_engine->updateWatchData(item->iname); + m_engine->updateLocals(); break; case LocalsIndividualFormatRole: { setIndividualFormat(item->iname, value.toInt()); - m_engine->updateWatchData(item->iname); + m_engine->updateLocals(); break; } } @@ -1304,14 +1304,14 @@ void WatchHandler::watchExpression(const QString &exp0, const QString &name) item->exp = exp; item->name = name.isEmpty() ? exp0 : name; item->iname = watcherName(exp); + m_model->insertItem(item); saveWatchers(); if (m_model->m_engine->state() == DebuggerNotReady) { item->setAllUnneeded(); item->setValue(QString(QLatin1Char(' '))); - m_model->insertItem(item); } else { - m_model->m_engine->updateWatchData(item->iname); + m_model->m_engine->updateItem(item->iname); } updateWatchersWindow(); } From 6c9c79d05878fe8f104276dcd03e5e81688198a3 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 16 Jul 2015 08:14:17 +0200 Subject: [PATCH 43/70] Debugger: Make LocationMark draggable Issue a DebuggerEngine::executeJumpToLine() in response. Change-Id: I7be5738241ce91f61002d6f6b49c796824569024 Reviewed-by: Christian Stenger --- src/plugins/debugger/debuggerengine.cpp | 27 +++++++++++++++++++++++-- src/plugins/debugger/debuggerengine.h | 2 ++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index 25171f7dead..96638cef077 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -134,6 +134,29 @@ Location::Location(const StackFrame &frame, bool marker) } +class LocationMark : public TextMark +{ +public: + LocationMark(DebuggerEngine *engine, const QString &file, int line) + : TextMark(file, line, Constants::TEXT_MARK_CATEGORY_LOCATION), m_engine(engine) + {} + +private: + bool isDraggable() const { return true; } + + void dragToLine(int line) + { + if (m_engine) { + ContextData data; + data.fileName = fileName(); + data.lineNumber = line; + m_engine->executeJumpToLine(data); + } + } + + QPointer m_engine; +}; + ////////////////////////////////////////////////////////////////////// // // DebuggerEnginePrivate @@ -319,7 +342,7 @@ public: DisassemblerAgent m_disassemblerAgent; MemoryAgent m_memoryAgent; - QScopedPointer m_locationMark; + QScopedPointer m_locationMark; QTimer m_locationTimer; bool m_isStateDebugging; @@ -610,7 +633,7 @@ void DebuggerEngine::gotoLocation(const Location &loc) editor->document()->setProperty(Constants::OPENED_BY_DEBUGGER, true); if (loc.needsMarker()) { - d->m_locationMark.reset(new TextMark(file, line, Constants::TEXT_MARK_CATEGORY_LOCATION)); + d->m_locationMark.reset(new LocationMark(this, file, line)); d->m_locationMark->setIcon(Internal::locationMarkIcon()); d->m_locationMark->setPriority(TextMark::HighPriority); } diff --git a/src/plugins/debugger/debuggerengine.h b/src/plugins/debugger/debuggerengine.h index e7b1eb0deae..c830a0ded35 100644 --- a/src/plugins/debugger/debuggerengine.h +++ b/src/plugins/debugger/debuggerengine.h @@ -65,6 +65,7 @@ class MemoryAgent; class WatchData; class WatchItem; class BreakHandler; +class LocationMark; class ModulesHandler; class RegisterHandler; class StackHandler; @@ -441,6 +442,7 @@ private: virtual void setState(DebuggerState state, bool forced = false); friend class DebuggerEnginePrivate; + friend class LocationMark; DebuggerEnginePrivate *d; }; From 7bc397b1ff61ddbed3e16cb22bfc20b59143988d Mon Sep 17 00:00:00 2001 From: Nikita Baryshnikov Date: Thu, 16 Jul 2015 01:53:25 +0300 Subject: [PATCH 44/70] GitPlugin: reorder namespaces endin that is all:) Change-Id: Idf32e241f6c94f5717518b4e0f66f41ea8aed034 Reviewed-by: Orgad Shaneh Reviewed-by: Tobias Hunger --- src/plugins/git/gitplugin.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/git/gitplugin.h b/src/plugins/git/gitplugin.h index 5ed7b29e674..8db2e37ed40 100644 --- a/src/plugins/git/gitplugin.h +++ b/src/plugins/git/gitplugin.h @@ -240,7 +240,7 @@ private: bool m_submitActionTriggered; }; -} // namespace Git } // namespace Internal +} // namespace Git #endif // GITPLUGIN_H From 0bc18df6554acdcc91654e719c0ee49482d21d2d Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Thu, 16 Jul 2015 11:54:11 +0200 Subject: [PATCH 45/70] Clang: Do not work on unspecified values in ProjectParts::remove Change-Id: Icc322bc64988cbc1b5ec4e6d6474b1b6b956c667 Reviewed-by: Nikolai Kosjar --- src/tools/clangbackend/ipcsource/projects.cpp | 13 +++++++++---- tests/unit/unittest/projecttest.cpp | 14 +++++++++++++- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/tools/clangbackend/ipcsource/projects.cpp b/src/tools/clangbackend/ipcsource/projects.cpp index 34dcc5e059b..42bdfde86d0 100644 --- a/src/tools/clangbackend/ipcsource/projects.cpp +++ b/src/tools/clangbackend/ipcsource/projects.cpp @@ -46,11 +46,16 @@ void ProjectParts::remove(const Utf8StringVector &projectPartIds) { Utf8StringVector processedProjectPartFilePaths = projectPartIds; - auto removeBeginIterator = std::remove_if(projects_.begin(), projects_.end(), [&processedProjectPartFilePaths] (const ProjectPart &project) { - return processedProjectPartFilePaths.removeFast(project.projectPartId()); - }); + const auto removeBeginIterator = std::remove_if(projects_.begin(), projects_.end(), + [&processedProjectPartFilePaths] (ProjectPart &project) { + const bool isRemoved = processedProjectPartFilePaths.removeFast(project.projectPartId()); + + if (isRemoved) + project.clearProjectPartId(); + + return isRemoved; + }); - std::for_each(removeBeginIterator, projects_.end(), [](ProjectPart &project) { project.clearProjectPartId(); }); projects_.erase(removeBeginIterator, projects_.end()); if (!processedProjectPartFilePaths.isEmpty()) diff --git a/tests/unit/unittest/projecttest.cpp b/tests/unit/unittest/projecttest.cpp index facf06dc376..07701dccc5e 100644 --- a/tests/unit/unittest/projecttest.cpp +++ b/tests/unit/unittest/projecttest.cpp @@ -153,7 +153,7 @@ TEST(ProjectPart, ProjectPartProjectPartIdIsEmptyfterRemoving) ASSERT_TRUE(project.projectPartId().isEmpty()); } -TEST(Project, ThrowsForNotExistingProjectPartButRemovesAllExistingProject) +TEST(ProjectPart, ThrowsForNotExistingProjectPartButRemovesAllExistingProject) { ClangBackEnd::ProjectPartContainer projectContainer(Utf8StringLiteral("pathToProjectPart.pro")); ClangBackEnd::ProjectParts projects; @@ -165,6 +165,18 @@ TEST(Project, ThrowsForNotExistingProjectPartButRemovesAllExistingProject) ASSERT_THAT(projects.projects(), Not(Contains(project))); } +TEST(ProjectPart, ProjectPartIdIsEmptyAfterRemove) +{ + ClangBackEnd::ProjectPartContainer projectContainer(Utf8StringLiteral("pathToProjectPart.pro")); + ClangBackEnd::ProjectParts projects; + projects.createOrUpdate({projectContainer}); + ClangBackEnd::ProjectPart project = *projects.findProjectPart(projectContainer.projectPartId()); + + projects.remove({projectContainer.projectPartId()}); + + ASSERT_THAT(project.projectPartId(), Utf8String()); +} + TEST(ProjectPart, HasProjectPart) { ClangBackEnd::ProjectPartContainer projectContainer(Utf8StringLiteral("pathToProjectPart.pro")); From c81407f28db0df84906984dd6a4e5d665df6070c Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 16 Jul 2015 08:49:43 +0200 Subject: [PATCH 46/70] Debugger: Lift restriction one-shot breakpoints deletion This was/is a workaround to not lose the extra information carefully crafted one-shot-breakpoints might carry (e.g. conditions). However, it gets into the way when simple one-shot breakpoints are used automatically ("Jump to line", or native-mixed debugging), so actually deleting the bp in the ui if it's gone on the debugger side seems the lesser evil nowadays. Change-Id: If00dc4e8f27881236c05b17109b57d7c53d424ab Reviewed-by: Christian Stenger --- src/plugins/debugger/breakhandler.cpp | 1 + src/plugins/debugger/gdb/gdbengine.cpp | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/plugins/debugger/breakhandler.cpp b/src/plugins/debugger/breakhandler.cpp index 969b011a9c5..baaef60d340 100644 --- a/src/plugins/debugger/breakhandler.cpp +++ b/src/plugins/debugger/breakhandler.cpp @@ -802,6 +802,7 @@ bool Breakpoint::isOneShot() const { return parameters().oneShot; } void Breakpoint::removeAlienBreakpoint() { + b->m_state = BreakpointRemoveProceeding; b->deleteThis(); } diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 16a2300247c..99135a09a71 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -598,8 +598,9 @@ void GdbEngine::handleResponse(const QByteArray &buff) // This also triggers when a temporary breakpoint is hit. // We do not really want that, as this loses all information. // FIXME: Use a special marker for this case? - if (!bp.isOneShot()) - bp.removeAlienBreakpoint(); + // if (!bp.isOneShot()) ... is not sufficient. + // It keeps temporary "Jump" breakpoints alive. + bp.removeAlienBreakpoint(); } } else if (asyncClass == "cmd-param-changed") { // New since 2012-08-09 From 3f084fa026a8a402583a91ef7882d49a24629542 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 16 Jul 2015 13:45:43 +0200 Subject: [PATCH 47/70] Debugger: Split update/expand paths also in mixed engine Change-Id: Ic341e4a3e974cfde3fbf4afd8cef41080b922067 Reviewed-by: Christian Stenger --- src/plugins/debugger/qml/qmlcppengine.cpp | 8 ++++++++ src/plugins/debugger/qml/qmlcppengine.h | 1 + 2 files changed, 9 insertions(+) diff --git a/src/plugins/debugger/qml/qmlcppengine.cpp b/src/plugins/debugger/qml/qmlcppengine.cpp index 7248d7846c6..a4277005120 100644 --- a/src/plugins/debugger/qml/qmlcppengine.cpp +++ b/src/plugins/debugger/qml/qmlcppengine.cpp @@ -122,6 +122,14 @@ void QmlCppEngine::updateItem(const QByteArray &iname) m_activeEngine->updateItem(iname); } +void QmlCppEngine::expandItem(const QByteArray &iname) +{ + if (iname.startsWith("inspect.")) + m_qmlEngine->expandItem(iname); + else + m_activeEngine->expandItem(iname); +} + void QmlCppEngine::selectWatchData(const QByteArray &iname) { if (iname.startsWith("inspect.")) diff --git a/src/plugins/debugger/qml/qmlcppengine.h b/src/plugins/debugger/qml/qmlcppengine.h index b0260a6d710..3b2ecc9137f 100644 --- a/src/plugins/debugger/qml/qmlcppengine.h +++ b/src/plugins/debugger/qml/qmlcppengine.h @@ -49,6 +49,7 @@ public: bool canDisplayTooltip() const; bool canHandleToolTip(const DebuggerToolTipContext &) const; void updateItem(const QByteArray &iname); + void expandItem(const QByteArray &iname); void selectWatchData(const QByteArray &iname); void watchPoint(const QPoint &); From 184b16122418bc791433365202cea0bdf6d0c641 Mon Sep 17 00:00:00 2001 From: Robert Loehning Date: Thu, 16 Jul 2015 12:34:18 +0200 Subject: [PATCH 48/70] Squish: Adjust expectations when using clang codemodel Change-Id: I204ff6eb3820f67d50f8f4b77012d538741cec47 Reviewed-by: Robert Loehning Reviewed-by: Christian Stenger --- tests/system/suite_CSUP/tst_CSUP06/test.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/system/suite_CSUP/tst_CSUP06/test.py b/tests/system/suite_CSUP/tst_CSUP06/test.py index a8881a80507..c71fca6f4a8 100644 --- a/tests/system/suite_CSUP/tst_CSUP06/test.py +++ b/tests/system/suite_CSUP/tst_CSUP06/test.py @@ -94,7 +94,7 @@ def checkIncludeCompletion(editor): if inclSnippet in missing: test.compare(changedLine, currentLine.lstrip("/"), "Include has not been modified.") else: - test.verify(changedLine.endswith('>') or changedLine.endswith('"'), + test.verify(changedLine[-1] in '>"/', "'%s' has been completed to '%s'" % (currentLine.lstrip("/"), changedLine)) performAutoCompletionTest(editor, ".*Complete includes.*", "//#include", @@ -118,9 +118,12 @@ def checkSymbolCompletion(editor, isClangCodeModel): if not isClangCodeModel: expectedSuggestion["using namespace st"] = ["std", "st"] missing.remove("using namespace st") - elif platform.system() in ('Microsoft', 'Windows'): - expectedSuggestion["using namespace st"] = ["std", "stdext"] - missing.remove("using namespace st") + else: + missing.remove("internal.o") + expectedSuggestion["internal.o"] = ["one", "operator="] + if platform.system() in ('Microsoft', 'Windows'): + expectedSuggestion["using namespace st"] = ["std", "stdext"] + missing.remove("using namespace st") # define test function to perform the _real_ auto completion test on the current line def testSymb(currentLine, *args): missing, expectedSug, expectedRes = args From f77f6e214480bacff055406de0043b4ee4ceec28 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 15 Jul 2015 17:49:04 +0200 Subject: [PATCH 49/70] Debugger: Make QmlEngine heed "Sort Struct Members Alphabetically" Change-Id: Ib24e62c60eea4b0af355c3e93e48a78dc0b51efc Reviewed-by: Christian Stenger --- src/plugins/debugger/qml/qmlengine.cpp | 13 +++++++++++++ src/plugins/debugger/qml/qmlengine.h | 1 + 2 files changed, 14 insertions(+) diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp index 6287a4a5b7e..0b38cf8424d 100644 --- a/src/plugins/debugger/qml/qmlengine.cpp +++ b/src/plugins/debugger/qml/qmlengine.cpp @@ -62,6 +62,7 @@ #include #include +#include #include #include @@ -90,6 +91,7 @@ using namespace ProjectExplorer; using namespace QmlDebug; using namespace QmlJS; using namespace TextEditor; +using namespace Utils; namespace Debugger { namespace Internal { @@ -937,6 +939,11 @@ void QmlEngine::reloadSourceFiles() d->scripts(4, QList(), true, QVariant()); } +void QmlEngine::updateAll() +{ + d->updateLocals(); +} + void QmlEngine::requestModuleSymbols(const QString &moduleName) { Q_UNUSED(moduleName) @@ -2354,6 +2361,12 @@ void QmlEnginePrivate::insertSubItems(WatchItem *parent, const QVariantList &pro item->setHasChildren(propertyData.properties.count()); parent->appendChild(item); } + + if (boolSetting(SortStructMembers)) + parent->sortChildren([](const TreeItem *item1, const TreeItem *item2) -> bool { + return static_cast(item1)->name + < static_cast(item2)->name; + }); } void QmlEnginePrivate::handleExecuteDebuggerCommand(const QVariantMap &response) diff --git a/src/plugins/debugger/qml/qmlengine.h b/src/plugins/debugger/qml/qmlengine.h index 26f6dd0b3af..18527199950 100644 --- a/src/plugins/debugger/qml/qmlengine.h +++ b/src/plugins/debugger/qml/qmlengine.h @@ -129,6 +129,7 @@ private: void reloadSourceFiles(); void reloadFullStack() {} + void updateAll(); void updateItem(const QByteArray &iname); void expandItem(const QByteArray &iname); void selectWatchData(const QByteArray &iname); From 8d23d80139eae570fe8496c39e9dc1be0782af17 Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Thu, 16 Jul 2015 12:32:02 +0200 Subject: [PATCH 50/70] Clang: Clear the project part completely on remove Change-Id: I6fdb1766a3b407fbaaf86b0216a0dd710673aec1 Reviewed-by: Marco Bubke --- src/tools/clangbackend/ipcsource/projectpart.cpp | 4 +++- src/tools/clangbackend/ipcsource/projectpart.h | 2 +- src/tools/clangbackend/ipcsource/projects.cpp | 2 +- tests/unit/unittest/projecttest.cpp | 6 +++++- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/tools/clangbackend/ipcsource/projectpart.cpp b/src/tools/clangbackend/ipcsource/projectpart.cpp index 9e25a7864e1..ed240c2fa4b 100644 --- a/src/tools/clangbackend/ipcsource/projectpart.cpp +++ b/src/tools/clangbackend/ipcsource/projectpart.cpp @@ -98,9 +98,11 @@ ProjectPart &ProjectPart::operator=(ProjectPart &&other) return *this; } -void ProjectPart::clearProjectPartId() +void ProjectPart::clear() { d->projectPartId.clear(); + d->clearArguments(); + updateLastChangeTimePoint(); } const Utf8String &ProjectPart::projectPartId() const diff --git a/src/tools/clangbackend/ipcsource/projectpart.h b/src/tools/clangbackend/ipcsource/projectpart.h index f5191cb5ad3..5c318be7f5f 100644 --- a/src/tools/clangbackend/ipcsource/projectpart.h +++ b/src/tools/clangbackend/ipcsource/projectpart.h @@ -58,7 +58,7 @@ public: ProjectPart(ProjectPart &&project); ProjectPart &operator=(ProjectPart &&project); - void clearProjectPartId(); + void clear(); const Utf8String &projectPartId() const; diff --git a/src/tools/clangbackend/ipcsource/projects.cpp b/src/tools/clangbackend/ipcsource/projects.cpp index 42bdfde86d0..5bb960fccbd 100644 --- a/src/tools/clangbackend/ipcsource/projects.cpp +++ b/src/tools/clangbackend/ipcsource/projects.cpp @@ -51,7 +51,7 @@ void ProjectParts::remove(const Utf8StringVector &projectPartIds) const bool isRemoved = processedProjectPartFilePaths.removeFast(project.projectPartId()); if (isRemoved) - project.clearProjectPartId(); + project.clear(); return isRemoved; }); diff --git a/tests/unit/unittest/projecttest.cpp b/tests/unit/unittest/projecttest.cpp index 07701dccc5e..78aab7c7bea 100644 --- a/tests/unit/unittest/projecttest.cpp +++ b/tests/unit/unittest/projecttest.cpp @@ -165,16 +165,20 @@ TEST(ProjectPart, ThrowsForNotExistingProjectPartButRemovesAllExistingProject) ASSERT_THAT(projects.projects(), Not(Contains(project))); } -TEST(ProjectPart, ProjectPartIdIsEmptyAfterRemove) +TEST(ProjectPart, ProjectPartIsClearedAfterRemove) { ClangBackEnd::ProjectPartContainer projectContainer(Utf8StringLiteral("pathToProjectPart.pro")); ClangBackEnd::ProjectParts projects; projects.createOrUpdate({projectContainer}); ClangBackEnd::ProjectPart project = *projects.findProjectPart(projectContainer.projectPartId()); + const auto lastChangeTimePoint = project.lastChangeTimePoint(); + std::this_thread::sleep_for(std::chrono::steady_clock::duration(1)); projects.remove({projectContainer.projectPartId()}); ASSERT_THAT(project.projectPartId(), Utf8String()); + ASSERT_THAT(project.argumentCount(), 0); + ASSERT_THAT(project.lastChangeTimePoint(), Gt(lastChangeTimePoint)); } TEST(ProjectPart, HasProjectPart) From 336501943ef71a9ec28c0768fdc61c0ca54c24ca Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Wed, 15 Jul 2015 16:59:19 +0200 Subject: [PATCH 51/70] Clang: Add tooltip for clang snippets Change-Id: Ifccfd72c52910c6e1086d6c782552c60fbb89f5f Reviewed-by: Nikolai Kosjar --- .../clangcompletionassistprocessor.cpp | 10 ++++------ .../completionchunkstotextconverter.cpp | 12 ++++++++++++ .../clangcodemodel/completionchunkstotextconverter.h | 2 +- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp b/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp index 61c893601eb..505b5fcc223 100644 --- a/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp +++ b/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp @@ -100,14 +100,12 @@ QList toAssistProposalItems(const CodeCompletions &complet item = new ClangAssistProposalItem; items.insert(name, item); item->setText(name); - item->setDetail(ccr.hint().toString()); item->setOrder(ccr.priority()); - const QString snippet = ccr.snippet().toString(); - if (!snippet.isEmpty()) - item->setData(snippet); - else - item->setData(qVariantFromValue(ccr)); + if (ccr.completionKind() == CodeCompletion::KeywordCompletionKind) + item->setDetail(CompletionChunksToTextConverter::convertToToolTip(ccr.chunks())); + + item->setData(QVariant::fromValue(ccr)); } // FIXME: show the effective accessebility instead of availability diff --git a/src/plugins/clangcodemodel/completionchunkstotextconverter.cpp b/src/plugins/clangcodemodel/completionchunkstotextconverter.cpp index 3c7c58c6a3c..92d9c300744 100644 --- a/src/plugins/clangcodemodel/completionchunkstotextconverter.cpp +++ b/src/plugins/clangcodemodel/completionchunkstotextconverter.cpp @@ -114,6 +114,18 @@ QString CompletionChunksToTextConverter::convertToName(const QVector &codeCompletionChunks) +{ + CompletionChunksToTextConverter converter; + converter.setAddPlaceHolderText(true); + converter.setAddSpaces(true); + converter.setAddExtraVerticalSpaceBetweenBraces(true); + + converter.parseChunks(codeCompletionChunks); + + return converter.text(); +} + void CompletionChunksToTextConverter::parse(const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk) { using ClangBackEnd::CodeCompletionChunk; diff --git a/src/plugins/clangcodemodel/completionchunkstotextconverter.h b/src/plugins/clangcodemodel/completionchunkstotextconverter.h index 32a9a040989..6e1e6b290fb 100644 --- a/src/plugins/clangcodemodel/completionchunkstotextconverter.h +++ b/src/plugins/clangcodemodel/completionchunkstotextconverter.h @@ -59,7 +59,7 @@ public: static QString convertToFunctionSignature(const QVector &codeCompletionChunks); static QString convertToName(const QVector &codeCompletionChunks); - + static QString convertToToolTip(const QVector &codeCompletionChunks); private: void parse(const ClangBackEnd::CodeCompletionChunk & codeCompletionChunk); void parseResultType(const Utf8String &text); From 5df8085529883e82e082a2cf1b1e28a906da8ea1 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Wed, 15 Jul 2015 12:42:12 +0200 Subject: [PATCH 52/70] Clang: Remove the hint and snippet field from the CodeCompletion It is not used and is producing overhead. Change-Id: I1398b18a40c0f5c0b90fe4c058996d7eb109f9f2 Reviewed-by: Nikolai Kosjar --- src/libs/clangbackendipc/codecompletion.cpp | 21 --------------------- src/libs/clangbackendipc/codecompletion.h | 7 ------- tests/unit/unittest/clangipcservertest.cpp | 12 ------------ tests/unit/unittest/codecompletiontest.cpp | 14 -------------- 4 files changed, 54 deletions(-) diff --git a/src/libs/clangbackendipc/codecompletion.cpp b/src/libs/clangbackendipc/codecompletion.cpp index 5e4d010de48..e9c5ad569f2 100644 --- a/src/libs/clangbackendipc/codecompletion.cpp +++ b/src/libs/clangbackendipc/codecompletion.cpp @@ -38,15 +38,11 @@ namespace ClangBackEnd { CodeCompletion::CodeCompletion(const Utf8String &text, - const Utf8String &hint, - const Utf8String &snippet, quint32 priority, Kind completionKind, Availability availability, bool hasParameters) : text_(text), - hint_(hint), - snippet_(snippet), priority_(priority), completionKind_(completionKind), availability_(availability), @@ -63,15 +59,6 @@ const Utf8String &CodeCompletion::text() const { return text_; } -const Utf8String &CodeCompletion::hint() const -{ - return hint_; -} - -const Utf8String &CodeCompletion::snippet() const -{ - return snippet_; -} void CodeCompletion::setCompletionKind(CodeCompletion::Kind completionKind) { @@ -136,8 +123,6 @@ quint32 &CodeCompletion::availabilityAsInt() QDataStream &operator<<(QDataStream &out, const CodeCompletion &command) { out << command.text_; - out << command.hint_; - out << command.snippet_; out << command.chunks_; out << command.priority_; out << command.completionKind_; @@ -150,8 +135,6 @@ QDataStream &operator<<(QDataStream &out, const CodeCompletion &command) QDataStream &operator>>(QDataStream &in, CodeCompletion &command) { in >> command.text_; - in >> command.hint_; - in >> command.snippet_; in >> command.chunks_; in >> command.priority_; in >> command.completionKindAsInt(); @@ -213,8 +196,6 @@ QDebug operator<<(QDebug debug, const CodeCompletion &command) debug.nospace() << "CodeCompletion("; debug.nospace() << command.text_ << ", "; - debug.nospace() << command.hint_ << ", "; - debug.nospace() << command.snippet_ << ", "; debug.nospace() << command.priority_ << ", "; debug.nospace() << completionKindToString(command.completionKind_) << ", "; debug.nospace() << availabilityToString(command.availability_) << ", "; @@ -230,8 +211,6 @@ void PrintTo(const CodeCompletion &command, ::std::ostream* os) *os << "CodeCompletion("; *os << command.text_.constData() << ", "; - *os << command.hint_.constData() << ", "; - *os << command.snippet_.constData() << ", "; *os << command.priority_ << ", "; *os << completionKindToString(command.completionKind_) << ", "; *os << availabilityToString(command.availability_) << ", "; diff --git a/src/libs/clangbackendipc/codecompletion.h b/src/libs/clangbackendipc/codecompletion.h index 44f34a8b090..5c7064b5e5b 100644 --- a/src/libs/clangbackendipc/codecompletion.h +++ b/src/libs/clangbackendipc/codecompletion.h @@ -80,8 +80,6 @@ public: public: CodeCompletion() = default; CodeCompletion(const Utf8String &text, - const Utf8String &hint = Utf8String(), - const Utf8String &snippet = Utf8String(), quint32 priority = 0, Kind completionKind = Other, Availability availability = Available, @@ -90,9 +88,6 @@ public: void setText(const Utf8String &text); const Utf8String &text() const; - const Utf8String &hint() const; - const Utf8String &snippet() const; - void setCompletionKind(Kind completionKind); Kind completionKind() const; @@ -114,8 +109,6 @@ private: private: Utf8String text_; - Utf8String hint_; - Utf8String snippet_; QVector chunks_; quint32 priority_ = 0; Kind completionKind_ = Other; diff --git a/tests/unit/unittest/clangipcservertest.cpp b/tests/unit/unittest/clangipcservertest.cpp index 1c7c74da79d..690e03b0b19 100644 --- a/tests/unit/unittest/clangipcservertest.cpp +++ b/tests/unit/unittest/clangipcservertest.cpp @@ -149,8 +149,6 @@ TEST_F(ClangIpcServer, GetCodeCompletion) 1, projectPartId); CodeCompletion codeCompletion(Utf8StringLiteral("Function"), - Utf8String(), - Utf8String(), 34, CodeCompletion::FunctionCompletionKind); @@ -167,8 +165,6 @@ TEST_F(ClangIpcServer, GetCodeCompletionDependingOnArgumets) 1, projectPartId); CodeCompletion codeCompletion(Utf8StringLiteral("ArgumentDefinitionVariable"), - Utf8String(), - Utf8String(), 34, CodeCompletion::VariableCompletionKind); @@ -214,8 +210,6 @@ TEST_F(ClangIpcServer, GetCodeCompletionForUnsavedFile) 1, projectPartId); CodeCompletion codeCompletion(Utf8StringLiteral("Method2"), - Utf8String(), - Utf8String(), 34, CodeCompletion::FunctionCompletionKind); @@ -233,8 +227,6 @@ TEST_F(ClangIpcServer, GetNoCodeCompletionAfterRemovingUnsavedFile) 1, projectPartId); CodeCompletion codeCompletion(Utf8StringLiteral("Method2"), - Utf8String(), - Utf8String(), 34, CodeCompletion::FunctionCompletionKind); @@ -255,8 +247,6 @@ TEST_F(ClangIpcServer, GetNewCodeCompletionAfterUpdatingUnsavedFile) 1, projectPartId); CodeCompletion codeCompletion(Utf8StringLiteral("Method3"), - Utf8String(), - Utf8String(), 34, CodeCompletion::FunctionCompletionKind); @@ -367,8 +357,6 @@ TEST_F(ClangIpcServer, TicketNumberIsForwarded) 1, projectPartId); CodeCompletion codeCompletion(Utf8StringLiteral("Function"), - Utf8String(), - Utf8String(), 34, CodeCompletion::FunctionCompletionKind); diff --git a/tests/unit/unittest/codecompletiontest.cpp b/tests/unit/unittest/codecompletiontest.cpp index efb4551a0ab..62bbbb6b9ca 100644 --- a/tests/unit/unittest/codecompletiontest.cpp +++ b/tests/unit/unittest/codecompletiontest.cpp @@ -95,28 +95,18 @@ TEST_F(CodeCompleter, FunctionInUnsavedFile) { ASSERT_THAT(completer.complete(100, 1), AllOf(Contains(CodeCompletion(Utf8StringLiteral("functionWithArguments"), - Utf8String(), - Utf8String(), 0, CodeCompletion::FunctionCompletionKind)), Contains(CodeCompletion(Utf8StringLiteral("function"), - Utf8String(), - Utf8String(), 0, CodeCompletion::FunctionCompletionKind)), Contains(CodeCompletion(Utf8StringLiteral("newFunction"), - Utf8String(), - Utf8String(), 0, CodeCompletion::FunctionCompletionKind)), Contains(CodeCompletion(Utf8StringLiteral("f"), - Utf8String(), - Utf8String(), 0, CodeCompletion::FunctionCompletionKind)), Not(Contains(CodeCompletion(Utf8StringLiteral("otherFunction"), - Utf8String(), - Utf8String(), 0, CodeCompletion::FunctionCompletionKind))))); } @@ -126,8 +116,6 @@ TEST_F(CodeCompleter, Macro) { ASSERT_THAT(completer.complete(100, 1), Contains(CodeCompletion(Utf8StringLiteral("Macro"), - Utf8String(), - Utf8String(), 0, CodeCompletion::PreProcessorCompletionKind))); } @@ -136,8 +124,6 @@ TEST_F(CodeCompleter, Keyword) { ASSERT_THAT(completer.complete(100, 1), Contains(CodeCompletion(Utf8StringLiteral("switch"), - Utf8String(), - Utf8String(), 0, CodeCompletion::KeywordCompletionKind))); } From f6d67bebcfbe584240c158d8ad058c0223cc2f88 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Wed, 15 Jul 2015 17:38:46 +0200 Subject: [PATCH 53/70] Clang: Decrease the priority of operators Change-Id: Ib04d2a14989fd221ab6d8f36c92d3520261b99ee Reviewed-by: Nikolai Kosjar --- .../ipcsource/codecompletionsextractor.cpp | 19 +++++++++++++++++++ .../ipcsource/codecompletionsextractor.h | 1 + 2 files changed, 20 insertions(+) diff --git a/src/tools/clangbackend/ipcsource/codecompletionsextractor.cpp b/src/tools/clangbackend/ipcsource/codecompletionsextractor.cpp index c6a5febe76d..56e826db6fd 100644 --- a/src/tools/clangbackend/ipcsource/codecompletionsextractor.cpp +++ b/src/tools/clangbackend/ipcsource/codecompletionsextractor.cpp @@ -109,6 +109,7 @@ void CodeCompletionsExtractor::extractCompletionKind() extractMethodCompletionKind(); break; case CXCursor_FunctionDecl: + case CXCursor_ConversionFunction: currentCodeCompletion_.setCompletionKind(CodeCompletion::FunctionCompletionKind); break; case CXCursor_VariableRef: @@ -259,6 +260,7 @@ void CodeCompletionsExtractor::adaptPriority() decreasePriorityForNonAvailableCompletions(); decreasePriorityForQObjectInternals(); decreasePriorityForSignals(); + decreasePriorityForOperators(); } void CodeCompletionsExtractor::decreasePriorityForNonAvailableCompletions() @@ -295,6 +297,23 @@ void CodeCompletionsExtractor::decreasePriorityForQObjectInternals() currentCodeCompletion_.setPriority(priority); } +bool isOperator(CXCursorKind cxCursorKind, const Utf8String &name) +{ + return cxCursorKind == CXCursor_ConversionFunction + || (cxCursorKind == CXCursor_CXXMethod + && name.startsWith(Utf8StringLiteral("operator"))); +} + +void CodeCompletionsExtractor::decreasePriorityForOperators() +{ + quint32 priority = currentCodeCompletion_.priority(); + + if (isOperator(currentCxCodeCompleteResult.CursorKind, currentCodeCompletion().text())) + priority *= 100; + + currentCodeCompletion_.setPriority(priority); +} + bool CodeCompletionsExtractor::hasText(const Utf8String &text, CXCompletionString cxCompletionString) const { const uint completionChunkCount = clang_getNumCompletionChunks(cxCompletionString); diff --git a/src/tools/clangbackend/ipcsource/codecompletionsextractor.h b/src/tools/clangbackend/ipcsource/codecompletionsextractor.h index 2456d42fe9c..f01b12b64cb 100644 --- a/src/tools/clangbackend/ipcsource/codecompletionsextractor.h +++ b/src/tools/clangbackend/ipcsource/codecompletionsextractor.h @@ -72,6 +72,7 @@ private: void decreasePriorityForDestructors(); void decreasePriorityForSignals(); void decreasePriorityForQObjectInternals(); + void decreasePriorityForOperators(); bool hasText(const Utf8String &text, CXCompletionString cxCompletionString) const; From 799461ee7ab1c0e6ede542845a6791b2044c9d4c Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 16 Jul 2015 14:12:16 +0200 Subject: [PATCH 54/70] Debugger: Fix evaluation of "this" item in JS debugger Change-Id: I88a502f044fca4c842c21563988d0a95e128c664 Reviewed-by: Christian Stenger --- src/plugins/debugger/qml/qmlengine.cpp | 27 ++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp index 0b38cf8424d..d10984c41ae 100644 --- a/src/plugins/debugger/qml/qmlengine.cpp +++ b/src/plugins/debugger/qml/qmlengine.cpp @@ -165,7 +165,7 @@ public: void handleBacktrace(const QVariantMap &response); void handleLookup(const QVariantMap &response); void handleExecuteDebuggerCommand(const QVariantMap &response); - void handleEvaluateWatcher(const QVariantMap &response, const QString &expr); + void handleEvaluateExpression(const QVariantMap &response, const QByteArray &iname, const QString &expr); void handleFrame(const QVariantMap &response); void handleScope(const QVariantMap &response); void handleVersion(const QVariantMap &response); @@ -996,8 +996,8 @@ void QmlEngine::updateItem(const QByteArray &iname) QTC_ASSERT(item, return); QString exp = QString::fromUtf8(item->exp); - d->evaluate(exp, [this, exp](const QVariantMap &response) { - d->handleEvaluateWatcher(response, exp); + d->evaluate(exp, [this, iname, exp](const QVariantMap &response) { + d->handleEvaluateExpression(response, iname, exp); }); } @@ -1356,7 +1356,9 @@ void QmlEnginePrivate::evaluate(const QString expr, const QmlCallback &cb) runCommand(cmd, cb); } -void QmlEnginePrivate::handleEvaluateWatcher(const QVariantMap &response, const QString &exp) +void QmlEnginePrivate::handleEvaluateExpression(const QVariantMap &response, + const QByteArray &iname, + const QString &exp) { // { "seq" : , // "type" : "response", @@ -1371,8 +1373,6 @@ void QmlEnginePrivate::handleEvaluateWatcher(const QVariantMap &response, const QmlV8ObjectData body = extractData(bodyVal); WatchHandler *watchHandler = engine->watchHandler(); - QByteArray iname = watchHandler->watcherName(exp.toLatin1()); - auto item = new WatchItem(iname, exp); item->exp = exp.toLatin1(); item->id = body.handle; @@ -1385,8 +1385,8 @@ void QmlEnginePrivate::handleEvaluateWatcher(const QVariantMap &response, const //Do not set type since it is unknown item->setError(body.value.toString()); } - watchHandler->insertItem(item); insertSubItems(item, body.properties); + watchHandler->insertItem(item); } void QmlEnginePrivate::lookup(const LookupItems &items) @@ -2188,7 +2188,10 @@ void QmlEnginePrivate::handleFrame(const QVariantMap &response) // Always add a "this" variable { - auto item = new WatchItem("local.this", QLatin1String("this")); + QByteArray iname = "local.this"; + QString exp = QLatin1String("this"); + + auto item = new WatchItem(iname, exp); QmlV8ObjectData objectData = extractData(body.value(_("receiver"))); item->id = objectData.handle; item->type = objectData.type; @@ -2201,6 +2204,9 @@ void QmlEnginePrivate::handleFrame(const QVariantMap &response) item->id = 0; } watchHandler->insertItem(item); + evaluate(exp, [this, iname, exp](const QVariantMap &response) { + handleEvaluateExpression(response, iname, exp); + }); } currentFrameScopes.clear(); @@ -2220,8 +2226,9 @@ void QmlEnginePrivate::handleFrame(const QVariantMap &response) if (stackHandler->isContentsValid() && stackHandler->currentFrame().isUsable()) { QStringList watchers = watchHandler->watchedExpressions(); foreach (const QString &exp, watchers) { - evaluate(exp, [this, exp](const QVariantMap &response) { - handleEvaluateWatcher(response, exp); + const QByteArray iname = watchHandler->watcherName(exp.toLatin1()); + evaluate(exp, [this, iname, exp](const QVariantMap &response) { + handleEvaluateExpression(response, iname, exp); }); } } From 7a675e2d649fa9aca3b1da1189141fd5525bad15 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 16 Jul 2015 11:13:21 +0200 Subject: [PATCH 55/70] Utils: Make Environment::diff() result not contain common entries The resulting diff contained all the items that were equal as well. Since the function was unused so far, no real harm was done, but the function would be useful to have in the debugger. Change-Id: Ia0b0cea79cfc3ee5442aaf7bb392121590c0f338 Reviewed-by: Tobias Hunger Reviewed-by: Daniel Teske --- src/libs/utils/environment.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libs/utils/environment.cpp b/src/libs/utils/environment.cpp index 500b0166266..298987ee557 100644 --- a/src/libs/utils/environment.cpp +++ b/src/libs/utils/environment.cpp @@ -390,7 +390,8 @@ QList Environment::diff(const Environment &other) const result.append(EnvironmentItem(otherIt.key(), otherIt.value())); ++otherIt; } else { - result.append(EnvironmentItem(otherIt.key(), otherIt.value())); + if (thisIt.value() != otherIt.value()) + result.append(EnvironmentItem(otherIt.key(), otherIt.value())); ++otherIt; ++thisIt; } From d4206752ca2cbbcda46259f9f86cd8c9028661a7 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 16 Jul 2015 11:12:43 +0200 Subject: [PATCH 56/70] Debugger: Only pass environmental differences to inferior This amends 0f46ad4a552439a4b137bc8cab2d6c41edb5cbc0. Passing the whole environment is unneeded, and can cause problems with multi-line variables. Change-Id: I49a32c550ba52737bb8f797e227bb883be8b1df1 Reviewed-by: BogDan Vatra Reviewed-by: Niels Weber --- src/plugins/debugger/gdb/gdbengine.cpp | 10 +++++++--- src/plugins/debugger/lldb/lldbengine.cpp | 12 +++++++++--- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 99135a09a71..5eac84b1169 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -4263,9 +4263,13 @@ void GdbEngine::loadInitScript() void GdbEngine::setEnvironmentVariables() { - if (runParameters().environment.size()) { - foreach (const QString &env, runParameters().environment.toStringList()) - postCommand("-gdb-set environment " + env.toUtf8()); + Environment sysEnv = Environment::systemEnvironment(); + Environment runEnv = runParameters().environment; + foreach (const EnvironmentItem &item, sysEnv.diff(runEnv)) { + if (item.unset) + postCommand("unset environment " + item.name.toUtf8()); + else + postCommand("-gdb-set environment " + item.name.toUtf8() + '=' + item.value.toUtf8()); } } diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp index 753a483199f..860c7f472f4 100644 --- a/src/plugins/debugger/lldb/lldbengine.cpp +++ b/src/plugins/debugger/lldb/lldbengine.cpp @@ -290,9 +290,15 @@ void LldbEngine::startLldbStage2() void LldbEngine::setupInferior() { - if (runParameters().environment.size()) { - foreach (const QString &env, runParameters().environment.toStringList()) - runCommand("env " + env.toUtf8()); + Environment sysEnv = Environment::systemEnvironment(); + Environment runEnv = runParameters().environment; + foreach (const EnvironmentItem &item, sysEnv.diff(runEnv)) { + DebuggerCommand cmd("executeDebuggerCommand"); + if (item.unset) + cmd.arg("command", "settings remove target.env-vars " + item.name.toUtf8()); + else + cmd.arg("command", "settings set target.env-vars " + item.name.toUtf8() + '=' + item.value.toUtf8()); + runCommand(cmd); } const QString path = stringSetting(ExtraDumperFile); From af394ecc8bc83aa02c5cccb705c6490e4396501e Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 15 Jul 2015 12:51:32 +0200 Subject: [PATCH 57/70] Debugger: Hide "Tracepoint only" item from breakpoint options Did only work for Symbian, for now the user can use something like echo Trace hit! continue in the "Commands:" field instead. Change-Id: Ib7ad273bc6de4bbd46845c9e1c75c99e5bddd2bc Reviewed-by: Niels Weber --- src/plugins/debugger/breakwindow.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/plugins/debugger/breakwindow.cpp b/src/plugins/debugger/breakwindow.cpp index 86fdf481e0c..1147a597ff6 100644 --- a/src/plugins/debugger/breakwindow.cpp +++ b/src/plugins/debugger/breakwindow.cpp @@ -383,13 +383,17 @@ void BreakpointDialog::setPartsEnabled(unsigned partsMask) m_lineEditModule->setEnabled(partsMask & ModulePart); m_labelTracepoint->setEnabled(partsMask & TracePointPart); + m_labelTracepoint->hide(); m_checkBoxTracepoint->setEnabled(partsMask & TracePointPart); + m_checkBoxTracepoint->hide(); m_labelCommands->setEnabled(partsMask & TracePointPart); m_textEditCommands->setEnabled(partsMask & TracePointPart); m_labelMessage->setEnabled(partsMask & TracePointPart); + m_labelMessage->hide(); m_lineEditMessage->setEnabled(partsMask & TracePointPart); + m_lineEditMessage->hide(); } void BreakpointDialog::clearOtherParts(unsigned partsMask) From efada549503ac21fa23822e20ae5d058bdca8da0 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 15 Jul 2015 13:00:50 +0200 Subject: [PATCH 58/70] Debugger: Fix enable state of breakpoint command text field There was no actual error in practice, as the handling was lumped together with the tracepoint checkmark, which (accidentally) did the right thing in all cases. Change-Id: Icf12aaf0c48855b747d25a0252c8215e259c4227 Reviewed-by: Niels Weber --- src/plugins/debugger/breakpoint.h | 32 +++++++++--------- src/plugins/debugger/breakwindow.cpp | 49 +++++++++++++++------------- 2 files changed, 42 insertions(+), 39 deletions(-) diff --git a/src/plugins/debugger/breakpoint.h b/src/plugins/debugger/breakpoint.h index 1d442f39801..64afe5ab4d0 100644 --- a/src/plugins/debugger/breakpoint.h +++ b/src/plugins/debugger/breakpoint.h @@ -137,23 +137,23 @@ enum BreakpointPathUsage enum BreakpointParts { - NoParts = 0, - FileAndLinePart = 0x1, - FunctionPart = 0x2, - AddressPart = 0x4, - ExpressionPart = 0x8, - ConditionPart = 0x10, - IgnoreCountPart = 0x20, - ThreadSpecPart = 0x40, - ModulePart = 0x80, - TracePointPart = 0x100, + NoParts = 0, + FileAndLinePart = (1 << 0), + FunctionPart = (1 << 1), + AddressPart = (1 << 2), + ExpressionPart = (1 << 3), + ConditionPart = (1 << 4), + IgnoreCountPart = (1 << 5), + ThreadSpecPart = (1 << 6), + ModulePart = (1 << 7), + TracePointPart = (1 << 8), - EnabledPart = 0x200, - TypePart = 0x400, - PathUsagePart = 0x800, - CommandPart = 0x1000, - MessagePart = 0x2000, - OneShotPart = 0x4000, + EnabledPart = (1 << 9), + TypePart = (1 << 10), + PathUsagePart = (1 << 11), + CommandPart = (1 << 12), + MessagePart = (1 << 13), + OneShotPart = (1 << 14), AllConditionParts = ConditionPart|IgnoreCountPart|ThreadSpecPart |OneShotPart, diff --git a/src/plugins/debugger/breakwindow.cpp b/src/plugins/debugger/breakwindow.cpp index 1147a597ff6..53dc281ff90 100644 --- a/src/plugins/debugger/breakwindow.cpp +++ b/src/plugins/debugger/breakwindow.cpp @@ -387,8 +387,8 @@ void BreakpointDialog::setPartsEnabled(unsigned partsMask) m_checkBoxTracepoint->setEnabled(partsMask & TracePointPart); m_checkBoxTracepoint->hide(); - m_labelCommands->setEnabled(partsMask & TracePointPart); - m_textEditCommands->setEnabled(partsMask & TracePointPart); + m_labelCommands->setEnabled(partsMask & CommandPart); + m_textEditCommands->setEnabled(partsMask & CommandPart); m_labelMessage->setEnabled(partsMask & TracePointPart); m_labelMessage->hide(); @@ -424,9 +424,10 @@ void BreakpointDialog::clearOtherParts(unsigned partsMask) if (partsMask & OneShotPart) m_checkBoxOneShot->setChecked(false); + if (invertedPartsMask & CommandPart) + m_textEditCommands->clear(); if (invertedPartsMask & TracePointPart) { m_checkBoxTracepoint->setChecked(false); - m_textEditCommands->clear(); m_lineEditMessage->clear(); } } @@ -460,9 +461,10 @@ void BreakpointDialog::getParts(unsigned partsMask, BreakpointParameters *data) if (partsMask & OneShotPart) data->oneShot = m_checkBoxOneShot->isChecked(); + if (partsMask & CommandPart) + data->command = m_textEditCommands->toPlainText().trimmed(); if (partsMask & TracePointPart) { data->tracepoint = m_checkBoxTracepoint->isChecked(); - data->command = m_textEditCommands->toPlainText().trimmed(); data->message = m_lineEditMessage->text(); } } @@ -471,7 +473,6 @@ void BreakpointDialog::setParts(unsigned mask, const BreakpointParameters &data) { m_checkBoxEnabled->setChecked(data.enabled); m_comboBoxPathUsage->setCurrentIndex(data.pathUsage); - m_textEditCommands->setPlainText(data.command); m_lineEditMessage->setText(data.message); if (mask & FileAndLinePart) { @@ -512,6 +513,8 @@ void BreakpointDialog::setParts(unsigned mask, const BreakpointParameters &data) m_checkBoxOneShot->setChecked(data.oneShot); if (mask & TracePointPart) m_checkBoxTracepoint->setChecked(data.tracepoint); + if (mask & CommandPart) + m_textEditCommands->setPlainText(data.command); } void BreakpointDialog::typeChanged(int) @@ -525,10 +528,10 @@ void BreakpointDialog::typeChanged(int) case LastBreakpointType: break; case BreakpointByFileAndLine: - getParts(FileAndLinePart|ModulePart|AllConditionParts|TracePointPart, &m_savedParameters); + getParts(FileAndLinePart|ModulePart|AllConditionParts|TracePointPart|CommandPart, &m_savedParameters); break; case BreakpointByFunction: - getParts(FunctionPart|ModulePart|AllConditionParts|TracePointPart, &m_savedParameters); + getParts(FunctionPart|ModulePart|AllConditionParts|TracePointPart|CommandPart, &m_savedParameters); break; case BreakpointAtThrow: case BreakpointAtCatch: @@ -541,10 +544,10 @@ void BreakpointDialog::typeChanged(int) break; case BreakpointByAddress: case WatchpointAtAddress: - getParts(AddressPart|AllConditionParts|TracePointPart, &m_savedParameters); + getParts(AddressPart|AllConditionParts|TracePointPart|CommandPart, &m_savedParameters); break; case WatchpointAtExpression: - getParts(ExpressionPart|AllConditionParts|TracePointPart, &m_savedParameters); + getParts(ExpressionPart|AllConditionParts|TracePointPart|CommandPart, &m_savedParameters); break; case BreakpointOnQmlSignalEmit: getParts(FunctionPart, &m_savedParameters); @@ -556,14 +559,14 @@ void BreakpointDialog::typeChanged(int) case LastBreakpointType: break; case BreakpointByFileAndLine: - setParts(FileAndLinePart|AllConditionParts|ModulePart|TracePointPart, m_savedParameters); - setPartsEnabled(FileAndLinePart|AllConditionParts|ModulePart|TracePointPart); - clearOtherParts(FileAndLinePart|AllConditionParts|ModulePart|TracePointPart); + setParts(FileAndLinePart|AllConditionParts|ModulePart|TracePointPart|CommandPart, m_savedParameters); + setPartsEnabled(FileAndLinePart|AllConditionParts|ModulePart|TracePointPart|CommandPart); + clearOtherParts(FileAndLinePart|AllConditionParts|ModulePart|TracePointPart|CommandPart); break; case BreakpointByFunction: - setParts(FunctionPart|AllConditionParts|ModulePart|TracePointPart, m_savedParameters); - setPartsEnabled(FunctionPart|AllConditionParts|ModulePart|TracePointPart); - clearOtherParts(FunctionPart|AllConditionParts|ModulePart|TracePointPart); + setParts(FunctionPart|AllConditionParts|ModulePart|TracePointPart|CommandPart, m_savedParameters); + setPartsEnabled(FunctionPart|AllConditionParts|ModulePart|TracePointPart|CommandPart); + clearOtherParts(FunctionPart|AllConditionParts|ModulePart|TracePointPart|CommandPart); break; case BreakpointAtThrow: case BreakpointAtCatch: @@ -571,8 +574,8 @@ void BreakpointDialog::typeChanged(int) case BreakpointAtExec: //case BreakpointAtVFork: case BreakpointAtSysCall: - clearOtherParts(AllConditionParts|ModulePart|TracePointPart); - setPartsEnabled(AllConditionParts|TracePointPart); + clearOtherParts(AllConditionParts|ModulePart|TracePointPart|CommandPart); + setPartsEnabled(AllConditionParts|TracePointPart|CommandPart); break; case BreakpointAtJavaScriptThrow: clearOtherParts(AllParts); @@ -585,14 +588,14 @@ void BreakpointDialog::typeChanged(int) break; case BreakpointByAddress: case WatchpointAtAddress: - setParts(AddressPart|AllConditionParts|TracePointPart, m_savedParameters); - setPartsEnabled(AddressPart|AllConditionParts|TracePointPart); - clearOtherParts(AddressPart|AllConditionParts|TracePointPart); + setParts(AddressPart|AllConditionParts|TracePointPart|CommandPart, m_savedParameters); + setPartsEnabled(AddressPart|AllConditionParts|TracePointPart|CommandPart); + clearOtherParts(AddressPart|AllConditionParts|TracePointPart|CommandPart); break; case WatchpointAtExpression: - setParts(ExpressionPart|AllConditionParts|TracePointPart, m_savedParameters); - setPartsEnabled(ExpressionPart|AllConditionParts|TracePointPart); - clearOtherParts(ExpressionPart|AllConditionParts|TracePointPart); + setParts(ExpressionPart|AllConditionParts|TracePointPart|CommandPart, m_savedParameters); + setPartsEnabled(ExpressionPart|AllConditionParts|TracePointPart|CommandPart); + clearOtherParts(ExpressionPart|AllConditionParts|TracePointPart|CommandPart); break; case BreakpointOnQmlSignalEmit: setParts(FunctionPart, m_savedParameters); From 2443f18b852ee92ab4ef804f43dedb1e4fc9d44a Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Thu, 16 Jul 2015 19:57:52 +0200 Subject: [PATCH 59/70] Clang: Reparse the translation unit for unsaved file changes Change-Id: I49711ce040a995f193d36961e010decc27c34c4c Reviewed-by: Nikolai Kosjar --- .../ipcsource/translationunit.cpp | 53 +++++++++++---- .../clangbackend/ipcsource/translationunit.h | 13 +++- tests/unit/unittest/translationunittest.cpp | 66 ++++++++++++++++++- 3 files changed, 114 insertions(+), 18 deletions(-) diff --git a/src/tools/clangbackend/ipcsource/translationunit.cpp b/src/tools/clangbackend/ipcsource/translationunit.cpp index f74b555f383..17871176fae 100644 --- a/src/tools/clangbackend/ipcsource/translationunit.cpp +++ b/src/tools/clangbackend/ipcsource/translationunit.cpp @@ -52,7 +52,8 @@ public: ~TranslationUnitData(); public: - time_point lastChangeTimePoint; + time_point lastProjectPartChangeTimePoint; + time_point lastUnsavedFilesChangeTimePoint; ProjectPart projectPart; Utf8String filePath; CXTranslationUnit translationUnit = nullptr; @@ -63,7 +64,8 @@ public: TranslationUnitData::TranslationUnitData(const Utf8String &filePath, const UnsavedFiles &unsavedFiles, const ProjectPart &projectPart) - : lastChangeTimePoint(std::chrono::steady_clock::now()), + : lastProjectPartChangeTimePoint(std::chrono::steady_clock::now()), + lastUnsavedFilesChangeTimePoint(lastProjectPartChangeTimePoint), projectPart(projectPart), filePath(filePath), unsavedFiles(unsavedFiles) @@ -109,10 +111,9 @@ CXIndex TranslationUnit::index() const CXTranslationUnit TranslationUnit::cxTranslationUnit() const { checkIfNull(); - - removeOutdatedTranslationUnit(); - + removeTranslationUnitIfProjectPartWasChanged(); createTranslationUnitIfNeeded(); + reparseTranslationUnitIfUnsavedFilesAreChanged(); return d->translationUnit; } @@ -131,9 +132,19 @@ const Utf8String &TranslationUnit::projectPartId() const return d->projectPart.projectPartId(); } -const time_point &TranslationUnit::lastChangeTimePoint() const +const time_point &TranslationUnit::lastProjectPartChangeTimePoint() const { - return d->lastChangeTimePoint; + return d->lastProjectPartChangeTimePoint; +} + +const time_point &TranslationUnit::lastUnsavedFilesChangeTimePoint() const +{ + return d->lastUnsavedFilesChangeTimePoint; +} + +bool TranslationUnit::isNeedingReparse() const +{ + return d->lastUnsavedFilesChangeTimePoint < d->unsavedFiles.lastChangeTimePoint(); } void TranslationUnit::checkIfNull() const @@ -148,19 +159,29 @@ void TranslationUnit::checkIfFileExists() const throw TranslationUnitFileNotExitsException(d->filePath); } -void TranslationUnit::updateLastChangeTimePoint() const +void TranslationUnit::updateLastProjectPartChangeTimePoint() const { - d->lastChangeTimePoint = std::chrono::steady_clock::now(); + d->lastProjectPartChangeTimePoint = std::chrono::steady_clock::now(); } -void TranslationUnit::removeOutdatedTranslationUnit() const +void TranslationUnit::updateLastUnsavedFilesChangeTimePoint() const { - if (d->projectPart.lastChangeTimePoint() >= d->lastChangeTimePoint) { + d->lastUnsavedFilesChangeTimePoint = std::chrono::steady_clock::now(); +} + +void TranslationUnit::removeTranslationUnitIfProjectPartWasChanged() const +{ + if (projectPartIsOutdated()) { clang_disposeTranslationUnit(d->translationUnit); d->translationUnit = nullptr; } } +bool TranslationUnit::projectPartIsOutdated() const +{ + return d->projectPart.lastChangeTimePoint() >= d->lastProjectPartChangeTimePoint; +} + void TranslationUnit::createTranslationUnitIfNeeded() const { if (!d->translationUnit) { @@ -180,7 +201,7 @@ void TranslationUnit::createTranslationUnitIfNeeded() const // e.g. clang_codeCompleteAt() dramatically. reparseTranslationUnit(); - updateLastChangeTimePoint(); + updateLastProjectPartChangeTimePoint(); } } @@ -198,6 +219,14 @@ void TranslationUnit::reparseTranslationUnit() const d->unsavedFiles.count(), d->unsavedFiles.cxUnsavedFiles(), clang_defaultReparseOptions(d->translationUnit)); + + updateLastUnsavedFilesChangeTimePoint(); +} + +void TranslationUnit::reparseTranslationUnitIfUnsavedFilesAreChanged() const +{ + if (isNeedingReparse()) + reparseTranslationUnit(); } int TranslationUnit::defaultOptions() diff --git a/src/tools/clangbackend/ipcsource/translationunit.h b/src/tools/clangbackend/ipcsource/translationunit.h index 75dd39e8614..5491f0acec8 100644 --- a/src/tools/clangbackend/ipcsource/translationunit.h +++ b/src/tools/clangbackend/ipcsource/translationunit.h @@ -82,16 +82,23 @@ public: const Utf8String &filePath() const; const Utf8String &projectPartId() const; - const time_point &lastChangeTimePoint() const; + const time_point &lastProjectPartChangeTimePoint() const; + const time_point &lastUnsavedFilesChangeTimePoint() const; + + bool isNeedingReparse() const; private: void checkIfNull() const; void checkIfFileExists() const; - void updateLastChangeTimePoint() const; - void removeOutdatedTranslationUnit() const; + void updateLastProjectPartChangeTimePoint() const; + void updateLastUnsavedFilesChangeTimePoint() const; + void removeTranslationUnitIfProjectPartWasChanged() const; + bool projectPartIsOutdated() const; void createTranslationUnitIfNeeded() const; void checkTranslationUnitErrorCode(CXErrorCode errorCode) const; void reparseTranslationUnit() const; + void reparseTranslationUnitIfUnsavedFilesAreChanged() const; + void printIncludes() const; static int defaultOptions(); private: diff --git a/tests/unit/unittest/translationunittest.cpp b/tests/unit/unittest/translationunittest.cpp index 25235940bf0..29ae9cd4686 100644 --- a/tests/unit/unittest/translationunittest.cpp +++ b/tests/unit/unittest/translationunittest.cpp @@ -132,15 +132,75 @@ TEST(TranslationUnit, ResetedTranslationUnitIsNull) ASSERT_TRUE(translationUnit.isNull()); } -TEST(TranslationUnit, TimeStampIsUpdatedAsNewCxTranslationUnitIsGenerated) +TEST(TranslationUnit, TimeStampForProjectPartChangeIsUpdatedAsNewCxTranslationUnitIsGenerated) { TranslationUnit translationUnit(Utf8StringLiteral(TESTDATA_DIR"/complete_testfile_1.cpp"), UnsavedFiles(), ProjectPart(Utf8StringLiteral("/path/to/projectfile"))); - auto lastChangeTimePoint = translationUnit.lastChangeTimePoint(); + auto lastChangeTimePoint = translationUnit.lastProjectPartChangeTimePoint(); std::this_thread::sleep_for(std::chrono::steady_clock::duration(1)); translationUnit.cxTranslationUnit(); - ASSERT_THAT(translationUnit.lastChangeTimePoint(), Gt(lastChangeTimePoint)); + ASSERT_THAT(translationUnit.lastProjectPartChangeTimePoint(), Gt(lastChangeTimePoint)); +} + +TEST(TranslationUnit, TimeStampForProjectPartChangeIsUpdatedAsProjectPartIsCleared) +{ + ProjectPart projectPart(Utf8StringLiteral("/path/to/projectfile")); + TranslationUnit translationUnit(Utf8StringLiteral(TESTDATA_DIR"/complete_testfile_1.cpp"), UnsavedFiles(), projectPart); + translationUnit.cxTranslationUnit(); + auto lastChangeTimePoint = translationUnit.lastProjectPartChangeTimePoint(); + std::this_thread::sleep_for(std::chrono::steady_clock::duration(1)); + + projectPart.clear(); + translationUnit.cxTranslationUnit(); + + ASSERT_THAT(translationUnit.lastProjectPartChangeTimePoint(), Gt(lastChangeTimePoint)); +} + +TEST(TranslationUnit, ReparseIsNeededAfterUnsavedFilesAreChanged) +{ + UnsavedFiles unsavedFiles; + TranslationUnit translationUnit(Utf8StringLiteral(TESTDATA_DIR"/complete_testfile_1.cpp"), + unsavedFiles, + ProjectPart(Utf8StringLiteral("/path/to/projectfile"))); + translationUnit.cxTranslationUnit(); + unsavedFiles.clear(); + translationUnit.cxTranslationUnit(); + + unsavedFiles.clear(); + + ASSERT_TRUE(translationUnit.isNeedingReparse()); +} + +TEST(TranslationUnit, NeedsNoReparseAfterUnsavedFilesAreNotChanged) +{ + UnsavedFiles unsavedFiles; + TranslationUnit translationUnit(Utf8StringLiteral(TESTDATA_DIR"/complete_testfile_1.cpp"), + unsavedFiles, + ProjectPart(Utf8StringLiteral("/path/to/projectfile"))); + translationUnit.cxTranslationUnit(); + unsavedFiles.clear(); + translationUnit.cxTranslationUnit(); + + ASSERT_FALSE(translationUnit.isNeedingReparse()); +} + +TEST(TranslationUnit, TimeStampForUnsavedFilesChange) +{ + UnsavedFiles unsavedFiles; + TranslationUnit translationUnit(Utf8StringLiteral(TESTDATA_DIR"/complete_testfile_1.cpp"), + unsavedFiles, + ProjectPart(Utf8StringLiteral("/path/to/projectfile"))); + translationUnit.cxTranslationUnit(); + unsavedFiles.clear(); + translationUnit.cxTranslationUnit(); + auto lastChangeTimePoint = translationUnit.lastUnsavedFilesChangeTimePoint(); + std::this_thread::sleep_for(std::chrono::steady_clock::duration(1)); + + unsavedFiles.clear(); + translationUnit.cxTranslationUnit(); + + ASSERT_THAT(translationUnit.lastUnsavedFilesChangeTimePoint(), Gt(lastChangeTimePoint)); } From 2d306934501e2373359691e570c009c6b80741f9 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 16 Jul 2015 12:03:11 +0200 Subject: [PATCH 60/70] Debugger: Fix LLDB extra dumper passing Change-Id: I1601a894b8adb3365894b21e06d4929e381b7a01 Reviewed-by: Niels Weber --- src/plugins/debugger/lldb/lldbengine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp index 860c7f472f4..6d135df89ca 100644 --- a/src/plugins/debugger/lldb/lldbengine.cpp +++ b/src/plugins/debugger/lldb/lldbengine.cpp @@ -311,7 +311,7 @@ void LldbEngine::setupInferior() const QString commands = stringSetting(ExtraDumperCommands); if (!commands.isEmpty()) { DebuggerCommand cmd("executeDebuggerCommand"); - cmd.arg("commands", commands.toUtf8()); + cmd.arg("command", commands.toUtf8()); runCommand(cmd); } From c1e418c290d44d279fa2841d4dbf301c158ddba4 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 16 Jul 2015 13:29:05 +0200 Subject: [PATCH 61/70] Debugger: Don't do unnecessary work ... after the "Sort Members of Classes Alphabetically" option is toggled. The option only influences the contents of the "Locals and Expressions" view, so it is sufficient to update only that. Change-Id: I9eade679eddbfb108c7ed478cce6c13fadcca317 Reviewed-by: Oswald Buddenhagen Reviewed-by: Niels Weber --- src/plugins/debugger/watchhandler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index 8fbfaec3772..cd557c1267c 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -331,7 +331,7 @@ WatchModel::WatchModel(WatchHandler *handler, DebuggerEngine *engine) this, &WatchModel::updateStarted); connect(action(SortStructMembers), &SavedAction::valueChanged, - m_engine, &DebuggerEngine::updateAll); + m_engine, &DebuggerEngine::updateLocals); connect(action(ShowStdNamespace), &SavedAction::valueChanged, m_engine, &DebuggerEngine::updateAll); connect(action(ShowQtNamespace), &SavedAction::valueChanged, From 4dbc0bdbf7f99bbb940da2f100ba4e5460507983 Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Wed, 15 Jul 2015 13:48:55 +0200 Subject: [PATCH 62/70] Wizards: Do not offer UI files in Qt Quick projects based on qmlproject Task-number: QTCREATORBUG-14712 Change-Id: Ic171cbeb4b5e4c52f872c7c4ccedcbfa61be4ab8 Reviewed-by: Robert Loehning Reviewed-by: Alessandro Portale --- .../projects/qmlproject/qtquickapplication/wizard.json | 9 ++++++--- .../qmlproject/qtquickcontrolsapplication/wizard.json | 9 ++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/share/qtcreator/templates/wizards/projects/qmlproject/qtquickapplication/wizard.json b/share/qtcreator/templates/wizards/projects/qmlproject/qtquickapplication/wizard.json index efc71de1d51..3a1eddfd435 100644 --- a/share/qtcreator/templates/wizards/projects/qmlproject/qtquickapplication/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qmlproject/qtquickapplication/wizard.json @@ -15,7 +15,9 @@ { "key": "QmlProjectFileName", "value": "%{JS: Util.fileName('%{ProjectDirectory}/%{ProjectName}', 'qmlproject')}" }, { "key": "MainQmlFileName", "value": "%{JS: Util.fileName('%{ProjectName}', 'qml')}" }, { "key": "QtQuickVersion", "value": "%{JS: %{QtVersion}.qtQuickVersion}" }, - { "key": "QtQuickWindowVersion", "value": "%{JS: %{QtVersion}.qtQuickWindowVersion}" } + { "key": "QtQuickWindowVersion", "value": "%{JS: %{QtVersion}.qtQuickWindowVersion}" }, + { "key": "UiSupport", "value": "%{JS: '%{QtQuickVersion}' !== '2.3' }" }, + { "key": "IsUiFileInUse", "value": "%{JS: %{UiSupport} && %{QmlUiSplit} }" } ], "pages": @@ -67,9 +69,10 @@ } }, { - "name": "QmlUISplit", + "name": "QmlUiSplit", "trDisplayName": "With ui.qml file", "type": "CheckBox", + "visible": "%{UiSupport}", "data": { "checked": false @@ -102,7 +105,7 @@ { "source": "../../qmake/qtquickapplication/MainForm.ui.qml", "target": "%{ProjectDirectory}/MainForm.ui.qml", - "condition": "%{QmlUISplit}" + "condition": "%{IsUiFileInUse}" }, { "source": "../../git.ignore", diff --git a/share/qtcreator/templates/wizards/projects/qmlproject/qtquickcontrolsapplication/wizard.json b/share/qtcreator/templates/wizards/projects/qmlproject/qtquickcontrolsapplication/wizard.json index 9e19f93b925..657d5501d0d 100644 --- a/share/qtcreator/templates/wizards/projects/qmlproject/qtquickcontrolsapplication/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qmlproject/qtquickcontrolsapplication/wizard.json @@ -17,7 +17,9 @@ { "key": "QtQuickVersion", "value": "%{JS: %{QtVersion}.qtQuickVersion}" }, { "key": "QtQuickControlsVersion", "value": "%{JS: %{QtVersion}.qtQuickControlsVersion}" }, { "key": "QtQuickDialogsVersion", "value": "%{JS: %{QtVersion}.qtQuickDialogsVersion}" }, - { "key": "QtQuickLayoutsVersion", "value": "%{JS: %{QtVersion}.qtQuickLayoutsVersion}" } + { "key": "QtQuickLayoutsVersion", "value": "%{JS: %{QtVersion}.qtQuickLayoutsVersion}" }, + { "key": "UiSupport", "value": "%{JS: '%{QtQuickVersion}' !== '2.3' }" }, + { "key": "IsUiFileInUse", "value": "%{JS: %{UiSupport} && %{QmlUiSplit} }" } ], "pages": @@ -75,9 +77,10 @@ } }, { - "name": "QmlUISplit", + "name": "QmlUiSplit", "trDisplayName": "With ui.qml file", "type": "CheckBox", + "visible": "%{UiSupport}", "data": { "checked": true @@ -110,7 +113,7 @@ { "source": "../../qmake/qtquickcontrolsapplication/MainForm.ui.qml", "target": "%{ProjectDirectory}/MainForm.ui.qml", - "condition": "%{QmlUISplit}" + "condition": "%{IsUiFileInUse}" }, { "source": "../../git.ignore", From 09ce021627deab9a0aacee4d6450e3e515a4a5bd Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Fri, 17 Jul 2015 10:55:39 +0200 Subject: [PATCH 63/70] Clang: Fix command name for QDebug Change-Id: If29a41aaefeda725965a85f0c7ff47124e2a23c7 Reviewed-by: Erik Verbruggen --- .../cmbregisterprojectsforcodecompletioncommand.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/clangbackendipc/cmbregisterprojectsforcodecompletioncommand.cpp b/src/libs/clangbackendipc/cmbregisterprojectsforcodecompletioncommand.cpp index 3b8ea87b4f3..3fd1573d9bf 100644 --- a/src/libs/clangbackendipc/cmbregisterprojectsforcodecompletioncommand.cpp +++ b/src/libs/clangbackendipc/cmbregisterprojectsforcodecompletioncommand.cpp @@ -76,7 +76,7 @@ bool operator<(const RegisterProjectPartsForCodeCompletionCommand &first, const QDebug operator<<(QDebug debug, const RegisterProjectPartsForCodeCompletionCommand &command) { - debug.nospace() << "RegisterProjectPartsForCodeCompletion("; + debug.nospace() << "RegisterProjectPartsForCodeCompletionCommand("; for (const ProjectPartContainer &projectContainer : command.projectContainers()) debug.nospace() << projectContainer<< ", "; @@ -88,7 +88,7 @@ QDebug operator<<(QDebug debug, const RegisterProjectPartsForCodeCompletionComma void PrintTo(const RegisterProjectPartsForCodeCompletionCommand &command, ::std::ostream* os) { - *os << "RegisterProjectPartsForCodeCompletion("; + *os << "RegisterProjectPartsForCodeCompletionCommand("; for (const ProjectPartContainer &projectContainer : command.projectContainers()) PrintTo(projectContainer, os); From e8041f225426f5cf61725162cf234a5b5bb277da Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Wed, 15 Jul 2015 15:01:35 +0200 Subject: [PATCH 64/70] Clang: Update class name in assert Change-Id: Ib7aa42fbe8cc66fa8629cf9079e81fd0449fe14d Reviewed-by: Erik Verbruggen --- src/plugins/clangcodemodel/clangbackendipcintegration.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/clangcodemodel/clangbackendipcintegration.cpp b/src/plugins/clangcodemodel/clangbackendipcintegration.cpp index 8100b9cf4a5..d03b56b89a6 100644 --- a/src/plugins/clangcodemodel/clangbackendipcintegration.cpp +++ b/src/plugins/clangcodemodel/clangbackendipcintegration.cpp @@ -157,7 +157,7 @@ void IpcReceiver::translationUnitDoesNotExist(const TranslationUnitDoesNotExistC void IpcReceiver::projectPartsDoNotExist(const ProjectPartsDoNotExistCommand &command) { - QTC_CHECK(!"Got ProjectDoesNotExistCommand"); + QTC_CHECK(!"Got ProjectPartsDoNotExistCommand"); qCDebug(log) << "<<< ERROR:" << command; } From 73cee4d64aa99ce04ecdd03761ceed68ab4f70f0 Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Fri, 17 Jul 2015 11:17:11 +0200 Subject: [PATCH 65/70] Clang: Tests: Mini refactorings Change-Id: I4a058d4c68c126d74badfc699a239ef9b2790f3a Reviewed-by: Erik Verbruggen --- .../test/clangcodecompletion_test.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/plugins/clangcodemodel/test/clangcodecompletion_test.cpp b/src/plugins/clangcodemodel/test/clangcodecompletion_test.cpp index 9cbcaf92727..584b47b3c21 100644 --- a/src/plugins/clangcodemodel/test/clangcodecompletion_test.cpp +++ b/src/plugins/clangcodemodel/test/clangcodecompletion_test.cpp @@ -71,10 +71,15 @@ using namespace ClangCodeModel::Internal; namespace { -QString _(const char text[]) { return QString::fromUtf8(text); } +QString _(const char text[]) +{ return QString::fromUtf8(text); } + QString qrcPath(const QByteArray relativeFilePath) { return QLatin1String(":/unittests/ClangCodeModel/") + QString::fromUtf8(relativeFilePath); } +QString fileName(const QString &filePath) +{ return QFileInfo(filePath).fileName(); } + struct LogOutput { LogOutput(const QString &text) : text(text.toUtf8()) {} @@ -260,8 +265,8 @@ QString toString(const FileContainer &fileContainer) { QString out; QTextStream ts(&out); - ts << " Path: " << QFileInfo(fileContainer.filePath().toString()).fileName() - << " ProjectPart: " << fileContainer.projectPartId().toString() << "\n"; + ts << " Path: " << fileName(fileContainer.filePath().toString()) + << " ProjectPart: " << fileName(fileContainer.projectPartId().toString()) << "\n"; return out; } @@ -279,7 +284,7 @@ QString toString(const ProjectPartContainer &projectPartContainer) QString out; QTextStream ts(&out); ts << " ProjectPartContainer" - << " id: " << QFileInfo(projectPartContainer.projectPartId().toString()).fileName(); + << " id: " << fileName(projectPartContainer.projectPartId().toString()); return out; } From 569932496b1bfe97af2cc729d836da37d017cbd2 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Mon, 13 Jul 2015 10:09:14 +0200 Subject: [PATCH 66/70] Refactor handling of statically deployed files This is a partial fix for QTCREATORBUG-14490. Change-Id: I014554e371c222a844c16196a1e3106fd5e45f9e Reviewed-by: Oswald Buddenhagen --- share/qtcreator/static.pri | 39 ++++++++++++++++++++++++++++++++++++++ share/qtcreator/static.pro | 29 ++++++++-------------------- 2 files changed, 47 insertions(+), 21 deletions(-) create mode 100644 share/qtcreator/static.pri diff --git a/share/qtcreator/static.pri b/share/qtcreator/static.pri new file mode 100644 index 00000000000..6cea5a804a3 --- /dev/null +++ b/share/qtcreator/static.pri @@ -0,0 +1,39 @@ +# This pri file is used to deploy files that are not compiled while building +# Qt Creator. It handles copying of files into the build directory if using +# a shadow build and adds the respective install target as well. +# +# Usage: Define variables (details below) and include this pri file afterwards. +# +# STATIC_BASE - base directory for the files listed in STATIC_FILES +# STATIC_FILES - list of files to be deployed + +include(../../qtcreator.pri) + +# used in custom compilers which just copy files +defineReplace(stripStaticBase) { + return($$relative_path($$1, $$STATIC_BASE)) +} + +# handle conditional copying; copydata will be set by qtcreator.pri +!isEmpty(STATIC_FILES) { + isEmpty(STATIC_BASE): \ + error("Using STATIC_FILES without having STATIC_BASE set") + + !isEmpty(copydata) { + copy2build.input += STATIC_FILES + copy2build.output = $$IDE_DATA_PATH/${QMAKE_FUNC_FILE_IN_stripStaticBase} + isEmpty(vcproj):copy2build.variable_out = PRE_TARGETDEPS + win32:copy2build.commands = $$QMAKE_COPY \"${QMAKE_FILE_IN}\" \"${QMAKE_FILE_OUT}\" + unix:copy2build.commands = $$QMAKE_COPY ${QMAKE_FILE_IN} ${QMAKE_FILE_OUT} + copy2build.name = COPY ${QMAKE_FILE_IN} + copy2build.config += no_link + QMAKE_EXTRA_COMPILERS += copy2build + } + + !osx { + static.files = $$STATIC_FILES + static.base = $$STATIC_BASE + static.path = $$QTC_PREFIX/share/qtcreator + INSTALLS += static + } +} diff --git a/share/qtcreator/static.pro b/share/qtcreator/static.pro index 37a44a1aa66..59bb5d342f4 100644 --- a/share/qtcreator/static.pro +++ b/share/qtcreator/static.pro @@ -1,5 +1,3 @@ -include(../../qtcreator.pri) - TEMPLATE = app TARGET = phony_target CONFIG -= qt sdk separate_debug_info gdb_dwarf_index @@ -23,6 +21,9 @@ isEmpty(vcproj) { QMAKE_EXTRA_COMPILERS += phony_src } +STATIC_BASE = $$PWD + +# files/folders that are conditionally "deployed" to the build directory DATA_DIRS = \ welcomescreen \ examplebrowser \ @@ -46,28 +47,14 @@ macx: DATA_DIRS += scripts for(data_dir, DATA_DIRS) { files = $$files($$PWD/$$data_dir/*, true) # Info.plist.in are handled below - for(file, files):!contains(file, ".*/Info\\.plist\\.in$"):!exists($$file/*):FILES += $$file + for(file, files):!contains(file, ".*/Info\\.plist\\.in$"):!exists($$file/*): \ + STATIC_FILES += $$file } -# conditionally deployed data -!isEmpty(copydata) { - copy2build.input = FILES - copy2build.output = $$IDE_DATA_PATH/${QMAKE_FUNC_FILE_IN_stripSrcDir} - isEmpty(vcproj):copy2build.variable_out = PRE_TARGETDEPS - win32:copy2build.commands = $$QMAKE_COPY \"${QMAKE_FILE_IN}\" \"${QMAKE_FILE_OUT}\" - unix:copy2build.commands = $$QMAKE_COPY ${QMAKE_FILE_IN} ${QMAKE_FILE_OUT} - copy2build.name = COPY ${QMAKE_FILE_IN} - copy2build.CONFIG += no_link - QMAKE_EXTRA_COMPILERS += copy2build -} +include(static.pri) -!macx { - for(data_dir, DATA_DIRS) { - eval($${data_dir}.files = $$quote($$PWD/$$data_dir)) - eval($${data_dir}.path = $$QTC_PREFIX/share/qtcreator) - INSTALLS += $$data_dir - } -} else { +# stuff that cannot be handled by static.pri +osx { # do version magic for app bundles dumpinfo.input = qml/qmldump/Info.plist.in dumpinfo.output = $$IDE_DATA_PATH/qml/qmldump/Info.plist From 38d2baa2ddd3dbf2969ef7b17f6a6adccc15aefa Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 16 Jul 2015 16:14:43 +0200 Subject: [PATCH 67/70] Debugger: Ask JS debug server to evaluate(something) only when stopped The server on the Qt side Q_ASSERTs otherwise, killing the application. Change-Id: I273f12c4bc89bd3488fa6409fdbebc6a6ac2b606 Reviewed-by: Christian Stenger Reviewed-by: hjk --- src/plugins/debugger/qml/qmlengine.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp index d10984c41ae..735840fee12 100644 --- a/src/plugins/debugger/qml/qmlengine.cpp +++ b/src/plugins/debugger/qml/qmlengine.cpp @@ -995,10 +995,14 @@ void QmlEngine::updateItem(const QByteArray &iname) const WatchItem *item = watchHandler()->findItem(iname); QTC_ASSERT(item, return); - QString exp = QString::fromUtf8(item->exp); - d->evaluate(exp, [this, iname, exp](const QVariantMap &response) { - d->handleEvaluateExpression(response, iname, exp); - }); + if (state() == InferiorStopOk) { + // The Qt side Q_ASSERTs otherwise. So postpone the evaluation, + // it will be triggered from from upateLocals() later. + QString exp = QString::fromUtf8(item->exp); + d->evaluate(exp, [this, iname, exp](const QVariantMap &response) { + d->handleEvaluateExpression(response, iname, exp); + }); + } } void QmlEngine::selectWatchData(const QByteArray &iname) @@ -1348,6 +1352,10 @@ void QmlEnginePrivate::evaluate(const QString expr, const QmlCallback &cb) // } // } + // The Qt side Q_ASSERTs otherwise. So ignore the request and hope + // it will be repeated soon enough (which it will, e.g. in updateLocals) + QTC_ASSERT(engine->state() == InferiorStopOk, return); + DebuggerCommand cmd(EVALUATE); cmd.arg(EXPRESSION, expr); From db6126b82d661971593c24bf83374e607209adcf Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 17 Jul 2015 09:49:08 +0200 Subject: [PATCH 68/70] Utils: Remove unused TreeItem::m_populated Left over from the original implementation used for the VariableChooser. Change-Id: I164cb306815823c988b6d79966f007298f6d1e59 Reviewed-by: Niels Weber --- src/libs/utils/treemodel.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/utils/treemodel.h b/src/libs/utils/treemodel.h index c151fe1509d..cd3da441389 100644 --- a/src/libs/utils/treemodel.h +++ b/src/libs/utils/treemodel.h @@ -116,7 +116,6 @@ private: TreeModel *m_model; // Not owned. QVector m_children; // Owned. QStringList *m_displays; - mutable bool m_populated; Qt::ItemFlags m_flags; friend class TreeModel; From 6c4c8b8a9490672f78c85aca35073f8157d85f02 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 17 Jul 2015 12:28:00 +0200 Subject: [PATCH 69/70] Debugger: Remove cache of fetched item names in Locals Views This was originally present to prevent multiple evaluations of the same items when using GDB/MI varobjs. This also prevented a proper update of child item count. Until recently this did not negatively affect the GUI due to excessive use of reset() in the view. This has changed, so the missing update was visible now, solved here by removing the cache, which is not needed anyways, since we don't use varobjs anymore. Task-number: QTCREATORBUG-14705 Change-Id: I3bbcd0525f02c10765f20be3a55708835747b307 Reviewed-by: Christian Stenger Reviewed-by: Orgad Shaneh --- src/plugins/debugger/watchhandler.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index cd557c1267c..b8fbacb202f 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -301,7 +301,6 @@ public: SeparatedView *m_separatedView; // Not owned. QSet m_expandedINames; - QSet m_fetchTriggered; QTimer m_requestUpdateTimer; QHash m_reportedTypeFormats; // Type name -> Dumper Formats @@ -670,17 +669,13 @@ bool WatchItem::canFetchMore() const return false; if (!model->m_contentsValid && !isInspect()) return false; - return !model->m_fetchTriggered.contains(iname); + return true; } void WatchItem::fetchMore() { WatchModel *model = watchModel(); - if (model->m_fetchTriggered.contains(iname)) - return; - model->m_expandedINames.insert(iname); - model->m_fetchTriggered.insert(iname); if (children().isEmpty()) { setChildrenNeeded(); model->m_engine->expandItem(iname); @@ -1177,6 +1172,8 @@ void WatchModel::insertItem(WatchItem *item) if (!found) parent->appendChild(item); + item->update(); + item->walkTree([this](TreeItem *sub) { showEditValue(static_cast(sub)); }); } @@ -1665,7 +1662,6 @@ QString WatchHandler::editorContents() void WatchHandler::scheduleResetLocation() { - m_model->m_fetchTriggered.clear(); m_model->m_contentsValid = false; m_model->m_resetLocationScheduled = true; } From 503e4a08cb208392efcb3a744c1853f91a619e98 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 17 Jul 2015 13:49:32 +0200 Subject: [PATCH 70/70] Utils: Properly terminate loop in Environment::diff() The iterator needs to be tested against the end() of the same container. Change-Id: Ia4d208650d922d529ea074d4cd0eac9f4ac76b87 Reviewed-by: BogDan Vatra Reviewed-by: Tobias Hunger --- src/libs/utils/environment.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/utils/environment.cpp b/src/libs/utils/environment.cpp index 298987ee557..9ff5b4be87d 100644 --- a/src/libs/utils/environment.cpp +++ b/src/libs/utils/environment.cpp @@ -376,7 +376,7 @@ QList Environment::diff(const Environment &other) const if (thisIt == constEnd()) { result.append(EnvironmentItem(otherIt.key(), otherIt.value())); ++otherIt; - } else if (otherIt == constEnd()) { + } else if (otherIt == other.constEnd()) { EnvironmentItem item(thisIt.key(), QString()); item.unset = true; result.append(item);