diff options
author | Tim Jenssen <tim.jenssen@qt.io> | 2016-11-23 13:13:38 +0100 |
---|---|---|
committer | Tim Jenssen <tim.jenssen@qt.io> | 2016-11-23 12:16:04 +0000 |
commit | 7f757884c5a04484820a97e592afae74beff95a9 (patch) | |
tree | d5066d8a24965523b5024ba37d210c74cd68446c | |
parent | 52fc4a4ebdc840cc351a0ed465a6523d5bc53ac2 (diff) | |
download | qt-creator-7f757884c5a04484820a97e592afae74beff95a9.tar.gz |
Clang: Extend clang query
It's a first step to introduce clang query.
Change-Id: I4d001a8883f56066765ce6bc561fa3f49611c0a4
Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
70 files changed, 1914 insertions, 646 deletions
diff --git a/src/libs/clangbackendipc/cancelmessage.cpp b/src/libs/clangbackendipc/cancelmessage.cpp new file mode 100644 index 0000000000..470b8263c7 --- /dev/null +++ b/src/libs/clangbackendipc/cancelmessage.cpp @@ -0,0 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "cancelmessage.h" + +#include <QDebug> + +namespace ClangBackEnd { + +QDebug operator<<(QDebug debug, const CancelMessage &) +{ + debug.nospace() << "CancelMessage()"; + + return debug; +} + +void PrintTo(const CancelMessage &, ::std::ostream* os) +{ + *os << "CancelMessage()"; +} + +} // namespace ClangBackEnd diff --git a/src/libs/clangbackendipc/cancelmessage.h b/src/libs/clangbackendipc/cancelmessage.h new file mode 100644 index 0000000000..1107fee21e --- /dev/null +++ b/src/libs/clangbackendipc/cancelmessage.h @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "clangbackendipc_global.h" + +namespace ClangBackEnd { + +class CancelMessage +{ +public: + friend QDataStream &operator<<(QDataStream &out, const CancelMessage &/*message*/) + { + return out; + } + + friend QDataStream &operator>>(QDataStream &in, CancelMessage &/*message*/) + { + return in; + } + + friend bool operator==(const CancelMessage &/*first*/, const CancelMessage &/*second*/) + { + return true; + } +}; + +CMBIPC_EXPORT QDebug operator<<(QDebug debug, const CancelMessage &message); +void PrintTo(const CancelMessage &message, ::std::ostream* os); + +DECLARE_MESSAGE(CancelMessage) +} // namespace ClangBackEnd diff --git a/src/libs/clangbackendipc/clangbackendipc-lib.pri b/src/libs/clangbackendipc/clangbackendipc-lib.pri index 8cc4a89171..ced97b0d31 100644 --- a/src/libs/clangbackendipc/clangbackendipc-lib.pri +++ b/src/libs/clangbackendipc/clangbackendipc-lib.pri @@ -59,6 +59,7 @@ SOURCES += $$PWD/clangcodemodelserverinterface.cpp \ $$PWD/requestsourcelocationforrenamingmessage.cpp \ $$PWD/filepath.cpp \ $$PWD/sourcerangescontainer.cpp \ + $$PWD/sourcefilepathcontainerbase.cpp \ $$PWD/sourcerangecontainerv2.cpp \ $$PWD/dynamicastmatcherdiagnosticcontainer.cpp \ $$PWD/dynamicastmatcherdiagnosticcontextcontainer.cpp \ @@ -66,7 +67,8 @@ SOURCES += $$PWD/clangcodemodelserverinterface.cpp \ $$PWD/requestsourcerangesanddiagnosticsforquerymessage.cpp \ $$PWD/sourcerangesanddiagnosticsforquerymessage.cpp \ $$PWD/sourcerangewithtextcontainer.cpp \ - $$PWD/filecontainerv2.cpp + $$PWD/filecontainerv2.cpp \ + $$PWD/cancelmessage.cpp HEADERS += \ $$PWD/clangcodemodelserverinterface.h \ @@ -130,6 +132,7 @@ HEADERS += \ $$PWD/requestsourcerangesanddiagnosticsforquerymessage.h \ $$PWD/sourcerangesanddiagnosticsforquerymessage.h \ $$PWD/sourcerangewithtextcontainer.h \ - $$PWD/filecontainerv2.h + $$PWD/filecontainerv2.h \ + $$PWD/cancelmessage.h contains(QT_CONFIG, reduce_exports):CONFIG += hide_symbols diff --git a/src/libs/clangbackendipc/clangbackendipc_global.h b/src/libs/clangbackendipc/clangbackendipc_global.h index 33e1c8883d..306a9d085a 100644 --- a/src/libs/clangbackendipc/clangbackendipc_global.h +++ b/src/libs/clangbackendipc/clangbackendipc_global.h @@ -46,7 +46,7 @@ #endif namespace Utils { -template<uint Size> +template <uint Size> class BasicSmallString; using SmallString = BasicSmallString<31>; } @@ -122,7 +122,9 @@ enum class MessageType : quint8 { RequestSourceLocationsForRenamingMessage, RequestSourceRangesAndDiagnosticsForQueryMessage, - SourceRangesAndDiagnosticsForQueryMessage + SourceRangesAndDiagnosticsForQueryMessage, + + CancelMessage }; template<MessageType messageEnumeration> diff --git a/src/libs/clangbackendipc/refactoringserverinterface.cpp b/src/libs/clangbackendipc/refactoringserverinterface.cpp index fe1cc7103f..9e45779140 100644 --- a/src/libs/clangbackendipc/refactoringserverinterface.cpp +++ b/src/libs/clangbackendipc/refactoringserverinterface.cpp @@ -28,6 +28,7 @@ #include "messageenvelop.h" #include "requestsourcelocationforrenamingmessage.h" #include "requestsourcerangesanddiagnosticsforquerymessage.h" +#include "cancelmessage.h" #include <QDebug> @@ -45,6 +46,9 @@ void RefactoringServerInterface::dispatch(const MessageEnvelop &messageEnvelop) case MessageType::RequestSourceRangesAndDiagnosticsForQueryMessage: requestSourceRangesAndDiagnosticsForQueryMessage(messageEnvelop.message<RequestSourceRangesAndDiagnosticsForQueryMessage>()); break; + case MessageType::CancelMessage: + cancel(); + break; default: qWarning() << "Unknown IpcClientMessage"; } diff --git a/src/libs/clangbackendipc/refactoringserverinterface.h b/src/libs/clangbackendipc/refactoringserverinterface.h index f06a5904bf..a22f4c1f1f 100644 --- a/src/libs/clangbackendipc/refactoringserverinterface.h +++ b/src/libs/clangbackendipc/refactoringserverinterface.h @@ -34,6 +34,7 @@ namespace ClangBackEnd { class RefactoringClientInterface; class RequestSourceLocationsForRenamingMessage; class RequestSourceRangesAndDiagnosticsForQueryMessage; +class CancelMessage; class CMBIPC_EXPORT RefactoringServerInterface : public IpcServerInterface<RefactoringClientInterface> { @@ -43,6 +44,7 @@ public: virtual void end() = 0; virtual void requestSourceLocationsForRenamingMessage(RequestSourceLocationsForRenamingMessage &&message) = 0; virtual void requestSourceRangesAndDiagnosticsForQueryMessage(RequestSourceRangesAndDiagnosticsForQueryMessage &&message) = 0; + virtual void cancel() = 0; bool isUsable() const { diff --git a/src/libs/clangbackendipc/refactoringserverproxy.cpp b/src/libs/clangbackendipc/refactoringserverproxy.cpp index be6ee5457c..77f7e7e6fa 100644 --- a/src/libs/clangbackendipc/refactoringserverproxy.cpp +++ b/src/libs/clangbackendipc/refactoringserverproxy.cpp @@ -25,6 +25,7 @@ #include "refactoringserverproxy.h" +#include "cancelmessage.h" #include "cmbendmessage.h" #include "messageenvelop.h" #include "refactoringclientinterface.h" @@ -59,6 +60,11 @@ void RefactoringServerProxy::requestSourceRangesAndDiagnosticsForQueryMessage(Re writeMessageBlock.write(message); } +void RefactoringServerProxy::cancel() +{ + writeMessageBlock.write(CancelMessage()); +} + void RefactoringServerProxy::readMessages() { for (const auto &message : readMessageBlock.readAll()) diff --git a/src/libs/clangbackendipc/refactoringserverproxy.h b/src/libs/clangbackendipc/refactoringserverproxy.h index 43f1b354a3..44eb2065b2 100644 --- a/src/libs/clangbackendipc/refactoringserverproxy.h +++ b/src/libs/clangbackendipc/refactoringserverproxy.h @@ -42,7 +42,7 @@ namespace ClangBackEnd { class RefactoringClientInterface; -class CMBIPC_EXPORT RefactoringServerProxy : public RefactoringServerInterface +class CMBIPC_EXPORT RefactoringServerProxy final : public RefactoringServerInterface { public: explicit RefactoringServerProxy(RefactoringClientInterface *client, QIODevice *ioDevice); @@ -50,8 +50,9 @@ public: const RefactoringServerProxy &operator=(const RefactoringServerProxy&) = delete; void end() override; - void requestSourceLocationsForRenamingMessage(ClangBackEnd::RequestSourceLocationsForRenamingMessage &&message) override; - void requestSourceRangesAndDiagnosticsForQueryMessage(RequestSourceRangesAndDiagnosticsForQueryMessage &&message); + void requestSourceLocationsForRenamingMessage(RequestSourceLocationsForRenamingMessage &&message) override; + void requestSourceRangesAndDiagnosticsForQueryMessage(RequestSourceRangesAndDiagnosticsForQueryMessage &&message) override; + void cancel() override; void readMessages(); diff --git a/src/libs/clangbackendipc/requestsourcerangesanddiagnosticsforquerymessage.h b/src/libs/clangbackendipc/requestsourcerangesanddiagnosticsforquerymessage.h index a6a2b50960..d56a536d1c 100644 --- a/src/libs/clangbackendipc/requestsourcerangesanddiagnosticsforquerymessage.h +++ b/src/libs/clangbackendipc/requestsourcerangesanddiagnosticsforquerymessage.h @@ -25,13 +25,11 @@ #pragma once -#include "clangbackendipc_global.h" - #include "filecontainerv2.h" namespace ClangBackEnd { -class CMBIPC_EXPORT RequestSourceRangesAndDiagnosticsForQueryMessage +class RequestSourceRangesAndDiagnosticsForQueryMessage { public: RequestSourceRangesAndDiagnosticsForQueryMessage() = default; diff --git a/src/libs/clangbackendipc/sourcefilepathcontainerbase.cpp b/src/libs/clangbackendipc/sourcefilepathcontainerbase.cpp new file mode 100644 index 0000000000..66d44d8827 --- /dev/null +++ b/src/libs/clangbackendipc/sourcefilepathcontainerbase.cpp @@ -0,0 +1,32 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "sourcefilepathcontainerbase.h" + +namespace ClangBackEnd { + + + +} // namespace ClangBackEnd diff --git a/src/libs/clangbackendipc/sourcefilepathcontainerbase.h b/src/libs/clangbackendipc/sourcefilepathcontainerbase.h index fc59613a9c..40a5a68db6 100644 --- a/src/libs/clangbackendipc/sourcefilepathcontainerbase.h +++ b/src/libs/clangbackendipc/sourcefilepathcontainerbase.h @@ -44,9 +44,11 @@ public: void insertFilePath(uint fileId, Utils::SmallString &&fileDirectory, Utils::SmallString &&fileName) { - filePathHash.emplace(std::piecewise_construct, - std::forward_as_tuple(fileId), - std::forward_as_tuple(std::move(fileDirectory), std::move(fileName))); + if (filePathHash.find(fileId) == filePathHash.end()) { + filePathHash.emplace(std::piecewise_construct, + std::forward_as_tuple(fileId), + std::forward_as_tuple(std::move(fileDirectory), std::move(fileName))); + } } void reserve(std::size_t size) diff --git a/src/libs/clangbackendipc/sourcerangewithtextcontainer.cpp b/src/libs/clangbackendipc/sourcerangewithtextcontainer.cpp index a418af0488..2be07150da 100644 --- a/src/libs/clangbackendipc/sourcerangewithtextcontainer.cpp +++ b/src/libs/clangbackendipc/sourcerangewithtextcontainer.cpp @@ -25,6 +25,10 @@ #include "sourcerangewithtextcontainer.h" +#ifdef UNIT_TESTS +#include <gtest/gtest.h> +#endif + namespace ClangBackEnd { QDebug operator<<(QDebug debug, const SourceRangeWithTextContainer &container) @@ -40,12 +44,18 @@ QDebug operator<<(QDebug debug, const SourceRangeWithTextContainer &container) void PrintTo(const SourceRangeWithTextContainer &container, ::std::ostream* os) { + Q_UNUSED(container) + Q_UNUSED(os) +#ifdef UNIT_TESTS *os << "((" << container.start().line() << ", " - << container.start().column() << "), (" + << container.start().column() << ", " + << container.start().offset() << "), (" << container.end().line() << ", " << container.end().column() << ", " - << "\"" << container.text() << "\"" - << "))"; + << container.end().offset() << "), " + << testing::PrintToString(container.text()) + << ")"; +#endif } } // namespace ClangBackEnd diff --git a/src/plugins/clangrefactoring/clangquerycurrentfilefindfilter.cpp b/src/plugins/clangrefactoring/clangquerycurrentfilefindfilter.cpp deleted file mode 100644 index 5df78f9bdc..0000000000 --- a/src/plugins/clangrefactoring/clangquerycurrentfilefindfilter.cpp +++ /dev/null @@ -1,129 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "clangquerycurrentfilefindfilter.h" - -#include "projectpartutilities.h" -#include "refactoringclient.h" -#include "refactoringcompileroptionsbuilder.h" -#include "searchinterface.h" - -#include <refactoringserverinterface.h> -#include <requestsourcerangesanddiagnosticsforquerymessage.h> - -namespace ClangRefactoring { - -ClangQueryCurrentFileFindFilter::ClangQueryCurrentFileFindFilter( - ClangBackEnd::RefactoringServerInterface &server, - SearchInterface &searchInterface, - RefactoringClient &refactoringClient) - : server(server), - searchInterface(searchInterface), - refactoringClient(refactoringClient) -{ -} - -QString ClangQueryCurrentFileFindFilter::id() const -{ - return QStringLiteral("Clang Query Current File"); -} - -QString ClangQueryCurrentFileFindFilter::displayName() const -{ - return tr("Clang Query Current File"); -} - -bool ClangQueryCurrentFileFindFilter::isEnabled() const -{ - return true; -} - -void ClangQueryCurrentFileFindFilter::findAll(const QString &queryText, Core::FindFlags) -{ - searchHandle = searchInterface.startNewSearch(tr("Clang Query"), queryText); - - refactoringClient.setSearchHandle(searchHandle.get()); - - server.requestSourceRangesAndDiagnosticsForQueryMessage(createMessage(queryText)); -} - -Core::FindFlags ClangQueryCurrentFileFindFilter::supportedFindFlags() const -{ - return 0; -} - -void ClangQueryCurrentFileFindFilter::setCurrentDocumentFilePath(const QString &filePath) -{ - currentDocumentFilePath = filePath; -} - -void ClangQueryCurrentFileFindFilter::setUnsavedDocumentContent(const QString &unsavedContent) -{ - unsavedDocumentContent = unsavedContent; -} - -void ClangQueryCurrentFileFindFilter::setProjectPart(const CppTools::ProjectPart::Ptr &projectPart) -{ - this->projectPart = projectPart; -} - -void ClangQueryCurrentFileFindFilter::setUsable(bool isUsable) -{ - server.setUsable(isUsable); -} - -bool ClangQueryCurrentFileFindFilter::isUsable() const -{ - return server.isUsable(); -} - -ClangBackEnd::RequestSourceRangesAndDiagnosticsForQueryMessage -ClangQueryCurrentFileFindFilter::createMessage(const QString &queryText) const -{ - std::vector<ClangBackEnd::V2::FileContainer> fileContainers; - fileContainers.emplace_back(ClangBackEnd::FilePath(currentDocumentFilePath), - unsavedDocumentContent, - createCommandLine()); - - return ClangBackEnd::RequestSourceRangesAndDiagnosticsForQueryMessage( - Utils::SmallString(queryText), - std::move(fileContainers)); -} - -Utils::SmallStringVector ClangQueryCurrentFileFindFilter::createCommandLine() const -{ - using ClangRefactoring::RefactoringCompilerOptionsBuilder; - - auto commandLine = RefactoringCompilerOptionsBuilder::build( - projectPart.data(), - fileKindInProjectPart(projectPart.data(), currentDocumentFilePath), - RefactoringCompilerOptionsBuilder::PchUsage::None); - - commandLine.push_back(currentDocumentFilePath); - - return commandLine; -} - -} // namespace ClangRefactoring diff --git a/src/plugins/clangrefactoring/clangquerycurrentfilefindfilter.h b/src/plugins/clangrefactoring/clangquerycurrentfilefindfilter.h deleted file mode 100644 index d51f862613..0000000000 --- a/src/plugins/clangrefactoring/clangquerycurrentfilefindfilter.h +++ /dev/null @@ -1,82 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#pragma once - -#include "searchhandleinterface.h" - -#include <cpptools/projectpart.h> - -#include <coreplugin/find/ifindfilter.h> - -#include <utils/smallstringvector.h> - -namespace ClangBackEnd { -class RefactoringServerInterface; -class RequestSourceRangesAndDiagnosticsForQueryMessage; -} - -namespace ClangRefactoring { - -class RefactoringClient; -class SearchInterface; - -class ClangQueryCurrentFileFindFilter : public Core::IFindFilter -{ -public: - ClangQueryCurrentFileFindFilter(ClangBackEnd::RefactoringServerInterface &server, - SearchInterface &searchInterface, - RefactoringClient &refactoringClient); - QString id() const; - QString displayName() const; - bool isEnabled() const; - void findAll(const QString &queryText, Core::FindFlags findFlags = 0); - Core::FindFlags supportedFindFlags() const; - - void setCurrentDocumentFilePath(const QString &filePath); - void setUnsavedDocumentContent(const QString &unsavedContent); - void setCurrentDocumentRevision(int revision); - void setProjectPart(const CppTools::ProjectPart::Ptr &projectPart); - - void setUsable(bool isUsable); - bool isUsable() const; - -private: - ClangBackEnd::RequestSourceRangesAndDiagnosticsForQueryMessage createMessage( - const QString &queryText) const; - - Utils::SmallStringVector createCommandLine() const; - -private: - QString currentDocumentFilePath; - QString unsavedDocumentContent; - std::unique_ptr<SearchHandleInterface> searchHandle; - CppTools::ProjectPart::Ptr projectPart; - ClangBackEnd::RefactoringServerInterface &server; - SearchInterface &searchInterface; - RefactoringClient &refactoringClient; -}; - -} // namespace ClangRefactoring diff --git a/src/plugins/clangrefactoring/clangqueryprojectsfindfilter.cpp b/src/plugins/clangrefactoring/clangqueryprojectsfindfilter.cpp index 56f9dc1e21..a97658db0d 100644 --- a/src/plugins/clangrefactoring/clangqueryprojectsfindfilter.cpp +++ b/src/plugins/clangrefactoring/clangqueryprojectsfindfilter.cpp @@ -25,10 +25,13 @@ #include "clangqueryprojectsfindfilter.h" +#include "projectpartutilities.h" #include "refactoringclient.h" +#include "refactoringcompileroptionsbuilder.h" #include "searchinterface.h" #include <refactoringserverinterface.h> +#include <requestsourcerangesanddiagnosticsforquerymessage.h> namespace ClangRefactoring { @@ -61,9 +64,15 @@ void ClangQueryProjectsFindFilter::findAll(const QString &queryText, Core::FindF { searchHandle = searchInterface.startNewSearch(tr("Clang Query"), queryText); + searchHandle->setRefactoringServer(&server); + refactoringClient.setSearchHandle(searchHandle.get()); - //server.requestSourceRangesAndDiagnosticsForQueryMessage(createMessage(queryText)); + auto message = createMessage(queryText); + + refactoringClient.setExpectedResultCount(message.fileContainers().size()); + + server.requestSourceRangesAndDiagnosticsForQueryMessage(std::move(message)); } Core::FindFlags ClangQueryProjectsFindFilter::supportedFindFlags() const @@ -71,6 +80,11 @@ Core::FindFlags ClangQueryProjectsFindFilter::supportedFindFlags() const return 0; } +void ClangQueryProjectsFindFilter::setProjectParts(const std::vector<CppTools::ProjectPart::Ptr> &projectParts) +{ + this->projectParts = projectParts; +} + bool ClangQueryProjectsFindFilter::isUsable() const { return server.isUsable(); @@ -81,4 +95,53 @@ void ClangQueryProjectsFindFilter::setUsable(bool isUsable) server.setUsable(isUsable); } +SearchHandle *ClangQueryProjectsFindFilter::searchHandleForTestOnly() const +{ + return searchHandle.get(); +} + +namespace { + +Utils::SmallStringVector createCommandLine(CppTools::ProjectPart *projectPart, + const QString &documentFilePath, + CppTools::ProjectFile::Kind fileKind) +{ + using ClangRefactoring::RefactoringCompilerOptionsBuilder; + + auto commandLine = RefactoringCompilerOptionsBuilder::build(projectPart, + fileKind, + CppTools::CompilerOptionsBuilder::PchUsage::None); + + commandLine.push_back(documentFilePath); + + return commandLine; +} + +std::vector<ClangBackEnd::V2::FileContainer> +createFileContainers(const std::vector<CppTools::ProjectPart::Ptr> &projectParts) +{ + std::vector<ClangBackEnd::V2::FileContainer> fileContainers; + + for (const CppTools::ProjectPart::Ptr &projectPart : projectParts) { + for (const CppTools::ProjectFile &projectFile : projectPart->files) { + fileContainers.emplace_back(ClangBackEnd::FilePath(projectFile.path), + "", + createCommandLine(projectPart.data(), + projectFile.path, + projectFile.kind)); + } + } + + return fileContainers; +} +} + +ClangBackEnd::RequestSourceRangesAndDiagnosticsForQueryMessage ClangQueryProjectsFindFilter::createMessage(const QString &queryText) const +{ + return ClangBackEnd::RequestSourceRangesAndDiagnosticsForQueryMessage( + Utils::SmallString(queryText), + createFileContainers(projectParts)); +} + + } // namespace ClangRefactoring diff --git a/src/plugins/clangrefactoring/clangqueryprojectsfindfilter.h b/src/plugins/clangrefactoring/clangqueryprojectsfindfilter.h index 5cefbe5d21..29bd24a0bc 100644 --- a/src/plugins/clangrefactoring/clangqueryprojectsfindfilter.h +++ b/src/plugins/clangrefactoring/clangqueryprojectsfindfilter.h @@ -25,10 +25,14 @@ #pragma once -#include "searchhandleinterface.h" +#include "searchhandle.h" + +#include <cpptools/projectpart.h> #include <coreplugin/find/ifindfilter.h> +#include <utils/smallstringvector.h> + #include <memory> namespace ClangBackEnd { @@ -54,11 +58,20 @@ public: void findAll(const QString &queryText, Core::FindFlags findFlags = 0); Core::FindFlags supportedFindFlags() const; + void setProjectParts(const std::vector<CppTools::ProjectPart::Ptr> &projectParts); + bool isUsable() const; void setUsable(bool isUsable); + SearchHandle* searchHandleForTestOnly() const; + +private: + ClangBackEnd::RequestSourceRangesAndDiagnosticsForQueryMessage createMessage( + const QString &queryText) const; + private: - std::unique_ptr<SearchHandleInterface> searchHandle; + std::unique_ptr<SearchHandle> searchHandle; + std::vector<CppTools::ProjectPart::Ptr> projectParts; ClangBackEnd::RefactoringServerInterface &server; SearchInterface &searchInterface; RefactoringClient &refactoringClient; diff --git a/src/plugins/clangrefactoring/clangrefactoring-source.pri b/src/plugins/clangrefactoring/clangrefactoring-source.pri index f3d0297bc9..52093ffbda 100644 --- a/src/plugins/clangrefactoring/clangrefactoring-source.pri +++ b/src/plugins/clangrefactoring/clangrefactoring-source.pri @@ -8,7 +8,6 @@ HEADERS += \ $$PWD/searchinterface.h \ $$PWD/searchhandleinterface.h \ $$PWD/projectpartutilities.h \ - $$PWD/clangquerycurrentfilefindfilter.h \ $$PWD/clangqueryprojectsfindfilter.h SOURCES += \ @@ -19,5 +18,4 @@ SOURCES += \ $$PWD/searchinterface.cpp \ $$PWD/searchhandleinterface.cpp \ $$PWD/projectpartutilities.cpp \ - $$PWD/clangquerycurrentfilefindfilter.cpp \ $$PWD/clangqueryprojectsfindfilter.cpp diff --git a/src/plugins/clangrefactoring/qtcreatorclangqueryfindfilter.cpp b/src/plugins/clangrefactoring/qtcreatorclangqueryfindfilter.cpp index 2a4e0de514..4dcdec43b2 100644 --- a/src/plugins/clangrefactoring/qtcreatorclangqueryfindfilter.cpp +++ b/src/plugins/clangrefactoring/qtcreatorclangqueryfindfilter.cpp @@ -25,66 +25,48 @@ #include "qtcreatorclangqueryfindfilter.h" -#include <texteditor/textdocument.h> - #include <cpptools/cppmodelmanager.h> -#include <cpptools/baseeditordocumentparser.h> +#include <cpptools/projectinfo.h> -#include <coreplugin/editormanager/editormanager.h> -#include <coreplugin/editormanager/ieditor.h> +#include <projectexplorer/session.h> namespace ClangRefactoring { QtCreatorClangQueryFindFilter::QtCreatorClangQueryFindFilter(ClangBackEnd::RefactoringServerInterface &server, SearchInterface &searchInterface, RefactoringClient &refactoringClient) - : ClangQueryCurrentFileFindFilter(server, searchInterface, refactoringClient) + : ClangQueryProjectsFindFilter(server, searchInterface, refactoringClient) { } -namespace { -CppTools::CppModelManager *cppToolManager() +void QtCreatorClangQueryFindFilter::findAll(const QString &queryText, Core::FindFlags findFlags) { - return CppTools::CppModelManager::instance(); -} + prepareFind(); -bool isCppEditor(Core::IEditor *currentEditor) -{ - return cppToolManager()->isCppEditor(currentEditor); + ClangQueryProjectsFindFilter::findAll(queryText, findFlags); } -CppTools::ProjectPart::Ptr projectPartForFile(const QString &filePath) +namespace { +std::vector<CppTools::ProjectPart::Ptr> +convertProjectParts(const QList<CppTools::ProjectPart::Ptr> &projectPartList) { - if (const auto parser = CppTools::BaseEditorDocumentParser::get(filePath)) - return parser->projectPart(); - return CppTools::ProjectPart::Ptr(); -} + std::vector<CppTools::ProjectPart::Ptr> projectPartVector; + projectPartVector.reserve(projectPartList.size()); -} + std::copy(projectPartList.begin(), projectPartList.end(), std::back_inserter(projectPartVector)); -void QtCreatorClangQueryFindFilter::findAll(const QString &queryText, Core::FindFlags findFlags) -{ - prepareFind(); + return projectPartVector; +} - ClangQueryCurrentFileFindFilter::findAll(queryText, findFlags); } void QtCreatorClangQueryFindFilter::prepareFind() { - Core::IEditor *currentEditor = Core::EditorManager::currentEditor(); - - if (isCppEditor(currentEditor)) { - Core::IDocument *currentDocument = currentEditor->document(); - auto currentTextDocument = static_cast<TextEditor::TextDocument*>(currentDocument); - const QString filePath = currentDocument->filePath().toString(); + ProjectExplorer::Project *currentProject = ProjectExplorer::SessionManager::startupProject(); - setCurrentDocumentFilePath(filePath); - setCurrentDocumentRevision(currentTextDocument->document()->revision()); - setProjectPart(projectPartForFile(filePath)); + const CppTools::ProjectInfo projectInfo = CppTools::CppModelManager::instance()->projectInfo(currentProject); - if (currentTextDocument->isModified()) - setUnsavedDocumentContent(currentTextDocument->document()->toPlainText()); - } + setProjectParts(convertProjectParts(projectInfo.projectParts())); } } // namespace ClangRefactoring diff --git a/src/plugins/clangrefactoring/qtcreatorclangqueryfindfilter.h b/src/plugins/clangrefactoring/qtcreatorclangqueryfindfilter.h index 937e591a7c..8157779bc9 100644 --- a/src/plugins/clangrefactoring/qtcreatorclangqueryfindfilter.h +++ b/src/plugins/clangrefactoring/qtcreatorclangqueryfindfilter.h @@ -25,18 +25,18 @@ #pragma once -#include "clangquerycurrentfilefindfilter.h" +#include "clangqueryprojectsfindfilter.h" namespace ClangRefactoring { -class QtCreatorClangQueryFindFilter final : public ClangQueryCurrentFileFindFilter +class QtCreatorClangQueryFindFilter final : public ClangQueryProjectsFindFilter { public: QtCreatorClangQueryFindFilter(ClangBackEnd::RefactoringServerInterface &server, SearchInterface &searchInterface, RefactoringClient &refactoringClient); - void findAll(const QString &queryText, Core::FindFlags findFlags = 0); + void findAll(const QString &queryText, Core::FindFlags findFlags = 0) override; private: void prepareFind(); diff --git a/src/plugins/clangrefactoring/qtcreatorsearch.cpp b/src/plugins/clangrefactoring/qtcreatorsearch.cpp index 43d303e198..61f317c22a 100644 --- a/src/plugins/clangrefactoring/qtcreatorsearch.cpp +++ b/src/plugins/clangrefactoring/qtcreatorsearch.cpp @@ -27,6 +27,10 @@ #include "qtcreatorsearchhandle.h" +#include <coreplugin/editormanager/editormanager.h> + +#include <QDir> + namespace ClangRefactoring { QtCreatorSearch::QtCreatorSearch(Core::SearchResultWindow &searchResultWindow) @@ -34,7 +38,7 @@ QtCreatorSearch::QtCreatorSearch(Core::SearchResultWindow &searchResultWindow) { } -std::unique_ptr<SearchHandleInterface> QtCreatorSearch::startNewSearch(const QString &searchLabel, +std::unique_ptr<SearchHandle> QtCreatorSearch::startNewSearch(const QString &searchLabel, const QString &searchTerm) { Core::SearchResult *searchResult = searchResultWindow.startNewSearch( @@ -44,7 +48,24 @@ std::unique_ptr<SearchHandleInterface> QtCreatorSearch::startNewSearch(const QSt Core::SearchResultWindow::SearchOnly, Core::SearchResultWindow::PreserveCaseEnabled); - return std::unique_ptr<SearchHandleInterface>(new QtCreatorSearchHandle(searchResult)); + QObject::connect(searchResult, + &Core::SearchResult::activated, + &QtCreatorSearch::openEditor); + + auto searchHandle = std::unique_ptr<SearchHandle>(new QtCreatorSearchHandle(searchResult)); + + QObject::connect(searchResult, + &Core::SearchResult::cancelled, + [handle=searchHandle.get()] () { handle->cancel(); }); + + return searchHandle; +} + +void QtCreatorSearch::openEditor(const Core::SearchResultItem &item) +{ + Core::EditorManager::openEditorAt(QDir::fromNativeSeparators(item.path.first()), + item.mainRange.begin.line, + item.mainRange.begin.column); } } // namespace ClangRefactoring diff --git a/src/plugins/clangrefactoring/qtcreatorsearch.h b/src/plugins/clangrefactoring/qtcreatorsearch.h index 50c2f629ea..68d884a180 100644 --- a/src/plugins/clangrefactoring/qtcreatorsearch.h +++ b/src/plugins/clangrefactoring/qtcreatorsearch.h @@ -29,6 +29,10 @@ #include <coreplugin/find/searchresultwindow.h> +namespace Core { +class SearchResultItem; +} + namespace ClangRefactoring { class QtCreatorSearch final : public SearchInterface @@ -36,10 +40,13 @@ class QtCreatorSearch final : public SearchInterface public: QtCreatorSearch(Core::SearchResultWindow &searchResultWindow); - std::unique_ptr<SearchHandleInterface> startNewSearch(const QString &searchLabel, + std::unique_ptr<SearchHandle> startNewSearch(const QString &searchLabel, const QString &searchTerm); private: + static void openEditor(const Core::SearchResultItem &item); + +private: Core::SearchResultWindow &searchResultWindow; }; diff --git a/src/plugins/clangrefactoring/qtcreatorsearchhandle.cpp b/src/plugins/clangrefactoring/qtcreatorsearchhandle.cpp index 5f16d5dfcb..6308c641ec 100644 --- a/src/plugins/clangrefactoring/qtcreatorsearchhandle.cpp +++ b/src/plugins/clangrefactoring/qtcreatorsearchhandle.cpp @@ -25,21 +25,40 @@ #include "qtcreatorsearchhandle.h" +#include <coreplugin/progressmanager/progressmanager.h> + +#include <QCoreApplication> + namespace ClangRefactoring { QtCreatorSearchHandle::QtCreatorSearchHandle(Core::SearchResult *searchResult) : searchResult(searchResult) { + auto title = QCoreApplication::translate("QtCreatorSearchHandle", "Clang Query"); + Core::ProgressManager::addTask(promise.future(), title, "clang query", 0); +} + +void QtCreatorSearchHandle::addResult(const QString &fileName, + const QString &lineText, + Core::TextRange textRange) +{ + searchResult->addResult(fileName, lineText, textRange); +} + +void QtCreatorSearchHandle::setExpectedResultCount(uint count) +{ + promise.setExpectedResultCount(count); } -void QtCreatorSearchHandle::addResult(const QString &fileName, int lineNumber, const QString &lineText, int searchTermStart, int searchTermLength) +void QtCreatorSearchHandle::setResultCounter(uint counter) { - searchResult->addResult(fileName, lineNumber, lineText, searchTermStart, searchTermLength); + promise.setProgressValue(counter); } void QtCreatorSearchHandle::finishSearch() { searchResult->finishSearch(false); + promise.reportFinished(); } } // namespace ClangRefactoring diff --git a/src/plugins/clangrefactoring/qtcreatorsearchhandle.h b/src/plugins/clangrefactoring/qtcreatorsearchhandle.h index a0741ba9f9..76932edb1f 100644 --- a/src/plugins/clangrefactoring/qtcreatorsearchhandle.h +++ b/src/plugins/clangrefactoring/qtcreatorsearchhandle.h @@ -25,27 +25,31 @@ #pragma once -#include "searchhandleinterface.h" +#include "searchhandle.h" #include <coreplugin/find/searchresultwindow.h> +#include <QFutureInterface> + namespace ClangRefactoring { -class QtCreatorSearchHandle final : public SearchHandleInterface +class QtCreatorSearchHandle final : public SearchHandle { public: QtCreatorSearchHandle(Core::SearchResult *searchResult); void addResult(const QString &fileName, - int lineNumber, const QString &lineText, - int searchTermStart, - int searchTermLength); + Core::TextRange textRange) override; + + void setExpectedResultCount(uint count) override; + void setResultCounter(uint counter) override; - void finishSearch(); + void finishSearch() override; private: Core::SearchResult *searchResult; + QFutureInterface<void> promise; }; } // namespace ClangRefactoring diff --git a/src/plugins/clangrefactoring/refactoringclient.cpp b/src/plugins/clangrefactoring/refactoringclient.cpp index 87ee586430..da0701c2f5 100644 --- a/src/plugins/clangrefactoring/refactoringclient.cpp +++ b/src/plugins/clangrefactoring/refactoringclient.cpp @@ -48,8 +48,9 @@ void RefactoringClient::sourceLocationsForRenamingMessage( void RefactoringClient::sourceRangesAndDiagnosticsForQueryMessage( ClangBackEnd::SourceRangesAndDiagnosticsForQueryMessage &&message) { + ++resultCounter_; addSearchResults(message.sourceRanges()); - sendSearchIsFinished(); + setResultCounterAndSendSearchIsFinishedIfFinished(); } void RefactoringClient::setLocalRenamingCallback( @@ -63,14 +64,14 @@ void RefactoringClient::setRefactoringEngine(RefactoringEngine *refactoringEngin this->refactoringEngine = refactoringEngine; } -void RefactoringClient::setSearchHandle(SearchHandleInterface *searchHandleInterface) +void RefactoringClient::setSearchHandle(SearchHandle *searchHandle) { - this->searchHandleInterface = searchHandleInterface; + this->searchHandle_ = searchHandle; } -SearchHandleInterface *RefactoringClient::searchHandle() const +SearchHandle *RefactoringClient::searchHandle() const { - return searchHandleInterface; + return searchHandle_; } bool RefactoringClient::hasValidLocalRenamingCallback() const @@ -78,6 +79,23 @@ bool RefactoringClient::hasValidLocalRenamingCallback() const return bool(localRenamingCallback); } +void RefactoringClient::setExpectedResultCount(uint count) +{ + expectedResultCount_ = count; + resultCounter_ = 0; + searchHandle_->setExpectedResultCount(count); +} + +uint RefactoringClient::expectedResultCount() const +{ + return expectedResultCount_; +} + +uint RefactoringClient::resultCounter() const +{ + return resultCounter_; +} + namespace { Utils::SmallString concatenateFilePath(const ClangBackEnd::FilePath &filePath) @@ -122,16 +140,19 @@ void RefactoringClient::addSearchResults(const ClangBackEnd::SourceRangesContain void RefactoringClient::addSearchResult(const ClangBackEnd::SourceRangeWithTextContainer &sourceRangeWithText, std::unordered_map<uint, QString> &filePaths) { - searchHandleInterface->addResult(filePaths[sourceRangeWithText.fileHash()], - int(sourceRangeWithText.start().line()), - sourceRangeWithText.text(), - int(sourceRangeWithText.start().column()), - int(sourceRangeWithText.end().column())); + searchHandle_->addResult(filePaths[sourceRangeWithText.fileHash()], + sourceRangeWithText.text(), + {{int(sourceRangeWithText.start().line()), + int(sourceRangeWithText.start().column())}, + {int(sourceRangeWithText.end().line()), + int(sourceRangeWithText.end().column())}}); } -void RefactoringClient::sendSearchIsFinished() +void RefactoringClient::setResultCounterAndSendSearchIsFinishedIfFinished() { - searchHandleInterface->finishSearch(); + searchHandle_->setResultCounter(resultCounter_); + if (resultCounter_ == expectedResultCount_) + searchHandle_->finishSearch(); } } // namespace ClangRefactoring diff --git a/src/plugins/clangrefactoring/refactoringclient.h b/src/plugins/clangrefactoring/refactoringclient.h index aa8b9a4e59..c1de5fff31 100644 --- a/src/plugins/clangrefactoring/refactoringclient.h +++ b/src/plugins/clangrefactoring/refactoringclient.h @@ -27,7 +27,7 @@ #include "refactoringengine.h" -#include <searchhandleinterface.h> +#include <searchhandle.h> #include <refactoringclientinterface.h> @@ -53,23 +53,35 @@ public: void setLocalRenamingCallback( CppTools::RefactoringEngineInterface::RenameCallback &&localRenamingCallback) final; void setRefactoringEngine(ClangRefactoring::RefactoringEngine *refactoringEngine); - void setSearchHandle(ClangRefactoring::SearchHandleInterface *searchHandleInterface); - ClangRefactoring::SearchHandleInterface *searchHandle() const; + void setSearchHandle(ClangRefactoring::SearchHandle *searchHandleInterface); + ClangRefactoring::SearchHandle *searchHandle() const; bool hasValidLocalRenamingCallback() const; static std::unordered_map<uint, QString> convertFilePaths( const std::unordered_map<uint, ClangBackEnd::FilePath> &filePaths); -private: - void addSearchResults(const ClangBackEnd::SourceRangesContainer &sourceRanges); + void setExpectedResultCount(uint count); + uint expectedResultCount() const; + uint resultCounter() const; + + +UNIT_TEST_PUBLIC: void addSearchResult(const ClangBackEnd::SourceRangeWithTextContainer &sourceRange, std::unordered_map<uint, QString> &filePaths); + +private: + void addSearchResults(const ClangBackEnd::SourceRangesContainer &sourceRanges); + + void setResultCounterAndSendSearchIsFinishedIfFinished(); void sendSearchIsFinished(); + private: CppTools::RefactoringEngineInterface::RenameCallback localRenamingCallback; - ClangRefactoring::SearchHandleInterface *searchHandleInterface = nullptr; + ClangRefactoring::SearchHandle *searchHandle_ = nullptr; ClangRefactoring::RefactoringEngine *refactoringEngine = nullptr; + uint expectedResultCount_ = 0; + uint resultCounter_ = 0; }; } // namespace ClangRefactoring diff --git a/src/plugins/clangrefactoring/searchhandle.cpp b/src/plugins/clangrefactoring/searchhandle.cpp new file mode 100644 index 0000000000..c73aa4e96c --- /dev/null +++ b/src/plugins/clangrefactoring/searchhandle.cpp @@ -0,0 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "searchhandle.h" + +namespace ClangRefactoring { + +SearchHandle::~SearchHandle() +{ +} + +void SearchHandle::cancel() +{ + server->cancel(); +} + +void SearchHandle::setRefactoringServer(ClangBackEnd::RefactoringServerInterface *server) +{ + this->server = server; +} + +} // namespace ClangRefactoring diff --git a/src/plugins/clangrefactoring/searchhandle.h b/src/plugins/clangrefactoring/searchhandle.h new file mode 100644 index 0000000000..185be306a2 --- /dev/null +++ b/src/plugins/clangrefactoring/searchhandle.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include <coreplugin/find/searchresultitem.h> + +#include <refactoringserverinterface.h> + +namespace ClangRefactoring { + +class SearchHandle +{ +public: + virtual ~SearchHandle(); + + virtual void addResult(const QString &fileName, + const QString &lineText, + Core::Search::TextRange textRange) = 0; + + virtual void setExpectedResultCount(uint count) = 0; + virtual void setResultCounter(uint counter) = 0; + + virtual void finishSearch() = 0; + + void cancel(); + + void setRefactoringServer(ClangBackEnd::RefactoringServerInterface *server); + +private: + ClangBackEnd::RefactoringServerInterface *server = nullptr; +}; + +} // namespace ClangRefactoring diff --git a/src/plugins/clangrefactoring/searchhandleinterface.cpp b/src/plugins/clangrefactoring/searchhandleinterface.cpp index 6be77457cb..8eed7e59be 100644 --- a/src/plugins/clangrefactoring/searchhandleinterface.cpp +++ b/src/plugins/clangrefactoring/searchhandleinterface.cpp @@ -27,13 +27,18 @@ namespace ClangRefactoring { -SearchHandleInterface::SearchHandleInterface() +SearchHandle::~SearchHandle() { +} +void SearchHandle::cancel() +{ + server->cancel(); } -SearchHandleInterface::~SearchHandleInterface() +void SearchHandle::setRefactoringServer(ClangBackEnd::RefactoringServerInterface *server) { + this->server = server; } } // namespace ClangRefactoring diff --git a/src/plugins/clangrefactoring/searchhandleinterface.h b/src/plugins/clangrefactoring/searchhandleinterface.h index 7e41cc7f32..185be306a2 100644 --- a/src/plugins/clangrefactoring/searchhandleinterface.h +++ b/src/plugins/clangrefactoring/searchhandleinterface.h @@ -25,23 +25,32 @@ #pragma once -#include <QString> +#include <coreplugin/find/searchresultitem.h> + +#include <refactoringserverinterface.h> namespace ClangRefactoring { -class SearchHandleInterface +class SearchHandle { public: - SearchHandleInterface(); - virtual ~SearchHandleInterface(); + virtual ~SearchHandle(); virtual void addResult(const QString &fileName, - int lineNumber, const QString &lineText, - int searchTermStart, - int searchTermLength) = 0; + Core::Search::TextRange textRange) = 0; + + virtual void setExpectedResultCount(uint count) = 0; + virtual void setResultCounter(uint counter) = 0; virtual void finishSearch() = 0; + + void cancel(); + + void setRefactoringServer(ClangBackEnd::RefactoringServerInterface *server); + +private: + ClangBackEnd::RefactoringServerInterface *server = nullptr; }; } // namespace ClangRefactoring diff --git a/src/plugins/clangrefactoring/searchinterface.cpp b/src/plugins/clangrefactoring/searchinterface.cpp index f39d38e04c..666da7eb26 100644 --- a/src/plugins/clangrefactoring/searchinterface.cpp +++ b/src/plugins/clangrefactoring/searchinterface.cpp @@ -27,5 +27,9 @@ namespace ClangRefactoring { +SearchInterface::~SearchInterface() +{ + +} } // namespace ClangRefactoring diff --git a/src/plugins/clangrefactoring/searchinterface.h b/src/plugins/clangrefactoring/searchinterface.h index 32ef07b080..72e921b76f 100644 --- a/src/plugins/clangrefactoring/searchinterface.h +++ b/src/plugins/clangrefactoring/searchinterface.h @@ -25,7 +25,7 @@ #pragma once -#include "searchhandleinterface.h" +#include "searchhandle.h" #include <QString> @@ -36,9 +36,8 @@ namespace ClangRefactoring { class SearchInterface { public: - virtual ~SearchInterface() {} - - virtual std::unique_ptr<SearchHandleInterface> startNewSearch(const QString &searchLabel, + virtual ~SearchInterface(); + virtual std::unique_ptr<SearchHandle> startNewSearch(const QString &searchLabel, const QString &searchTerm) = 0; }; diff --git a/src/shared/qbs b/src/shared/qbs -Subproject ab14d325eaa1ee762dacc8b9fbbc902dae4d5e6 +Subproject 0971e0b7453439f01c72551870d8a2a14075859 diff --git a/src/tools/clangrefactoringbackend/source/clangquery.cpp b/src/tools/clangrefactoringbackend/source/clangquery.cpp index 2fd5b0689b..95ec23affb 100644 --- a/src/tools/clangrefactoringbackend/source/clangquery.cpp +++ b/src/tools/clangrefactoringbackend/source/clangquery.cpp @@ -26,6 +26,7 @@ #include "clangquery.h" #include "sourcelocationsutils.h" +#include "sourcerangeextractor.h" #include <sourcerangescontainer.h> @@ -76,16 +77,7 @@ void ClangQuery::findLocations() std::vector<std::unique_ptr<clang::ASTUnit>> asts; - { - QTime timer; - timer.start(); - tool.buildASTs(asts); - - qWarning() << "ASTs are built: " << timer.elapsed(); - } - - std::vector<clang::SourceRange> sourceRanges; - sourceRanges.reserve(100); + tool.buildASTs(asts); std::for_each (std::make_move_iterator(asts.begin()), std::make_move_iterator(asts.end()), @@ -95,7 +87,7 @@ void ClangQuery::findLocations() nullptr, &diagnostics); parseDiagnostics(diagnostics); - matchLocation(optionalMatcher, std::move(ast), sourceRanges); + matchLocation(optionalMatcher, std::move(ast)); }); } @@ -189,10 +181,28 @@ void ClangQuery::parseDiagnostics(const clang::ast_matchers::dynamic::Diagnostic } } +namespace { +std::vector<clang::SourceRange> generateSourceRangesFromMatches(const std::vector<BoundNodes> &matches) +{ + std::vector<clang::SourceRange> sourceRanges; + sourceRanges.reserve(matches.size()); + + for (const auto boundNodes : matches) { + for (const auto &mapEntry : boundNodes.getMap()) { + const auto sourceRange = mapEntry.second.getSourceRange(); + if (sourceRange.isValid()) + sourceRanges.push_back(sourceRange); + } + + } + + return sourceRanges; +} +} + void ClangQuery::matchLocation( const llvm::Optional< clang::ast_matchers::internal::DynTypedMatcher> &optionalStartMatcher, - std::unique_ptr<clang::ASTUnit> ast, - std::vector<clang::SourceRange> &sourceRanges) + std::unique_ptr<clang::ASTUnit> ast) { if (optionalStartMatcher) { auto matcher = *optionalStartMatcher; @@ -207,18 +217,13 @@ void ClangQuery::matchLocation( finder.matchAST(ast->getASTContext()); - for (const auto &boundNodes : matches) { - for (const auto &mapEntry : boundNodes.getMap()) { - const auto sourceRange = mapEntry.second.getSourceRange(); - if (sourceRange.isValid()) - sourceRanges.push_back(sourceRange); - } + auto sourceRanges = generateSourceRangesFromMatches(matches); - } + SourceRangeExtractor extractor(ast->getSourceManager(), + ast->getLangOpts(), + sourceRangesContainer); + extractor.addSourceRanges(sourceRanges); - appendSourceRangesToSourceRangesContainer(sourceRangesContainer, - sourceRanges, - ast->getSourceManager()); } } diff --git a/src/tools/clangrefactoringbackend/source/clangquery.h b/src/tools/clangrefactoringbackend/source/clangquery.h index b1a5be3648..93190449a5 100644 --- a/src/tools/clangrefactoringbackend/source/clangquery.h +++ b/src/tools/clangrefactoringbackend/source/clangquery.h @@ -61,8 +61,7 @@ public: private: void parseDiagnostics(const clang::ast_matchers::dynamic::Diagnostics &diagnostics); void matchLocation(const llvm::Optional< clang::ast_matchers::internal::DynTypedMatcher> &optionalStartMatcher, - std::unique_ptr<clang::ASTUnit> ast, - std::vector<clang::SourceRange> &sourceRanges); + std::unique_ptr<clang::ASTUnit> ast); private: SourceRangesContainer sourceRangesContainer; diff --git a/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri b/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri index 45eb821a18..3cd46a5e25 100644 --- a/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri +++ b/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri @@ -5,11 +5,12 @@ SOURCES += \ $$PWD/symbolfinder.cpp \ $$PWD/symbollocationfinderaction.cpp \ $$PWD/refactoringserver.cpp \ - $$PWD/sourcefilecallbacks.cpp \ $$PWD/macropreprocessorcallbacks.cpp \ $$PWD/findusrforcursoraction.cpp \ $$PWD/clangquery.cpp \ - $$PWD/clangtool.cpp + $$PWD/clangtool.cpp \ + $$PWD/sourcerangeextractor.cpp \ + $$PWD/locationsourcefilecallbacks.cpp HEADERS += \ $$PWD/refactoringcompilationdatabase.h \ @@ -17,11 +18,12 @@ HEADERS += \ $$PWD/symbolfinder.h \ $$PWD/symbollocationfinderaction.h \ $$PWD/refactoringserver.h \ - $$PWD/sourcefilecallbacks.h \ $$PWD/macropreprocessorcallbacks.h \ $$PWD/sourcelocationsutils.h \ $$PWD/findcursorusr.h \ $$PWD/findusrforcursoraction.h \ $$PWD/findlocationsofusrs.h \ $$PWD/clangquery.h \ - $$PWD/clangtool.h + $$PWD/clangtool.h \ + $$PWD/sourcerangeextractor.h \ + $$PWD/locationsourcefilecallbacks.h diff --git a/src/tools/clangrefactoringbackend/source/clangtool.cpp b/src/tools/clangrefactoringbackend/source/clangtool.cpp index d447121379..aaef2845e0 100644 --- a/src/tools/clangrefactoringbackend/source/clangtool.cpp +++ b/src/tools/clangrefactoringbackend/source/clangtool.cpp @@ -57,6 +57,24 @@ void ClangTool::addFile(std::string &&directory, sourceFilePaths.push_back(fileContent.filePath); } +void ClangTool::addFiles(const Utils::SmallStringVector &filePaths, + const Utils::SmallStringVector &arguments) +{ + for (const Utils::SmallString &filePath : filePaths) { + auto found = std::find(filePath.rbegin(), filePath.rend(), '/'); + + auto fileNameBegin = found.base(); + + std::vector<std::string> commandLine(arguments.begin(), arguments.end()); + commandLine.push_back(filePath); + + addFile({filePath.begin(), std::prev(fileNameBegin)}, + {fileNameBegin, filePath.end()}, + {}, + std::move(commandLine)); + } +} + clang::tooling::ClangTool ClangTool::createTool() const { clang::tooling::ClangTool tool(compilationDatabase, sourceFilePaths); diff --git a/src/tools/clangrefactoringbackend/source/clangtool.h b/src/tools/clangrefactoringbackend/source/clangtool.h index 8627798d97..b16b7a94dd 100644 --- a/src/tools/clangrefactoringbackend/source/clangtool.h +++ b/src/tools/clangrefactoringbackend/source/clangtool.h @@ -74,6 +74,8 @@ public: std::string &&fileName, std::string &&content, std::vector<std::string> &&commandLine); + void addFiles(const Utils::SmallStringVector &filePaths, + const Utils::SmallStringVector &arguments); clang::tooling::ClangTool createTool() const; diff --git a/src/tools/clangrefactoringbackend/source/collectincludesaction.h b/src/tools/clangrefactoringbackend/source/collectincludesaction.h new file mode 100644 index 0000000000..1586ba3f8b --- /dev/null +++ b/src/tools/clangrefactoringbackend/source/collectincludesaction.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include <collectincludespreprocessorcallbacks.h> + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +#include <clang/Frontend/FrontendActions.h> +#include <clang/Frontend/CompilerInstance.h> +#include <clang/Lex/Preprocessor.h> + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +namespace ClangBackEnd { + +class CollectIncludesAction final : public clang::PreprocessOnlyAction +{ +public: + CollectIncludesAction(Utils::SmallStringVector &includes, + const std::vector<uint> &excludedIncludeUID, + std::vector<uint> &alreadyIncludedFileUIDs) + : includes(includes), + excludedIncludeUID(excludedIncludeUID), + alreadyIncludedFileUIDs(alreadyIncludedFileUIDs) + { + } + + bool BeginSourceFileAction(clang::CompilerInstance &compilerInstance, + llvm::StringRef filename) override + { + if (clang::PreprocessOnlyAction::BeginSourceFileAction(compilerInstance, filename)) { + auto &preprocessor = compilerInstance.getPreprocessor(); + auto &headerSearch = preprocessor.getHeaderSearchInfo(); + + auto macroPreprocessorCallbacks = new CollectIncludesPreprocessorCallbacks(headerSearch, + includes, + excludedIncludeUID, + alreadyIncludedFileUIDs); + + preprocessor.addPPCallbacks(std::unique_ptr<clang::PPCallbacks>(macroPreprocessorCallbacks)); + + return true; + } + + return false; + } + + void EndSourceFileAction() override + { + clang::PreprocessOnlyAction::EndSourceFileAction(); + } + +private: + Utils::SmallStringVector &includes; + const std::vector<uint> &excludedIncludeUID; + std::vector<uint> &alreadyIncludedFileUIDs; +}; + +} // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/collectincludespreprocessorcallbacks.h b/src/tools/clangrefactoringbackend/source/collectincludespreprocessorcallbacks.h new file mode 100644 index 0000000000..b1f3d2c202 --- /dev/null +++ b/src/tools/clangrefactoringbackend/source/collectincludespreprocessorcallbacks.h @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +#include <clang/Basic/SourceManager.h> +#include <clang/Lex/MacroInfo.h> +#include <clang/Lex/HeaderSearch.h> +#include <clang/Lex/PPCallbacks.h> +#include <clang/Lex/Preprocessor.h> + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +#include <utils/smallstringvector.h> + +#include <algorithm> + +#include <QDebug> + +namespace ClangBackEnd { + +class CollectIncludesPreprocessorCallbacks final : public clang::PPCallbacks +{ +public: + CollectIncludesPreprocessorCallbacks(clang::HeaderSearch &headerSearch, + Utils::SmallStringVector &includes, + const std::vector<uint> &excludedIncludeUID, + std::vector<uint> &alreadyIncludedFileUIDs) + : headerSearch(headerSearch), + includes(includes), + excludedIncludeUID(excludedIncludeUID), + alreadyIncludedFileUIDs(alreadyIncludedFileUIDs) + {} + + void InclusionDirective(clang::SourceLocation /*hashLocation*/, + const clang::Token &/*includeToken*/, + llvm::StringRef fileName, + bool /*isAngled*/, + clang::CharSourceRange /*fileNameRange*/, + const clang::FileEntry *file, + llvm::StringRef /*searchPath*/, + llvm::StringRef /*relativePath*/, + const clang::Module */*imported*/) override + { + auto fileUID = file->getUID(); + + flagIncludeAlreadyRead(file); + + if (isNotInExcludedIncludeUID(fileUID)) { + auto notAlreadyIncluded = isNotAlreadyIncluded(fileUID); + if (notAlreadyIncluded.first) { + alreadyIncludedFileUIDs.insert(notAlreadyIncluded.second, file->getUID()); + includes.emplace_back(fileName.data(), fileName.size()); + } + } + } + + bool isNotInExcludedIncludeUID(uint uid) const + { + return !std::binary_search(excludedIncludeUID.begin(), + excludedIncludeUID.end(), + uid); + } + + + std::pair<bool, std::vector<uint>::iterator> isNotAlreadyIncluded(uint uid) + { + auto range = std::equal_range(alreadyIncludedFileUIDs.begin(), + alreadyIncludedFileUIDs.end(), + uid); + + return {range.first == range.second, range.first}; + } + + void flagIncludeAlreadyRead(const clang::FileEntry *file) + { + auto &headerFileInfo = headerSearch.getFileInfo(file); + + headerFileInfo.isImport = true; + ++headerFileInfo.NumIncludes; + + } + +private: + clang::HeaderSearch &headerSearch; + std::vector<Utils::SmallString> &includes; + const std::vector<uint> &excludedIncludeUID; + std::vector<uint> &alreadyIncludedFileUIDs; +}; + +} // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/collectincludestoolaction.h b/src/tools/clangrefactoringbackend/source/collectincludestoolaction.h new file mode 100644 index 0000000000..017b2efe2a --- /dev/null +++ b/src/tools/clangrefactoringbackend/source/collectincludestoolaction.h @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "collectincludesaction.h" + +#include <clang/Tooling/Tooling.h> + +namespace ClangBackEnd { + +class CollectIncludesToolAction final : public clang::tooling::FrontendActionFactory +{ +public: + CollectIncludesToolAction(Utils::SmallStringVector &includes, + const std::vector<uint> &excludedIncludeUIDs) + : includes(includes), + excludedIncludeUIDs(excludedIncludeUIDs) + {} + + clang::FrontendAction *create() + { + return new CollectIncludesAction(includes, excludedIncludeUIDs, alreadyIncludedFileUIDs); + } + +private: + Utils::SmallStringVector &includes; + const std::vector<uint> &excludedIncludeUIDs; + std::vector<uint> alreadyIncludedFileUIDs; +}; + +} // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/includecollector.cpp b/src/tools/clangrefactoringbackend/source/includecollector.cpp new file mode 100644 index 0000000000..914df823c1 --- /dev/null +++ b/src/tools/clangrefactoringbackend/source/includecollector.cpp @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "includecollector.h" + +#include "collectincludestoolaction.h" + +namespace ClangBackEnd { + +void IncludeCollector::collectIncludes() +{ + clang::tooling::ClangTool tool = createTool(); + + auto excludedIncludeFileUIDs = generateExcludedIncludeFileUIDs(tool.getFiles()); + + auto action = std::unique_ptr<CollectIncludesToolAction>( + new CollectIncludesToolAction(includes, excludedIncludeFileUIDs)); + + tool.run(action.get()); +} + +void IncludeCollector::setExcludedIncludes(Utils::SmallStringVector &&excludedIncludes) +{ + this->excludedIncludes = std::move(excludedIncludes); +} + +Utils::SmallStringVector IncludeCollector::takeIncludes() +{ + std::sort(includes.begin(), includes.end()); + + return std::move(includes); +} + +std::vector<uint> IncludeCollector::generateExcludedIncludeFileUIDs(clang::FileManager &fileManager) const +{ + std::vector<uint> fileUIDs; + fileUIDs.reserve(excludedIncludes.size()); + + auto generateUID = [&] (const Utils::SmallString &filePath) { + return fileManager.getFile({filePath.data(), filePath.size()})->getUID(); + }; + + std::transform(excludedIncludes.begin(), + excludedIncludes.end(), + std::back_inserter(fileUIDs), + generateUID); + + std::sort(fileUIDs.begin(), fileUIDs.end()); + + return fileUIDs; +} + +} // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/includecollector.h b/src/tools/clangrefactoringbackend/source/includecollector.h new file mode 100644 index 0000000000..738ff077d2 --- /dev/null +++ b/src/tools/clangrefactoringbackend/source/includecollector.h @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "clangtool.h" + +namespace ClangBackEnd { + +class IncludeCollector : public ClangTool +{ +public: + void collectIncludes(); + + void setExcludedIncludes(Utils::SmallStringVector &&excludedIncludes); + + Utils::SmallStringVector takeIncludes(); + +private: + std::vector<uint> generateExcludedIncludeFileUIDs(clang::FileManager &fileManager) const; + +private: + Utils::SmallStringVector excludedIncludes; + Utils::SmallStringVector includes; +}; + +} // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/sourcefilecallbacks.cpp b/src/tools/clangrefactoringbackend/source/locationsourcefilecallbacks.cpp index 3963fbb6f5..c5f2d4edde 100644 --- a/src/tools/clangrefactoringbackend/source/sourcefilecallbacks.cpp +++ b/src/tools/clangrefactoringbackend/source/locationsourcefilecallbacks.cpp @@ -23,7 +23,7 @@ ** ****************************************************************************/ -#include "sourcefilecallbacks.h" +#include "locationsourcefilecallbacks.h" #include "macropreprocessorcallbacks.h" @@ -43,13 +43,13 @@ namespace ClangBackEnd { -SourceFileCallbacks::SourceFileCallbacks(uint line, uint column) +LocationSourceFileCallbacks::LocationSourceFileCallbacks(uint line, uint column) : line(line), column(column) { } -bool SourceFileCallbacks::handleBeginSource(clang::CompilerInstance &compilerInstance, llvm::StringRef /*fileName*/) +bool LocationSourceFileCallbacks::handleBeginSource(clang::CompilerInstance &compilerInstance, llvm::StringRef /*fileName*/) { auto &preprocessor = compilerInstance.getPreprocessor(); @@ -64,17 +64,17 @@ bool SourceFileCallbacks::handleBeginSource(clang::CompilerInstance &compilerIns return true; } -SourceLocationsContainer SourceFileCallbacks::takeSourceLocations() +SourceLocationsContainer LocationSourceFileCallbacks::takeSourceLocations() { return std::move(sourceLocationsContainer); } -Utils::SmallString SourceFileCallbacks::takeSymbolName() +Utils::SmallString LocationSourceFileCallbacks::takeSymbolName() { return std::move(symbolName); } -bool SourceFileCallbacks::hasSourceLocations() const +bool LocationSourceFileCallbacks::hasSourceLocations() const { return sourceLocationsContainer.hasContent(); } diff --git a/src/tools/clangrefactoringbackend/source/sourcefilecallbacks.h b/src/tools/clangrefactoringbackend/source/locationsourcefilecallbacks.h index 9a8b1cfe4b..98f4cb9aea 100644 --- a/src/tools/clangrefactoringbackend/source/sourcefilecallbacks.h +++ b/src/tools/clangrefactoringbackend/source/locationsourcefilecallbacks.h @@ -51,10 +51,10 @@ namespace ClangBackEnd { class MacroPreprocessorCallbacks; class SourceLocationsContainer; -class SourceFileCallbacks : public clang::tooling::SourceFileCallbacks +class LocationSourceFileCallbacks : public clang::tooling::SourceFileCallbacks { public: - SourceFileCallbacks(uint line, uint column); + LocationSourceFileCallbacks(uint line, uint column); bool handleBeginSource(clang::CompilerInstance &compilerInstance, llvm::StringRef fileName) override; diff --git a/src/tools/clangrefactoringbackend/source/refactoringserver.cpp b/src/tools/clangrefactoringbackend/source/refactoringserver.cpp index e66dce78c7..debc827968 100644 --- a/src/tools/clangrefactoringbackend/source/refactoringserver.cpp +++ b/src/tools/clangrefactoringbackend/source/refactoringserver.cpp @@ -39,11 +39,13 @@ #include <algorithm> #include <chrono> #include <future> +#include <atomic> namespace ClangBackEnd { RefactoringServer::RefactoringServer() { + pollEventLoop = [] () { QCoreApplication::processEvents(); }; } void RefactoringServer::end() @@ -67,19 +69,43 @@ void RefactoringServer::requestSourceLocationsForRenamingMessage(RequestSourceLo message.textDocumentRevision()}); } +void RefactoringServer::requestSourceRangesAndDiagnosticsForQueryMessage( + RequestSourceRangesAndDiagnosticsForQueryMessage &&message) +{ + gatherSourceRangesAndDiagnosticsForQueryMessage(message.takeFileContainers(), message.takeQuery()); +} + +void RefactoringServer::cancel() +{ + cancelWork = true; +} + +bool RefactoringServer::isCancelingJobs() const +{ + return cancelWork; +} + +void RefactoringServer::supersedePollEventLoop(std::function<void ()> &&pollEventLoop) +{ + this->pollEventLoop = std::move(pollEventLoop); +} + namespace { SourceRangesAndDiagnosticsForQueryMessage createSourceRangesAndDiagnosticsForQueryMessage( V2::FileContainer &&fileContainer, - Utils::SmallString &&query) { + Utils::SmallString &&query, + const std::atomic_bool &cancelWork) { ClangQuery clangQuery(std::move(query)); - clangQuery.addFile(fileContainer.filePath().directory(), - fileContainer.filePath().name(), - fileContainer.takeUnsavedFileContent(), - fileContainer.takeCommandLineArguments()); + if (!cancelWork) { + clangQuery.addFile(fileContainer.filePath().directory(), + fileContainer.filePath().name(), + fileContainer.takeUnsavedFileContent(), + fileContainer.takeCommandLineArguments()); - clangQuery.findLocations(); + clangQuery.findLocations(); + } return {clangQuery.takeSourceRanges(), clangQuery.takeDiagnosticContainers()}; } @@ -87,12 +113,6 @@ SourceRangesAndDiagnosticsForQueryMessage createSourceRangesAndDiagnosticsForQue } -void RefactoringServer::requestSourceRangesAndDiagnosticsForQueryMessage( - RequestSourceRangesAndDiagnosticsForQueryMessage &&message) -{ - gatherSourceRangesAndDiagnosticsForQueryMessage(message.takeFileContainers(), message.takeQuery()); -} - void RefactoringServer::gatherSourceRangesAndDiagnosticsForQueryMessage( std::vector<V2::FileContainer> &&fileContainers, Utils::SmallString &&query) @@ -108,7 +128,7 @@ void RefactoringServer::gatherSourceRangesAndDiagnosticsForQueryMessage( Future &&future = std::async(std::launch::async, createSourceRangesAndDiagnosticsForQueryMessage, std::move(fileContainers.back()), - query.clone()); + query.clone(), std::ref(cancelWork)); fileContainers.pop_back(); futures.emplace_back(std::move(future)); @@ -122,6 +142,8 @@ void RefactoringServer::gatherSourceRangesAndDiagnosticsForQueryMessage( std::size_t RefactoringServer::waitForNewSourceRangesAndDiagnosticsForQueryMessage(std::vector<Future> &futures) { while (true) { + pollEventLoop(); + std::vector<Future> readyFutures; readyFutures.reserve(futures.size()); diff --git a/src/tools/clangrefactoringbackend/source/refactoringserver.h b/src/tools/clangrefactoringbackend/source/refactoringserver.h index 47615a9f3f..f61509e60d 100644 --- a/src/tools/clangrefactoringbackend/source/refactoringserver.h +++ b/src/tools/clangrefactoringbackend/source/refactoringserver.h @@ -47,11 +47,21 @@ public: void end() override; void requestSourceLocationsForRenamingMessage(RequestSourceLocationsForRenamingMessage &&message) override; void requestSourceRangesAndDiagnosticsForQueryMessage(RequestSourceRangesAndDiagnosticsForQueryMessage &&message) override; + void cancel() override; + + bool isCancelingJobs() const; + + void supersedePollEventLoop(std::function<void()> &&pollEventLoop); private: void gatherSourceRangesAndDiagnosticsForQueryMessage(std::vector<V2::FileContainer> &&fileContainers, Utils::SmallString &&query); std::size_t waitForNewSourceRangesAndDiagnosticsForQueryMessage(std::vector<Future> &futures); + +private: + std::function<void()> pollEventLoop; + std::atomic_bool cancelWork{false}; + }; } // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/sourcelocationsutils.h b/src/tools/clangrefactoringbackend/source/sourcelocationsutils.h index 8e3dba86b2..eda4accf70 100644 --- a/src/tools/clangrefactoringbackend/source/sourcelocationsutils.h +++ b/src/tools/clangrefactoringbackend/source/sourcelocationsutils.h @@ -34,6 +34,7 @@ #endif #include <clang/Basic/SourceManager.h> +#include <clang/Lex/Lexer.h> #include <llvm/Support/FileSystem.h> #include <llvm/Support/FileUtilities.h> @@ -41,6 +42,7 @@ #pragma GCC diagnostic pop #endif +#include <iterator> #include <cctype> namespace ClangBackEnd { @@ -68,75 +70,6 @@ Utils::SmallString fromNativePath(Container container) return path; } -inline Utils::SmallString getSourceText(const clang::FullSourceLoc &startFullSourceLocation, - uint startOffset, - uint endOffset) -{ - auto startBuffer = startFullSourceLocation.getBufferData(); - const auto bufferSize = endOffset - startOffset; - - return Utils::SmallString(startBuffer.data() + startOffset, bufferSize + 1); -} - -inline void makePrintable(Utils::SmallString &text) -{ - text.replace("\n", " "); - text.replace("\t", " "); - - auto end = std::unique(text.begin(), text.end(), [](char l, char r){ - return std::isspace(l) && std::isspace(r) && l == r; - }); - text.resize(std::distance(text.begin(), end)); -} - -inline void appendSourceRangeToSourceRangesContainer( - const clang::SourceRange &sourceRange, - ClangBackEnd::SourceRangesContainer &sourceRangesContainer, - const clang::SourceManager &sourceManager) -{ - clang::FullSourceLoc startFullSourceLocation(sourceRange.getBegin(), sourceManager); - clang::FullSourceLoc endFullSourceLocation(sourceRange.getEnd(), sourceManager); - if (startFullSourceLocation.isFileID() && endFullSourceLocation.isFileID()) { - const auto startDecomposedLoction = startFullSourceLocation.getDecomposedLoc(); - const auto endDecomposedLoction = endFullSourceLocation.getDecomposedLoc(); - const auto fileId = startDecomposedLoction.first; - 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 content = getSourceText(startFullSourceLocation, - startOffset, - endOffset); - makePrintable(content); - - sourceRangesContainer.insertFilePath(fileId.getHashValue(), - fromNativePath(filePath), - fromNativePath(fileName)); - sourceRangesContainer.insertSourceRange(fileId.getHashValue(), - startFullSourceLocation.getSpellingLineNumber(), - startFullSourceLocation.getSpellingColumnNumber(), - startOffset, - endFullSourceLocation.getSpellingLineNumber(), - endFullSourceLocation.getSpellingColumnNumber(), - endOffset, - std::move(content)); - } -} - -inline -void appendSourceRangesToSourceRangesContainer( - ClangBackEnd::SourceRangesContainer &sourceRangesContainer, - const std::vector<clang::SourceRange> &sourceRanges, - const clang::SourceManager &sourceManager) -{ - sourceRangesContainer.reserve(sourceRanges.size()); - - for (const auto &sourceRange : sourceRanges) - appendSourceRangeToSourceRangesContainer(sourceRange, sourceRangesContainer, sourceManager); -} - inline void appendSourceLocationsToSourceLocationsContainer( ClangBackEnd::SourceLocationsContainer &sourceLocationsContainer, diff --git a/src/tools/clangrefactoringbackend/source/sourcerangeextractor.cpp b/src/tools/clangrefactoringbackend/source/sourcerangeextractor.cpp new file mode 100644 index 0000000000..2a79260349 --- /dev/null +++ b/src/tools/clangrefactoringbackend/source/sourcerangeextractor.cpp @@ -0,0 +1,178 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "sourcerangeextractor.h" + +#include "sourcelocationsutils.h" + +#include <sourcerangescontainer.h> + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +#include <clang/Basic/SourceManager.h> +#include <clang/Lex/Lexer.h> +#include <llvm/Support/FileSystem.h> +#include <llvm/Support/FileUtilities.h> +#include <llvm/ADT/SmallVector.h> + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +namespace ClangBackEnd { + +SourceRangeExtractor::SourceRangeExtractor(const clang::SourceManager &sourceManager, + const clang::LangOptions &languageOptions, + SourceRangesContainer &sourceRangesContainer) + : sourceManager(sourceManager), + languageOptions(languageOptions), + sourceRangesContainer(sourceRangesContainer) +{ +} + +const char *SourceRangeExtractor::findStartOfLineInBuffer(llvm::StringRef buffer, uint startOffset) +{ + auto beginText = buffer.begin() + startOffset; + auto reverseEnd = std::make_reverse_iterator(buffer.begin()); + + auto found = std::find_if(std::make_reverse_iterator(beginText), + reverseEnd, + [] (const char character) { + return character == '\n' || character == '\r'; + }); + + if (found != reverseEnd) + return found.base(); + + return buffer.begin(); +} + +const char *SourceRangeExtractor::findEndOfLineInBuffer(llvm::StringRef buffer, uint endOffset) +{ + auto beginText = buffer.begin() + endOffset; + + auto found = std::find_if(beginText, + buffer.end(), + [] (const char character) { + return character == '\n' || character == '\r'; + }); + + if (found != buffer.end()) + return found; + + return buffer.end(); +} + +Utils::SmallString SourceRangeExtractor::getExpandedText(llvm::StringRef buffer, + uint startOffset, + uint endOffset) +{ + auto startBuffer = findStartOfLineInBuffer(buffer, startOffset); + auto endBuffer = findEndOfLineInBuffer(buffer, endOffset); + + return Utils::SmallString(startBuffer, endBuffer); +} + +const clang::SourceRange SourceRangeExtractor::extendSourceRangeToLastTokenEnd(const clang::SourceRange sourceRange) +{ + auto endLocation = sourceRange.getEnd(); + uint length = clang::Lexer::MeasureTokenLength(sourceManager.getSpellingLoc(endLocation), + sourceManager, + languageOptions); + endLocation = endLocation.getLocWithOffset(length); + + return {sourceRange.getBegin(), endLocation}; +} + +void SourceRangeExtractor::insertSourceRange(uint fileHash, + Utils::SmallString &&directoryPath, + Utils::SmallString &&fileName, + 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, + startLocation.getSpellingLineNumber(), + startLocation.getSpellingColumnNumber(), + startOffset, + endLocation.getSpellingLineNumber(), + endLocation.getSpellingColumnNumber(), + endOffset, + std::move(lineSnippet)); +} + +void SourceRangeExtractor::addSourceRange(const clang::SourceRange &sourceRange) +{ + auto extendedSourceRange = extendSourceRangeToLastTokenEnd(sourceRange); + + clang::FullSourceLoc startSourceLocation(extendedSourceRange.getBegin(), sourceManager); + clang::FullSourceLoc endSourceLocation(extendedSourceRange.getEnd(), sourceManager); + if (startSourceLocation.isFileID() && endSourceLocation.isFileID()) { + const auto startDecomposedLoction = startSourceLocation.getDecomposedLoc(); + const auto endDecomposedLoction = endSourceLocation.getDecomposedLoc(); + const auto fileId = startDecomposedLoction.first; + 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()}, + startSourceLocation, + startOffset, + endSourceLocation, + endOffset, + std::move(lineSnippet)); + + } +} + +void SourceRangeExtractor::addSourceRanges(const std::vector<clang::SourceRange> &sourceRanges) +{ + sourceRangesContainer.reserve(sourceRanges.size() + sourceRangeWithTextContainers().size()); + + for (const clang::SourceRange &sourceRange : sourceRanges) + addSourceRange(sourceRange); +} + +const std::vector<SourceRangeWithTextContainer> &SourceRangeExtractor::sourceRangeWithTextContainers() const +{ + return sourceRangesContainer.sourceRangeWithTextContainers(); +} + +} // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/sourcerangeextractor.h b/src/tools/clangrefactoringbackend/source/sourcerangeextractor.h new file mode 100644 index 0000000000..05ba1f7132 --- /dev/null +++ b/src/tools/clangrefactoringbackend/source/sourcerangeextractor.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include <vector> + +using uint = unsigned int; + +namespace Utils { +template <uint Size> +class BasicSmallString; +using SmallString = BasicSmallString<31>; +} + +namespace llvm { +class StringRef; +} + +namespace clang { +class SourceManager; +class LangOptions; +class SourceRange; +class FullSourceLoc; +} + +namespace ClangBackEnd { + +class SourceRangesContainer; +class SourceRangeWithTextContainer; + +class SourceRangeExtractor +{ +public: + SourceRangeExtractor(const clang::SourceManager &sourceManager, + const clang::LangOptions &languageOptions, + SourceRangesContainer &sourceRangesContainer); + + void addSourceRange(const clang::SourceRange &sourceRange); + void addSourceRanges(const std::vector<clang::SourceRange> &sourceRanges); + + const std::vector<SourceRangeWithTextContainer> &sourceRangeWithTextContainers() const; + + static const char *findStartOfLineInBuffer(const llvm::StringRef buffer, uint startOffset); + static const char *findEndOfLineInBuffer(llvm::StringRef buffer, uint endOffset); + static Utils::SmallString getExpandedText(llvm::StringRef buffer, uint startOffset, uint endOffset); + + const clang::SourceRange extendSourceRangeToLastTokenEnd(const clang::SourceRange sourceRange); + +private: + void insertSourceRange(uint fileHash, + Utils::SmallString &&directoryPath, + Utils::SmallString &&fileName, + const clang::FullSourceLoc &startLocation, + uint startOffset, + const clang::FullSourceLoc &endLocation, + uint endOffset, + Utils::SmallString &&lineSnippet); + +private: + const clang::SourceManager &sourceManager; + const clang::LangOptions &languageOptions; + SourceRangesContainer &sourceRangesContainer; +}; + +} // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/symbolfinder.cpp b/src/tools/clangrefactoringbackend/source/symbolfinder.cpp index 198a889ce1..02f727b614 100644 --- a/src/tools/clangrefactoringbackend/source/symbolfinder.cpp +++ b/src/tools/clangrefactoringbackend/source/symbolfinder.cpp @@ -25,7 +25,7 @@ #include "symbolfinder.h" -#include "sourcefilecallbacks.h" +#include "locationsourcefilecallbacks.h" #include "symbollocationfinderaction.h" namespace ClangBackEnd { diff --git a/src/tools/clangrefactoringbackend/source/symbolfinder.h b/src/tools/clangrefactoringbackend/source/symbolfinder.h index fb1ddae5e1..3a9999f66b 100644 --- a/src/tools/clangrefactoringbackend/source/symbolfinder.h +++ b/src/tools/clangrefactoringbackend/source/symbolfinder.h @@ -28,7 +28,7 @@ #include "clangtool.h" #include "findusrforcursoraction.h" #include "symbollocationfinderaction.h" -#include "sourcefilecallbacks.h" +#include "locationsourcefilecallbacks.h" #include <sourcelocationscontainer.h> @@ -61,7 +61,7 @@ private: Utils::SmallString symbolName; USRFindingAction usrFindingAction; SymbolLocationFinderAction symbolLocationFinderAction; - SourceFileCallbacks sourceFileCallbacks; + LocationSourceFileCallbacks sourceFileCallbacks; ClangBackEnd::SourceLocationsContainer sourceLocations_; }; diff --git a/tests/unit/unittest/clangquery-test.cpp b/tests/unit/unittest/clangquery-test.cpp index bfb47fc7fc..91947f4ae6 100644 --- a/tests/unit/unittest/clangquery-test.cpp +++ b/tests/unit/unittest/clangquery-test.cpp @@ -71,7 +71,7 @@ TEST_F(ClangQuery, RootSourceRangeForSimpleFunctionDeclarationRange) simpleFunctionQuery.findLocations(); ASSERT_THAT(simpleFunctionQuery.takeSourceRanges().sourceRangeWithTextContainers().at(0), - IsSourceRangeWithText(1, 1, 8, 1, "int function(int* pointer, int value) { if (pointer == nullptr) { return value + 1; } else { return value - 1; } }")); + IsSourceRangeWithText(1, 1, 8, 2, "int function(int* pointer, int value)\n{\n if (pointer == nullptr) {\n return value + 1;\n } else {\n return value - 1;\n }\n}")); } TEST_F(ClangQuery, RootSourceRangeForSimpleFieldDeclarationRange) @@ -81,7 +81,7 @@ TEST_F(ClangQuery, RootSourceRangeForSimpleFieldDeclarationRange) simpleClassQuery.findLocations(); ASSERT_THAT(simpleClassQuery.takeSourceRanges().sourceRangeWithTextContainers().at(0), - IsSourceRangeWithText(4, 5, 4, 9, "int x")); + IsSourceRangeWithText(4, 5, 4, 10, " int x;")); } TEST_F(ClangQuery, NoSourceRangesForEmptyQuery) diff --git a/tests/unit/unittest/clangquerycurrentfilefindfilter-test.cpp b/tests/unit/unittest/clangquerycurrentfilefindfilter-test.cpp deleted file mode 100644 index c83680d335..0000000000 --- a/tests/unit/unittest/clangquerycurrentfilefindfilter-test.cpp +++ /dev/null @@ -1,156 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "googletest.h" - -#include "mockrefactoringserver.h" -#include "mocksearch.h" -#include "mocksearchhandle.h" - -#include <clangquerycurrentfilefindfilter.h> -#include <refactoringcompileroptionsbuilder.h> -#include <refactoringclient.h> - -#include <requestsourcelocationforrenamingmessage.h> -#include <requestsourcerangesanddiagnosticsforquerymessage.h> -#include <sourcelocationsforrenamingmessage.h> -#include <sourcerangesanddiagnosticsforquerymessage.h> - -#include <cpptools/projectpart.h> - -namespace { - -using ::testing::_; -using ::testing::NiceMock; -using ::testing::NotNull; -using ::testing::ReturnNew; -using ::testing::DefaultValue; - -using ClangRefactoring::RefactoringCompilerOptionsBuilder; - -class ClangQueryCurrentFileFindFilter : public ::testing::Test -{ -protected: - void SetUp(); - -protected: - NiceMock<MockRefactoringServer> mockRefactoringServer; - NiceMock<MockSearch> mockSearch; - ClangRefactoring::RefactoringClient refactoringClient; - ClangRefactoring::ClangQueryCurrentFileFindFilter findFilter{mockRefactoringServer, mockSearch, refactoringClient}; - QString findDeclQueryText{"functionDecl()"}; - QString curentDocumentFilePath{"/path/to/file.cpp"}; - QString unsavedDocumentContent{"void f();"}; - Utils::SmallStringVector commandLine; - CppTools::ProjectPart::Ptr projectPart; - CppTools::ProjectFile projectFile{curentDocumentFilePath, CppTools::ProjectFile::CXXSource}; -}; - -TEST_F(ClangQueryCurrentFileFindFilter, SupportedFindFlags) -{ - auto findFlags = findFilter.supportedFindFlags(); - - ASSERT_FALSE(findFlags); -} - -TEST_F(ClangQueryCurrentFileFindFilter, IsNotUsableForUnusableServer) -{ - auto isUsable = findFilter.isUsable(); - - ASSERT_FALSE(isUsable); -} - -TEST_F(ClangQueryCurrentFileFindFilter, IsUsableForUsableServer) -{ - mockRefactoringServer.setUsable(true); - - auto isUsable = findFilter.isUsable(); - - ASSERT_TRUE(isUsable); -} - -TEST_F(ClangQueryCurrentFileFindFilter, ServerIsUsableForUsableFindFilter) -{ - findFilter.setUsable(true); - - auto isUsable = mockRefactoringServer.isUsable(); - - ASSERT_TRUE(isUsable); -} - -TEST_F(ClangQueryCurrentFileFindFilter, SearchHandleSetIsSetAfterFindAll) -{ - findFilter.findAll(findDeclQueryText); - - auto searchHandle = refactoringClient.searchHandle(); - - ASSERT_THAT(searchHandle, NotNull()); -} - - -TEST_F(ClangQueryCurrentFileFindFilter, FindAllIsCallingStartNewSearch) -{ - EXPECT_CALL(mockSearch, startNewSearch(QStringLiteral("Clang Query"), - findDeclQueryText)) - .Times(1); - - findFilter.findAll(findDeclQueryText); -} - -TEST_F(ClangQueryCurrentFileFindFilter, FindAllIsCallingRequestSourceRangesAndDiagnosticsForQueryMessage) -{ - ClangBackEnd::RequestSourceRangesAndDiagnosticsForQueryMessage message(findDeclQueryText, - {{{"/path/to", "file.cpp"}, - unsavedDocumentContent, - commandLine.clone(), - 1}}); - - EXPECT_CALL(mockRefactoringServer, requestSourceRangesAndDiagnosticsForQueryMessage(message)) - .Times(1); - - findFilter.findAll(findDeclQueryText); -} - -void ClangQueryCurrentFileFindFilter::SetUp() -{ - projectPart = CppTools::ProjectPart::Ptr(new CppTools::ProjectPart); - projectPart->files.push_back(projectFile); - - commandLine = RefactoringCompilerOptionsBuilder::build( - projectPart.data(), - projectFile.kind, - RefactoringCompilerOptionsBuilder::PchUsage::None); - commandLine.push_back(curentDocumentFilePath); - - findFilter.setCurrentDocumentFilePath(curentDocumentFilePath); - findFilter.setUnsavedDocumentContent(unsavedDocumentContent); - findFilter.setProjectPart(projectPart); - - DefaultValue<std::unique_ptr<ClangRefactoring::SearchHandleInterface>>::SetFactory([] () { - return std::unique_ptr<ClangRefactoring::SearchHandleInterface>(new MockSearchHandle); }); - -} - -} diff --git a/tests/unit/unittest/clangqueryprojectfindfilter-test.cpp b/tests/unit/unittest/clangqueryprojectfindfilter-test.cpp index f641aa4b1b..f389c75bd9 100644 --- a/tests/unit/unittest/clangqueryprojectfindfilter-test.cpp +++ b/tests/unit/unittest/clangqueryprojectfindfilter-test.cpp @@ -43,8 +43,10 @@ namespace { using ::testing::_; using ::testing::NiceMock; using ::testing::NotNull; +using ::testing::Return; using ::testing::ReturnNew; using ::testing::DefaultValue; +using ::testing::ByMove; using ClangRefactoring::RefactoringCompilerOptionsBuilder; @@ -52,6 +54,7 @@ class ClangQueryProjectFindFilter : public ::testing::Test { protected: void SetUp(); + std::unique_ptr<ClangRefactoring::SearchHandle> createSearchHandle(); protected: NiceMock<MockRefactoringServer> mockRefactoringServer; @@ -61,10 +64,8 @@ protected: QString findDeclQueryText{"functionDecl()"}; QString curentDocumentFilePath{"/path/to/file.cpp"}; QString unsavedDocumentContent{"void f();"}; - Utils::SmallStringVector commandLine; - CppTools::ProjectPart::Ptr projectPart1; - CppTools::ProjectPart::Ptr projectPart2; - CppTools::ProjectFile projectFile{curentDocumentFilePath, CppTools::ProjectFile::CXXSource}; + std::vector<Utils::SmallStringVector> commandLines; + std::vector<CppTools::ProjectPart::Ptr> projectsParts; }; TEST_F(ClangQueryProjectFindFilter, SupportedFindFlags) @@ -117,13 +118,25 @@ TEST_F(ClangQueryProjectFindFilter, FindAllIsCallingStartNewSearch) findFilter.findAll(findDeclQueryText); } +TEST_F(ClangQueryProjectFindFilter, FindAllIsSettingExprectedResultCountInTheRefactoringClient) +{ + findFilter.findAll(findDeclQueryText); + + ASSERT_THAT(refactoringClient.expectedResultCount(), 3); +} + TEST_F(ClangQueryProjectFindFilter, FindAllIsCallingRequestSourceRangesAndDiagnosticsForQueryMessage) { ClangBackEnd::RequestSourceRangesAndDiagnosticsForQueryMessage message(findDeclQueryText, - {{{"/path/to", "file.cpp"}, - unsavedDocumentContent, - commandLine.clone(), - 1}}); + {{{"/path/to", "file1.h"}, + "", + commandLines[0].clone()}, + {{"/path/to", "file1.cpp"}, + "", + commandLines[1].clone()}, + {{"/path/to", "file2.cpp"}, + "", + commandLines[2].clone()}}); EXPECT_CALL(mockRefactoringServer, requestSourceRangesAndDiagnosticsForQueryMessage(message)) .Times(1); @@ -131,23 +144,64 @@ TEST_F(ClangQueryProjectFindFilter, FindAllIsCallingRequestSourceRangesAndDiagno findFilter.findAll(findDeclQueryText); } +TEST_F(ClangQueryProjectFindFilter, CancelSearch) +{ + EXPECT_CALL(mockRefactoringServer, cancel()) + .Times(1); + + findFilter.findAll(findDeclQueryText); + + findFilter.searchHandleForTestOnly()->cancel(); +} + +std::vector<CppTools::ProjectPart::Ptr> createProjectParts() +{ + auto projectPart1 = CppTools::ProjectPart::Ptr(new CppTools::ProjectPart); + projectPart1->files.append({"/path/to/file1.h", CppTools::ProjectFile::CXXSource}); + projectPart1->files.append({"/path/to/file1.cpp", CppTools::ProjectFile::CXXHeader}); + + auto projectPart2 = CppTools::ProjectPart::Ptr(new CppTools::ProjectPart); + projectPart1->files.append({"/path/to/file2.cpp", CppTools::ProjectFile::CXXHeader}); + + return {projectPart1, projectPart2}; +} + +std::vector<Utils::SmallStringVector> +createCommandLines(const std::vector<CppTools::ProjectPart::Ptr> &projectParts) +{ + std::vector<Utils::SmallStringVector> commandLines; + + for (const CppTools::ProjectPart::Ptr &projectPart : projectParts) { + for (const CppTools::ProjectFile &projectFile : projectPart->files) { + auto commandLine = RefactoringCompilerOptionsBuilder::build(projectPart.data(), + projectFile.kind, + CppTools::CompilerOptionsBuilder::PchUsage::None); + commandLine.emplace_back(projectFile.path); + commandLines.push_back(commandLine); + } + } + + return commandLines; +} + void ClangQueryProjectFindFilter::SetUp() { -// projectPart = CppTools::ProjectPart::Ptr(new CppTools::ProjectPart); -// projectPart->files.push_back(projectFile); + projectsParts = createProjectParts(); + commandLines = createCommandLines(projectsParts); -// commandLine = RefactoringCompilerOptionsBuilder::build(projectPart.data(), -// projectFile.kind); - commandLine.push_back(curentDocumentFilePath); + findFilter.setProjectParts(projectsParts); -// findFilter.setCurrentDocumentFilePath(curentDocumentFilePath); -// findFilter.setCurrentDocumentRevision(documentRevision); -// findFilter.setUnsavedDocumentContent(unsavedDocumentContent); -// findFilter.setProjectPart(projectPart); + ON_CALL(mockSearch, startNewSearch(QStringLiteral("Clang Query"), findDeclQueryText)) + .WillByDefault(Return(ByMove(createSearchHandle()))); - DefaultValue<std::unique_ptr<ClangRefactoring::SearchHandleInterface>>::SetFactory([] () { - return std::unique_ptr<ClangRefactoring::SearchHandleInterface>(new MockSearchHandle); }); +} + +std::unique_ptr<ClangRefactoring::SearchHandle> ClangQueryProjectFindFilter::createSearchHandle() +{ + std::unique_ptr<ClangRefactoring::SearchHandle> handle(new NiceMock<MockSearchHandle>); + handle->setRefactoringServer(&mockRefactoringServer); + return handle; } } diff --git a/tests/unit/unittest/data/sourcerangeextractor_location.cpp b/tests/unit/unittest/data/sourcerangeextractor_location.cpp new file mode 100644 index 0000000000..8e63dcf97e --- /dev/null +++ b/tests/unit/unittest/data/sourcerangeextractor_location.cpp @@ -0,0 +1,2 @@ +int value; + diff --git a/tests/unit/unittest/googletest.h b/tests/unit/unittest/googletest.h index da028e9f64..a3a74ded2f 100644 --- a/tests/unit/unittest/googletest.h +++ b/tests/unit/unittest/googletest.h @@ -28,4 +28,8 @@ #include <gmock/gmock.h> #include <gmock/gmock-matchers.h> #include <gtest/gtest.h> + #include "gtest-qt-printing.h" +#ifdef CLANG_UNIT_TESTS +# include "gtest-clang-printing.h" +#endif diff --git a/tests/unit/unittest/gtest-clang-printing.cpp b/tests/unit/unittest/gtest-clang-printing.cpp new file mode 100644 index 0000000000..7b9167540e --- /dev/null +++ b/tests/unit/unittest/gtest-clang-printing.cpp @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +#ifdef CLANG_UNIT_TESTS +#include <clang/Basic/SourceLocation.h> +#include <clang/Basic/SourceManager.h> +#endif + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +#include <gtest/gtest-printers.h> + +namespace TestGlobal { + +const clang::SourceManager *globalSourceManager = nullptr; + +void setSourceManager(const clang::SourceManager *sourceManager) +{ + globalSourceManager = sourceManager; +} + +} + +namespace llvm { +std::ostream &operator<<(std::ostream &out, const StringRef stringReference) +{ + out.write(stringReference.data(), std::streamsize(stringReference.size())); + + return out; +} +} + +namespace clang { + +void PrintTo(const FullSourceLoc &sourceLocation, ::std::ostream *os) +{ + auto &&sourceManager = sourceLocation.getManager(); + auto fileName = sourceManager.getFileEntryForID(sourceLocation.getFileID())->getName(); + + *os << "(\"" + << fileName << ", " + << sourceLocation.getSpellingLineNumber() << ", " + << sourceLocation.getSpellingColumnNumber() << ")"; +} + +void PrintTo(const SourceRange &sourceRange, ::std::ostream *os) +{ + if (TestGlobal::globalSourceManager) { + *os << "(" + << sourceRange.getBegin().printToString(*TestGlobal::globalSourceManager) << ", " + << sourceRange.getEnd().printToString(*TestGlobal::globalSourceManager) << ")"; + } else { + *os << "(" + << sourceRange.getBegin().getRawEncoding() << ", " + << sourceRange.getEnd().getRawEncoding() << ")"; + } +} + +} diff --git a/tests/unit/unittest/gtest-clang-printing.h b/tests/unit/unittest/gtest-clang-printing.h new file mode 100644 index 0000000000..7ed5a8b960 --- /dev/null +++ b/tests/unit/unittest/gtest-clang-printing.h @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include <iosfwd> + +namespace llvm { + +class StringRef; + +std::ostream &operator<<(std::ostream &out, const StringRef stringReference); +} + +namespace clang { +class FullSourceLoc; +class SourceRange; +class SourceManager; + +void PrintTo(const FullSourceLoc &sourceLocation, ::std::ostream *os); +void PrintTo(const SourceRange &sourceLocation, ::std::ostream *os); + +} + +namespace TestGlobal { +void setSourceManager(const clang::SourceManager *sourceManager); +} + diff --git a/tests/unit/unittest/mockrefactoringclient.h b/tests/unit/unittest/mockrefactoringclient.h index d35f55ad31..80db17eb96 100644 --- a/tests/unit/unittest/mockrefactoringclient.h +++ b/tests/unit/unittest/mockrefactoringclient.h @@ -32,7 +32,7 @@ #include <gtest/gtest.h> #include "gtest-qt-printing.h" -class MockRefactoringClient final : public ClangBackEnd::RefactoringClientInterface +class MockRefactoringClient : public ClangBackEnd::RefactoringClientInterface { public: MOCK_METHOD0(alive, diff --git a/tests/unit/unittest/mockrefactoringserver.h b/tests/unit/unittest/mockrefactoringserver.h index cc828f3b57..c88ab1d36b 100644 --- a/tests/unit/unittest/mockrefactoringserver.h +++ b/tests/unit/unittest/mockrefactoringserver.h @@ -41,6 +41,9 @@ public: MOCK_METHOD1(requestSourceRangesAndDiagnosticsForQueryMessage, void (const ClangBackEnd::RequestSourceRangesAndDiagnosticsForQueryMessage&)); + MOCK_METHOD0(cancel, + void ()); + void requestSourceLocationsForRenamingMessage(ClangBackEnd::RequestSourceLocationsForRenamingMessage &&message) override { requestSourceLocationsForRenamingMessage(message); diff --git a/tests/unit/unittest/mocksearch.h b/tests/unit/unittest/mocksearch.h index 668d57233d..539c07833d 100644 --- a/tests/unit/unittest/mocksearch.h +++ b/tests/unit/unittest/mocksearch.h @@ -33,6 +33,6 @@ class MockSearch : public ClangRefactoring::SearchInterface { public: MOCK_METHOD2(startNewSearch, - std::unique_ptr<ClangRefactoring::SearchHandleInterface>(const QString &searchLabel, - const QString &searchTerm)); + std::unique_ptr<ClangRefactoring::SearchHandle>(const QString &searchLabel, + const QString &searchTerm)); }; diff --git a/tests/unit/unittest/mocksearchhandle.h b/tests/unit/unittest/mocksearchhandle.h index 61c68d4b21..f13b06b2a8 100644 --- a/tests/unit/unittest/mocksearchhandle.h +++ b/tests/unit/unittest/mocksearchhandle.h @@ -27,16 +27,19 @@ #include "googletest.h" -#include <searchhandleinterface.h> +#include <searchhandle.h> -class MockSearchHandle : public ClangRefactoring::SearchHandleInterface +class MockSearchHandle : public ClangRefactoring::SearchHandle { public: - MOCK_METHOD5(addResult, + MockSearchHandle() = default; + using ClangRefactoring::SearchHandle::SearchHandle; + + MOCK_METHOD3(addResult, void(const QString &fileName, - int lineNumber, const QString &lineText, - int searchTermStart, - int searchTermLength)); + Core::Search::TextRange textRange)); + MOCK_METHOD1(setExpectedResultCount, void(uint count)); + MOCK_METHOD1(setResultCounter, void(uint counter)); MOCK_METHOD0(finishSearch, void()); }; diff --git a/tests/unit/unittest/refactoringclient-test.cpp b/tests/unit/unittest/refactoringclient-test.cpp index ce21df5b7f..5f779223c9 100644 --- a/tests/unit/unittest/refactoringclient-test.cpp +++ b/tests/unit/unittest/refactoringclient-test.cpp @@ -138,7 +138,7 @@ TEST_F(RefactoringClient, AfterStartLocalRenameHasValidCallback) TEST_F(RefactoringClient, CallAddResultsForEmptyQueryMessage) { - EXPECT_CALL(mockSearchHandle, addResult(_ ,_ ,_ , _, _)) + EXPECT_CALL(mockSearchHandle, addResult(_ ,_ ,_)) .Times(0); client.sourceRangesAndDiagnosticsForQueryMessage(std::move(emptyQueryResultMessage)); @@ -146,7 +146,7 @@ TEST_F(RefactoringClient, CallAddResultsForEmptyQueryMessage) TEST_F(RefactoringClient, CallAddResultsForQueryMessage) { - EXPECT_CALL(mockSearchHandle, addResult(_ ,_ ,_ , _, _)) + EXPECT_CALL(mockSearchHandle, addResult(_ ,_ ,_)) .Times(2); client.sourceRangesAndDiagnosticsForQueryMessage(std::move(queryResultMessage)); @@ -168,6 +168,61 @@ TEST_F(RefactoringClient, CallFinishSearchQueryMessage) client.sourceRangesAndDiagnosticsForQueryMessage(std::move(queryResultMessage)); } +TEST_F(RefactoringClient, CallFinishSearchForTwoQueryMessages) +{ + client.setExpectedResultCount(2); + + EXPECT_CALL(mockSearchHandle, finishSearch()) + .Times(1); + + client.sourceRangesAndDiagnosticsForQueryMessage(std::move(queryResultMessage)); + client.sourceRangesAndDiagnosticsForQueryMessage(std::move(queryResultMessage)); +} + +TEST_F(RefactoringClient, CallSetExpectedResultCountInSearchHandle) +{ + EXPECT_CALL(mockSearchHandle, setExpectedResultCount(3)) + .Times(1); + + client.setExpectedResultCount(3); +} + +TEST_F(RefactoringClient, ResultCounterIsOneAfterQueryMessage) +{ + client.sourceRangesAndDiagnosticsForQueryMessage(std::move(queryResultMessage)); + + ASSERT_THAT(client.resultCounter(), 1); +} + +TEST_F(RefactoringClient, ResultCounterIsSetInSearchHandleToOne) +{ + EXPECT_CALL(mockSearchHandle, setResultCounter(1)) + .Times(1); + + client.sourceRangesAndDiagnosticsForQueryMessage(std::move(queryResultMessage)); +} + +TEST_F(RefactoringClient, ResultCounterIsSetInSearchHandleToTwo) +{ + client.sourceRangesAndDiagnosticsForQueryMessage(std::move(queryResultMessage)); + + EXPECT_CALL(mockSearchHandle, setResultCounter(2)) + .Times(1); + + client.sourceRangesAndDiagnosticsForQueryMessage(std::move(queryResultMessage)); +} + + +TEST_F(RefactoringClient, ResultCounterIsZeroAfterSettingExpectedResultCount) +{ + client.sourceRangesAndDiagnosticsForQueryMessage(std::move(queryResultMessage)); + + client.setExpectedResultCount(3); + + ASSERT_THAT(client.resultCounter(), 0); +} + + TEST_F(RefactoringClient, ConvertFilePaths) { std::unordered_map<uint, ClangBackEnd::FilePath> filePaths{{42u, clangBackEndFilePath.clone()}}; @@ -189,6 +244,7 @@ void RefactoringClient::SetUp() RefactoringCompilerOptionsBuilder::PchUsage::None); client.setSearchHandle(&mockSearchHandle); + client.setExpectedResultCount(1); } } diff --git a/tests/unit/unittest/refactoringclientserverinprocess-test.cpp b/tests/unit/unittest/refactoringclientserverinprocess-test.cpp index 74cc523b2f..c966161f9b 100644 --- a/tests/unit/unittest/refactoringclientserverinprocess-test.cpp +++ b/tests/unit/unittest/refactoringclientserverinprocess-test.cpp @@ -146,6 +146,16 @@ TEST_F(RefactoringClientServerInProcess, RequestSourceRangesAndDiagnosticsForQue scheduleServerMessages(); } +TEST_F(RefactoringClientServerInProcess, CancelMessage) +{ + EXPECT_CALL(mockRefactoringServer, cancel()) + .Times(1); + + serverProxy.cancel(); + scheduleServerMessages(); +} + + RefactoringClientServerInProcess::RefactoringClientServerInProcess() : serverProxy(&mockRefactoringClient, &buffer), clientProxy(&mockRefactoringServer, &buffer) diff --git a/tests/unit/unittest/refactoringserver-test.cpp b/tests/unit/unittest/refactoringserver-test.cpp index 04f862feca..97c35645e1 100644 --- a/tests/unit/unittest/refactoringserver-test.cpp +++ b/tests/unit/unittest/refactoringserver-test.cpp @@ -39,6 +39,7 @@ namespace { using testing::AllOf; using testing::Contains; +using testing::NiceMock; using testing::Pair; using testing::PrintToString; using testing::Property; @@ -70,7 +71,11 @@ class RefactoringServer : public ::testing::Test protected: ClangBackEnd::RefactoringServer refactoringServer; - MockRefactoringClient mockRefactoringClient; + NiceMock<MockRefactoringClient> mockRefactoringClient; + Utils::SmallString fileContent{"void f()\n {}"}; + FileContainer fileContainer{{TESTDATA_DIR, "query_simplefunction.cpp"}, + fileContent.clone(), + {"cc", "query_simplefunction.cpp"}}; }; @@ -101,15 +106,13 @@ TEST_F(RefactoringServer, RequestSourceLocationsForRenamingMessage) TEST_F(RefactoringServer, RequestSingleSourceRangesAndDiagnosticsForQueryMessage) { RequestSourceRangesAndDiagnosticsForQueryMessage requestSourceRangesAndDiagnosticsForQueryMessage{"functionDecl()", - {{{TESTDATA_DIR, "query_simplefunction.cpp"}, - "void f()\n \t{}", - {"cc", "query_simplefunction.cpp"}}}}; + {fileContainer.clone()}}; EXPECT_CALL(mockRefactoringClient, sourceRangesAndDiagnosticsForQueryMessage( Property(&SourceRangesAndDiagnosticsForQueryMessage::sourceRanges, Property(&SourceRangesContainer::sourceRangeWithTextContainers, - Contains(IsSourceRangeWithText(1, 1, 2, 4, "void f() {}")))))) + Contains(IsSourceRangeWithText(1, 1, 2, 4, fileContent)))))) .Times(1); refactoringServer.requestSourceRangesAndDiagnosticsForQueryMessage(std::move(requestSourceRangesAndDiagnosticsForQueryMessage)); @@ -118,18 +121,13 @@ TEST_F(RefactoringServer, RequestSingleSourceRangesAndDiagnosticsForQueryMessage TEST_F(RefactoringServer, RequestTwoSourceRangesAndDiagnosticsForQueryMessage) { RequestSourceRangesAndDiagnosticsForQueryMessage requestSourceRangesAndDiagnosticsForQueryMessage{"functionDecl()", - {{{TESTDATA_DIR, "query_simplefunction.cpp"}, - "void f()\n \t{}", - {"cc", "query_simplefunction.cpp"}}, - {{TESTDATA_DIR, "query_simplefunction.cpp"}, - "void f()\n \t{}", - {"cc", "query_simplefunction.cpp"}}}}; + {fileContainer.clone(), fileContainer.clone()}}; EXPECT_CALL(mockRefactoringClient, sourceRangesAndDiagnosticsForQueryMessage( Property(&SourceRangesAndDiagnosticsForQueryMessage::sourceRanges, Property(&SourceRangesContainer::sourceRangeWithTextContainers, - Contains(IsSourceRangeWithText(1, 1, 2, 4, "void f() {}")))))) + Contains(IsSourceRangeWithText(1, 1, 2, 4, fileContent)))))) .Times(2); refactoringServer.requestSourceRangesAndDiagnosticsForQueryMessage(std::move(requestSourceRangesAndDiagnosticsForQueryMessage)); @@ -140,9 +138,7 @@ TEST_F(RefactoringServer, RequestManySourceRangesAndDiagnosticsForQueryMessage) std::vector<FileContainer> fileContainers; std::fill_n(std::back_inserter(fileContainers), std::thread::hardware_concurrency() + 3, - FileContainer{{TESTDATA_DIR, "query_simplefunction.cpp"}, - "void f()\n \t{}", - {"cc", "query_simplefunction.cpp"}}); + fileContainer.clone()); RequestSourceRangesAndDiagnosticsForQueryMessage requestSourceRangesAndDiagnosticsForQueryMessage{"functionDecl()", std::move(fileContainers)}; @@ -150,12 +146,34 @@ TEST_F(RefactoringServer, RequestManySourceRangesAndDiagnosticsForQueryMessage) sourceRangesAndDiagnosticsForQueryMessage( Property(&SourceRangesAndDiagnosticsForQueryMessage::sourceRanges, Property(&SourceRangesContainer::sourceRangeWithTextContainers, - Contains(IsSourceRangeWithText(1, 1, 2, 4, "void f() {}")))))) + Contains(IsSourceRangeWithText(1, 1, 2, 4, fileContent)))))) .Times(std::thread::hardware_concurrency() + 3); refactoringServer.requestSourceRangesAndDiagnosticsForQueryMessage(std::move(requestSourceRangesAndDiagnosticsForQueryMessage)); } +TEST_F(RefactoringServer, CancelJobs) +{ + refactoringServer.cancel(); + + ASSERT_TRUE(refactoringServer.isCancelingJobs()); +} + +TEST_F(RefactoringServer, PollEventLoopAsQueryIsRunning) +{ + std::vector<FileContainer> fileContainers; + std::fill_n(std::back_inserter(fileContainers), + std::thread::hardware_concurrency() + 3, + fileContainer.clone()); + RequestSourceRangesAndDiagnosticsForQueryMessage requestSourceRangesAndDiagnosticsForQueryMessage{"functionDecl()", std::move(fileContainers)}; + bool eventLoopIsPolled = false; + refactoringServer.supersedePollEventLoop([&] () { eventLoopIsPolled = true; }); + + refactoringServer.requestSourceRangesAndDiagnosticsForQueryMessage(std::move(requestSourceRangesAndDiagnosticsForQueryMessage)); + + ASSERT_TRUE(eventLoopIsPolled); +} + void RefactoringServer::SetUp() { refactoringServer.setClient(&mockRefactoringClient); diff --git a/tests/unit/unittest/sourcerangecontainer-matcher.h b/tests/unit/unittest/sourcerangecontainer-matcher.h index 1bd9776288..ddb9f1e823 100644 --- a/tests/unit/unittest/sourcerangecontainer-matcher.h +++ b/tests/unit/unittest/sourcerangecontainer-matcher.h @@ -52,8 +52,8 @@ MATCHER_P5(IsSourceRangeWithText, startLine, startColumn, endLine, endColumn, te + ", " + PrintToString(startColumn) + "), (" + PrintToString(endLine) + ", " + PrintToString(endColumn) - + "), \"" + PrintToString(text) - + "\")" + + "), " + PrintToString(text) + + ")" ) { return arg.start().line() == uint(startLine) diff --git a/tests/unit/unittest/sourcerangeextractor-test.cpp b/tests/unit/unittest/sourcerangeextractor-test.cpp new file mode 100644 index 0000000000..759ee2cd7f --- /dev/null +++ b/tests/unit/unittest/sourcerangeextractor-test.cpp @@ -0,0 +1,186 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "googletest.h" +#include "testclangtool.h" + +#include <sourcerangeextractor.h> +#include <sourcerangescontainer.h> + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +#include <clang/Basic/SourceManager.h> +#include <clang/Lex/Lexer.h> + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +using testing::Contains; +using ::testing::Eq; +using ::testing::StrEq; + +using ClangBackEnd::SourceRangeWithTextContainer; +using ClangBackEnd::SourceRangeExtractor; + +namespace { + +class SourceRangeExtractor : public ::testing::Test +{ +protected: + void SetUp() override; + void TearDown() override; + +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}; + clang::SourceLocation startLocation = sourceManager.getLocForStartOfFile(sourceManager.getMainFileID()); + clang::SourceLocation endLocation = sourceManager.getLocForStartOfFile(sourceManager.getMainFileID()).getLocWithOffset(4); + clang::SourceRange sourceRange{startLocation, endLocation}; + clang::SourceRange extendedSourceRange{startLocation, endLocation.getLocWithOffset(5)}; +}; + +TEST_F(SourceRangeExtractor, ExtractSourceRangeContainer) +{ + SourceRangeWithTextContainer sourceRangeContainer{1, 1, 1, 0, 1, 10, 9, Utils::SmallString("int value;")}; + + extractor.addSourceRange(sourceRange); + + ASSERT_THAT(extractor.sourceRangeWithTextContainers(), Contains(sourceRangeContainer)); +} + +TEST_F(SourceRangeExtractor, ExtendedSourceRange) +{ + auto range = extractor.extendSourceRangeToLastTokenEnd(sourceRange); + + ASSERT_THAT(range, extendedSourceRange); +} + +TEST_F(SourceRangeExtractor, FindStartOfLineInEmptyBuffer) +{ + clang::StringRef text = ""; + + auto found = ::SourceRangeExtractor::findStartOfLineInBuffer(text, 0); + + ASSERT_THAT(found, StrEq("")); +} + +TEST_F(SourceRangeExtractor, FindStartOfLineInBufferInFirstLine) +{ + clang::StringRef text = "first line"; + + auto found = ::SourceRangeExtractor::findStartOfLineInBuffer(text, 5); + + ASSERT_THAT(found, StrEq("first line")); +} + +TEST_F(SourceRangeExtractor, FindStartOfNewLineInBufferInSecondLine) +{ + clang::StringRef text = "first line\nsecond line"; + + auto found = ::SourceRangeExtractor::findStartOfLineInBuffer(text, 15); + + ASSERT_THAT(found, StrEq("second line")); +} + +TEST_F(SourceRangeExtractor, FindStartOfCarriageReturnInBufferInSecondLine) +{ + clang::StringRef text = "first line\rsecond line"; + + auto found = ::SourceRangeExtractor::findStartOfLineInBuffer(text, 15); + + ASSERT_THAT(found, StrEq("second line")); +} + +TEST_F(SourceRangeExtractor, FindStartOfNewLineCarriageReturnInBufferInSecondLine) +{ + clang::StringRef text = "first line\n\rsecond line"; + + auto found = ::SourceRangeExtractor::findStartOfLineInBuffer(text, 15); + + ASSERT_THAT(found, StrEq("second line")); +} + +TEST_F(SourceRangeExtractor, FindEndOfLineInEmptyBuffer) +{ + clang::StringRef text = ""; + + auto found = ::SourceRangeExtractor::findEndOfLineInBuffer(text, 0); + + ASSERT_THAT(found, StrEq("")); +} + +TEST_F(SourceRangeExtractor, FindEndOfLineInBuffer) +{ + clang::StringRef text = "first line"; + + auto found = ::SourceRangeExtractor::findEndOfLineInBuffer(text, 5); + + ASSERT_THAT(found, StrEq("")); +} + +TEST_F(SourceRangeExtractor, FindEndOfLineInBufferInFirstLineWithNewLine) +{ + clang::StringRef text = "first line\nsecond line\nthird line"; + + auto found = ::SourceRangeExtractor::findEndOfLineInBuffer(text, 15); + + ASSERT_THAT(found, StrEq("\nthird line")); +} + +TEST_F(SourceRangeExtractor, FindEndOfLineInBufferInFirstLineWithCarriageReturn) +{ + clang::StringRef text = "first line\rsecond line\rthird line"; + + auto found = ::SourceRangeExtractor::findEndOfLineInBuffer(text, 15); + + ASSERT_THAT(found, StrEq("\rthird line")); +} + +TEST_F(SourceRangeExtractor, EpandText) +{ + clang::StringRef text = "first line\nsecond line\nthird line\nforth line"; + + auto expandedText = ::SourceRangeExtractor::getExpandedText(text, 15, 25); + + ASSERT_THAT(expandedText, StrEq("second line\nthird line")); +} + +void SourceRangeExtractor::SetUp() +{ + TestGlobal::setSourceManager(&sourceManager); +} + +void SourceRangeExtractor::TearDown() +{ + TestGlobal::setSourceManager(nullptr); +} +} + diff --git a/tests/unit/unittest/testclangtool.cpp b/tests/unit/unittest/testclangtool.cpp new file mode 100644 index 0000000000..de41e42a81 --- /dev/null +++ b/tests/unit/unittest/testclangtool.cpp @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "testclangtool.h" + +TestClangTool::TestClangTool(std::string &&directory, + std::string &&fileName, + std::string &&content, + std::vector<std::string> &&commandLine) +{ + addFile(std::move(directory), std::move(fileName), std::move(content), std::move(commandLine)); + + auto clangTool = createTool(); + + clangTool.buildASTs(asts); +} + +const clang::ASTUnit *TestClangTool::ast() const +{ + return asts.front().get(); +} + +const clang::SourceManager &TestClangTool::sourceManager() const +{ + return ast()->getSourceManager(); +} + +const clang::LangOptions &TestClangTool::languageOptions() const +{ + return ast()->getLangOpts(); +} diff --git a/tests/unit/unittest/testclangtool.h b/tests/unit/unittest/testclangtool.h new file mode 100644 index 0000000000..f8ae0caf16 --- /dev/null +++ b/tests/unit/unittest/testclangtool.h @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include <clangtool.h> + +class TestClangTool : public ClangBackEnd::ClangTool +{ +public: + TestClangTool(std::string &&directory, + std::string &&fileName, + std::string &&content, + std::vector<std::string> &&commandLine); + + const clang::ASTUnit *ast() const; + const clang::SourceManager &sourceManager() const; + const clang::LangOptions &languageOptions() const; + +private: + std::vector<std::unique_ptr<clang::ASTUnit>> asts; +}; + diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro index 7bca7f4ee0..601efbbd91 100644 --- a/tests/unit/unittest/unittest.pro +++ b/tests/unit/unittest/unittest.pro @@ -34,7 +34,8 @@ SOURCES += \ smallstring-test.cpp \ spydummy.cpp \ unittests-main.cpp \ - utf8-test.cpp + utf8-test.cpp \ + gtest-qt-printing.cpp !isEmpty(LIBCLANG_LIBS) { SOURCES += \ @@ -72,7 +73,6 @@ SOURCES += \ diagnosticset-test.cpp \ diagnostic-test.cpp \ fixit-test.cpp \ - gtest-qt-printing.cpp \ highlightingmarksreporter-test.cpp \ highlightingmarks-test.cpp \ projectpart-test.cpp \ @@ -95,14 +95,16 @@ SOURCES += \ !isEmpty(LIBTOOLING_LIBS) { SOURCES += \ clangquery-test.cpp \ - clangquerycurrentfilefindfilter-test.cpp \ clangqueryprojectfindfilter-test.cpp \ refactoringclientserverinprocess-test.cpp \ refactoringclient-test.cpp \ refactoringcompilationdatabase-test.cpp \ refactoringengine-test.cpp \ refactoringserver-test.cpp \ - symbolfinder-test.cpp + symbolfinder-test.cpp \ + sourcerangeextractor-test.cpp \ + gtest-clang-printing.cpp \ + testclangtool.cpp } exists($$GOOGLEBENCHMARK_DIR) { @@ -120,7 +122,7 @@ HEADERS += \ dynamicastmatcherdiagnosticcontainer-matcher.h \ mocksearchresult.h \ mocksearch.h \ - mocksearchhandle.h + mocksearchhandle.h \ !isEmpty(LIBCLANG_LIBS) { HEADERS += \ @@ -137,7 +139,9 @@ HEADERS += \ HEADERS += \ mockrefactoringclientcallback.h \ mockrefactoringclient.h \ - mockrefactoringserver.h + mockrefactoringserver.h \ + gtest-clang-printing.h \ + testclangtool.h } OTHER_FILES += $$files(data/*) |