From 35ca318d187eb1356f36dce86946f12a530dfd6f Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Fri, 30 Jun 2017 16:05:21 +0200 Subject: [PATCH 01/15] TextEditor: Add comment for convertPosition() Change-Id: I45883ad3d42b41bbb2ecfe79805ae34c69eeeab4 Reviewed-by: David Schulz --- src/plugins/texteditor/convenience.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/texteditor/convenience.h b/src/plugins/texteditor/convenience.h index e4f5f0480bc..f4302cd5f31 100644 --- a/src/plugins/texteditor/convenience.h +++ b/src/plugins/texteditor/convenience.h @@ -37,6 +37,7 @@ QT_END_NAMESPACE namespace TextEditor { namespace Convenience { +// line is 1-based, column is 0-based TEXTEDITOR_EXPORT bool convertPosition(const QTextDocument *document, int pos, int *line, int *column); From dae4477cd367d115e2011cfedae6b1d5dbc22cb7 Mon Sep 17 00:00:00 2001 From: Tim Jenssen Date: Mon, 3 Jul 2017 11:12:00 +0200 Subject: [PATCH 02/15] Clang: Make file ids unique Clang file ids are only unique for one query. Because we query in parallel we have to manage our own unique ids. Change-Id: I67d57d8b1766cab75ad252a14e57bbf9dc5fdb79 Reviewed-by: Tim Jenssen --- .../clangbackendipc/clangbackendipc-lib.pri | 1 + src/libs/clangbackendipc/filepath.h | 70 +++++++++---------- .../sourcefilepathcontainerbase.h | 9 +-- .../sourcelocationcontainerv2.cpp | 4 +- .../sourcerangewithtextcontainer.h | 2 + .../clangbackendipc}/stringcache.h | 25 ++++++- src/libs/utils/smallstringio.h | 4 +- src/libs/utils/smallstringview.h | 5 ++ .../clangrefactoring/refactoringclient.cpp | 15 +--- .../source/clangpchmanagerbackend-source.pri | 1 - .../source/clangquery.cpp | 23 ++---- .../source/clangquery.h | 5 +- .../source/clangquerygatherer.cpp | 13 ++-- .../source/clangquerygatherer.h | 10 +-- .../source/clangtool.cpp | 16 +---- .../source/clangtool.h | 4 +- .../source/refactoringserver.cpp | 3 +- .../source/refactoringserver.h | 6 ++ .../source/sourcelocationsutils.h | 12 ++-- .../source/sourcerangeextractor.cpp | 41 ++++++----- .../source/sourcerangeextractor.h | 17 ++++- tests/unit/unittest/clangquery-test.cpp | 12 ++-- .../unit/unittest/clangquerygatherer-test.cpp | 12 ++-- tests/unit/unittest/filepath-test.cpp | 56 +++++++++++++++ tests/unit/unittest/pchcreator-test.cpp | 2 +- .../unittest/sourcerangeextractor-test.cpp | 20 ++---- tests/unit/unittest/unittest.pro | 2 + 27 files changed, 231 insertions(+), 159 deletions(-) rename src/{tools/clangpchmanagerbackend/source => libs/clangbackendipc}/stringcache.h (89%) create mode 100644 tests/unit/unittest/filepath-test.cpp diff --git a/src/libs/clangbackendipc/clangbackendipc-lib.pri b/src/libs/clangbackendipc/clangbackendipc-lib.pri index 36afd9ae70f..9664775dd1d 100644 --- a/src/libs/clangbackendipc/clangbackendipc-lib.pri +++ b/src/libs/clangbackendipc/clangbackendipc-lib.pri @@ -155,6 +155,7 @@ HEADERS += \ $$PWD/pchmanagerclientproxy.h \ $$PWD/projectpartpch.h \ $$PWD/precompiledheadersupdatedmessage.h \ + $$PWD/stringcache.h \ $$PWD/removepchprojectpartsmessage.h \ $$PWD/clangcodemodelclientmessages.h \ $$PWD/clangcodemodelservermessages.h \ diff --git a/src/libs/clangbackendipc/filepath.h b/src/libs/clangbackendipc/filepath.h index d435441a133..717d0207905 100644 --- a/src/libs/clangbackendipc/filepath.h +++ b/src/libs/clangbackendipc/filepath.h @@ -37,66 +37,62 @@ class FilePath { public: FilePath() = default; - explicit FilePath(Utils::SmallString &&filePath) + explicit FilePath(Utils::PathString &&filePath) + : m_path(std::move(filePath)) { - auto foundReverse = std::find(filePath.rbegin(), filePath.rend(), '/'); + auto foundReverse = std::find(m_path.rbegin(), m_path.rend(), '/'); auto found = foundReverse.base(); + --found; - Utils::SmallString fileName(found, filePath.end()); - if (foundReverse != filePath.rend()) - filePath.resize(std::size_t(std::distance(filePath.begin(), --found))); + m_slashIndex = std::size_t(std::distance(m_path.begin(), found)); + } - directory_ = std::move(filePath); - name_ = std::move(fileName); + explicit FilePath(const Utils::PathString &filePath) + : FilePath(filePath.clone()) + { + } + + explicit FilePath(Utils::PathString &&filePath, std::size_t slashIndex) + : m_path(std::move(filePath)), + m_slashIndex(slashIndex) + { } explicit FilePath(const QString &filePath) - : FilePath(Utils::SmallString(filePath)) + : FilePath(Utils::PathString(filePath)) { } - FilePath(Utils::SmallString &&directory, Utils::SmallString &&name) - : directory_(std::move(directory)), - name_(std::move(name)) + FilePath(const Utils::PathString &directory, const Utils::PathString &name) + : m_path({std::move(directory), "/", std::move(name)}), + m_slashIndex(directory.size()) {} - const Utils::SmallString &directory() const + Utils::SmallStringView directory() const { - return directory_; + return m_path.mid(0, m_slashIndex); } - Utils::SmallString takeDirectory() + Utils::SmallStringView name() const { - return std::move(directory_); + return m_path.mid(m_slashIndex + 1, m_path.size() - m_slashIndex - 1); } - const Utils::SmallString &name() const + const Utils::PathString &path() const { - return name_; - } - - Utils::SmallString takeName() - { - return std::move(name_); - } - - Utils::PathString path() const - { - return {directory_, "/", name_}; + return m_path; } friend QDataStream &operator<<(QDataStream &out, const FilePath &filePath) { - out << filePath.directory_; - out << filePath.name_; + out << filePath.m_path; return out; } friend QDataStream &operator>>(QDataStream &in, FilePath &filePath) { - in >> filePath.directory_; - in >> filePath.name_; + in >> filePath.m_path; return in; } @@ -110,24 +106,22 @@ public: friend bool operator==(const FilePath &first, const FilePath &second) { - return first.name_ == second.name_ - && first.directory_ == second.directory_; + return first.m_path == second.m_path; } friend bool operator<(const FilePath &first, const FilePath &second) { - return std::tie(first.name_, first.directory_) - < std::tie(second.name_, second.directory_); + return first.m_path < second.m_path; } FilePath clone() const { - return FilePath(directory_.clone(), name_.clone()); + return FilePath(m_path.clone(), m_slashIndex); } private: - Utils::SmallString directory_; - Utils::SmallString name_; + Utils::PathString m_path = "/"; + std::size_t m_slashIndex = 0; }; CMBIPC_EXPORT QDebug operator<<(QDebug debug, const FilePath &filePath); diff --git a/src/libs/clangbackendipc/sourcefilepathcontainerbase.h b/src/libs/clangbackendipc/sourcefilepathcontainerbase.h index af5f8b570c6..ec5b78e9a7b 100644 --- a/src/libs/clangbackendipc/sourcefilepathcontainerbase.h +++ b/src/libs/clangbackendipc/sourcefilepathcontainerbase.h @@ -42,13 +42,10 @@ public: { } - void insertFilePath(uint fileId, Utils::SmallString &&fileDirectory, Utils::SmallString &&fileName) + void insertFilePath(uint fileId, Utils::PathString &&filePath) { - if (m_filePathHash.find(fileId) == m_filePathHash.end()) { - m_filePathHash.emplace(std::piecewise_construct, - std::forward_as_tuple(fileId), - std::forward_as_tuple(std::move(fileDirectory), std::move(fileName))); - } + if (m_filePathHash.find(fileId) == m_filePathHash.end()) + m_filePathHash.emplace(fileId, std::move(filePath)); } void reserve(std::size_t size) diff --git a/src/libs/clangbackendipc/sourcelocationcontainerv2.cpp b/src/libs/clangbackendipc/sourcelocationcontainerv2.cpp index b65803e7c65..3206daf2b58 100644 --- a/src/libs/clangbackendipc/sourcelocationcontainerv2.cpp +++ b/src/libs/clangbackendipc/sourcelocationcontainerv2.cpp @@ -46,10 +46,10 @@ QDebug operator<<(QDebug debug, const SourceLocationContainer &container) std::ostream &operator<<(std::ostream &os, const SourceLocationContainer &container) { os << "(" + << container.fileHash() << ", " << container.line() << ", " << container.column() << ", " - << container.offset() << ", " - << container.fileHash() + << container.offset() << ")"; return os; diff --git a/src/libs/clangbackendipc/sourcerangewithtextcontainer.h b/src/libs/clangbackendipc/sourcerangewithtextcontainer.h index 12b25084c3d..82d17f884a4 100644 --- a/src/libs/clangbackendipc/sourcerangewithtextcontainer.h +++ b/src/libs/clangbackendipc/sourcerangewithtextcontainer.h @@ -110,6 +110,8 @@ private: Utils::SmallString m_text; }; +using SourceRangeWithTextContainers = std::vector; + CMBIPC_EXPORT QDebug operator<<(QDebug debug, const SourceRangeWithTextContainer &container); std::ostream &operator<<(std::ostream &os, const SourceRangeWithTextContainer &container); } // namespace ClangBackEnd diff --git a/src/tools/clangpchmanagerbackend/source/stringcache.h b/src/libs/clangbackendipc/stringcache.h similarity index 89% rename from src/tools/clangpchmanagerbackend/source/stringcache.h rename to src/libs/clangbackendipc/stringcache.h index a85c314700b..7b4230b5770 100644 --- a/src/tools/clangpchmanagerbackend/source/stringcache.h +++ b/src/libs/clangbackendipc/stringcache.h @@ -25,16 +25,26 @@ #pragma once -#include "clangpchmanagerbackend_global.h" - #include #include +#include #include namespace ClangBackEnd { -template +class NonLockingMutex +{ +public: + constexpr NonLockingMutex() noexcept {} + NonLockingMutex(const NonLockingMutex&) = delete; + NonLockingMutex& operator=(const NonLockingMutex&) = delete; + void lock() {} + void unlock() {} +}; + +template class StringCache { class StringCacheEntry @@ -79,6 +89,8 @@ public: uint stringId(Utils::SmallStringView stringView) { + std::lock_guard lock(m_mutex); + Found found = find(stringView); if (!found.wasFound) @@ -89,6 +101,8 @@ public: std::vector stringIds(const std::vector &strings) { + std::lock_guard lock(m_mutex); + std::vector ids; ids.reserve(strings.size()); @@ -102,11 +116,15 @@ public: const StringType &string(uint id) const { + std::lock_guard lock(m_mutex); + return m_strings.at(m_indices.at(id)).string; } std::vector strings(const std::vector &ids) const { + std::lock_guard lock(m_mutex); + std::vector strings; strings.reserve(ids.size()); @@ -155,6 +173,7 @@ private: private: StringCacheEntries m_strings; std::vector m_indices; + mutable Mutex m_mutex; }; } // namespace ClangBackEnd diff --git a/src/libs/utils/smallstringio.h b/src/libs/utils/smallstringio.h index 26424b22fe0..8dabbcc4d01 100644 --- a/src/libs/utils/smallstringio.h +++ b/src/libs/utils/smallstringio.h @@ -68,8 +68,8 @@ QDataStream &operator>>(QDataStream &in, BasicSmallString &string) return in; } -inline -QDebug &operator<<(QDebug &debug, const SmallString &string) +template +QDebug &operator<<(QDebug &debug, const String &string) { using QT_PREPEND_NAMESPACE(operator<<); diff --git a/src/libs/utils/smallstringview.h b/src/libs/utils/smallstringview.h index 2d445501c2e..3e11497ed3e 100644 --- a/src/libs/utils/smallstringview.h +++ b/src/libs/utils/smallstringview.h @@ -104,6 +104,11 @@ public: return const_reverse_iterator(begin() - static_cast(1)); } + operator std::string() const + { + return std::string(data(), size()); + } + private: const char *m_pointer; size_type m_size; diff --git a/src/plugins/clangrefactoring/refactoringclient.cpp b/src/plugins/clangrefactoring/refactoringclient.cpp index 83b058d6263..4cb954e2313 100644 --- a/src/plugins/clangrefactoring/refactoringclient.cpp +++ b/src/plugins/clangrefactoring/refactoringclient.cpp @@ -104,19 +104,6 @@ void RefactoringClient::setRefactoringConnectionClient( this->connectionClient = connectionClient; } -namespace { - -Utils::SmallString concatenateFilePath(const ClangBackEnd::FilePath &filePath) -{ - Utils::SmallString concatenatedFilePath = filePath.directory().clone(); - concatenatedFilePath.append("/"); - concatenatedFilePath.append(filePath.name().clone()); - - return concatenatedFilePath; -} - -} - std::unordered_map RefactoringClient::convertFilePaths( const ClangBackEnd::FilePathDict &filePaths) { @@ -126,7 +113,7 @@ std::unordered_map RefactoringClient::convertFilePaths( auto convertFilePath = [] (const ClangBackEnd::FilePathDict::value_type &dictonaryEntry) { return std::make_pair(dictonaryEntry.first, - concatenateFilePath(dictonaryEntry.second).toQString()); + dictonaryEntry.second.path().toQString()); }; std::transform(filePaths.begin(), diff --git a/src/tools/clangpchmanagerbackend/source/clangpchmanagerbackend-source.pri b/src/tools/clangpchmanagerbackend/source/clangpchmanagerbackend-source.pri index 2bb0d0ab7b2..926280a5fa8 100644 --- a/src/tools/clangpchmanagerbackend/source/clangpchmanagerbackend-source.pri +++ b/src/tools/clangpchmanagerbackend/source/clangpchmanagerbackend-source.pri @@ -19,7 +19,6 @@ HEADERS += \ $$PWD/environment.h \ $$PWD/clangpathwatcher.h \ $$PWD/projectparts.h \ - $$PWD/stringcache.h \ $$PWD/idpaths.h \ $$PWD/pchcreatorinterface.h \ $$PWD/clangpathwatcherinterface.h \ diff --git a/src/tools/clangrefactoringbackend/source/clangquery.cpp b/src/tools/clangrefactoringbackend/source/clangquery.cpp index d24b981f458..be93b61a1a6 100644 --- a/src/tools/clangrefactoringbackend/source/clangquery.cpp +++ b/src/tools/clangrefactoringbackend/source/clangquery.cpp @@ -30,27 +30,15 @@ #include -#include +#include -#if defined(__GNUC__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wunused-parameter" -#elif defined(_MSC_VER) -# pragma warning(push) -# pragma warning( disable : 4100 ) -#endif +#include #include #include #include #include -#if defined(__GNUC__) -# pragma GCC diagnostic pop -#elif defined(_MSC_VER) -# pragma warning(pop) -#endif - using clang::ast_matchers::dynamic::Diagnostics; using clang::ast_matchers::dynamic::Parser; using clang::ast_matchers::BoundNodes; @@ -66,8 +54,10 @@ struct CollectBoundNodes : MatchFinder::MatchCallback { } }; -ClangQuery::ClangQuery(Utils::SmallString &&query) - : query(std::move(query)) +ClangQuery::ClangQuery(StringCache &filePathCache, + Utils::SmallString &&query) + : query(std::move(query)), + filePathCache(filePathCache) { } @@ -226,6 +216,7 @@ void ClangQuery::matchLocation( SourceRangeExtractor extractor(ast->getSourceManager(), ast->getLangOpts(), + filePathCache, sourceRangesContainer); extractor.addSourceRanges(sourceRanges); diff --git a/src/tools/clangrefactoringbackend/source/clangquery.h b/src/tools/clangrefactoringbackend/source/clangquery.h index 93190449a5d..20b38a7ab10 100644 --- a/src/tools/clangrefactoringbackend/source/clangquery.h +++ b/src/tools/clangrefactoringbackend/source/clangquery.h @@ -30,6 +30,8 @@ #include #include +#include + namespace clang { namespace ast_matchers { namespace dynamic { @@ -49,7 +51,7 @@ namespace ClangBackEnd { class ClangQuery : public ClangTool { public: - ClangQuery(Utils::SmallString &&query={}); + ClangQuery(StringCache &filePathCache, Utils::SmallString &&query={}); void setQuery(Utils::SmallString &&query); @@ -67,6 +69,7 @@ private: SourceRangesContainer sourceRangesContainer; Utils::SmallString query; std::vector diagnosticContainers_; + StringCache &filePathCache; }; } // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/clangquerygatherer.cpp b/src/tools/clangrefactoringbackend/source/clangquerygatherer.cpp index cbf9a9c70c2..09c96a69b53 100644 --- a/src/tools/clangrefactoringbackend/source/clangquerygatherer.cpp +++ b/src/tools/clangrefactoringbackend/source/clangquerygatherer.cpp @@ -29,10 +29,12 @@ namespace ClangBackEnd { -ClangQueryGatherer::ClangQueryGatherer(std::vector &&sources, +ClangQueryGatherer::ClangQueryGatherer(StringCache *filePathCache, + std::vector &&sources, std::vector &&unsaved, Utils::SmallString &&query) - : m_sources(std::move(sources)), + : m_filePathCache(filePathCache), + m_sources(std::move(sources)), m_unsaved(std::move(unsaved)), m_query(std::move(query)) { @@ -40,11 +42,12 @@ ClangQueryGatherer::ClangQueryGatherer(std::vector &&sources, SourceRangesAndDiagnosticsForQueryMessage ClangQueryGatherer::createSourceRangesAndDiagnosticsForSource( + StringCache *filePathCache, V2::FileContainer &&source, const std::vector &unsaved, Utils::SmallString &&query) { - ClangQuery clangQuery(std::move(query)); + ClangQuery clangQuery(*filePathCache, std::move(query)); clangQuery.addFile(source.filePath().directory(), source.filePath().name(), @@ -65,7 +68,8 @@ bool ClangQueryGatherer::canCreateSourceRangesAndDiagnostics() const SourceRangesAndDiagnosticsForQueryMessage ClangQueryGatherer::createNextSourceRangesAndDiagnostics() { - auto message = createSourceRangesAndDiagnosticsForSource(std::move(m_sources.back()), + auto message = createSourceRangesAndDiagnosticsForSource(m_filePathCache, + std::move(m_sources.back()), m_unsaved, m_query.clone()); m_sources.pop_back(); @@ -77,6 +81,7 @@ ClangQueryGatherer::Future ClangQueryGatherer::startCreateNextSourceRangesAndDia { Future future = std::async(std::launch::async, createSourceRangesAndDiagnosticsForSource, + m_filePathCache, std::move(m_sources.back()), m_unsaved, m_query.clone()); diff --git a/src/tools/clangrefactoringbackend/source/clangquerygatherer.h b/src/tools/clangrefactoringbackend/source/clangquerygatherer.h index a7ba8fac790..b9370563791 100644 --- a/src/tools/clangrefactoringbackend/source/clangquerygatherer.h +++ b/src/tools/clangrefactoringbackend/source/clangquerygatherer.h @@ -27,6 +27,7 @@ #include #include +#include #include @@ -38,16 +39,16 @@ public: using Future = std::future; ClangQueryGatherer() = default; - ClangQueryGatherer(std::vector &&sources, + ClangQueryGatherer(StringCache *filePathCache, + std::vector &&sources, std::vector &&unsaved, Utils::SmallString &&query); - static - SourceRangesAndDiagnosticsForQueryMessage createSourceRangesAndDiagnosticsForSource( + static SourceRangesAndDiagnosticsForQueryMessage createSourceRangesAndDiagnosticsForSource( + StringCache *filePathCache, V2::FileContainer &&source, const std::vector &unsaved, Utils::SmallString &&query); - bool canCreateSourceRangesAndDiagnostics() const; SourceRangesAndDiagnosticsForQueryMessage createNextSourceRangesAndDiagnostics(); Future startCreateNextSourceRangesAndDiagnosticsMessage(); @@ -66,6 +67,7 @@ protected: std::vector finishedFutures(); private: + StringCache *m_filePathCache = nullptr; std::vector m_sources; std::vector m_unsaved; Utils::SmallString m_query; diff --git a/src/tools/clangrefactoringbackend/source/clangtool.cpp b/src/tools/clangrefactoringbackend/source/clangtool.cpp index dd4b6c57a3f..2ffad739655 100644 --- a/src/tools/clangrefactoringbackend/source/clangtool.cpp +++ b/src/tools/clangrefactoringbackend/source/clangtool.cpp @@ -84,23 +84,12 @@ template void ClangTool::addFiles(const Utils::PathStringVector &filePaths, const Utils::SmallStringVector &arguments); -namespace { -Utils::SmallString toNativeFilePath(const FilePath &filePath) -{ - Utils::SmallString filePathString = filePath.directory().clone(); - filePathString.append("/"); - filePathString.append(filePath.name()); - - return toNativePath(std::move(filePathString)); -} -} - void ClangTool::addUnsavedFiles(const V2::FileContainers &unsavedFiles) { unsavedFileContents.reserve(unsavedFileContents.size() + unsavedFiles.size()); auto convertToUnsavedFileContent = [] (const V2::FileContainer &unsavedFile) { - return UnsavedFileContent{toNativeFilePath(unsavedFile.filePath()), + return UnsavedFileContent{toNativePath(unsavedFile.filePath().path().clone()), unsavedFile.unsavedFileContent().clone()}; }; @@ -111,7 +100,8 @@ void ClangTool::addUnsavedFiles(const V2::FileContainers &unsavedFiles) } namespace { -llvm::StringRef toStringRef(const Utils::SmallString &string) +template +llvm::StringRef toStringRef(const String &string) { return llvm::StringRef(string.data(), string.size()); } diff --git a/src/tools/clangrefactoringbackend/source/clangtool.h b/src/tools/clangrefactoringbackend/source/clangtool.h index c7ee2a83e02..c6439209143 100644 --- a/src/tools/clangrefactoringbackend/source/clangtool.h +++ b/src/tools/clangrefactoringbackend/source/clangtool.h @@ -77,13 +77,13 @@ struct FileContent struct UnsavedFileContent { - UnsavedFileContent(Utils::SmallString &&filePath, + UnsavedFileContent(Utils::PathString &&filePath, Utils::SmallString &&content) : filePath(std::move(filePath)), content(std::move(content)) {} - Utils::SmallString filePath; + Utils::PathString filePath; Utils::SmallString content; }; diff --git a/src/tools/clangrefactoringbackend/source/refactoringserver.cpp b/src/tools/clangrefactoringbackend/source/refactoringserver.cpp index 58e944784df..cf233baf34f 100644 --- a/src/tools/clangrefactoringbackend/source/refactoringserver.cpp +++ b/src/tools/clangrefactoringbackend/source/refactoringserver.cpp @@ -37,6 +37,7 @@ #include #include +#include namespace ClangBackEnd { @@ -125,7 +126,7 @@ void RefactoringServer::gatherSourceRangesAndDiagnosticsForQueryMessages( uint freeProcessors = std::thread::hardware_concurrency(); #endif - m_gatherer = ClangQueryGatherer(std::move(sources), std::move(unsaved), std::move(query)); + m_gatherer = ClangQueryGatherer(&m_filePathCache, std::move(sources), std::move(unsaved), std::move(query)); m_gatherer.setProcessingSlotCount(freeProcessors); m_pollTimer.start(); diff --git a/src/tools/clangrefactoringbackend/source/refactoringserver.h b/src/tools/clangrefactoringbackend/source/refactoringserver.h index e3b40d3c56f..1befa076216 100644 --- a/src/tools/clangrefactoringbackend/source/refactoringserver.h +++ b/src/tools/clangrefactoringbackend/source/refactoringserver.h @@ -30,7 +30,12 @@ #include #include +#include +#include + +#include +#include #include namespace ClangBackEnd { @@ -65,6 +70,7 @@ private: Utils::SmallString &&query); private: + StringCache m_filePathCache; ClangQueryGatherer m_gatherer; QTimer m_pollTimer; }; diff --git a/src/tools/clangrefactoringbackend/source/sourcelocationsutils.h b/src/tools/clangrefactoringbackend/source/sourcelocationsutils.h index 78076f5f2bd..df07b42daa1 100644 --- a/src/tools/clangrefactoringbackend/source/sourcelocationsutils.h +++ b/src/tools/clangrefactoringbackend/source/sourcelocationsutils.h @@ -53,7 +53,7 @@ namespace ClangBackEnd { inline -llvm::SmallString<256> absolutePath(const llvm::StringRef &path) +llvm::SmallString<256> absolutePath(clang::StringRef path) { llvm::SmallString<256> absolutePath(path); @@ -64,9 +64,9 @@ llvm::SmallString<256> absolutePath(const llvm::StringRef &path) } template -Utils::SmallString fromNativePath(Container container) +Utils::PathString fromNativePath(Container container) { - Utils::SmallString path(container.data(), container.size()); + Utils::PathString path(container.data(), container.size()); #ifdef _WIN32 std::replace(path.begin(), path.end(), '\\', '/'); @@ -89,13 +89,9 @@ void appendSourceLocationsToSourceLocationsContainer( const auto fileId = decomposedLoction.first; const auto offset = decomposedLoction.second; const auto fileEntry = sourceManager.getFileEntryForID(fileId); - auto filePath = absolutePath(fileEntry->getName()); - const auto fileName = llvm::sys::path::filename(filePath); - llvm::sys::path::remove_filename(filePath); sourceLocationsContainer.insertFilePath(fileId.getHashValue(), - fromNativePath(filePath), - fromNativePath(fileName)); + fromNativePath(fileEntry->tryGetRealPathName())); sourceLocationsContainer.insertSourceLocation(fileId.getHashValue(), fullSourceLocation.getSpellingLineNumber(), fullSourceLocation.getSpellingColumnNumber(), diff --git a/src/tools/clangrefactoringbackend/source/sourcerangeextractor.cpp b/src/tools/clangrefactoringbackend/source/sourcerangeextractor.cpp index 18b6288cae5..e83f6a3c383 100644 --- a/src/tools/clangrefactoringbackend/source/sourcerangeextractor.cpp +++ b/src/tools/clangrefactoringbackend/source/sourcerangeextractor.cpp @@ -51,11 +51,14 @@ namespace ClangBackEnd { -SourceRangeExtractor::SourceRangeExtractor(const clang::SourceManager &sourceManager, - const clang::LangOptions &languageOptions, - SourceRangesContainer &sourceRangesContainer) +SourceRangeExtractor::SourceRangeExtractor( + const clang::SourceManager &sourceManager, + const clang::LangOptions &languageOptions, + ClangBackEnd::StringCache &filePathCache, + SourceRangesContainer &sourceRangesContainer) : sourceManager(sourceManager), languageOptions(languageOptions), + filePathCache(filePathCache), sourceRangesContainer(sourceRangesContainer) { } @@ -123,19 +126,16 @@ const clang::SourceRange SourceRangeExtractor::extendSourceRangeToLastTokenEnd(c return {sourceRange.getBegin(), endLocation}; } -void SourceRangeExtractor::insertSourceRange(uint fileHash, - Utils::SmallString &&directoryPath, - Utils::SmallString &&fileName, +void SourceRangeExtractor::insertSourceRange(uint fileId, + Utils::PathString &&filePath, const clang::FullSourceLoc &startLocation, uint startOffset, const clang::FullSourceLoc &endLocation, uint endOffset, Utils::SmallString &&lineSnippet) { - sourceRangesContainer.insertFilePath(fileHash, - std::move(directoryPath), - std::move(fileName)); - sourceRangesContainer.insertSourceRange(fileHash, + sourceRangesContainer.insertFilePath(fileId, std::move(filePath)); + sourceRangesContainer.insertSourceRange(fileId, startLocation.getSpellingLineNumber(), startLocation.getSpellingColumnNumber(), startOffset, @@ -145,6 +145,17 @@ void SourceRangeExtractor::insertSourceRange(uint fileHash, std::move(lineSnippet)); } +uint SourceRangeExtractor::findFileId(clang::FileID fileId, const clang::FileEntry *fileEntry) const +{ + auto found = m_fileIdMapping.find(fileId.getHashValue()); + if (found != m_fileIdMapping.end()) { + return found->second; + } + + auto filePath = absolutePath(fileEntry->tryGetRealPathName()); + return filePathCache.stringId(fromNativePath(filePath)); +} + void SourceRangeExtractor::addSourceRange(const clang::SourceRange &sourceRange) { auto extendedSourceRange = extendSourceRangeToLastTokenEnd(sourceRange); @@ -158,15 +169,13 @@ void SourceRangeExtractor::addSourceRange(const clang::SourceRange &sourceRange) const auto startOffset = startDecomposedLoction.second; const auto endOffset = endDecomposedLoction.second; const auto fileEntry = sourceManager.getFileEntryForID(fileId); - auto filePath = absolutePath(fileEntry->getName()); - const auto fileName = llvm::sys::path::filename(filePath); - llvm::sys::path::remove_filename(filePath); + Utils::SmallString lineSnippet = getExpandedText(startSourceLocation.getBufferData(), startOffset, endOffset); - insertSourceRange(fileId.getHashValue(), - fromNativePath(filePath), - {fileName.data(), fileName.size()}, + + insertSourceRange(findFileId(fileId, fileEntry), + fromNativePath(fileEntry->tryGetRealPathName()), startSourceLocation, startOffset, endSourceLocation, diff --git a/src/tools/clangrefactoringbackend/source/sourcerangeextractor.h b/src/tools/clangrefactoringbackend/source/sourcerangeextractor.h index 5bd6cf75ab7..7a07e5c3f87 100644 --- a/src/tools/clangrefactoringbackend/source/sourcerangeextractor.h +++ b/src/tools/clangrefactoringbackend/source/sourcerangeextractor.h @@ -25,9 +25,14 @@ #pragma once +#include + +#include + #include #include +#include using uint = unsigned int; @@ -40,6 +45,8 @@ class SourceManager; class LangOptions; class SourceRange; class FullSourceLoc; +class FileID; +class FileEntry; } namespace ClangBackEnd { @@ -52,6 +59,7 @@ class SourceRangeExtractor public: SourceRangeExtractor(const clang::SourceManager &sourceManager, const clang::LangOptions &languageOptions, + ClangBackEnd::StringCache &filePathCache, SourceRangesContainer &sourceRangesContainer); void addSourceRange(const clang::SourceRange &sourceRange); @@ -66,18 +74,21 @@ public: const clang::SourceRange extendSourceRangeToLastTokenEnd(const clang::SourceRange sourceRange); private: - void insertSourceRange(uint fileHash, - Utils::SmallString &&directoryPath, - Utils::SmallString &&fileName, + void insertSourceRange(uint fileId, + Utils::PathString &&filePath, const clang::FullSourceLoc &startLocation, uint startOffset, const clang::FullSourceLoc &endLocation, uint endOffset, Utils::SmallString &&lineSnippet); + uint findFileId(clang::FileID fileId, const clang::FileEntry *fileEntry) const; + private: + mutable std::unordered_map m_fileIdMapping; const clang::SourceManager &sourceManager; const clang::LangOptions &languageOptions; + ClangBackEnd::StringCache &filePathCache; SourceRangesContainer &sourceRangesContainer; }; diff --git a/tests/unit/unittest/clangquery-test.cpp b/tests/unit/unittest/clangquery-test.cpp index b71e267697d..39f82e09555 100644 --- a/tests/unit/unittest/clangquery-test.cpp +++ b/tests/unit/unittest/clangquery-test.cpp @@ -29,7 +29,10 @@ #include +#include + using ClangBackEnd::ClangQuery; +using ClangBackEnd::StringCache; using testing::IsEmpty; using testing::Not; @@ -43,8 +46,9 @@ protected: void SetUp() override; protected: - ::ClangQuery simpleFunctionQuery; - ::ClangQuery simpleClassQuery; + StringCache filePathCache; + ::ClangQuery simpleFunctionQuery{filePathCache}; + ::ClangQuery simpleClassQuery{filePathCache}; }; using ClangQuerySlowTest = ClangQuery; @@ -77,7 +81,7 @@ TEST_F(ClangQuerySlowTest, RootSourceRangeForSimpleFunctionDeclarationRange) TEST_F(ClangQuerySlowTest, SourceRangeInUnsavedFileDeclarationRange) { - ::ClangQuery query; + ::ClangQuery query(filePathCache); query.addFile(TESTDATA_DIR, "query_simplefunction.cpp", "#include \"unsaved.h\"", {"cc", "query_simplefunction.cpp", "-std=c++14"}); query.setQuery("functionDecl()"); ClangBackEnd::V2::FileContainer unsavedFile{{TESTDATA_DIR, "unsaved.h"}, "void unsaved();", {}}; @@ -91,7 +95,7 @@ TEST_F(ClangQuerySlowTest, SourceRangeInUnsavedFileDeclarationRange) TEST_F(ClangQuerySlowTest, DISABLED_SourceRangeInUnsavedFileDeclarationRangeOverride) // seems not to work in Clang { - ::ClangQuery query; + ::ClangQuery query(filePathCache); query.addFile(TESTDATA_DIR, "query_simplefunction.cpp", "void f() {}", {"cc", "query_simplefunction.cpp", "-std=c++14"}); query.setQuery("functionDecl()"); ClangBackEnd::V2::FileContainer unsavedFile{{TESTDATA_DIR, "query_simplefunction.cpp"}, "void unsaved();", {}}; diff --git a/tests/unit/unittest/clangquerygatherer-test.cpp b/tests/unit/unittest/clangquerygatherer-test.cpp index 089f273f062..0e24e4fa6d4 100644 --- a/tests/unit/unittest/clangquerygatherer-test.cpp +++ b/tests/unit/unittest/clangquerygatherer-test.cpp @@ -71,6 +71,7 @@ protected: void SetUp() override; protected: + ClangBackEnd::StringCache filePathCache; Utils::SmallString sourceContent{"#include \"query_simplefunction.h\"\nvoid f()\n {}"}; FileContainer source{{TESTDATA_DIR, "query_simplefunction.cpp"}, sourceContent.clone(), @@ -80,15 +81,16 @@ protected: unsavedContent.clone(), {}}; Utils::SmallString query{"functionDecl()"}; - ClangBackEnd::ClangQueryGatherer gatherer{{source.clone()}, {unsaved.clone()}, query.clone()}; - ClangBackEnd::ClangQueryGatherer manyGatherer{{source.clone(), source.clone(), source.clone()}, + ClangBackEnd::ClangQueryGatherer gatherer{&filePathCache, {source.clone()}, {unsaved.clone()}, query.clone()}; + ClangBackEnd::ClangQueryGatherer manyGatherer{&filePathCache, + {source.clone(), source.clone(), source.clone()}, {unsaved.clone()}, query.clone()}; }; TEST_F(ClangQueryGatherer, CreateSourceRangesAndDiagnostics) { - auto sourceRangesAndDiagnostics = gatherer.createSourceRangesAndDiagnosticsForSource(source.clone(), {}, query.clone()); + auto sourceRangesAndDiagnostics = gatherer.createSourceRangesAndDiagnosticsForSource(&filePathCache, source.clone(), {}, query.clone()); ASSERT_THAT(sourceRangesAndDiagnostics, Property(&SourceRangesAndDiagnosticsForQueryMessage::sourceRanges, @@ -98,7 +100,7 @@ TEST_F(ClangQueryGatherer, CreateSourceRangesAndDiagnostics) TEST_F(ClangQueryGatherer, CreateSourceRangesAndDiagnosticssWithUnsavedContent) { - auto sourceRangesAndDiagnostics = gatherer.createSourceRangesAndDiagnosticsForSource(source.clone(), {unsaved}, query.clone()); + auto sourceRangesAndDiagnostics = gatherer.createSourceRangesAndDiagnosticsForSource(&filePathCache, source.clone(), {unsaved}, query.clone()); ASSERT_THAT(sourceRangesAndDiagnostics, Property(&SourceRangesAndDiagnosticsForQueryMessage::sourceRanges, @@ -113,7 +115,7 @@ TEST_F(ClangQueryGatherer, CanCreateSourceRangesAndDiagnosticsIfItHasSources) TEST_F(ClangQueryGatherer, CanNotCreateSourceRangesAndDiagnosticsIfItHasNoSources) { - ClangBackEnd::ClangQueryGatherer empthyGatherer{{}, {unsaved.clone()}, query.clone()}; + ClangBackEnd::ClangQueryGatherer empthyGatherer{&filePathCache, {}, {unsaved.clone()}, query.clone()}; ASSERT_FALSE(empthyGatherer.canCreateSourceRangesAndDiagnostics()); } diff --git a/tests/unit/unittest/filepath-test.cpp b/tests/unit/unittest/filepath-test.cpp new file mode 100644 index 00000000000..d82e94f2119 --- /dev/null +++ b/tests/unit/unittest/filepath-test.cpp @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "googletest.h" + +#include + +namespace { + +TEST(FilePath, CreateFromPathString) +{ + ClangBackEnd::FilePath filePath{Utils::PathString{"/file/pathOne"}}; + + ASSERT_THAT(filePath.directory(), "/file"); + ASSERT_THAT(filePath.name(), "pathOne"); +} + +TEST(FilePath, CreateFromQString) +{ + ClangBackEnd::FilePath filePath{QString{"/file/pathOne"}}; + + ASSERT_THAT(filePath.directory(), "/file"); + ASSERT_THAT(filePath.name(), "pathOne"); +} + +TEST(FilePath, EmptyFilePath) +{ + ClangBackEnd::FilePath filePath; + + ASSERT_THAT(filePath.directory(), ""); + ASSERT_THAT(filePath.name(), ""); +} + +} diff --git a/tests/unit/unittest/pchcreator-test.cpp b/tests/unit/unittest/pchcreator-test.cpp index 0798e9d63c1..763521da420 100644 --- a/tests/unit/unittest/pchcreator-test.cpp +++ b/tests/unit/unittest/pchcreator-test.cpp @@ -73,7 +73,7 @@ protected: PathString main2Path = TESTDATA_DIR "/includecollector_main2.cpp"; PathString header1Path = TESTDATA_DIR "/includecollector_header1.h"; PathString header2Path = TESTDATA_DIR "/includecollector_header2.h"; - SmallString generatedFileName = "includecollector_generated_file.h"; + PathString generatedFileName = "includecollector_generated_file.h"; PathString generatedFilePath = TESTDATA_DIR "/includecollector_generated_file.h"; ProjectPartContainer projectPart1{"project1", {"-I", TESTDATA_DIR, "-Wno-pragma-once-outside-header"}, diff --git a/tests/unit/unittest/sourcerangeextractor-test.cpp b/tests/unit/unittest/sourcerangeextractor-test.cpp index df527b4e620..8bf676b7962 100644 --- a/tests/unit/unittest/sourcerangeextractor-test.cpp +++ b/tests/unit/unittest/sourcerangeextractor-test.cpp @@ -28,23 +28,12 @@ #include #include - -#if defined(__GNUC__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wunused-parameter" -#elif defined(_MSC_VER) -# pragma warning(push) -# pragma warning( disable : 4100 ) -#endif +#include #include #include -#if defined(__GNUC__) -# pragma GCC diagnostic pop -#elif defined(_MSC_VER) -# pragma warning(pop) -#endif +#include using testing::Contains; using ::testing::Eq; @@ -65,7 +54,8 @@ protected: TestClangTool clangTool{TESTDATA_DIR, "sourcerangeextractor_location.cpp", "", {"cc", "sourcerangeextractor_location.cpp"}}; ClangBackEnd::SourceRangesContainer sourceRangesContainer; const clang::SourceManager &sourceManager{clangTool.sourceManager()}; - ClangBackEnd::SourceRangeExtractor extractor{sourceManager, clangTool.languageOptions(), sourceRangesContainer}; + ClangBackEnd::StringCache filePathCache; + ClangBackEnd::SourceRangeExtractor extractor{sourceManager, clangTool.languageOptions(), filePathCache, sourceRangesContainer}; clang::SourceLocation startLocation = sourceManager.getLocForStartOfFile(sourceManager.getMainFileID()); clang::SourceLocation endLocation = sourceManager.getLocForStartOfFile(sourceManager.getMainFileID()).getLocWithOffset(4); clang::SourceRange sourceRange{startLocation, endLocation}; @@ -76,7 +66,7 @@ using SourceRangeExtractorSlowTest = SourceRangeExtractor; TEST_F(SourceRangeExtractorSlowTest, ExtractSourceRangeContainer) { - SourceRangeWithTextContainer sourceRangeContainer{1, 1, 1, 0, 1, 10, 9, Utils::SmallString("int value;")}; + SourceRangeWithTextContainer sourceRangeContainer{0, 1, 1, 0, 1, 10, 9, Utils::SmallString("int value;")}; extractor.addSourceRange(sourceRange); diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro index 73e0ed31a3f..4e32ce0413c 100644 --- a/tests/unit/unittest/unittest.pro +++ b/tests/unit/unittest/unittest.pro @@ -63,6 +63,8 @@ SOURCES += \ projectupdater-test.cpp \ pchmanagerserver-test.cpp \ pchmanagerclientserverinprocess-test.cpp \ + clangquerygatherer-test.cpp \ + filepath-test.cpp !isEmpty(LIBCLANG_LIBS) { SOURCES += \ From 1607a34a9aee965f65b8e57817c52c6c10c9ef41 Mon Sep 17 00:00:00 2001 From: Ivan Donchevskii Date: Thu, 29 Jun 2017 15:04:01 +0200 Subject: [PATCH 03/15] Utils: use unique_ptr for QFile object Do not use raw pointer. Change-Id: I6810c3ec3a60a43829130cf5e5a00e52db95b965 Reviewed-by: Joerg Bornemann --- src/libs/utils/fileutils.cpp | 25 ++++++++----------------- src/libs/utils/fileutils.h | 10 +++++----- 2 files changed, 13 insertions(+), 22 deletions(-) diff --git a/src/libs/utils/fileutils.cpp b/src/libs/utils/fileutils.cpp index d90775e5033..cedf84e2291 100644 --- a/src/libs/utils/fileutils.cpp +++ b/src/libs/utils/fileutils.cpp @@ -395,18 +395,11 @@ FileSaverBase::FileSaverBase() { } -FileSaverBase::~FileSaverBase() -{ - delete m_file; -} - bool FileSaverBase::finalize() { m_file->close(); setResult(m_file->error() == QFile::NoError); - // We delete the object, so it is really closed even if it is a QTemporaryFile. - delete m_file; - m_file = 0; + m_file.reset(); return !m_hasError; } @@ -488,10 +481,10 @@ FileSaver::FileSaver(const QString &filename, QIODevice::OpenMode mode) } } if (mode & (QIODevice::ReadOnly | QIODevice::Append)) { - m_file = new QFile(filename); + m_file.reset(new QFile{filename}); m_isSafe = false; } else { - m_file = new SaveFile(filename); + m_file.reset(new SaveFile{filename}); m_isSafe = true; } if (!m_file->open(QIODevice::WriteOnly | mode)) { @@ -507,22 +500,22 @@ bool FileSaver::finalize() if (!m_isSafe) return FileSaverBase::finalize(); - SaveFile *sf = static_cast(m_file); + SaveFile *sf = static_cast(m_file.get()); if (m_hasError) { if (sf->isOpen()) sf->rollback(); } else { setResult(sf->commit()); } - delete sf; - m_file = 0; + m_file.reset(); return !m_hasError; } TempFileSaver::TempFileSaver(const QString &templ) : m_autoRemove(true) { - QTemporaryFile *tempFile = new QTemporaryFile(); + m_file.reset(new QTemporaryFile{}); + QTemporaryFile *tempFile = static_cast(m_file.get()); if (!templ.isEmpty()) tempFile->setFileTemplate(templ); tempFile->setAutoRemove(false); @@ -532,14 +525,12 @@ TempFileSaver::TempFileSaver(const QString &templ) tempFile->errorString()); m_hasError = true; } - m_file = tempFile; m_fileName = tempFile->fileName(); } TempFileSaver::~TempFileSaver() { - delete m_file; - m_file = 0; + m_file.reset(); if (m_autoRemove) QFile::remove(m_fileName); } diff --git a/src/libs/utils/fileutils.h b/src/libs/utils/fileutils.h index 43f7fc2e86e..b53c0e58c59 100644 --- a/src/libs/utils/fileutils.h +++ b/src/libs/utils/fileutils.h @@ -35,6 +35,7 @@ #include #include +#include namespace Utils {class FileName; } @@ -174,7 +175,7 @@ class QTCREATOR_UTILS_EXPORT FileSaverBase Q_DECLARE_TR_FUNCTIONS(Utils::FileUtils) // sic! public: FileSaverBase(); - virtual ~FileSaverBase(); + virtual ~FileSaverBase() = default; QString fileName() const { return m_fileName; } bool hasError() const { return m_hasError; } @@ -190,8 +191,10 @@ public: bool setResult(QXmlStreamWriter *stream); bool setResult(bool ok); + QFile *file() { return m_file.get(); } + protected: - QFile *m_file; + std::unique_ptr m_file; QString m_fileName; QString m_errorString; bool m_hasError; @@ -208,7 +211,6 @@ public: virtual bool finalize(); using FileSaverBase::finalize; - QFile *file() { return m_file; } private: bool m_isSafe; @@ -221,8 +223,6 @@ public: explicit TempFileSaver(const QString &templ = QString()); ~TempFileSaver(); - QTemporaryFile *file() { return reinterpret_cast(m_file); } - void setAutoRemove(bool on) { m_autoRemove = on; } private: From 07c3a37054397389f54e90531cf8aab4c4c8e593 Mon Sep 17 00:00:00 2001 From: Ivan Donchevskii Date: Thu, 29 Jun 2017 15:16:26 +0200 Subject: [PATCH 04/15] Utils: improve failed file saving behavior Remove temporary files left after fail. Set error string for locked file. Task-number: QTCREATORBUG-15449 Change-Id: Ibc8b01a4ea47870c29493a69718db929070ac13f Reviewed-by: Oswald Buddenhagen --- src/libs/utils/fileutils.cpp | 9 +++++++-- src/libs/utils/savefile.cpp | 13 +++++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/libs/utils/fileutils.cpp b/src/libs/utils/fileutils.cpp index cedf84e2291..7f25dc722b3 100644 --- a/src/libs/utils/fileutils.cpp +++ b/src/libs/utils/fileutils.cpp @@ -437,8 +437,13 @@ bool FileSaverBase::write(const QByteArray &bytes) bool FileSaverBase::setResult(bool ok) { if (!ok && !m_hasError) { - m_errorString = tr("Cannot write file %1. Disk full?").arg( - QDir::toNativeSeparators(m_fileName)); + if (!m_file->errorString().isEmpty()) { + m_errorString = tr("Cannot write file %1: %2").arg( + QDir::toNativeSeparators(m_fileName), m_file->errorString()); + } else { + m_errorString = tr("Cannot write file %1. Disk full?").arg( + QDir::toNativeSeparators(m_fileName)); + } m_hasError = true; } return ok; diff --git a/src/libs/utils/savefile.cpp b/src/libs/utils/savefile.cpp index b514d6233d0..aeac15a6273 100644 --- a/src/libs/utils/savefile.cpp +++ b/src/libs/utils/savefile.cpp @@ -113,10 +113,19 @@ bool SaveFile::commit() QString finalFileName = FileUtils::resolveSymlinks(FileName::fromString(m_finalFileName)).toString(); QString bakname = finalFileName + QLatin1Char('~'); - QFile::remove(bakname); // Kill old backup - QFile::rename(finalFileName, bakname); // Backup current file + + if (QFile::exists(finalFileName)) { + QFile::remove(bakname); // Kill old backup + // Try to back up current file + if (!QFile::rename(finalFileName, bakname)) { + remove(); + setErrorString(tr("File might be locked.")); + return false; + } + } if (!rename(finalFileName)) { // Replace current file QFile::rename(bakname, finalFileName); // Rollback to current file + remove(); return false; } if (!m_backup) From 23cae9a9e046adf3332614bd7524b89f72f02dd1 Mon Sep 17 00:00:00 2001 From: Tim Jenssen Date: Mon, 3 Jul 2017 11:53:47 +0200 Subject: [PATCH 05/15] Clang: Filter duplicates in clang query output Because we can visit headers many times, we get results many times too. Change-Id: I3bbe7d7a5d01c2580a4569bfe115f14a69edc8a7 Reviewed-by: Tim Jenssen --- ...ourcerangesanddiagnosticsforquerymessage.h | 5 + .../clangbackendipc/sourcerangescontainer.h | 5 + .../sourcerangewithtextcontainer.h | 17 +++ .../source/clangquerygatherer.cpp | 5 +- .../source/clangquerygatherer.h | 3 + .../source/clangrefactoringbackend-source.pri | 6 +- .../source/refactoringserver.cpp | 5 + .../source/refactoringserver.h | 2 + .../source/sourcerangefilter.cpp | 59 ++++++++++ .../source/sourcerangefilter.h | 47 ++++++++ .../unit/unittest/clangquerygatherer-test.cpp | 73 +++++++++--- .../unittest/data/query_simplefunction2.cpp | 4 + .../unittest/data/query_simplefunction2.h | 2 + .../unittest/data/query_simplefunction3.cpp | 4 + .../unit/unittest/refactoringserver-test.cpp | 24 +++- .../unit/unittest/sourcerangefilter-test.cpp | 106 ++++++++++++++++++ tests/unit/unittest/unittest.pro | 3 +- 17 files changed, 347 insertions(+), 23 deletions(-) create mode 100644 src/tools/clangrefactoringbackend/source/sourcerangefilter.cpp create mode 100644 src/tools/clangrefactoringbackend/source/sourcerangefilter.h create mode 100644 tests/unit/unittest/data/query_simplefunction2.cpp create mode 100644 tests/unit/unittest/data/query_simplefunction2.h create mode 100644 tests/unit/unittest/data/query_simplefunction3.cpp create mode 100644 tests/unit/unittest/sourcerangefilter-test.cpp diff --git a/src/libs/clangbackendipc/sourcerangesanddiagnosticsforquerymessage.h b/src/libs/clangbackendipc/sourcerangesanddiagnosticsforquerymessage.h index f6c17a95290..6634d501956 100644 --- a/src/libs/clangbackendipc/sourcerangesanddiagnosticsforquerymessage.h +++ b/src/libs/clangbackendipc/sourcerangesanddiagnosticsforquerymessage.h @@ -47,6 +47,11 @@ public: return sourceRangesContainer; } + SourceRangesContainer &sourceRanges() + { + return sourceRangesContainer; + } + const std::vector &diagnostics() const { return diagnosticContainers; diff --git a/src/libs/clangbackendipc/sourcerangescontainer.h b/src/libs/clangbackendipc/sourcerangescontainer.h index 11ea542136a..147b7cb53ae 100644 --- a/src/libs/clangbackendipc/sourcerangescontainer.h +++ b/src/libs/clangbackendipc/sourcerangescontainer.h @@ -54,6 +54,11 @@ public: return m_sourceRangeWithTextContainers; } + std::vector &sourceRangeWithTextContainers() + { + return m_sourceRangeWithTextContainers; + } + std::vector takeSourceRangeWithTextContainers() { return std::move(m_sourceRangeWithTextContainers); diff --git a/src/libs/clangbackendipc/sourcerangewithtextcontainer.h b/src/libs/clangbackendipc/sourcerangewithtextcontainer.h index 82d17f884a4..8a92086319b 100644 --- a/src/libs/clangbackendipc/sourcerangewithtextcontainer.h +++ b/src/libs/clangbackendipc/sourcerangewithtextcontainer.h @@ -115,3 +115,20 @@ using SourceRangeWithTextContainers = std::vector; CMBIPC_EXPORT QDebug operator<<(QDebug debug, const SourceRangeWithTextContainer &container); std::ostream &operator<<(std::ostream &os, const SourceRangeWithTextContainer &container); } // namespace ClangBackEnd + +namespace std +{ +template<> struct hash +{ + using argument_type = ClangBackEnd::SourceRangeWithTextContainer; + using result_type = std::size_t; + result_type operator()(const argument_type &container) const + { + const result_type h1{std::hash{}(container.fileHash())}; + const result_type h2{std::hash{}(container.start().offset())}; + const result_type h3{std::hash{}(container.end().offset())}; + + return h1 ^ (h2 << 8) ^ (h3 << 16); + } +}; +} diff --git a/src/tools/clangrefactoringbackend/source/clangquerygatherer.cpp b/src/tools/clangrefactoringbackend/source/clangquerygatherer.cpp index 09c96a69b53..219011eff2a 100644 --- a/src/tools/clangrefactoringbackend/source/clangquerygatherer.cpp +++ b/src/tools/clangrefactoringbackend/source/clangquerygatherer.cpp @@ -34,6 +34,7 @@ ClangQueryGatherer::ClangQueryGatherer(StringCache &&unsaved, Utils::SmallString &&query) : m_filePathCache(filePathCache), + m_sourceRangeFilter(sources.size()), m_sources(std::move(sources)), m_unsaved(std::move(unsaved)), m_query(std::move(query)) @@ -125,7 +126,7 @@ std::vector ClangQueryGatherer::allCu std::vector messages; for (Future &future : m_sourceFutures) - messages.push_back(future.get()); + messages.push_back(m_sourceRangeFilter.removeDuplicates(future.get())); return messages; } @@ -135,7 +136,7 @@ std::vector ClangQueryGatherer::finis std::vector messages; for (auto &&future : finishedFutures()) - messages.push_back(future.get()); + messages.push_back(m_sourceRangeFilter.removeDuplicates(future.get())); return messages; } diff --git a/src/tools/clangrefactoringbackend/source/clangquerygatherer.h b/src/tools/clangrefactoringbackend/source/clangquerygatherer.h index b9370563791..67e662bd86c 100644 --- a/src/tools/clangrefactoringbackend/source/clangquerygatherer.h +++ b/src/tools/clangrefactoringbackend/source/clangquerygatherer.h @@ -25,6 +25,8 @@ #pragma once +#include "sourcerangefilter.h" + #include #include #include @@ -68,6 +70,7 @@ protected: private: StringCache *m_filePathCache = nullptr; + SourceRangeFilter m_sourceRangeFilter; std::vector m_sources; std::vector m_unsaved; Utils::SmallString m_query; diff --git a/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri b/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri index 7a695e5ca4d..8af6b89974c 100644 --- a/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri +++ b/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri @@ -1,7 +1,8 @@ INCLUDEPATH += $$PWD HEADERS += \ - $$PWD/clangrefactoringbackend_global.h + $$PWD/clangrefactoringbackend_global.h \ + $$PWD/sourcerangefilter.h !isEmpty(LIBTOOLING_LIBS) { SOURCES += \ @@ -33,3 +34,6 @@ HEADERS += \ $$PWD/locationsourcefilecallbacks.h \ $$PWD/clangquerygatherer.h } + +SOURCES += \ + $$PWD/sourcerangefilter.cpp diff --git a/src/tools/clangrefactoringbackend/source/refactoringserver.cpp b/src/tools/clangrefactoringbackend/source/refactoringserver.cpp index cf233baf34f..80fdbe86e3e 100644 --- a/src/tools/clangrefactoringbackend/source/refactoringserver.cpp +++ b/src/tools/clangrefactoringbackend/source/refactoringserver.cpp @@ -115,6 +115,11 @@ bool RefactoringServer::pollTimerIsActive() const return m_pollTimer.isActive(); } +void RefactoringServer::setGathererProcessingSlotCount(uint count) +{ + m_gatherer.setProcessingSlotCount(count); +} + void RefactoringServer::gatherSourceRangesAndDiagnosticsForQueryMessages( std::vector &&sources, std::vector &&unsaved, diff --git a/src/tools/clangrefactoringbackend/source/refactoringserver.h b/src/tools/clangrefactoringbackend/source/refactoringserver.h index 1befa076216..8926ce7c017 100644 --- a/src/tools/clangrefactoringbackend/source/refactoringserver.h +++ b/src/tools/clangrefactoringbackend/source/refactoringserver.h @@ -64,6 +64,8 @@ public: bool pollTimerIsActive() const; + void setGathererProcessingSlotCount(uint count); + private: void gatherSourceRangesAndDiagnosticsForQueryMessages(std::vector &&sources, std::vector &&unsaved, diff --git a/src/tools/clangrefactoringbackend/source/sourcerangefilter.cpp b/src/tools/clangrefactoringbackend/source/sourcerangefilter.cpp new file mode 100644 index 00000000000..bc566ea7d40 --- /dev/null +++ b/src/tools/clangrefactoringbackend/source/sourcerangefilter.cpp @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "sourcerangefilter.h" + +#include + +namespace ClangBackEnd { + +SourceRangeFilter::SourceRangeFilter(std::size_t sourcesCount) +{ + m_collectedSourceRanges.reserve(sourcesCount); +} + +SourceRangesAndDiagnosticsForQueryMessage SourceRangeFilter::removeDuplicates(SourceRangesAndDiagnosticsForQueryMessage &&message) +{ + removeDuplicates(message.sourceRanges().sourceRangeWithTextContainers()); + + return std::move(message); +} + +void SourceRangeFilter::removeDuplicates(SourceRangeWithTextContainers &sourceRanges) +{ + auto partitionPoint = std::stable_partition(sourceRanges.begin(), + sourceRanges.end(), + [&] (const SourceRangeWithTextContainer &sourceRange) { + return m_collectedSourceRanges.find(sourceRange) == m_collectedSourceRanges.end(); + }); + + sourceRanges.erase(partitionPoint, sourceRanges.end()); + + std::copy(sourceRanges.begin(), + sourceRanges.end(), + std::inserter(m_collectedSourceRanges, m_collectedSourceRanges.end())); +} + +} // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/sourcerangefilter.h b/src/tools/clangrefactoringbackend/source/sourcerangefilter.h new file mode 100644 index 00000000000..8c6c3ac42f8 --- /dev/null +++ b/src/tools/clangrefactoringbackend/source/sourcerangefilter.h @@ -0,0 +1,47 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include + +#include + +namespace ClangBackEnd { + +class SourceRangeFilter +{ +public: + SourceRangeFilter(std::size_t sourcesCount = 0); + + SourceRangesAndDiagnosticsForQueryMessage + removeDuplicates(SourceRangesAndDiagnosticsForQueryMessage &&message); + void removeDuplicates(SourceRangeWithTextContainers &sourceRanges); + +private: + std::unordered_set m_collectedSourceRanges; +}; + +} // namespace ClangBackEnd diff --git a/tests/unit/unittest/clangquerygatherer-test.cpp b/tests/unit/unittest/clangquerygatherer-test.cpp index 0e24e4fa6d4..b4808b45c57 100644 --- a/tests/unit/unittest/clangquerygatherer-test.cpp +++ b/tests/unit/unittest/clangquerygatherer-test.cpp @@ -38,6 +38,7 @@ using testing::AtLeast; using testing::AtMost; using testing::Contains; using testing::Each; +using testing::ElementsAre; using testing::Eq; using testing::Ge; using testing::IsEmpty; @@ -47,6 +48,7 @@ using testing::Pair; using testing::PrintToString; using testing::Property; using testing::SizeIs; +using testing::UnorderedElementsAre; using testing::_; using ClangBackEnd::V2::FileContainer; @@ -72,10 +74,16 @@ protected: protected: ClangBackEnd::StringCache filePathCache; - Utils::SmallString sourceContent{"#include \"query_simplefunction.h\"\nvoid f()\n {}"}; + Utils::SmallString sourceContent{"#include \"query_simplefunction.h\"\nvoid f() {}"}; FileContainer source{{TESTDATA_DIR, "query_simplefunction.cpp"}, sourceContent.clone(), - {"cc", "query_simplefunction.cpp"}}; + {"cc", TESTDATA_DIR"/query_simplefunction.cpp", "-I", TESTDATA_DIR}}; + FileContainer source2{{TESTDATA_DIR, "query_simplefunction2.cpp"}, + {}, + {"cc", TESTDATA_DIR"/query_simplefunction2.cpp", "-I", TESTDATA_DIR}}; + FileContainer source3{{TESTDATA_DIR, "query_simplefunction3.cpp"}, + {}, + {"cc", TESTDATA_DIR"/query_simplefunction3.cpp", "-I", TESTDATA_DIR}}; Utils::SmallString unsavedContent{"void f();"}; FileContainer unsaved{{TESTDATA_DIR, "query_simplefunction.h"}, unsavedContent.clone(), @@ -83,19 +91,19 @@ protected: Utils::SmallString query{"functionDecl()"}; ClangBackEnd::ClangQueryGatherer gatherer{&filePathCache, {source.clone()}, {unsaved.clone()}, query.clone()}; ClangBackEnd::ClangQueryGatherer manyGatherer{&filePathCache, - {source.clone(), source.clone(), source.clone()}, + {source3.clone(), source2.clone(), source.clone()}, {unsaved.clone()}, query.clone()}; }; TEST_F(ClangQueryGatherer, CreateSourceRangesAndDiagnostics) { - auto sourceRangesAndDiagnostics = gatherer.createSourceRangesAndDiagnosticsForSource(&filePathCache, source.clone(), {}, query.clone()); + auto sourceRangesAndDiagnostics = gatherer.createSourceRangesAndDiagnosticsForSource(&filePathCache, source.clone(), {unsaved}, query.clone()); ASSERT_THAT(sourceRangesAndDiagnostics, Property(&SourceRangesAndDiagnosticsForQueryMessage::sourceRanges, Property(&SourceRangesContainer::sourceRangeWithTextContainers, - Contains(IsSourceRangeWithText(2, 1, 3, 4, "void f()\n {}"))))); + Contains(IsSourceRangeWithText(2, 1, 2, 12, "void f() {}"))))); } TEST_F(ClangQueryGatherer, CreateSourceRangesAndDiagnosticssWithUnsavedContent) @@ -176,14 +184,18 @@ TEST_F(ClangQueryGatherer, AfterStartCreateSourceRangesAndDiagnosticsMessagesGet manyGatherer.startCreateNextSourceRangesAndDiagnosticsMessages(); ASSERT_THAT(manyGatherer.allCurrentProcessedMessages(), - Each( + UnorderedElementsAre( Property(&SourceRangesAndDiagnosticsForQueryMessage::sourceRanges, Property(&SourceRangesContainer::sourceRangeWithTextContainers, - Contains(IsSourceRangeWithText(1, 1, 1, 9, "void f();")))))); + UnorderedElementsAre(IsSourceRangeWithText(1, 1, 1, 9, "void f();"), + IsSourceRangeWithText(2, 1, 2, 12, "void f() {}")))), + Property(&SourceRangesAndDiagnosticsForQueryMessage::sourceRanges, + Property(&SourceRangesContainer::sourceRangeWithTextContainers, + UnorderedElementsAre( + IsSourceRangeWithText(1, 1, 1, 13, "int header();"), + IsSourceRangeWithText(3, 1, 3, 15, "int function();")))))); } - - TEST_F(ClangQueryGatherer, GetFinishedMessages) { manyGatherer.startCreateNextSourceRangesAndDiagnosticsMessages(); @@ -193,10 +205,17 @@ TEST_F(ClangQueryGatherer, GetFinishedMessages) ASSERT_THAT(messages, AllOf(SizeIs(2), - Each( + UnorderedElementsAre( Property(&SourceRangesAndDiagnosticsForQueryMessage::sourceRanges, Property(&SourceRangesContainer::sourceRangeWithTextContainers, - Contains(IsSourceRangeWithText(1, 1, 1, 9, "void f();"))))))); + UnorderedElementsAre( + IsSourceRangeWithText(1, 1, 1, 9, "void f();"), + IsSourceRangeWithText(2, 1, 2, 12, "void f() {}")))), + Property(&SourceRangesAndDiagnosticsForQueryMessage::sourceRanges, + Property(&SourceRangesContainer::sourceRangeWithTextContainers, + UnorderedElementsAre( + IsSourceRangeWithText(1, 1, 1, 13, "int header();"), + IsSourceRangeWithText(3, 1, 3, 15, "int function();"))))))); } TEST_F(ClangQueryGatherer, GetFinishedMessagesAfterSecondPass) @@ -211,10 +230,38 @@ TEST_F(ClangQueryGatherer, GetFinishedMessagesAfterSecondPass) ASSERT_THAT(messages, AllOf(SizeIs(1), - Each( + ElementsAre( Property(&SourceRangesAndDiagnosticsForQueryMessage::sourceRanges, Property(&SourceRangesContainer::sourceRangeWithTextContainers, - Contains(IsSourceRangeWithText(1, 1, 1, 9, "void f();"))))))); + UnorderedElementsAre( + IsSourceRangeWithText(3, 1, 3, 15, "int function();"))))))); +} + +TEST_F(ClangQueryGatherer, FilterDuplicates) +{ + manyGatherer.setProcessingSlotCount(3); + manyGatherer.startCreateNextSourceRangesAndDiagnosticsMessages(); + manyGatherer.waitForFinished(); + + auto messages = manyGatherer.finishedMessages(); + + ASSERT_THAT(messages, + AllOf(SizeIs(3), + UnorderedElementsAre( + Property(&SourceRangesAndDiagnosticsForQueryMessage::sourceRanges, + Property(&SourceRangesContainer::sourceRangeWithTextContainers, + UnorderedElementsAre( + IsSourceRangeWithText(1, 1, 1, 9, "void f();"), + IsSourceRangeWithText(2, 1, 2, 12, "void f() {}")))), + Property(&SourceRangesAndDiagnosticsForQueryMessage::sourceRanges, + Property(&SourceRangesContainer::sourceRangeWithTextContainers, + UnorderedElementsAre( + IsSourceRangeWithText(1, 1, 1, 13, "int header();"), + IsSourceRangeWithText(3, 1, 3, 15, "int function();")))), + Property(&SourceRangesAndDiagnosticsForQueryMessage::sourceRanges, + Property(&SourceRangesContainer::sourceRangeWithTextContainers, + UnorderedElementsAre( + IsSourceRangeWithText(3, 1, 3, 15, "int function();"))))))); } TEST_F(ClangQueryGatherer, AfterGetFinishedMessagesFuturesAreReduced) diff --git a/tests/unit/unittest/data/query_simplefunction2.cpp b/tests/unit/unittest/data/query_simplefunction2.cpp new file mode 100644 index 00000000000..fbf4d8d8fd0 --- /dev/null +++ b/tests/unit/unittest/data/query_simplefunction2.cpp @@ -0,0 +1,4 @@ +#include "query_simplefunction2.h" + +int function(); + diff --git a/tests/unit/unittest/data/query_simplefunction2.h b/tests/unit/unittest/data/query_simplefunction2.h new file mode 100644 index 00000000000..9251cf100a9 --- /dev/null +++ b/tests/unit/unittest/data/query_simplefunction2.h @@ -0,0 +1,2 @@ +int header(); + diff --git a/tests/unit/unittest/data/query_simplefunction3.cpp b/tests/unit/unittest/data/query_simplefunction3.cpp new file mode 100644 index 00000000000..fbf4d8d8fd0 --- /dev/null +++ b/tests/unit/unittest/data/query_simplefunction3.cpp @@ -0,0 +1,4 @@ +#include "query_simplefunction2.h" + +int function(); + diff --git a/tests/unit/unittest/refactoringserver-test.cpp b/tests/unit/unittest/refactoringserver-test.cpp index 33b63534e3f..39db78bdcd0 100644 --- a/tests/unit/unittest/refactoringserver-test.cpp +++ b/tests/unit/unittest/refactoringserver-test.cpp @@ -40,6 +40,7 @@ namespace { using testing::AllOf; using testing::Contains; using testing::NiceMock; +using testing::Not; using testing::Pair; using testing::PrintToString; using testing::Property; @@ -77,7 +78,8 @@ protected: Utils::SmallString sourceContent{"void f()\n {}"}; FileContainer source{{TESTDATA_DIR, "query_simplefunction.cpp"}, sourceContent.clone(), - {"cc", "query_simplefunction.cpp"}}; + {"cc", TESTDATA_DIR"/query_simplefunction.cpp"}}; + int processingSlotCount = 2; }; using RefactoringServerSlowTest = RefactoringServer; @@ -153,8 +155,12 @@ TEST_F(RefactoringServerSlowTest, RequestTwoSourceRangesAndDiagnosticsForQueryMe sourceRangesAndDiagnosticsForQueryMessage( Property(&SourceRangesAndDiagnosticsForQueryMessage::sourceRanges, Property(&SourceRangesContainer::sourceRangeWithTextContainers, - Contains(IsSourceRangeWithText(1, 1, 2, 4, sourceContent)))))) - .Times(2); + Contains(IsSourceRangeWithText(1, 1, 2, 4, sourceContent)))))); + EXPECT_CALL(mockRefactoringClient, + sourceRangesAndDiagnosticsForQueryMessage( + Property(&SourceRangesAndDiagnosticsForQueryMessage::sourceRanges, + Property(&SourceRangesContainer::sourceRangeWithTextContainers, + Not(Contains(IsSourceRangeWithText(1, 1, 2, 4, sourceContent))))))); refactoringServer.requestSourceRangesAndDiagnosticsForQueryMessage(std::move(requestSourceRangesAndDiagnosticsForQueryMessage)); } @@ -163,7 +169,7 @@ TEST_F(RefactoringServerVerySlowTest, RequestManySourceRangesAndDiagnosticsForQu { std::vector sources; std::fill_n(std::back_inserter(sources), - std::thread::hardware_concurrency() + 3, + processingSlotCount + 3, source.clone()); RequestSourceRangesAndDiagnosticsForQueryMessage requestSourceRangesAndDiagnosticsForQueryMessage{"functionDecl()", std::move(sources), @@ -173,8 +179,13 @@ TEST_F(RefactoringServerVerySlowTest, RequestManySourceRangesAndDiagnosticsForQu sourceRangesAndDiagnosticsForQueryMessage( Property(&SourceRangesAndDiagnosticsForQueryMessage::sourceRanges, Property(&SourceRangesContainer::sourceRangeWithTextContainers, - Contains(IsSourceRangeWithText(1, 1, 2, 4, sourceContent)))))) - .Times(std::thread::hardware_concurrency() + 3); + Contains(IsSourceRangeWithText(1, 1, 2, 4, sourceContent)))))); + EXPECT_CALL(mockRefactoringClient, + sourceRangesAndDiagnosticsForQueryMessage( + Property(&SourceRangesAndDiagnosticsForQueryMessage::sourceRanges, + Property(&SourceRangesContainer::sourceRangeWithTextContainers, + Not(Contains(IsSourceRangeWithText(1, 1, 2, 4, sourceContent))))))) + .Times(processingSlotCount + 2); refactoringServer.requestSourceRangesAndDiagnosticsForQueryMessage(std::move(requestSourceRangesAndDiagnosticsForQueryMessage)); } @@ -237,6 +248,7 @@ void RefactoringServer::SetUp() void RefactoringServer::TearDown() { + refactoringServer.setGathererProcessingSlotCount(uint(processingSlotCount)); refactoringServer.waitThatSourceRangesAndDiagnosticsForQueryMessagesAreFinished(); } diff --git a/tests/unit/unittest/sourcerangefilter-test.cpp b/tests/unit/unittest/sourcerangefilter-test.cpp new file mode 100644 index 00000000000..059f9827f62 --- /dev/null +++ b/tests/unit/unittest/sourcerangefilter-test.cpp @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "googletest.h" + +#include + +namespace { + +using testing::ContainerEq; +using testing::IsEmpty; + +using ClangBackEnd::SourceRangeWithTextContainer; +using ClangBackEnd::SourceRangeWithTextContainers; +using ClangBackEnd::SourceRangesAndDiagnosticsForQueryMessage; + +class SourceRangeFilter : public ::testing::Test +{ +protected: + + +protected: + SourceRangeWithTextContainers sourceRanges1{{1, 1, 1, 1, 2, 1, 4, "foo"}, + {2, 1, 1, 1, 2, 1, 4, "foo"}, + {1, 1, 1, 1, 2, 2, 5, "foo"}}; + SourceRangeWithTextContainers sourceRanges2{{1, 1, 1, 1, 2, 1, 4, "foo"}, + {3, 1, 1, 1, 2, 1, 4, "foo"}, + {1, 1, 1, 1, 2, 2, 6, "foo"}}; + SourceRangeWithTextContainers sourceRanges3{{3, 1, 1, 1, 2, 1, 4, "foo"}, + {1, 1, 1, 1, 2, 2, 6, "foo"}}; + SourceRangesAndDiagnosticsForQueryMessage message1{{{}, Utils::clone(sourceRanges1)}, {}}; + SourceRangesAndDiagnosticsForQueryMessage message2{{{}, Utils::clone(sourceRanges2)}, {}}; + ClangBackEnd::SourceRangeFilter filter{3}; +}; + +TEST_F(SourceRangeFilter, DontChangeForFirstTime) +{ + auto expectedSourceRanges = sourceRanges1; + + filter.removeDuplicates(sourceRanges1); + + ASSERT_THAT(sourceRanges1, ContainerEq(expectedSourceRanges)); +} + +TEST_F(SourceRangeFilter, DoNotFilterNonDuplicates) +{ + SourceRangeWithTextContainers expectedSourceRanges = sourceRanges3; + filter.removeDuplicates(sourceRanges1); + + filter.removeDuplicates(sourceRanges3); + + ASSERT_THAT(sourceRanges3, ContainerEq(expectedSourceRanges)); +} + +TEST_F(SourceRangeFilter, FilterDuplicates) +{ + filter.removeDuplicates(sourceRanges1); + + filter.removeDuplicates(sourceRanges2); + + ASSERT_THAT(sourceRanges2, ContainerEq(sourceRanges3)); +} + +TEST_F(SourceRangeFilter, FilterMoreDuplicates) +{ + filter.removeDuplicates(sourceRanges1); + filter.removeDuplicates(sourceRanges2); + + filter.removeDuplicates(sourceRanges3); + + ASSERT_THAT(sourceRanges3, IsEmpty()); +} + +TEST_F(SourceRangeFilter, FilterDuplicatesFromMessage) +{ + filter.removeDuplicates(std::move(message1)); + + auto filteredMessage = filter.removeDuplicates(std::move(message2)); + + ASSERT_THAT(filteredMessage.sourceRanges().sourceRangeWithTextContainers(), + ContainerEq(sourceRanges3)); +} + +} diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro index 4e32ce0413c..8409517e8f3 100644 --- a/tests/unit/unittest/unittest.pro +++ b/tests/unit/unittest/unittest.pro @@ -64,7 +64,8 @@ SOURCES += \ pchmanagerserver-test.cpp \ pchmanagerclientserverinprocess-test.cpp \ clangquerygatherer-test.cpp \ - filepath-test.cpp + filepath-test.cpp \ + sourcerangefilter-test.cpp !isEmpty(LIBCLANG_LIBS) { SOURCES += \ From 277b3313896f79498535278e052ca0329a24846b Mon Sep 17 00:00:00 2001 From: Ivan Donchevskii Date: Mon, 3 Jul 2017 12:02:26 +0200 Subject: [PATCH 06/15] Fix build Move constructor definition to .cpp file to avoid it being inlined Change-Id: I1c55095e5158740526af9e698c978abf33304e52 Reviewed-by: hjk --- src/libs/utils/fileutils.cpp | 2 ++ src/libs/utils/fileutils.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libs/utils/fileutils.cpp b/src/libs/utils/fileutils.cpp index 7f25dc722b3..02065a06ac0 100644 --- a/src/libs/utils/fileutils.cpp +++ b/src/libs/utils/fileutils.cpp @@ -395,6 +395,8 @@ FileSaverBase::FileSaverBase() { } +FileSaverBase::~FileSaverBase() = default; + bool FileSaverBase::finalize() { m_file->close(); diff --git a/src/libs/utils/fileutils.h b/src/libs/utils/fileutils.h index b53c0e58c59..f891e2d15f8 100644 --- a/src/libs/utils/fileutils.h +++ b/src/libs/utils/fileutils.h @@ -175,7 +175,7 @@ class QTCREATOR_UTILS_EXPORT FileSaverBase Q_DECLARE_TR_FUNCTIONS(Utils::FileUtils) // sic! public: FileSaverBase(); - virtual ~FileSaverBase() = default; + virtual ~FileSaverBase(); QString fileName() const { return m_fileName; } bool hasError() const { return m_hasError; } From e7f5a379c614bc541e27c8e24a134f23e564c645 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Mon, 3 Jul 2017 12:44:02 +0200 Subject: [PATCH 07/15] Clang: Workaround to fix compile for emplace Change-Id: Ic99f67819461eb682e531c578652336b6e2ada8d Reviewed-by: hjk --- src/libs/clangbackendipc/sourcefilepathcontainerbase.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/clangbackendipc/sourcefilepathcontainerbase.h b/src/libs/clangbackendipc/sourcefilepathcontainerbase.h index ec5b78e9a7b..ebf717f15e6 100644 --- a/src/libs/clangbackendipc/sourcefilepathcontainerbase.h +++ b/src/libs/clangbackendipc/sourcefilepathcontainerbase.h @@ -45,7 +45,7 @@ public: void insertFilePath(uint fileId, Utils::PathString &&filePath) { if (m_filePathHash.find(fileId) == m_filePathHash.end()) - m_filePathHash.emplace(fileId, std::move(filePath)); + m_filePathHash.emplace(fileId, FilePath(std::move(filePath))); } void reserve(std::size_t size) From 9d8b8ba65d94c72c06d1f9dcdbef05f3f5da1662 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 3 Jul 2017 14:25:47 +0200 Subject: [PATCH 08/15] TextEditor: Animate automatically completed text Change-Id: I35a183821363a201a68200f8692bf18dd36faed7 Reviewed-by: Christian Stenger --- src/plugins/texteditor/texteditor.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 0e64e0c61ff..6ba536f9b63 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -6316,7 +6316,8 @@ void TextEditorWidgetPrivate::autocompleterHighlight(const QTextCursor &cursor) m_autoCompleteHighlightPos.clear(); } else if (m_highlightAutoComplete) { m_autoCompleteHighlightPos.push_back(cursor); - } else if (m_animateAutoComplete) { + } + if (m_animateAutoComplete) { const QTextCharFormat &matchFormat = q->textDocument()->fontSettings().toTextCharFormat(C_AUTOCOMPLETE); cancelCurrentAnimations();// one animation is enough From 9bcbf4eec315910fc456e307498544d136b416cf Mon Sep 17 00:00:00 2001 From: hjk Date: Sat, 1 Jul 2017 19:13:06 +0200 Subject: [PATCH 09/15] Qnx: Remove RunControlFactory Registering the main runWorkers is enough. Change-Id: I0d2d148c6247e403463b548ca05993e18b0d88ee Reviewed-by: Christian Stenger --- src/plugins/qnx/qnx.pro | 2 - src/plugins/qnx/qnx.qbs | 2 - src/plugins/qnx/qnxanalyzesupport.cpp | 6 +- src/plugins/qnx/qnxanalyzesupport.h | 6 +- src/plugins/qnx/qnxplugin.cpp | 58 +++++++++--- src/plugins/qnx/qnxplugin.h | 9 +- src/plugins/qnx/qnxruncontrolfactory.cpp | 109 ----------------------- src/plugins/qnx/qnxruncontrolfactory.h | 47 ---------- 8 files changed, 54 insertions(+), 185 deletions(-) delete mode 100644 src/plugins/qnx/qnxruncontrolfactory.cpp delete mode 100644 src/plugins/qnx/qnxruncontrolfactory.h diff --git a/src/plugins/qnx/qnx.pro b/src/plugins/qnx/qnx.pro index b50f4b27fb4..bcfad2f36e1 100644 --- a/src/plugins/qnx/qnx.pro +++ b/src/plugins/qnx/qnx.pro @@ -8,7 +8,6 @@ SOURCES += qnxplugin.cpp \ qnxdevicefactory.cpp \ qnxdevicewizard.cpp \ qnxrunconfiguration.cpp \ - qnxruncontrolfactory.cpp \ qnxanalyzesupport.cpp \ qnxdebugsupport.cpp \ qnxdeploystepfactory.cpp \ @@ -41,7 +40,6 @@ HEADERS += qnxplugin.h\ qnxdevicefactory.h \ qnxdevicewizard.h \ qnxrunconfiguration.h \ - qnxruncontrolfactory.h \ qnxanalyzesupport.h \ qnxdebugsupport.h \ qnxdeploystepfactory.h \ diff --git a/src/plugins/qnx/qnx.qbs b/src/plugins/qnx/qnx.qbs index eee52f0f5d1..b617fc1b6a9 100644 --- a/src/plugins/qnx/qnx.qbs +++ b/src/plugins/qnx/qnx.qbs @@ -76,8 +76,6 @@ QtcPlugin { "qnxrunconfiguration.h", "qnxrunconfigurationfactory.cpp", "qnxrunconfigurationfactory.h", - "qnxruncontrolfactory.cpp", - "qnxruncontrolfactory.h", "qnxutils.cpp", "qnxutils.h", "qnx_export.h", diff --git a/src/plugins/qnx/qnxanalyzesupport.cpp b/src/plugins/qnx/qnxanalyzesupport.cpp index 52150107906..c4a0d71d940 100644 --- a/src/plugins/qnx/qnxanalyzesupport.cpp +++ b/src/plugins/qnx/qnxanalyzesupport.cpp @@ -75,9 +75,11 @@ private: // QnxDebugSupport -QnxAnalyzeSupport::QnxAnalyzeSupport(RunControl *runControl) +QnxQmlProfilerSupport::QnxQmlProfilerSupport(RunControl *runControl) : RunWorker(runControl) { + runControl->createWorker(runControl->runMode()); + setDisplayName("QnxAnalyzeSupport"); appendMessage(tr("Preparing remote side..."), Utils::LogMessageFormat); @@ -99,7 +101,7 @@ QnxAnalyzeSupport::QnxAnalyzeSupport(RunControl *runControl) // m_outputParser.processOutput(msg); } -void QnxAnalyzeSupport::start() +void QnxQmlProfilerSupport::start() { // runControl()->notifyRemoteSetupDone(m_qmlPort); reportStarted(); diff --git a/src/plugins/qnx/qnxanalyzesupport.h b/src/plugins/qnx/qnxanalyzesupport.h index cb049866f8e..9fbd11d0fe7 100644 --- a/src/plugins/qnx/qnxanalyzesupport.h +++ b/src/plugins/qnx/qnxanalyzesupport.h @@ -30,14 +30,12 @@ namespace Qnx { namespace Internal { -class Slog2InfoRunner; - -class QnxAnalyzeSupport : public ProjectExplorer::RunWorker +class QnxQmlProfilerSupport : public ProjectExplorer::RunWorker { Q_OBJECT public: - explicit QnxAnalyzeSupport(ProjectExplorer::RunControl *runControl); + explicit QnxQmlProfilerSupport(ProjectExplorer::RunControl *runControl); private: void start() override; diff --git a/src/plugins/qnx/qnxplugin.cpp b/src/plugins/qnx/qnxplugin.cpp index 2826b24cee7..a1f1cffc9c1 100644 --- a/src/plugins/qnx/qnxplugin.cpp +++ b/src/plugins/qnx/qnxplugin.cpp @@ -25,38 +25,49 @@ #include "qnxplugin.h" -#include "qnxconstants.h" +#include "qnxanalyzesupport.h" #include "qnxattachdebugsupport.h" -#include "qnxdevicefactory.h" -#include "qnxruncontrolfactory.h" -#include "qnxdeploystepfactory.h" -#include "qnxdeployconfigurationfactory.h" -#include "qnxrunconfigurationfactory.h" -#include "qnxqtversionfactory.h" -#include "qnxsettingspage.h" #include "qnxconfigurationmanager.h" +#include "qnxconstants.h" +#include "qnxdebugsupport.h" +#include "qnxdeployconfigurationfactory.h" +#include "qnxdeploystepfactory.h" +#include "qnxdevice.h" +#include "qnxdevicefactory.h" +#include "qnxqtversion.h" +#include "qnxqtversionfactory.h" +#include "qnxrunconfiguration.h" +#include "qnxrunconfigurationfactory.h" +#include "qnxsettingspage.h" #include "qnxtoolchain.h" -#include "qnxattachdebugsupport.h" +#include "qnxutils.h" #include #include #include #include #include + #include #include #include #include #include +#include +#include +#include +#include +#include + +#include #include #include using namespace ProjectExplorer; -using namespace Qnx::Internal; -QnxPlugin::QnxPlugin() : m_debugSeparator(0) , m_attachToQnxApplication(0) -{ } +namespace Qnx { +namespace Internal { bool QnxPlugin::initialize(const QStringList &arguments, QString *errorString) { @@ -67,13 +78,29 @@ bool QnxPlugin::initialize(const QStringList &arguments, QString *errorString) addAutoReleasedObject(new QnxConfigurationManager); addAutoReleasedObject(new QnxQtVersionFactory); addAutoReleasedObject(new QnxDeviceFactory); - addAutoReleasedObject(new QnxRunControlFactory); addAutoReleasedObject(new QnxDeployStepFactory); addAutoReleasedObject(new QnxDeployConfigurationFactory); addAutoReleasedObject(new QnxRunConfigurationFactory); addAutoReleasedObject(new QnxSettingsPage); - // Handle Qcc Compiler + auto constraint = [](RunConfiguration *runConfig) { + if (!runConfig->isEnabled() + || !runConfig->id().name().startsWith(Constants::QNX_QNX_RUNCONFIGURATION_PREFIX)) { + return false; + } + + auto dev = DeviceKitInformation::device(runConfig->target()->kit()) + .dynamicCast(); + return !dev.isNull(); + }; + + RunControl::registerWorker + (ProjectExplorer::Constants::NORMAL_RUN_MODE, constraint); + RunControl::registerWorker + (ProjectExplorer::Constants::DEBUG_RUN_MODE, constraint); + RunControl::registerWorker + (ProjectExplorer::Constants::QML_PROFILER_RUN_MODE, constraint); + addAutoReleasedObject(new QnxToolChainFactory); return true; @@ -118,3 +145,6 @@ void QnxPlugin::updateDebuggerActions() m_attachToQnxApplication->setVisible(false && hasValidQnxKit); // FIXME m_debugSeparator->setVisible(false && hasValidQnxKit); // FIXME QTCREATORBUG-16608 } + +} // Internal +} // Qnx diff --git a/src/plugins/qnx/qnxplugin.h b/src/plugins/qnx/qnxplugin.h index 1fd1367cb8d..798251810c0 100644 --- a/src/plugins/qnx/qnxplugin.h +++ b/src/plugins/qnx/qnxplugin.h @@ -40,18 +40,17 @@ class QnxPlugin : public ExtensionSystem::IPlugin Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "Qnx.json") public: - QnxPlugin(); + QnxPlugin() {} bool initialize(const QStringList &arguments, QString *errorString); void extensionsInitialized(); ShutdownFlag aboutToShutdown(); -private slots: +private: void updateDebuggerActions(); -private: - QAction *m_debugSeparator; - QAction *m_attachToQnxApplication; + QAction *m_debugSeparator = nullptr; + QAction *m_attachToQnxApplication = nullptr; }; } // namespace Internal diff --git a/src/plugins/qnx/qnxruncontrolfactory.cpp b/src/plugins/qnx/qnxruncontrolfactory.cpp deleted file mode 100644 index 18a44abd0b0..00000000000 --- a/src/plugins/qnx/qnxruncontrolfactory.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 BlackBerry Limited. All rights reserved. -** Contact: KDAB (info@kdab.com) -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "qnxruncontrolfactory.h" -#include "qnxconstants.h" -#include "qnxrunconfiguration.h" -#include "qnxdebugsupport.h" -#include "qnxdevice.h" -#include "qnxanalyzesupport.h" -#include "qnxqtversion.h" -#include "slog2inforunner.h" -#include "qnxutils.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace Debugger; -using namespace ProjectExplorer; - -namespace Qnx { -namespace Internal { - -QnxRunControlFactory::QnxRunControlFactory(QObject *parent) - : IRunControlFactory(parent) -{ -} - -bool QnxRunControlFactory::canRun(RunConfiguration *runConfiguration, Core::Id mode) const -{ - if (mode != ProjectExplorer::Constants::NORMAL_RUN_MODE - && mode != ProjectExplorer::Constants::DEBUG_RUN_MODE - && mode != ProjectExplorer::Constants::QML_PROFILER_RUN_MODE) { - return false; - } - - if (!runConfiguration->isEnabled() - || !runConfiguration->id().name().startsWith(Constants::QNX_QNX_RUNCONFIGURATION_PREFIX)) { - return false; - } - - const QnxDevice::ConstPtr dev = DeviceKitInformation::device(runConfiguration->target()->kit()) - .dynamicCast(); - if (dev.isNull()) - return false; - - return true; -} - -RunControl *QnxRunControlFactory::create(RunConfiguration *runConfig, Core::Id mode, QString *) -{ - QTC_ASSERT(canRun(runConfig, mode), return 0); - - if (mode == ProjectExplorer::Constants::NORMAL_RUN_MODE) { - auto runControl = new RunControl(runConfig, mode); - (void) new SimpleTargetRunner(runControl); - return runControl; - } - - if (mode == ProjectExplorer::Constants::DEBUG_RUN_MODE) { - auto runControl = new RunControl(runConfig, mode); - (void) new QnxDebugSupport(runControl); - return runControl; - } - - if (mode == ProjectExplorer::Constants::QML_PROFILER_RUN_MODE) { - RunControl *runControl = new RunControl(runConfig, mode); - runControl->createWorker(mode); - (void) new QnxAnalyzeSupport(runControl); - return runControl; - } - - QTC_CHECK(false); - return 0; -} - -} // namespace Internal -} // namespace Qnx diff --git a/src/plugins/qnx/qnxruncontrolfactory.h b/src/plugins/qnx/qnxruncontrolfactory.h deleted file mode 100644 index af19a7f3dd6..00000000000 --- a/src/plugins/qnx/qnxruncontrolfactory.h +++ /dev/null @@ -1,47 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 BlackBerry Limited. All rights reserved. -** Contact: KDAB (info@kdab.com) -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#pragma once - -#include - -namespace Qnx { -namespace Internal { - -class QnxRunControlFactory : public ProjectExplorer::IRunControlFactory -{ - Q_OBJECT - -public: - explicit QnxRunControlFactory(QObject *parent = 0); - - bool canRun(ProjectExplorer::RunConfiguration *runConfiguration, - Core::Id mode) const override; - ProjectExplorer::RunControl *create(ProjectExplorer::RunConfiguration *runConfiguration, - Core::Id mode, QString *errorMessage) override; -}; - -} // namespace Internal -} // namespace Qnx From 4823bc506c39c1d8c4074a70eff496abeb7cc783 Mon Sep 17 00:00:00 2001 From: Tim Jenssen Date: Mon, 3 Jul 2017 19:47:48 +0200 Subject: [PATCH 10/15] Clang: fix QDebug for SmallStringView Change-Id: I54b200dc142d3d143fd3238ea97c4d6277c6604f Reviewed-by: Marco Bubke --- src/libs/utils/smallstringio.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/utils/smallstringio.h b/src/libs/utils/smallstringio.h index 8dabbcc4d01..e212fc85672 100644 --- a/src/libs/utils/smallstringio.h +++ b/src/libs/utils/smallstringio.h @@ -73,7 +73,7 @@ QDebug &operator<<(QDebug &debug, const String &string) { using QT_PREPEND_NAMESPACE(operator<<); - debug.nospace() << "\"" << string.data() << "\""; + debug.nospace().quote() << QByteArray::fromRawData(string.data(), int(string.size())); return debug; } From 86b6b71937c3cfef59c90cb040ff918e0e73635e Mon Sep 17 00:00:00 2001 From: Tim Jenssen Date: Mon, 3 Jul 2017 19:53:32 +0200 Subject: [PATCH 11/15] Clang: fix separators for tests Change-Id: I951603294f2cf0a044463ddb431b80370b393bb6 Reviewed-by: Marco Bubke --- tests/unit/unittest/clangquerygatherer-test.cpp | 8 +++++--- tests/unit/unittest/refactoringserver-test.cpp | 3 ++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/unit/unittest/clangquerygatherer-test.cpp b/tests/unit/unittest/clangquerygatherer-test.cpp index b4808b45c57..d1ff0a508e3 100644 --- a/tests/unit/unittest/clangquerygatherer-test.cpp +++ b/tests/unit/unittest/clangquerygatherer-test.cpp @@ -25,6 +25,8 @@ #include "googletest.h" +#include "filesystem-utilities.h" + #include "sourcerangecontainer-matcher.h" #include @@ -77,13 +79,13 @@ protected: Utils::SmallString sourceContent{"#include \"query_simplefunction.h\"\nvoid f() {}"}; FileContainer source{{TESTDATA_DIR, "query_simplefunction.cpp"}, sourceContent.clone(), - {"cc", TESTDATA_DIR"/query_simplefunction.cpp", "-I", TESTDATA_DIR}}; + {"cc", toNativePath(TESTDATA_DIR"/query_simplefunction.cpp"), "-I", TESTDATA_DIR}}; FileContainer source2{{TESTDATA_DIR, "query_simplefunction2.cpp"}, {}, - {"cc", TESTDATA_DIR"/query_simplefunction2.cpp", "-I", TESTDATA_DIR}}; + {"cc", toNativePath(TESTDATA_DIR"/query_simplefunction2.cpp"), "-I", TESTDATA_DIR}}; FileContainer source3{{TESTDATA_DIR, "query_simplefunction3.cpp"}, {}, - {"cc", TESTDATA_DIR"/query_simplefunction3.cpp", "-I", TESTDATA_DIR}}; + {"cc", toNativePath(TESTDATA_DIR"/query_simplefunction3.cpp"), "-I", TESTDATA_DIR}}; Utils::SmallString unsavedContent{"void f();"}; FileContainer unsaved{{TESTDATA_DIR, "query_simplefunction.h"}, unsavedContent.clone(), diff --git a/tests/unit/unittest/refactoringserver-test.cpp b/tests/unit/unittest/refactoringserver-test.cpp index 39db78bdcd0..40ca87031ea 100644 --- a/tests/unit/unittest/refactoringserver-test.cpp +++ b/tests/unit/unittest/refactoringserver-test.cpp @@ -25,6 +25,7 @@ #include "googletest.h" +#include "filesystem-utilities.h" #include "mockrefactoringclient.h" #include "sourcerangecontainer-matcher.h" @@ -78,7 +79,7 @@ protected: Utils::SmallString sourceContent{"void f()\n {}"}; FileContainer source{{TESTDATA_DIR, "query_simplefunction.cpp"}, sourceContent.clone(), - {"cc", TESTDATA_DIR"/query_simplefunction.cpp"}}; + {"cc", toNativePath(TESTDATA_DIR"/query_simplefunction.cpp")}}; int processingSlotCount = 2; }; From 72d2003082a34b20c50f0cf7803d975d69a49638 Mon Sep 17 00:00:00 2001 From: Tim Jenssen Date: Mon, 3 Jul 2017 19:54:17 +0200 Subject: [PATCH 12/15] Clang: fix double file entry Change-Id: I3add0999df472c09a96db929fab25c1e1201d6f7 Reviewed-by: Marco Bubke --- tests/unit/unittest/unittest.pro | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro index 8409517e8f3..ca7f4fdb74a 100644 --- a/tests/unit/unittest/unittest.pro +++ b/tests/unit/unittest/unittest.pro @@ -63,7 +63,6 @@ SOURCES += \ projectupdater-test.cpp \ pchmanagerserver-test.cpp \ pchmanagerclientserverinprocess-test.cpp \ - clangquerygatherer-test.cpp \ filepath-test.cpp \ sourcerangefilter-test.cpp From 6ec8d1a7aa3757688ff56c476207c5a2abccca21 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Mon, 3 Jul 2017 09:08:49 +0200 Subject: [PATCH 13/15] AutoTest: Add optional verbosity for Qt tests Add options allowing verbose benchmarks and logging of signals and slots inside Qt tests. Beside this fixing a typo (recognition of results of type info) inside the plain text reader. Change-Id: Iaba7112c55bf30213584e56858d096c8f78307d0 Reviewed-by: David Schulz --- .../autotest/qtest/qttestconfiguration.cpp | 6 ++++++ .../autotest/qtest/qttestoutputreader.cpp | 2 +- src/plugins/autotest/qtest/qttestsettings.cpp | 6 ++++++ src/plugins/autotest/qtest/qttestsettings.h | 2 ++ .../autotest/qtest/qttestsettingspage.cpp | 4 ++++ .../autotest/qtest/qttestsettingspage.ui | 17 +++++++++++++++++ 6 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/plugins/autotest/qtest/qttestconfiguration.cpp b/src/plugins/autotest/qtest/qttestconfiguration.cpp index 2329bfe6bc5..0875ec18a63 100644 --- a/src/plugins/autotest/qtest/qttestconfiguration.cpp +++ b/src/plugins/autotest/qtest/qttestconfiguration.cpp @@ -67,6 +67,12 @@ QStringList QtTestConfiguration::argumentsForTestRunner() const if (!metricsOption.isEmpty()) arguments << metricsOption; + if (qtSettings->verboseBench) + arguments << "-vb"; + + if (qtSettings->logSignalsSlots) + arguments << "-vs"; + if (runMode() == DebuggableTestConfiguration::Debug) { if (qtSettings->noCrashHandler) arguments << "-nocrashhandler"; diff --git a/src/plugins/autotest/qtest/qttestoutputreader.cpp b/src/plugins/autotest/qtest/qttestoutputreader.cpp index aa86681a486..acf435fd88c 100644 --- a/src/plugins/autotest/qtest/qttestoutputreader.cpp +++ b/src/plugins/autotest/qtest/qttestoutputreader.cpp @@ -319,7 +319,7 @@ void QtTestOutputReader::processPlainTextOutput(const QByteArray &outputLine) static QRegExp finish("^[*]{9} Finished testing of (.*) [*]{9}$"); static QRegExp result("^(PASS |FAIL! |XFAIL |XPASS |SKIP |BPASS |BFAIL |RESULT " - "|INFO |QWARN |WARNING|QDEBUG ): (.*)$"); + "|INFO |QWARN |WARNING|QDEBUG ): (.*)$"); static QRegExp benchDetails("^\\s+([\\d,.]+ .* per iteration \\(total: [\\d,.]+, iterations: \\d+\\))$"); static QRegExp locationUnix("^ Loc: \\[(.*)\\]$"); diff --git a/src/plugins/autotest/qtest/qttestsettings.cpp b/src/plugins/autotest/qtest/qttestsettings.cpp index 1b672cd29dd..dba1be98e27 100644 --- a/src/plugins/autotest/qtest/qttestsettings.cpp +++ b/src/plugins/autotest/qtest/qttestsettings.cpp @@ -31,6 +31,8 @@ namespace Internal { static const char metricsKey[] = "Metrics"; static const char noCrashhandlerKey[] = "NoCrashhandlerOnDebug"; static const char useXMLOutputKey[] = "UseXMLOutput"; +static const char verboseBenchKey[] = "VerboseBench"; +static const char logSignalsSlotsKey[] = "LogSignalsSlots"; static MetricsType intToMetrics(int value) { @@ -60,6 +62,8 @@ void QtTestSettings::fromFrameworkSettings(const QSettings *s) metrics = intToMetrics(s->value(metricsKey, Walltime).toInt()); noCrashHandler = s->value(noCrashhandlerKey, true).toBool(); useXMLOutput = s->value(useXMLOutputKey, true).toBool(); + verboseBench = s->value(verboseBenchKey, false).toBool(); + logSignalsSlots = s->value(logSignalsSlotsKey, false).toBool(); } void QtTestSettings::toFrameworkSettings(QSettings *s) const @@ -67,6 +71,8 @@ void QtTestSettings::toFrameworkSettings(QSettings *s) const s->setValue(metricsKey, metrics); s->setValue(noCrashhandlerKey, noCrashHandler); s->setValue(useXMLOutputKey, useXMLOutput); + s->setValue(verboseBenchKey, verboseBench); + s->setValue(logSignalsSlotsKey, logSignalsSlots); } QString QtTestSettings::metricsTypeToOption(const MetricsType type) diff --git a/src/plugins/autotest/qtest/qttestsettings.h b/src/plugins/autotest/qtest/qttestsettings.h index 9418059243b..8f2c0954b9b 100644 --- a/src/plugins/autotest/qtest/qttestsettings.h +++ b/src/plugins/autotest/qtest/qttestsettings.h @@ -49,6 +49,8 @@ public: MetricsType metrics = Walltime; bool noCrashHandler = true; bool useXMLOutput = true; + bool verboseBench = false; + bool logSignalsSlots = false; protected: void fromFrameworkSettings(const QSettings *s) override; diff --git a/src/plugins/autotest/qtest/qttestsettingspage.cpp b/src/plugins/autotest/qtest/qttestsettingspage.cpp index 8258440ec4e..8aa4c6cc133 100644 --- a/src/plugins/autotest/qtest/qttestsettingspage.cpp +++ b/src/plugins/autotest/qtest/qttestsettingspage.cpp @@ -47,6 +47,8 @@ void QtTestSettingsWidget::setSettings(const QtTestSettings &settings) { m_ui.disableCrashhandlerCB->setChecked(settings.noCrashHandler); m_ui.useXMLOutputCB->setChecked(settings.useXMLOutput); + m_ui.verboseBenchmarksCB->setChecked(settings.verboseBench); + m_ui.logSignalsAndSlotsCB->setChecked(settings.logSignalsSlots); switch (settings.metrics) { case MetricsType::Walltime: m_ui.walltimeRB->setChecked(true); @@ -74,6 +76,8 @@ QtTestSettings QtTestSettingsWidget::settings() const result.noCrashHandler = m_ui.disableCrashhandlerCB->isChecked(); result.useXMLOutput = m_ui.useXMLOutputCB->isChecked(); + result.verboseBench = m_ui.verboseBenchmarksCB->isChecked(); + result.logSignalsSlots = m_ui.logSignalsAndSlotsCB->isChecked(); if (m_ui.walltimeRB->isChecked()) result.metrics = MetricsType::Walltime; else if (m_ui.tickcounterRB->isChecked()) diff --git a/src/plugins/autotest/qtest/qttestsettingspage.ui b/src/plugins/autotest/qtest/qttestsettingspage.ui index 38837afee87..4991107a022 100644 --- a/src/plugins/autotest/qtest/qttestsettingspage.ui +++ b/src/plugins/autotest/qtest/qttestsettingspage.ui @@ -46,6 +46,23 @@ Warning: Plain text output is missing some information (e.g. duration) + + + + Verbose benchmarks + + + + + + + Log every signal emission and resulting slot invocations. + + + Log signals and slots + + + From 6e7a31c4fecf82485f7b462b57f0c05218248c8a Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 30 Jun 2017 08:41:08 +0200 Subject: [PATCH 14/15] Debugger: Move startupRunConfiguration to RunConfiguration It's not really debugger-specific. Change-Id: I2246e08d896df1d625ecce9b8b5428e7ea398851 Reviewed-by: Christian Stenger --- src/plugins/debugger/analyzer/analyzermanager.h | 6 +----- src/plugins/debugger/debuggerplugin.cpp | 11 +---------- src/plugins/projectexplorer/runconfiguration.cpp | 15 +++++++++++++++ src/plugins/projectexplorer/runconfiguration.h | 2 ++ src/plugins/qmlprofiler/qmlprofilertool.cpp | 4 ++-- src/plugins/valgrind/callgrindtool.cpp | 2 +- src/plugins/valgrind/memchecktool.cpp | 2 +- 7 files changed, 23 insertions(+), 19 deletions(-) diff --git a/src/plugins/debugger/analyzer/analyzermanager.h b/src/plugins/debugger/analyzer/analyzermanager.h index 9a3dedd9d99..5907c819aa5 100644 --- a/src/plugins/debugger/analyzer/analyzermanager.h +++ b/src/plugins/debugger/analyzer/analyzermanager.h @@ -30,11 +30,7 @@ #include "../debuggermainwindow.h" -#include - -#include -#include -#include +#include #include diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index 16622638f37..72b69ab41b1 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -3416,19 +3416,10 @@ static bool buildTypeAccepted(QFlags toolMode, BuildConfiguration::Bui return false; } -RunConfiguration *startupRunConfiguration() -{ - if (Project *pro = SessionManager::startupProject()) { - if (const Target *target = pro->activeTarget()) - return target->activeRunConfiguration(); - } - return nullptr; -} - static BuildConfiguration::BuildType startupBuildType() { BuildConfiguration::BuildType buildType = BuildConfiguration::Unknown; - if (RunConfiguration *runConfig = startupRunConfiguration()) { + if (RunConfiguration *runConfig = RunConfiguration::startupRunConfiguration()) { if (const BuildConfiguration *buildConfig = runConfig->target()->activeBuildConfiguration()) buildType = buildConfig->buildType(); } diff --git a/src/plugins/projectexplorer/runconfiguration.cpp b/src/plugins/projectexplorer/runconfiguration.cpp index 79f7067104c..e95e49044dd 100644 --- a/src/plugins/projectexplorer/runconfiguration.cpp +++ b/src/plugins/projectexplorer/runconfiguration.cpp @@ -33,6 +33,7 @@ #include "environmentaspect.h" #include "kitinformation.h" #include "runnables.h" +#include "session.h" #include @@ -243,6 +244,20 @@ void RunConfiguration::ctor() [this] { return displayName(); }, false); } +/*! + * Returns the RunConfiguration of the currently active target + * of the startup project, if such exists, or \c nullptr otherwise. + */ + +RunConfiguration *RunConfiguration::startupRunConfiguration() +{ + if (Project *pro = SessionManager::startupProject()) { + if (const Target *target = pro->activeTarget()) + return target->activeRunConfiguration(); + } + return nullptr; +} + /*! Checks whether a run configuration is enabled. */ diff --git a/src/plugins/projectexplorer/runconfiguration.h b/src/plugins/projectexplorer/runconfiguration.h index cf1d5c7a9ad..cd954b98887 100644 --- a/src/plugins/projectexplorer/runconfiguration.h +++ b/src/plugins/projectexplorer/runconfiguration.h @@ -281,6 +281,8 @@ public: void addExtraAspect(IRunConfigurationAspect *aspect); + static RunConfiguration *startupRunConfiguration(); + signals: void enabledChanged(); void requestRunActionsUpdate(); diff --git a/src/plugins/qmlprofiler/qmlprofilertool.cpp b/src/plugins/qmlprofiler/qmlprofilertool.cpp index b661fab197f..8a655b955c6 100644 --- a/src/plugins/qmlprofiler/qmlprofilertool.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertool.cpp @@ -587,8 +587,8 @@ void QmlProfilerTool::attachToWaitingApplication() Debugger::selectPerspective(Constants::QmlProfilerPerspectiveId); - RunConfiguration *rc = Debugger::startupRunConfiguration(); - auto runControl = new RunControl(rc, ProjectExplorer::Constants::QML_PROFILER_RUN_MODE); + auto runConfig = RunConfiguration::startupRunConfiguration(); + auto runControl = new RunControl(runConfig, ProjectExplorer::Constants::QML_PROFILER_RUN_MODE); auto profiler = new QmlProfilerRunner(runControl); profiler->setServerUrl(serverUrl); diff --git a/src/plugins/valgrind/callgrindtool.cpp b/src/plugins/valgrind/callgrindtool.cpp index 1564fcb78d0..0c8f1478dbd 100644 --- a/src/plugins/valgrind/callgrindtool.cpp +++ b/src/plugins/valgrind/callgrindtool.cpp @@ -277,7 +277,7 @@ CallgrindTool::CallgrindTool(QObject *parent) menu->addAction(ActionManager::registerAction(action, CallgrindRemoteActionId), Debugger::Constants::G_ANALYZER_REMOTE_TOOLS); QObject::connect(action, &QAction::triggered, this, [this, action] { - RunConfiguration *runConfig = startupRunConfiguration(); + auto runConfig = RunConfiguration::startupRunConfiguration(); if (!runConfig) { showCannotStartDialog(action->text()); return; diff --git a/src/plugins/valgrind/memchecktool.cpp b/src/plugins/valgrind/memchecktool.cpp index 5ae5bf3f152..195aede309a 100644 --- a/src/plugins/valgrind/memchecktool.cpp +++ b/src/plugins/valgrind/memchecktool.cpp @@ -440,7 +440,7 @@ MemcheckTool::MemcheckTool(QObject *parent) menu->addAction(ActionManager::registerAction(action, "Memcheck.Remote"), Debugger::Constants::G_ANALYZER_REMOTE_TOOLS); QObject::connect(action, &QAction::triggered, this, [this, action] { - RunConfiguration *runConfig = startupRunConfiguration(); + auto runConfig = RunConfiguration::startupRunConfiguration(); if (!runConfig) { showCannotStartDialog(action->text()); return; From 3c6a2b79124bf05abf4853b2377b7599c254a998 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Thu, 29 Jun 2017 15:45:31 +0200 Subject: [PATCH 15/15] Extend search pane The search term line edit can now be hidden away and the options are hidden too too if they are all disabled. Change-Id: I2363d010acbdabb2abfc6c6cd2f98c07cd7d3a3d Reviewed-by: Eike Ziller --- src/plugins/coreplugin/find/finddialog.ui | 26 ++++++++++++++++--- .../coreplugin/find/findtoolwindow.cpp | 7 +++++ src/plugins/coreplugin/find/ifindfilter.cpp | 11 +++++++- src/plugins/coreplugin/find/ifindfilter.h | 1 + src/plugins/cpptools/symbolsfindfilter.cpp | 5 ---- src/plugins/cpptools/symbolsfindfilter.h | 1 - 6 files changed, 40 insertions(+), 11 deletions(-) diff --git a/src/plugins/coreplugin/find/finddialog.ui b/src/plugins/coreplugin/find/finddialog.ui index 1f3c900b3ff..7ada6ce0aa9 100644 --- a/src/plugins/coreplugin/find/finddialog.ui +++ b/src/plugins/coreplugin/find/finddialog.ui @@ -55,7 +55,7 @@ - + Sear&ch for: @@ -73,7 +73,16 @@ 0 - + + 0 + + + 0 + + + 0 + + 0 @@ -103,9 +112,18 @@ - + - + + 0 + + + 0 + + + 0 + + 0 diff --git a/src/plugins/coreplugin/find/findtoolwindow.cpp b/src/plugins/coreplugin/find/findtoolwindow.cpp index b29dfbe4f8e..ffcf3855253 100644 --- a/src/plugins/coreplugin/find/findtoolwindow.cpp +++ b/src/plugins/coreplugin/find/findtoolwindow.cpp @@ -147,6 +147,13 @@ void FindToolWindow::updateButtonStates() if (m_configWidget) m_configWidget->setEnabled(filterEnabled); + if (m_currentFilter) { + m_ui.searchTerm->setVisible(m_currentFilter->showSearchTermInput()); + m_ui.searchLabel->setVisible(m_currentFilter->showSearchTermInput()); + m_ui.optionsWidget->setVisible(m_currentFilter->supportedFindFlags() + & (FindCaseSensitively | FindWholeWords | FindRegularExpression)); + } + m_ui.matchCase->setEnabled(filterEnabled && (m_currentFilter->supportedFindFlags() & FindCaseSensitively)); m_ui.wholeWords->setEnabled(filterEnabled diff --git a/src/plugins/coreplugin/find/ifindfilter.cpp b/src/plugins/coreplugin/find/ifindfilter.cpp index e080e249f0c..d57a16370e1 100644 --- a/src/plugins/coreplugin/find/ifindfilter.cpp +++ b/src/plugins/coreplugin/find/ifindfilter.cpp @@ -142,6 +142,14 @@ your find filter supports global search and replace. */ +/*! + \fn bool showSearchTermInput() const + Returns whether the find filter wants to show the search term line edit. + + The default value is \c true, override this function to return \c false, if + your find filter does not want to show the search term line edit. +*/ + /*! \fn void IFindFilter::findAll(const QString &txt, Core::FindFlags findFlags) This function is called when the user selected this find scope and @@ -227,7 +235,8 @@ QKeySequence IFindFilter::defaultShortcut() const FindFlags IFindFilter::supportedFindFlags() const { return FindCaseSensitively - | FindRegularExpression | FindWholeWords; + | FindRegularExpression + | FindWholeWords; } QPixmap IFindFilter::pixmapForFindFlags(FindFlags flags) diff --git a/src/plugins/coreplugin/find/ifindfilter.h b/src/plugins/coreplugin/find/ifindfilter.h index 41a920379d9..9c67c29fc2e 100644 --- a/src/plugins/coreplugin/find/ifindfilter.h +++ b/src/plugins/coreplugin/find/ifindfilter.h @@ -50,6 +50,7 @@ public: virtual bool isValid() const { return true; } virtual QKeySequence defaultShortcut() const; virtual bool isReplaceSupported() const { return false; } + virtual bool showSearchTermInput() const { return true; } virtual FindFlags supportedFindFlags() const; virtual void findAll(const QString &txt, FindFlags findFlags) = 0; diff --git a/src/plugins/cpptools/symbolsfindfilter.cpp b/src/plugins/cpptools/symbolsfindfilter.cpp index 104cac2ba87..9286a61138d 100644 --- a/src/plugins/cpptools/symbolsfindfilter.cpp +++ b/src/plugins/cpptools/symbolsfindfilter.cpp @@ -100,11 +100,6 @@ void SymbolsFindFilter::setPaused(bool paused) watcher->setPaused(paused); } -FindFlags SymbolsFindFilter::supportedFindFlags() const -{ - return FindCaseSensitively | FindRegularExpression | FindWholeWords; -} - void SymbolsFindFilter::findAll(const QString &txt, FindFlags findFlags) { SearchResultWindow *window = SearchResultWindow::instance(); diff --git a/src/plugins/cpptools/symbolsfindfilter.h b/src/plugins/cpptools/symbolsfindfilter.h index 827bef9f7a2..b4e72b2a320 100644 --- a/src/plugins/cpptools/symbolsfindfilter.h +++ b/src/plugins/cpptools/symbolsfindfilter.h @@ -56,7 +56,6 @@ public: QString id() const; QString displayName() const; bool isEnabled() const; - Core::FindFlags supportedFindFlags() const; void findAll(const QString &txt, Core::FindFlags findFlags);