diff options
author | Marco Bubke <marco.bubke@qt.io> | 2016-08-04 15:26:53 +0200 |
---|---|---|
committer | Marco Bubke <marco.bubke@qt.io> | 2016-08-04 14:37:19 +0000 |
commit | 4cdb5bab157bfec52ece3a2ed6dd1ace82f80265 (patch) | |
tree | 091c985e8ffcb17171475239e7838ad3b20cbbb4 /src | |
parent | 2b9edb35ea85e3fdc56f112d7d73021ea47ece08 (diff) | |
download | qt-creator-4cdb5bab157bfec52ece3a2ed6dd1ace82f80265.tar.gz |
Clang: Add clang refactoring
Change-Id: I2e3f36f810276da3f8dc7dcc587b06f8edb586d3
GPush-Base: d02f51b48fc752fddcdef6dcb32b3f7f6c0195a3
Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
Diffstat (limited to 'src')
82 files changed, 4353 insertions, 88 deletions
diff --git a/src/libs/clangbackendipc/clangbackendipc-lib.pri b/src/libs/clangbackendipc/clangbackendipc-lib.pri index 3425c9623a..6ce39ccda8 100644 --- a/src/libs/clangbackendipc/clangbackendipc-lib.pri +++ b/src/libs/clangbackendipc/clangbackendipc-lib.pri @@ -44,11 +44,20 @@ SOURCES += $$PWD/clangcodemodelserverinterface.cpp \ $$PWD/updatetranslationunitsforeditormessage.cpp \ $$PWD/updatevisibletranslationunitsmessage.cpp \ $$PWD/highlightingmarkcontainer.cpp \ + $$PWD/refactoringclientinterface.cpp \ $$PWD/messageenvelop.cpp \ + $$PWD/refactoringserverinterface.cpp \ + $$PWD/refactoringserverproxy.cpp \ $$PWD/ipcclientinterface.cpp \ $$PWD/ipcserverinterface.cpp \ $$PWD/clangcodemodelconnectionclient.cpp \ - $$PWD/documentannotationschangedmessage.cpp + $$PWD/documentannotationschangedmessage.cpp \ + $$PWD/refactoringclientproxy.cpp \ + $$PWD/sourcelocationscontainer.cpp \ + $$PWD/sourcelocationcontainerv2.cpp \ + $$PWD/sourcelocationsforrenamingmessage.cpp \ + $$PWD/requestsourcelocationforrenamingmessage.cpp \ + $$PWD/filepath.cpp HEADERS += \ $$PWD/clangcodemodelserverinterface.h \ @@ -92,6 +101,15 @@ HEADERS += \ $$PWD/ipcclientinterface.h \ $$PWD/ipcserverinterface.h \ $$PWD/clangcodemodelconnectionclient.h \ - $$PWD/documentannotationschangedmessage.h + $$PWD/documentannotationschangedmessage.h \ + $$PWD/refactoringclientinterface.h \ + $$PWD/refactoringserverinterface.h \ + $$PWD/refactoringserverproxy.h \ + $$PWD/refactoringclientproxy.h \ + $$PWD/sourcelocationscontainer.h \ + $$PWD/sourcelocationcontainerv2.h \ + $$PWD/sourcelocationsforrenamingmessage.h \ + $$PWD/requestsourcelocationforrenamingmessage.h \ + $$PWD/filepath.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 73444f8779..7eb5ea0efa 100644 --- a/src/libs/clangbackendipc/clangbackendipc_global.h +++ b/src/libs/clangbackendipc/clangbackendipc_global.h @@ -106,7 +106,10 @@ enum class MessageType : quint8 { CodeCompletedMessage, TranslationUnitDoesNotExistMessage, - ProjectPartsDoNotExistMessage + ProjectPartsDoNotExistMessage, + + SourceLocationsForRenamingMessage, + RequestSourceLocationsForRenamingMessage }; template<MessageType messageEnumeration> diff --git a/src/libs/clangbackendipc/clangcodemodelconnectionclient.cpp b/src/libs/clangbackendipc/clangcodemodelconnectionclient.cpp index e37537c05c..9263fa4446 100644 --- a/src/libs/clangbackendipc/clangcodemodelconnectionclient.cpp +++ b/src/libs/clangbackendipc/clangcodemodelconnectionclient.cpp @@ -25,14 +25,26 @@ #include "clangcodemodelconnectionclient.h" +#include <QCoreApplication> +#include <QTemporaryDir> + namespace ClangBackEnd { +namespace { + +QString currentProcessId() +{ + return QString::number(QCoreApplication::applicationPid()); +} + +} ClangCodeModelConnectionClient::ClangCodeModelConnectionClient( ClangCodeModelClientInterface *client) : serverProxy_(client, ioDevice()) { - + stdErrPrefixer().setPrefix("ClangCodeModelConnectionClient.error:"); + stdOutPrefixer().setPrefix("ClangCodeModelConnectionClient.out:"); } ClangCodeModelConnectionClient::~ClangCodeModelConnectionClient() @@ -55,4 +67,14 @@ void ClangCodeModelConnectionClient::resetCounter() serverProxy_.resetCounter(); } +QString ClangCodeModelConnectionClient::connectionName() const +{ + return temporaryDirectory().path() + QStringLiteral("/ClangBackEnd-") + currentProcessId(); +} + +QString ClangCodeModelConnectionClient::outputName() const +{ + return QStringLiteral("ClangCodeModelConnectionClient"); +} + } // namespace ClangBackEnd diff --git a/src/libs/clangbackendipc/clangcodemodelconnectionclient.h b/src/libs/clangbackendipc/clangcodemodelconnectionclient.h index d9317d38a9..4069d654bd 100644 --- a/src/libs/clangbackendipc/clangcodemodelconnectionclient.h +++ b/src/libs/clangbackendipc/clangcodemodelconnectionclient.h @@ -41,6 +41,8 @@ public: protected: void sendEndCommand() override; void resetCounter() override; + QString connectionName() const override; + QString outputName() const override; private: ClangCodeModelServerProxy serverProxy_; diff --git a/src/libs/clangbackendipc/connectionclient.cpp b/src/libs/clangbackendipc/connectionclient.cpp index 3a4ce78aad..dd8309ada9 100644 --- a/src/libs/clangbackendipc/connectionclient.cpp +++ b/src/libs/clangbackendipc/connectionclient.cpp @@ -38,25 +38,6 @@ namespace ClangBackEnd { -namespace { -const QTemporaryDir &temporaryDirectory() -{ - static QTemporaryDir temporaryDirectory(QDir::tempPath() + QStringLiteral("/qtc-clang-XXXXXX")); - - return temporaryDirectory; -} - -QString currentProcessId() -{ - return QString::number(QCoreApplication::applicationPid()); -} - -QString connectionName() -{ - return temporaryDirectory().path() + QStringLiteral("/ClangBackEnd-") + currentProcessId(); -} -} - ConnectionClient::ConnectionClient() { processAliveTimer.setInterval(10000); @@ -72,7 +53,7 @@ ConnectionClient::ConnectionClient() void ConnectionClient::startProcessAndConnectToServerAsynchronously() { - process_ = startProcess(); + process_ = startProcess(); } bool ConnectionClient::disconnectFromServer() @@ -127,6 +108,23 @@ QProcessEnvironment ConnectionClient::processEnvironment() const return processEnvironment; } +const QTemporaryDir &ConnectionClient::temporaryDirectory() const +{ + static QTemporaryDir temporaryDirectory(QDir::tempPath() + QStringLiteral("/qtc-clang-XXXXXX")); + + return temporaryDirectory; +} + +LinePrefixer &ConnectionClient::stdErrPrefixer() +{ + return stdErrPrefixer_; +} + +LinePrefixer &ConnectionClient::stdOutPrefixer() +{ + return stdOutPrefixer_; +} + std::unique_ptr<QProcess> ConnectionClient::startProcess() { processIsStarting = true; @@ -207,17 +205,17 @@ void ConnectionClient::resetProcessIsStarting() void ConnectionClient::printLocalSocketError(QLocalSocket::LocalSocketError socketError) { if (socketError != QLocalSocket::ServerNotFoundError) - qWarning() << "ClangCodeModel ConnectionClient LocalSocket Error:" << localSocket.errorString(); + qWarning() << outputName() << "LocalSocket Error:" << localSocket.errorString(); } void ConnectionClient::printStandardOutput() { - qDebug("%s", stdOutPrefixer.prefix(process_->readAllStandardOutput()).constData()); + qDebug("%s", stdOutPrefixer_.prefix(process_->readAllStandardOutput()).constData()); } void ConnectionClient::printStandardError() { - qDebug("%s", stdErrPrefixer.prefix(process_->readAllStandardError()).constData()); + qDebug("%s", stdErrPrefixer_.prefix(process_->readAllStandardError()).constData()); } void ConnectionClient::connectLocalSocketConnected() @@ -240,8 +238,6 @@ void ConnectionClient::finishProcess() void ConnectionClient::finishProcess(std::unique_ptr<QProcess> &&process) { - TIME_SCOPE_DURATION("ConnectionClient::finishProcess"); - if (process) { processAliveTimer.stop(); @@ -251,7 +247,7 @@ void ConnectionClient::finishProcess(std::unique_ptr<QProcess> &&process) terminateProcess(process.get()); killProcess(process.get()); - resetCounter(); + resetCounter(); } } @@ -274,7 +270,7 @@ bool ConnectionClient::waitForConnected() } } - qWarning() << "Cannot connect:" << localSocket.errorString(); + qWarning() << outputName() << "cannot connect:" << localSocket.errorString(); return isConnected; } diff --git a/src/libs/clangbackendipc/connectionclient.h b/src/libs/clangbackendipc/connectionclient.h index 8d42fe4167..d08b050d6a 100644 --- a/src/libs/clangbackendipc/connectionclient.h +++ b/src/libs/clangbackendipc/connectionclient.h @@ -35,6 +35,7 @@ QT_BEGIN_NAMESPACE class QProcess; +class QTemporaryDir; QT_END_NAMESPACE class Utf8String; @@ -79,9 +80,14 @@ signals: protected: QIODevice *ioDevice(); + const QTemporaryDir &temporaryDirectory() const; + LinePrefixer &stdErrPrefixer(); + LinePrefixer &stdOutPrefixer(); virtual void sendEndCommand() = 0; virtual void resetCounter() = 0; + virtual QString connectionName() const = 0; + virtual QString outputName() const = 0; private: std::unique_ptr<QProcess> startProcess(); @@ -108,6 +114,9 @@ private: QProcessEnvironment processEnvironment() const; private: + LinePrefixer stdErrPrefixer_; + LinePrefixer stdOutPrefixer_; + mutable std::unique_ptr<QProcess> process_; QLocalSocket localSocket; QTimer processAliveTimer; @@ -115,8 +124,6 @@ private: bool isAliveTimerResetted = false; bool processIsStarting = false; - LinePrefixer stdErrPrefixer = QByteArrayLiteral("clangbackend.stderr: "); - LinePrefixer stdOutPrefixer = QByteArrayLiteral("clangbackend.stdout: "); }; } // namespace ClangBackEnd diff --git a/src/libs/clangbackendipc/connectionserver.h b/src/libs/clangbackendipc/connectionserver.h index 53033bf980..bebb9657c8 100644 --- a/src/libs/clangbackendipc/connectionserver.h +++ b/src/libs/clangbackendipc/connectionserver.h @@ -83,7 +83,7 @@ public: localServer.listen(ConnectionName::connectionName); } - void setClangCodeModelServer(ServerInterface *ipcServer) + void setServer(ServerInterface *ipcServer) { this->ipcServer = ipcServer; diff --git a/src/libs/clangbackendipc/filecontainer.h b/src/libs/clangbackendipc/filecontainer.h index b55ff2372a..5c8f6c4386 100644 --- a/src/libs/clangbackendipc/filecontainer.h +++ b/src/libs/clangbackendipc/filecontainer.h @@ -25,7 +25,7 @@ #pragma once -#include <clangbackendipc_global.h> +#include "clangbackendipc_global.h" #include <utf8string.h> #include <utf8stringvector.h> diff --git a/src/libs/clangbackendipc/filepath.cpp b/src/libs/clangbackendipc/filepath.cpp new file mode 100644 index 0000000000..77bb599ca6 --- /dev/null +++ b/src/libs/clangbackendipc/filepath.cpp @@ -0,0 +1,42 @@ +/**************************************************************************** +** +** 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 "filepath.h" + +namespace ClangBackEnd { + +QDebug operator<<(QDebug debug, const FilePath &filePath) +{ + debug.nospace() << filePath.directory() << "/" << filePath.name(); + + return debug; +} + +void PrintTo(const FilePath &filePath, ::std::ostream* os) +{ + *os << filePath.directory() << "/" << filePath.name(); +} + +} // namespace ClangBackEnd diff --git a/src/libs/clangbackendipc/filepath.h b/src/libs/clangbackendipc/filepath.h new file mode 100644 index 0000000000..31f6a0d55d --- /dev/null +++ b/src/libs/clangbackendipc/filepath.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 "clangbackendipc_global.h" + +#include <utils/smallstring.h> + +namespace ClangBackEnd { + +struct FilePath +{ +public: + FilePath() = default; + FilePath(Utils::SmallString &&directory, Utils::SmallString &&name) + : directory_(std::move(directory)), + name_(std::move(name)) + {} + + const Utils::SmallString &directory() const + { + return directory_; + } + + const Utils::SmallString &name() const + { + return name_; + } + + friend QDataStream &operator<<(QDataStream &out, const FilePath &filePath) + { + out << filePath.directory_; + out << filePath.name_; + + return out; + } + + friend QDataStream &operator>>(QDataStream &in, FilePath &filePath) + { + in >> filePath.directory_; + in >> filePath.name_; + + return in; + } + + friend bool operator==(const FilePath &first, const FilePath &second) + { + return first.directory_ == second.directory_ + && first.name_ == second.name_; + } + + FilePath clone() const + { + return FilePath(directory_.clone(), name_.clone()); + } + +private: + Utils::SmallString directory_; + Utils::SmallString name_; +}; + +CMBIPC_EXPORT QDebug operator<<(QDebug debug, const FilePath &filePath); +void PrintTo(const FilePath &filePath, ::std::ostream* os); + +} // namespace ClangBackEnd diff --git a/src/libs/clangbackendipc/lineprefixer.cpp b/src/libs/clangbackendipc/lineprefixer.cpp index 12adfa95c7..1f307f2bd4 100644 --- a/src/libs/clangbackendipc/lineprefixer.cpp +++ b/src/libs/clangbackendipc/lineprefixer.cpp @@ -28,10 +28,15 @@ namespace ClangBackEnd { LinePrefixer::LinePrefixer(const QByteArray &prefix) - : m_prefix(prefix) - , m_previousIsEndingWithNewLine(true) + : m_prefix(prefix), + m_previousIsEndingWithNewLine(true) {} +void LinePrefixer::setPrefix(const QByteArray &prefix) +{ + m_prefix = prefix; +} + QByteArray LinePrefixer::prefix(const QByteArray &text) { QByteArray output = text; diff --git a/src/libs/clangbackendipc/lineprefixer.h b/src/libs/clangbackendipc/lineprefixer.h index b2607720fe..a710997a8c 100644 --- a/src/libs/clangbackendipc/lineprefixer.h +++ b/src/libs/clangbackendipc/lineprefixer.h @@ -25,17 +25,20 @@ #pragma once +#include "clangbackendipc_global.h" + #include <QString> #include <QTextStream> #include <utf8string.h> namespace ClangBackEnd { -class LinePrefixer +class CMBIPC_EXPORT LinePrefixer { public: - LinePrefixer() = delete; - LinePrefixer(const QByteArray &m_prefix); + LinePrefixer() = default; + LinePrefixer(const QByteArray &prefix); + void setPrefix(const QByteArray &prefix); QByteArray prefix(const QByteArray &text); private: diff --git a/src/libs/clangbackendipc/projectpartcontainer.h b/src/libs/clangbackendipc/projectpartcontainer.h index 77905beb31..009e3a2fef 100644 --- a/src/libs/clangbackendipc/projectpartcontainer.h +++ b/src/libs/clangbackendipc/projectpartcontainer.h @@ -25,7 +25,7 @@ #pragma once -#include <clangbackendipc_global.h> +#include "clangbackendipc_global.h" #include <utf8stringvector.h> diff --git a/src/libs/clangbackendipc/refactoringclientinterface.cpp b/src/libs/clangbackendipc/refactoringclientinterface.cpp new file mode 100644 index 0000000000..3652f0a303 --- /dev/null +++ b/src/libs/clangbackendipc/refactoringclientinterface.cpp @@ -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. +** +****************************************************************************/ + +#include "refactoringclientinterface.h" + +#include "messageenvelop.h" +#include "sourcelocationsforrenamingmessage.h" + +#include <QDebug> + +namespace ClangBackEnd { + +void RefactoringClientInterface::dispatch(const MessageEnvelop &messageEnvelop) +{ + switch (messageEnvelop.messageType()) { + case MessageType::AliveMessage: + alive(); + break; + case MessageType::SourceLocationsForRenamingMessage: + sourceLocationsForRenamingMessage(messageEnvelop.message<SourceLocationsForRenamingMessage>()); + break; + default: + qWarning() << "Unknown IpcClientMessage"; + } +} + +} // namespace ClangBackEnd diff --git a/src/libs/clangbackendipc/refactoringclientinterface.h b/src/libs/clangbackendipc/refactoringclientinterface.h new file mode 100644 index 0000000000..af35dff054 --- /dev/null +++ b/src/libs/clangbackendipc/refactoringclientinterface.h @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** 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 "ipcclientinterface.h" + +#include <functional> + +namespace ClangBackEnd { + +class SourceLocationsForRenamingMessage; +class SourceLocationsContainer; + +class CMBIPC_EXPORT RefactoringClientInterface : public IpcClientInterface +{ +public: + using RenameCallback = std::function<void(const QString &, + const SourceLocationsContainer &, + int)>; + + void dispatch(const MessageEnvelop &messageEnvelop) override; + + virtual void alive() = 0; + virtual void sourceLocationsForRenamingMessage(SourceLocationsForRenamingMessage &&message) = 0; + + virtual void setLocalRenamingCallback(RenameCallback &&localRenamingCallback) = 0; +}; + +} // namespace ClangBackEnd diff --git a/src/libs/clangbackendipc/refactoringclientproxy.cpp b/src/libs/clangbackendipc/refactoringclientproxy.cpp new file mode 100644 index 0000000000..e4da38cf0b --- /dev/null +++ b/src/libs/clangbackendipc/refactoringclientproxy.cpp @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** 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 "refactoringclientproxy.h" + +#include "cmbalivemessage.h" +#include "messageenvelop.h" +#include "refactoringserverinterface.h" +#include "sourcelocationsforrenamingmessage.h" + +#include <QDebug> +#include <QIODevice> + +namespace ClangBackEnd { + +RefactoringClientProxy::RefactoringClientProxy(RefactoringServerInterface *server, QIODevice *ioDevice) + : writeMessageBlock(ioDevice), + readMessageBlock(ioDevice), + server(server), + ioDevice(ioDevice) +{ + QObject::connect(ioDevice, &QIODevice::readyRead, [this] () {RefactoringClientProxy::readMessages();}); +} + +RefactoringClientProxy::RefactoringClientProxy(RefactoringClientProxy &&other) + : writeMessageBlock(std::move(other.writeMessageBlock)), + readMessageBlock(std::move(other.readMessageBlock)), + server(std::move(other.server)), + ioDevice(std::move(other.ioDevice)) +{ + +} + +RefactoringClientProxy &RefactoringClientProxy::operator=(RefactoringClientProxy &&other) +{ + writeMessageBlock = std::move(other.writeMessageBlock); + readMessageBlock = std::move(other.readMessageBlock); + server = std::move(other.server); + ioDevice = std::move(other.ioDevice); + + return *this; +} + +void RefactoringClientProxy::readMessages() +{ + for (const MessageEnvelop &message : readMessageBlock.readAll()) + server->dispatch(message); +} + +void RefactoringClientProxy::alive() +{ + writeMessageBlock.write(AliveMessage()); +} + +void RefactoringClientProxy::sourceLocationsForRenamingMessage(SourceLocationsForRenamingMessage &&message) +{ + writeMessageBlock.write(message); +} + +} // namespace ClangBackEnd diff --git a/src/libs/clangbackendipc/refactoringclientproxy.h b/src/libs/clangbackendipc/refactoringclientproxy.h new file mode 100644 index 0000000000..da2b70e68f --- /dev/null +++ b/src/libs/clangbackendipc/refactoringclientproxy.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** 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" +#include "refactoringclientinterface.h" +#include "readmessageblock.h" +#include "writemessageblock.h" + +#include <memory> + +namespace ClangBackEnd { + +class RefactoringServerInterface; + +class CMBIPC_EXPORT RefactoringClientProxy : public RefactoringClientInterface +{ +public: + explicit RefactoringClientProxy(RefactoringServerInterface *server, QIODevice *ioDevice); + RefactoringClientProxy(const RefactoringClientProxy&) = delete; + const RefactoringClientProxy &operator=(const RefactoringClientProxy&) = delete; + + RefactoringClientProxy(RefactoringClientProxy&&other); + RefactoringClientProxy &operator=(RefactoringClientProxy&&other); + + void readMessages(); + + void alive() override; + void sourceLocationsForRenamingMessage(SourceLocationsForRenamingMessage &&message) override; + + void setLocalRenamingCallback(RenameCallback &&) {} + +private: + ClangBackEnd::WriteMessageBlock writeMessageBlock; + ClangBackEnd::ReadMessageBlock readMessageBlock; + RefactoringServerInterface *server = nullptr; + QIODevice *ioDevice = nullptr; +}; + +} // namespace ClangBackEnd diff --git a/src/libs/clangbackendipc/refactoringserverinterface.cpp b/src/libs/clangbackendipc/refactoringserverinterface.cpp new file mode 100644 index 0000000000..4a426073db --- /dev/null +++ b/src/libs/clangbackendipc/refactoringserverinterface.cpp @@ -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. +** +****************************************************************************/ + +#include "refactoringserverinterface.h" + +#include "messageenvelop.h" +#include "requestsourcelocationforrenamingmessage.h" + +#include <QDebug> + +namespace ClangBackEnd { + +void RefactoringServerInterface::dispatch(const MessageEnvelop &messageEnvelop) +{ + switch (messageEnvelop.messageType()) { + case MessageType::EndMessage: + end(); + break; + case MessageType::RequestSourceLocationsForRenamingMessage: + requestSourceLocationsForRenamingMessage(messageEnvelop.message<RequestSourceLocationsForRenamingMessage>()); + break; + default: + qWarning() << "Unknown IpcClientMessage"; + } +} + +} // namespace ClangBackEnd diff --git a/src/libs/clangbackendipc/refactoringserverinterface.h b/src/libs/clangbackendipc/refactoringserverinterface.h new file mode 100644 index 0000000000..63b32c6f8e --- /dev/null +++ b/src/libs/clangbackendipc/refactoringserverinterface.h @@ -0,0 +1,46 @@ +/**************************************************************************** +** +** 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 "ipcserverinterface.h" + +#include <memory> + +namespace ClangBackEnd { + +class RefactoringClientInterface; +class RequestSourceLocationsForRenamingMessage; + +class CMBIPC_EXPORT RefactoringServerInterface : public IpcServerInterface<RefactoringClientInterface> +{ +public: + void dispatch(const MessageEnvelop &messageEnvelop) override; + + virtual void end() = 0; + virtual void requestSourceLocationsForRenamingMessage(RequestSourceLocationsForRenamingMessage &&message) = 0; +}; + +} // namespace ClangBackEnd diff --git a/src/libs/clangbackendipc/refactoringserverproxy.cpp b/src/libs/clangbackendipc/refactoringserverproxy.cpp new file mode 100644 index 0000000000..491f8c3d98 --- /dev/null +++ b/src/libs/clangbackendipc/refactoringserverproxy.cpp @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** 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 "refactoringserverproxy.h" + +#include "cmbendmessage.h" +#include "messageenvelop.h" +#include "refactoringclientinterface.h" +#include "requestsourcelocationforrenamingmessage.h" + +#include <QIODevice> +#include <QVector> + +namespace ClangBackEnd { + +RefactoringServerProxy::RefactoringServerProxy(RefactoringClientInterface *client, QIODevice *ioDevice) + : writeMessageBlock(ioDevice), + readMessageBlock(ioDevice), + client(client) +{ + QObject::connect(ioDevice, &QIODevice::readyRead, [this] () { readMessages(); }); +} + +void RefactoringServerProxy::end() +{ + writeMessageBlock.write(EndMessage()); +} + +void RefactoringServerProxy::requestSourceLocationsForRenamingMessage(RequestSourceLocationsForRenamingMessage &&message) +{ + writeMessageBlock.write(message); +} + +void RefactoringServerProxy::readMessages() +{ + for (const auto &message : readMessageBlock.readAll()) + client->dispatch(message); +} + +void RefactoringServerProxy::resetCounter() +{ + writeMessageBlock.resetCounter(); + readMessageBlock.resetCounter(); +} + +} // namespace ClangBackEnd diff --git a/src/libs/clangbackendipc/refactoringserverproxy.h b/src/libs/clangbackendipc/refactoringserverproxy.h new file mode 100644 index 0000000000..75fb9aad67 --- /dev/null +++ b/src/libs/clangbackendipc/refactoringserverproxy.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** 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" +#include "refactoringserverinterface.h" +#include "readmessageblock.h" +#include "writemessageblock.h" + +#include <QtGlobal> + +#include <memory> + +QT_BEGIN_NAMESPACE +class QIODevice; +QT_END_NAMESPACE + +namespace ClangBackEnd { + +class RefactoringClientInterface; + +class CMBIPC_EXPORT RefactoringServerProxy : public RefactoringServerInterface +{ +public: + explicit RefactoringServerProxy(RefactoringClientInterface *client, QIODevice *ioDevice); + RefactoringServerProxy(const RefactoringServerProxy&) = delete; + const RefactoringServerProxy &operator=(const RefactoringServerProxy&) = delete; + + void end() override; + void requestSourceLocationsForRenamingMessage(ClangBackEnd::RequestSourceLocationsForRenamingMessage &&message) override; + + void readMessages(); + + void resetCounter(); + +private: + ClangBackEnd::WriteMessageBlock writeMessageBlock; + ClangBackEnd::ReadMessageBlock readMessageBlock; + RefactoringClientInterface *client = nullptr; + QIODevice *ioDevice = nullptr; +}; + +} // namespace ClangBackEnd diff --git a/src/libs/clangbackendipc/requestsourcelocationforrenamingmessage.cpp b/src/libs/clangbackendipc/requestsourcelocationforrenamingmessage.cpp new file mode 100644 index 0000000000..f09deee3a2 --- /dev/null +++ b/src/libs/clangbackendipc/requestsourcelocationforrenamingmessage.cpp @@ -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. +** +****************************************************************************/ + +#include "requestsourcelocationforrenamingmessage.h" + +namespace ClangBackEnd { + +QDebug operator<<(QDebug debug, const RequestSourceLocationsForRenamingMessage &message) +{ + debug.nospace() << "RequestSourceLocationsForRenamingMessage(" + << message.filePath() << ", " + << message.line() << ", " + << message.column() << ", " + << message.unsavedContent() << ")"; + + return debug; +} + +void PrintTo(const RequestSourceLocationsForRenamingMessage &message, ::std::ostream* os) +{ + *os << "RequestSourceLocationsForRenamingMessage("; + PrintTo(message.filePath(), os); + *os << ", " + << message.line() << ", " + << message.column() << ", "; + PrintTo(message.unsavedContent(), os); + *os << ", "; + PrintTo(message.commandLine(), os); + *os << ")"; +} + +} // namespace ClangBackEnd diff --git a/src/libs/clangbackendipc/requestsourcelocationforrenamingmessage.h b/src/libs/clangbackendipc/requestsourcelocationforrenamingmessage.h new file mode 100644 index 0000000000..db2d0e9343 --- /dev/null +++ b/src/libs/clangbackendipc/requestsourcelocationforrenamingmessage.h @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** 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" +#include "filepath.h" + +#include <utils/smallstringvector.h> + +namespace ClangBackEnd { + +class CMBIPC_EXPORT RequestSourceLocationsForRenamingMessage +{ +public: + RequestSourceLocationsForRenamingMessage() = default; + RequestSourceLocationsForRenamingMessage(FilePath &&filePath, + uint line, + uint column, + Utils::SmallString &&unsavedContent, + Utils::SmallStringVector &&commandLine, + int textDocumentRevision) + : filePath_(std::move(filePath)), + unsavedContent_(std::move(unsavedContent)), + commandLine_(std::move(commandLine)), + line_(line), + column_(column), + revision(textDocumentRevision) + {} + + const FilePath &filePath() const + { + return filePath_; + } + + uint line() const + { + return line_; + } + + uint column() const + { + return column_; + } + + const Utils::SmallString &unsavedContent() const + { + return unsavedContent_; + } + + const Utils::SmallStringVector &commandLine() const + { + return commandLine_; + } + + int textDocumentRevision() const + { + return revision; + } + + friend QDataStream &operator<<(QDataStream &out, const RequestSourceLocationsForRenamingMessage &message) + { + out << message.filePath_; + out << message.unsavedContent_; + out << message.commandLine_; + out << message.line_; + out << message.column_; + out << message.revision; + + return out; + } + + friend QDataStream &operator>>(QDataStream &in, RequestSourceLocationsForRenamingMessage &message) + { + in >> message.filePath_; + in >> message.unsavedContent_; + in >> message.commandLine_; + in >> message.line_; + in >> message.column_; + in >> message.revision; + + return in; + } + + friend bool operator==(const RequestSourceLocationsForRenamingMessage &first, const RequestSourceLocationsForRenamingMessage &second) + { + return first.filePath_ == second.filePath_ + && first.line_ == second.line_ + && first.column_ == second.column_ + && first.revision == second.revision + && first.unsavedContent_ == second.unsavedContent_ + && first.commandLine_ == second.commandLine_; + } + + RequestSourceLocationsForRenamingMessage clone() const + { + return RequestSourceLocationsForRenamingMessage(filePath_.clone(), + line_, column_, + unsavedContent_.clone(), + commandLine_.clone(), + revision); + } + +private: + FilePath filePath_; + Utils::SmallString unsavedContent_; + Utils::SmallStringVector commandLine_; + uint line_ = 1; + uint column_ = 1; + int revision = 1; +}; + +CMBIPC_EXPORT QDebug operator<<(QDebug debug, const RequestSourceLocationsForRenamingMessage &message); +void PrintTo(const RequestSourceLocationsForRenamingMessage &message, ::std::ostream* os); + +DECLARE_MESSAGE(RequestSourceLocationsForRenamingMessage) +} // namespace ClangBackEnd diff --git a/src/libs/clangbackendipc/sourcelocationcontainer.h b/src/libs/clangbackendipc/sourcelocationcontainer.h index e670cd3299..83810cb8ac 100644 --- a/src/libs/clangbackendipc/sourcelocationcontainer.h +++ b/src/libs/clangbackendipc/sourcelocationcontainer.h @@ -25,7 +25,7 @@ #pragma once -#include <clangbackendipc_global.h> +#include "clangbackendipc_global.h" #include <utf8string.h> diff --git a/src/libs/clangbackendipc/sourcelocationcontainerv2.cpp b/src/libs/clangbackendipc/sourcelocationcontainerv2.cpp new file mode 100644 index 0000000000..8f2a281f52 --- /dev/null +++ b/src/libs/clangbackendipc/sourcelocationcontainerv2.cpp @@ -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. +** +****************************************************************************/ + +#include "sourcelocationcontainerv2.h" + +#include <QDebug> + +#include <ostream> + +namespace ClangBackEnd { +namespace V2 { + +QDebug operator<<(QDebug debug, const SourceLocationContainer &container) +{ + debug.nospace() << "SourceLocationContainer(" + << container.fileHash() << ", " + << container.line() << ", " + << container.column() + << ")"; + return debug; +} + +void PrintTo(const SourceLocationContainer &container, ::std::ostream* os) +{ + *os << "[" + << container.fileHash() << ", " + << container.line() << ", " + << container.column() + << "]"; +} + +} // namespace V2 +} // namespace ClangBackEnd diff --git a/src/libs/clangbackendipc/sourcelocationcontainerv2.h b/src/libs/clangbackendipc/sourcelocationcontainerv2.h new file mode 100644 index 0000000000..8ff09bf8d8 --- /dev/null +++ b/src/libs/clangbackendipc/sourcelocationcontainerv2.h @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** 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" + +#include <QDataStream> + +namespace ClangBackEnd { +namespace V2 { + + +class SourceLocationContainer +{ +public: + SourceLocationContainer() = default; + SourceLocationContainer(uint fileHash, + uint line, + uint column) + : fileHash_(fileHash), + line_(line), + column_(column) + { + } + + uint fileHash() const + { + return fileHash_; + } + + uint line() const + { + return line_; + } + + uint column() const + { + return column_; + } + + friend QDataStream &operator<<(QDataStream &out, const SourceLocationContainer &container) + { + out << container.fileHash_; + out << container.line_; + out << container.column_; + + return out; + } + + friend QDataStream &operator>>(QDataStream &in, SourceLocationContainer &container) + { + in >> container.fileHash_; + in >> container.line_; + in >> container.column_; + + return in; + } + + friend bool operator==(const SourceLocationContainer &first, const SourceLocationContainer &second) + { + return !(first != second); + } + + friend bool operator!=(const SourceLocationContainer &first, const SourceLocationContainer &second) + { + return first.line_ != second.line_ + || first.column_ != second.column_ + || first.fileHash_ != second.fileHash_; + } + + SourceLocationContainer clone() const + { + return SourceLocationContainer(fileHash_, line_, column_); + } + +private: + uint fileHash_ = 0; + uint line_ = 1; + uint column_ = 1; +}; + +CMBIPC_EXPORT QDebug operator<<(QDebug debug, const SourceLocationContainer &container); +void PrintTo(const SourceLocationContainer &container, ::std::ostream* os); + +} // namespace V2 +} // namespace ClangBackEnd + diff --git a/src/libs/clangbackendipc/sourcelocationscontainer.cpp b/src/libs/clangbackendipc/sourcelocationscontainer.cpp new file mode 100644 index 0000000000..d174e30e62 --- /dev/null +++ b/src/libs/clangbackendipc/sourcelocationscontainer.cpp @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** 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 "sourcelocationscontainer.h" + +namespace ClangBackEnd { + +QDebug operator<<(QDebug debug, const SourceLocationsContainer &container) +{ + debug.nospace() << "SourceLocationsContainer(["; + for (const auto &sourceLocation: container.sourceLocationContainers()) { + debug.nospace() << "[" + << container.filePathForSourceLocation(sourceLocation).name() << "," + << sourceLocation.line() << "," + << sourceLocation.column() << "], "; + } + + debug.nospace() << "])"; + + return debug; +} + +void PrintTo(const SourceLocationsContainer &container, ::std::ostream* os) +{ + *os << "SourceLocationsContainer("; + for (const auto &sourceLocation: container.sourceLocationContainers()) { + *os << "[" + << container.filePathForSourceLocation(sourceLocation).name() << "," + << sourceLocation.line() << "," + << sourceLocation.column() << "], "; + } + *os << ")"; +} + +} // namespace ClangBackEnd diff --git a/src/libs/clangbackendipc/sourcelocationscontainer.h b/src/libs/clangbackendipc/sourcelocationscontainer.h new file mode 100644 index 0000000000..109fc3114e --- /dev/null +++ b/src/libs/clangbackendipc/sourcelocationscontainer.h @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** 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 "filepath.h" +#include "sourcelocationcontainerv2.h" + +#include <utils/smallstringvector.h> + +#include <unordered_map> + +namespace ClangBackEnd { + +class SourceLocationsContainer +{ +public: + SourceLocationsContainer() = default; + SourceLocationsContainer(std::unordered_map<uint, FilePath> &&filePathHash, + std::vector<V2::SourceLocationContainer> &&sourceLocationContainers) + : filePathHash(std::move(filePathHash)), + sourceLocationContainers_(std::move(sourceLocationContainers)) + {} + + const FilePath &filePathForSourceLocation(const V2::SourceLocationContainer &sourceLocation) const + { + auto found = filePathHash.find(sourceLocation.fileHash()); + + return found->second; + } + + const std::vector<V2::SourceLocationContainer> &sourceLocationContainers() const + { + return sourceLocationContainers_; + } + + bool hasContent() const + { + return !sourceLocationContainers_.empty(); + } + + 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))); + } + + void insertSourceLocation(uint fileId, uint line, uint column) + { + sourceLocationContainers_.emplace_back(fileId, line, column); + } + + void reserve(std::size_t size) + { + filePathHash.reserve(size / 3); + sourceLocationContainers_.reserve(size); + } + + friend QDataStream &operator<<(QDataStream &out, const SourceLocationsContainer &container) + { + out << container.filePathHash; + out << container.sourceLocationContainers_; + + return out; + } + + friend QDataStream &operator>>(QDataStream &in, SourceLocationsContainer &container) + { + in >> container.filePathHash; + in >> container.sourceLocationContainers_; + + return in; + } + + friend bool operator==(const SourceLocationsContainer &first, const SourceLocationsContainer &second) + { + return first.sourceLocationContainers_ == second.sourceLocationContainers_; + } + + SourceLocationsContainer clone() const + { + return SourceLocationsContainer(Utils::clone(filePathHash), Utils::clone(sourceLocationContainers_)); + } + +private: + std::unordered_map<uint, FilePath> filePathHash; + std::vector<V2::SourceLocationContainer> sourceLocationContainers_; +}; + + +CMBIPC_EXPORT QDebug operator<<(QDebug debug, const SourceLocationsContainer &container); +void PrintTo(const SourceLocationsContainer &container, ::std::ostream* os); + +} // namespace ClangBackEnd + diff --git a/src/libs/clangbackendipc/sourcelocationsforrenamingmessage.cpp b/src/libs/clangbackendipc/sourcelocationsforrenamingmessage.cpp new file mode 100644 index 0000000000..cbf93fb6ed --- /dev/null +++ b/src/libs/clangbackendipc/sourcelocationsforrenamingmessage.cpp @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** 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 "sourcelocationsforrenamingmessage.h" + +#include <QDebug> + +#include <ostream> + +namespace ClangBackEnd { + +QDebug operator<<(QDebug debug, const SourceLocationsForRenamingMessage &message) +{ + debug.nospace() << "SourceLocationsForRenamingMessage(" + << message.sourceLocations() + << ")"; + + return debug; +} + +void PrintTo(const SourceLocationsForRenamingMessage &message, ::std::ostream* os) +{ + *os << "SourceLocationsForRenamingMessage(\"" + << message.symbolName() << "\", " + << message.textDocumentRevision() << ", "; + PrintTo(message.sourceLocations(), os); + *os << ")"; +} + +} // namespace ClangBackEnd diff --git a/src/libs/clangbackendipc/sourcelocationsforrenamingmessage.h b/src/libs/clangbackendipc/sourcelocationsforrenamingmessage.h new file mode 100644 index 0000000000..0a69f36814 --- /dev/null +++ b/src/libs/clangbackendipc/sourcelocationsforrenamingmessage.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** 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 "sourcelocationscontainer.h" + +#include <utils/smallstring.h> + +namespace ClangBackEnd { + +class SourceLocationsForRenamingMessage +{ +public: + SourceLocationsForRenamingMessage() = default; + SourceLocationsForRenamingMessage(Utils::SmallString &&symbolName, + SourceLocationsContainer &&sourceLocationContainer, + int textDocumentRevision) + : symbolName_(std::move(symbolName)), + sourceLocationContainer(std::move(sourceLocationContainer)), + revision(textDocumentRevision) + {} + + const Utils::SmallString &symbolName() const + { + return symbolName_; + } + + int textDocumentRevision() const + { + return revision; + } + + const SourceLocationsContainer &sourceLocations() const + { + return sourceLocationContainer; + } + + friend QDataStream &operator<<(QDataStream &out, const SourceLocationsForRenamingMessage &message) + { + out << message.symbolName_; + out << message.sourceLocationContainer; + out << message.revision; + + return out; + } + + friend QDataStream &operator>>(QDataStream &in, SourceLocationsForRenamingMessage &message) + { + in >> message.symbolName_; + in >> message.sourceLocationContainer; + in >> message.revision; + + return in; + } + + friend bool operator==(const SourceLocationsForRenamingMessage &first, const SourceLocationsForRenamingMessage &second) + { + return first.revision == second.revision + && first.symbolName_ == second.symbolName_ + && first.sourceLocationContainer == second.sourceLocationContainer; + } + + SourceLocationsForRenamingMessage clone() const + { + return SourceLocationsForRenamingMessage(symbolName_.clone(), + sourceLocationContainer.clone(), + revision); + } + +private: + Utils::SmallString symbolName_; + SourceLocationsContainer sourceLocationContainer; + int revision; +}; + +CMBIPC_EXPORT QDebug operator<<(QDebug debug, const SourceLocationsForRenamingMessage &message); +void PrintTo(const SourceLocationsForRenamingMessage &message, ::std::ostream* os); + +DECLARE_MESSAGE(SourceLocationsForRenamingMessage) +} // namespace ClangBackEnd diff --git a/src/libs/clangbackendipc/updatevisibletranslationunitsmessage.h b/src/libs/clangbackendipc/updatevisibletranslationunitsmessage.h index 92f6de8f25..01d4e99c5a 100644 --- a/src/libs/clangbackendipc/updatevisibletranslationunitsmessage.h +++ b/src/libs/clangbackendipc/updatevisibletranslationunitsmessage.h @@ -25,7 +25,7 @@ #pragma once -#include <clangbackendipc_global.h> +#include "clangbackendipc_global.h" #include <utf8stringvector.h> diff --git a/src/plugins/clangrefactoring/ClangRefactoring.json.in b/src/plugins/clangrefactoring/ClangRefactoring.json.in new file mode 100644 index 0000000000..901a5b860a --- /dev/null +++ b/src/plugins/clangrefactoring/ClangRefactoring.json.in @@ -0,0 +1,20 @@ +{ + \"Name\" : \"ClangRefactoring\", + \"Version\" : \"$$QTCREATOR_VERSION\", + \"CompatVersion\" : \"$$QTCREATOR_COMPAT_VERSION\", + \"Experimental\" : true, + \"Vendor\" : \"The Qt Company Ltd\", + \"Copyright\" : \"(C) 2016 The Qt Company Ltd\", + \"License\" : [ \"Commercial Usage\", + \"\", + \"Licensees holding valid Qt Commercial licenses may use this plugin in accordance with the Qt 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.\", + \"\", + \"GNU General Public License Usage\", + \"\", + \"Alternatively, this plugin 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 plugin. 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.\" + ], + \"Category\" : \"C++\", + \"Description\" : \"Clang Refactoring plugin.\", + \"Url\" : \"http://www.qt.io\", + $$dependencyList +} diff --git a/src/plugins/clangrefactoring/clangrefactoring-source.pri b/src/plugins/clangrefactoring/clangrefactoring-source.pri new file mode 100644 index 0000000000..61048f6fe8 --- /dev/null +++ b/src/plugins/clangrefactoring/clangrefactoring-source.pri @@ -0,0 +1,13 @@ +INCLUDEPATH += $$PWD + +HEADERS += \ + $$PWD/refactoringengine.h \ + $$PWD/refactoringconnectionclient.h \ + $$PWD/refactoringcompileroptionsbuilder.h \ + $$PWD/refactoringclient.h + +SOURCES += \ + $$PWD/refactoringengine.cpp \ + $$PWD/refactoringconnectionclient.cpp \ + $$PWD/refactoringcompileroptionsbuilder.cpp \ + $$PWD/refactoringclient.cpp diff --git a/src/plugins/clangrefactoring/clangrefactoring.pro b/src/plugins/clangrefactoring/clangrefactoring.pro new file mode 100644 index 0000000000..3716c86b93 --- /dev/null +++ b/src/plugins/clangrefactoring/clangrefactoring.pro @@ -0,0 +1,12 @@ +include(../../qtcreatorplugin.pri) +include(clangrefactoring-source.pri) +include(../../shared/clang/clang_installation.pri) + +DEFINES += CLANG_VERSION=\\\"$${LLVM_VERSION}\\\" +DEFINES += "\"CLANG_RESOURCE_DIR=\\\"$${LLVM_LIBDIR}/clang/$${LLVM_VERSION}/include\\\"\"" + +HEADERS += \ + $$PWD/clangrefactoringplugin.h + +SOURCES += \ + $$PWD/clangrefactoringplugin.cpp diff --git a/src/plugins/clangrefactoring/clangrefactoring_dependencies.pri b/src/plugins/clangrefactoring/clangrefactoring_dependencies.pri new file mode 100644 index 0000000000..7426f517e2 --- /dev/null +++ b/src/plugins/clangrefactoring/clangrefactoring_dependencies.pri @@ -0,0 +1,9 @@ +QTC_PLUGIN_NAME = ClangRefactoring +QTC_LIB_DEPENDS += \ + utils \ + clangbackendipc +QTC_PLUGIN_DEPENDS += \ + coreplugin \ + cpptools \ + texteditor + diff --git a/src/plugins/clangrefactoring/clangrefactoringplugin.cpp b/src/plugins/clangrefactoring/clangrefactoringplugin.cpp new file mode 100644 index 0000000000..5db81cb46d --- /dev/null +++ b/src/plugins/clangrefactoring/clangrefactoringplugin.cpp @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** 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 "clangrefactoringplugin.h" + +#include <cpptools/cppmodelmanager.h> + +#include <coreplugin/icore.h> + +#include <utils/hostosinfo.h> + +namespace ClangRefactoring { + +namespace { + +QString backendProcessPath() +{ + return Core::ICore::libexecPath() + + QStringLiteral("/clangrefactoringbackend") + + QStringLiteral(QTC_HOST_EXE_SUFFIX); +} + +} // anonymous namespace + +RefactoringClient ClangRefactoringPlugin::client; +ClangBackEnd::RefactoringConnectionClient ClangRefactoringPlugin::connectionClient(&client); +RefactoringEngine ClangRefactoringPlugin::engine(connectionClient.serverProxy(), client); + +bool ClangRefactoringPlugin::initialize(const QStringList &/*arguments*/, QString */*errorMessage*/) +{ + client.setRefactoringEngine(&engine); + + connectBackend(); + startBackend(); + + return true; +} + +void ClangRefactoringPlugin::extensionsInitialized() +{ + CppTools::CppModelManager::setRefactoringEngine(&refactoringEngine()); +} + +RefactoringEngine &ClangRefactoringPlugin::refactoringEngine() +{ + return engine; +} + +void ClangRefactoringPlugin::startBackend() +{ + connectionClient.setProcessPath(backendProcessPath()); + + connectionClient.startProcessAndConnectToServerAsynchronously(); +} + +void ClangRefactoringPlugin::connectBackend() +{ + connect(&connectionClient, + &ClangBackEnd::RefactoringConnectionClient::connectedToLocalSocket, + this, + &ClangRefactoringPlugin::backendIsConnected); +} + +void ClangRefactoringPlugin::backendIsConnected() +{ + engine.setUsable(true); +} + +} // namespace ClangRefactoring diff --git a/src/plugins/clangrefactoring/clangrefactoringplugin.h b/src/plugins/clangrefactoring/clangrefactoringplugin.h new file mode 100644 index 0000000000..892683f67f --- /dev/null +++ b/src/plugins/clangrefactoring/clangrefactoringplugin.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** 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 "refactoringengine.h" +#include "refactoringclient.h" + +#include <refactoringconnectionclient.h> +#include <refactoringserverproxy.h> + +#include <extensionsystem/iplugin.h> + + +namespace ClangRefactoring { + +class ClangRefactoringPlugin : public ExtensionSystem::IPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "ClangRefactoring.json") + +public: + bool initialize(const QStringList &arguments, QString *errorMessage); + void extensionsInitialized(); + + static RefactoringEngine &refactoringEngine(); + +private: + void startBackend(); + void connectBackend(); + void backendIsConnected(); + +private: + static ClangBackEnd::RefactoringConnectionClient connectionClient; + static RefactoringClient client; + static RefactoringEngine engine; +}; + +} // namespace ClangRefactoring diff --git a/src/plugins/clangrefactoring/refactoringclient.cpp b/src/plugins/clangrefactoring/refactoringclient.cpp new file mode 100644 index 0000000000..015e67ac9e --- /dev/null +++ b/src/plugins/clangrefactoring/refactoringclient.cpp @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** 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 "refactoringclient.h" + +#include <sourcelocationsforrenamingmessage.h> + +namespace ClangRefactoring { + +void RefactoringClient::alive() +{ + +} + +void RefactoringClient::sourceLocationsForRenamingMessage(ClangBackEnd::SourceLocationsForRenamingMessage &&message) +{ + localRenamingCallback(message.symbolName().toQString(), + message.sourceLocations(), + message.textDocumentRevision()); + + refactoringEngine->setUsable(true); +} + +void RefactoringClient::setLocalRenamingCallback(CppTools::RefactoringEngineInterface::RenameCallback &&localRenamingCallback) +{ + this->localRenamingCallback = std::move(localRenamingCallback); +} + +void RefactoringClient::setRefactoringEngine(RefactoringEngine *refactoringEngine) +{ + this->refactoringEngine = refactoringEngine; +} + +bool RefactoringClient::hasValidLocalRenamingCallback() const +{ + return bool(localRenamingCallback); +} + +} // namespace ClangRefactoring diff --git a/src/plugins/clangrefactoring/refactoringclient.h b/src/plugins/clangrefactoring/refactoringclient.h new file mode 100644 index 0000000000..82f162c1f3 --- /dev/null +++ b/src/plugins/clangrefactoring/refactoringclient.h @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** 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 "refactoringengine.h" + +#include <refactoringclientinterface.h> + +#include <functional> + +namespace ClangRefactoring { + +class RefactoringClient : public ClangBackEnd::RefactoringClientInterface +{ +public: + void alive() override; + void sourceLocationsForRenamingMessage(ClangBackEnd::SourceLocationsForRenamingMessage &&message) override; + + void setLocalRenamingCallback(CppTools::RefactoringEngineInterface::RenameCallback &&localRenamingCallback); + void setRefactoringEngine(ClangRefactoring::RefactoringEngine *refactoringEngine); + + bool hasValidLocalRenamingCallback() const; + +private: + CppTools::RefactoringEngineInterface::RenameCallback localRenamingCallback; + ClangRefactoring::RefactoringEngine *refactoringEngine = nullptr; +}; + +} // namespace ClangRefactoring diff --git a/src/plugins/clangrefactoring/refactoringcompileroptionsbuilder.cpp b/src/plugins/clangrefactoring/refactoringcompileroptionsbuilder.cpp new file mode 100644 index 0000000000..6546e9b950 --- /dev/null +++ b/src/plugins/clangrefactoring/refactoringcompileroptionsbuilder.cpp @@ -0,0 +1,153 @@ +/**************************************************************************** +** +** 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 "refactoringcompileroptionsbuilder.h" + +namespace ClangRefactoring { + +namespace { + +QString getCreatorResourcePath() +{ +#ifndef UNIT_TESTS + return Core::ICore::instance()->resourcePath(); +#else + return QString(); +#endif +} + +QString getClangIncludeDirectory() +{ + QDir dir(getCreatorResourcePath() + QLatin1String("/cplusplus/clang/") + + QLatin1String(CLANG_VERSION) + QLatin1String("/include")); + if (!dir.exists() || !QFileInfo(dir, QLatin1String("stdint.h")).exists()) + dir = QDir(QLatin1String(CLANG_RESOURCE_DIR)); + return dir.canonicalPath(); +} + +} + +RefactoringCompilerOptionsBuilder::RefactoringCompilerOptionsBuilder(CppTools::ProjectPart *projectPart) + : CompilerOptionsBuilder(*projectPart) +{ +} + +bool RefactoringCompilerOptionsBuilder::excludeHeaderPath(const QString &path) const +{ + if (path.contains(QLatin1String("lib/gcc/i686-apple-darwin"))) + return true; + + // We already provide a custom clang include path matching the used libclang version, + // so better ignore the clang include paths from the system as this might lead to an + // unfavorable order with regard to include_next. + static QRegularExpression clangIncludeDir( + QLatin1String("\\A.*/lib/clang/\\d+\\.\\d+(\\.\\d+)?/include\\z")); + if (clangIncludeDir.match(path).hasMatch()) + return true; + + return false; +} + +void RefactoringCompilerOptionsBuilder::addPredefinedMacrosAndHeaderPathsOptions() +{ + if (m_projectPart.toolchainType == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID) + addPredefinedMacrosAndHeaderPathsOptionsForMsvc(); + else + addPredefinedMacrosAndHeaderPathsOptionsForNonMsvc(); +} + +void RefactoringCompilerOptionsBuilder::addPredefinedMacrosAndHeaderPathsOptionsForMsvc() +{ + add(QLatin1String("-nostdinc")); + add(QLatin1String("-undef")); +} + +void RefactoringCompilerOptionsBuilder::addPredefinedMacrosAndHeaderPathsOptionsForNonMsvc() +{ + static const QString resourceDir = getClangIncludeDirectory(); + if (!resourceDir.isEmpty()) { + add(QLatin1String("-nostdlibinc")); + add(QLatin1String("-I") + resourceDir); + add(QLatin1String("-undef")); + } +} + +void RefactoringCompilerOptionsBuilder::addWrappedQtHeadersIncludePath() +{ + static const QString wrappedQtHeaders = getCreatorResourcePath() + + QStringLiteral("/cplusplus/wrappedQtHeaders"); + + if (m_projectPart.qtVersion != CppTools::ProjectPart::NoQt) { + add(QLatin1String("-I") + wrappedQtHeaders); + add(QLatin1String("-I") + wrappedQtHeaders + QLatin1String("/QtCore")); + } +} + +void RefactoringCompilerOptionsBuilder::addProjectConfigFileInclude() +{ + if (!m_projectPart.projectConfigFile.isEmpty()) { + add(QLatin1String("-include")); + add(m_projectPart.projectConfigFile); + } +} + +void RefactoringCompilerOptionsBuilder::addExtraOptions() +{ + add(QLatin1String("-fmessage-length=0")); + add(QLatin1String("-fdiagnostics-show-note-include-stack")); + add(QLatin1String("-fmacro-backtrace-limit=0")); + add(QLatin1String("-fretain-comments-from-system-headers")); + add(QLatin1String("-ferror-limit=1000")); +} + +Utils::SmallStringVector RefactoringCompilerOptionsBuilder::build(CppTools::ProjectPart *projectPart, + CppTools::ProjectFile::Kind fileKind) +{ + if (projectPart == nullptr) + return Utils::SmallStringVector(); + + RefactoringCompilerOptionsBuilder optionsBuilder(projectPart); + + optionsBuilder.addTargetTriple(); + optionsBuilder.addLanguageOption(fileKind); + optionsBuilder.addOptionsForLanguage(/*checkForBorlandExtensions*/ true); + optionsBuilder.enableExceptions(); + + optionsBuilder.addToolchainAndProjectDefines(); + optionsBuilder.undefineCppLanguageFeatureMacrosForMsvc2015(); + + optionsBuilder.addPredefinedMacrosAndHeaderPathsOptions(); + optionsBuilder.addWrappedQtHeadersIncludePath(); + optionsBuilder.addHeaderPathOptions(); + optionsBuilder.addProjectConfigFileInclude(); + + optionsBuilder.addMsvcCompatibilityVersion(); + + optionsBuilder.addExtraOptions(); + + return Utils::SmallStringVector(optionsBuilder.options()); +} + +} // namespace ClangRefactoring diff --git a/src/plugins/clangrefactoring/refactoringcompileroptionsbuilder.h b/src/plugins/clangrefactoring/refactoringcompileroptionsbuilder.h new file mode 100644 index 0000000000..f0f0dcc016 --- /dev/null +++ b/src/plugins/clangrefactoring/refactoringcompileroptionsbuilder.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** 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 <cpptools/compileroptionsbuilder.h> + +#include <utils/smallstringvector.h> + +#include <projectexplorer/projectexplorerconstants.h> + +#include <coreplugin/icore.h> + +#include <QDir> +#include <QRegularExpression> + +namespace ClangRefactoring { + +class RefactoringCompilerOptionsBuilder : public CppTools::CompilerOptionsBuilder +{ +public: + static Utils::SmallStringVector build(CppTools::ProjectPart *projectPart, + CppTools::ProjectFile::Kind fileKind); + +private: + RefactoringCompilerOptionsBuilder(CppTools::ProjectPart *projectPart); + + bool excludeHeaderPath(const QString &path) const override; + void addPredefinedMacrosAndHeaderPathsOptions(); + void addPredefinedMacrosAndHeaderPathsOptionsForMsvc(); + void addPredefinedMacrosAndHeaderPathsOptionsForNonMsvc(); + void addWrappedQtHeadersIncludePath(); + void addProjectConfigFileInclude(); + void addExtraOptions(); +}; + +} // namespace ClangRefactoring diff --git a/src/plugins/clangrefactoring/refactoringconnectionclient.cpp b/src/plugins/clangrefactoring/refactoringconnectionclient.cpp new file mode 100644 index 0000000000..2d05722b19 --- /dev/null +++ b/src/plugins/clangrefactoring/refactoringconnectionclient.cpp @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** 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 "refactoringconnectionclient.h" + +#include <QCoreApplication> +#include <QTemporaryDir> + +namespace ClangBackEnd { + +namespace { + +QString currentProcessId() +{ + return QString::number(QCoreApplication::applicationPid()); +} + +} + +RefactoringConnectionClient::RefactoringConnectionClient(RefactoringClientInterface *client) + : serverProxy_(client, ioDevice()) +{ + stdErrPrefixer().setPrefix("RefactoringConnectionClient.error:"); + stdOutPrefixer().setPrefix("RefactoringConnectionClient.out:"); +} + +RefactoringServerProxy &RefactoringConnectionClient::serverProxy() +{ + return serverProxy_; +} + +void RefactoringConnectionClient::sendEndCommand() +{ + serverProxy_.end(); +} + +void RefactoringConnectionClient::resetCounter() +{ + serverProxy_.resetCounter(); +} + +QString RefactoringConnectionClient::connectionName() const +{ + return temporaryDirectory().path() + QStringLiteral("/ClangRefactoringBackEnd-") + currentProcessId(); +} + +QString RefactoringConnectionClient::outputName() const +{ + return QStringLiteral("RefactoringConnectionClient"); +} + +} // namespace ClangBackEnd diff --git a/src/plugins/clangrefactoring/refactoringconnectionclient.h b/src/plugins/clangrefactoring/refactoringconnectionclient.h new file mode 100644 index 0000000000..d1271bb6ba --- /dev/null +++ b/src/plugins/clangrefactoring/refactoringconnectionclient.h @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** 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 <connectionclient.h> +#include <refactoringserverproxy.h> + +namespace ClangBackEnd { + +class RefactoringClientInterface; + +class RefactoringConnectionClient : public ConnectionClient +{ +public: + RefactoringConnectionClient(RefactoringClientInterface *client); + + RefactoringServerProxy &serverProxy(); + +protected: + void sendEndCommand() override; + void resetCounter() override; + QString connectionName() const override; + QString outputName() const override; + +private: + RefactoringServerProxy serverProxy_; +}; + +} // namespace ClangBackEnd diff --git a/src/plugins/clangrefactoring/refactoringengine.cpp b/src/plugins/clangrefactoring/refactoringengine.cpp new file mode 100644 index 0000000000..fe33c82c09 --- /dev/null +++ b/src/plugins/clangrefactoring/refactoringengine.cpp @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** 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 "refactoringengine.h" + +#include <refactoringcompileroptionsbuilder.h> + +#include <refactoringserverinterface.h> +#include <requestsourcelocationforrenamingmessage.h> + +#include <QTextCursor> +#include <QTextDocument> + +#include <algorithm> + +namespace ClangRefactoring { + +using ClangBackEnd::RequestSourceLocationsForRenamingMessage; + +RefactoringEngine::RefactoringEngine(ClangBackEnd::RefactoringServerInterface &server, + ClangBackEnd::RefactoringClientInterface &client) + : server(server), + client(client) +{ +} + +namespace { + +ClangBackEnd::FilePath convertToClangBackEndFilePath(const Utils::FileName &filePath) +{ + Utils::SmallString utf8FilePath = filePath.toString(); + + auto found = std::find(utf8FilePath.rbegin(), utf8FilePath.rend(), '/').base(); + + Utils::SmallString fileName(found, utf8FilePath.end()); + utf8FilePath.resize(std::size_t(std::distance(utf8FilePath.begin(), --found))); + + return ClangBackEnd::FilePath(std::move(utf8FilePath), std::move(fileName)); +} + +CppTools::ProjectFile::Kind fileKind(CppTools::ProjectPart *projectPart, const QString &filePath) +{ + const auto &projectFiles = projectPart->files; + + auto comparePaths = [&] (const CppTools::ProjectFile &projectFile) { + return projectFile.path == filePath; + }; + + auto found = std::find_if(projectFiles.begin(), projectFiles.end(), comparePaths); + + if (found != projectFiles.end()) + return found->kind; + + return CppTools::ProjectFile::Unclassified; +} + +} + +void RefactoringEngine::startLocalRenaming(const QTextCursor &textCursor, + const Utils::FileName &filePath, + int revision, + CppTools::ProjectPart *projectPart, + RenameCallback &&renameSymbolsCallback) +{ + isUsable_ = false; + + client.setLocalRenamingCallback(std::move(renameSymbolsCallback)); + + auto commandLine = RefactoringCompilerOptionsBuilder::build(projectPart, + fileKind(projectPart, filePath.toString())); + + commandLine.push_back(filePath.toString()); + qDebug() << commandLine.join(" "); + + RequestSourceLocationsForRenamingMessage message(convertToClangBackEndFilePath(filePath), + uint(textCursor.blockNumber() + 1), + uint(textCursor.positionInBlock() + 1), + textCursor.document()->toPlainText(), + std::move(commandLine), + revision); + + + server.requestSourceLocationsForRenamingMessage(std::move(message)); +} + +bool RefactoringEngine::isUsable() const +{ + return isUsable_; +} + +void RefactoringEngine::setUsable(bool isUsable) +{ + isUsable_ = isUsable; +} + +} // namespace ClangRefactoring diff --git a/src/plugins/clangrefactoring/refactoringengine.h b/src/plugins/clangrefactoring/refactoringengine.h new file mode 100644 index 0000000000..4e577e0b51 --- /dev/null +++ b/src/plugins/clangrefactoring/refactoringengine.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** 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 <cpptools/refactoringengineinterface.h> + +namespace ClangBackEnd { +class RefactoringClientInterface; +class RefactoringServerInterface; +} + +namespace ClangRefactoring { + +class RefactoringEngine : public CppTools::RefactoringEngineInterface +{ +public: + RefactoringEngine(ClangBackEnd::RefactoringServerInterface &server, + ClangBackEnd::RefactoringClientInterface &client); + void startLocalRenaming(const QTextCursor &textCursor, + const Utils::FileName &filePath, + int revision, + CppTools::ProjectPart *projectPart, + RenameCallback &&renameSymbolsCallback) override; + + bool isUsable() const override; + void setUsable(bool isUsable); + +private: + ClangBackEnd::RefactoringServerInterface &server; + ClangBackEnd::RefactoringClientInterface &client; + bool isUsable_ = false; +}; + +} // namespace ClangRefactoring diff --git a/src/plugins/coreplugin/core_global.h b/src/plugins/coreplugin/core_global.h index 663b2e7e5c..5be3bc4a25 100644 --- a/src/plugins/coreplugin/core_global.h +++ b/src/plugins/coreplugin/core_global.h @@ -29,6 +29,8 @@ #if defined(CORE_LIBRARY) # define CORE_EXPORT Q_DECL_EXPORT +#elif defined(CORE_STATIC_LIBRARY) // Abuse single files for manual tests +# define CORE_EXPORT #else # define CORE_EXPORT Q_DECL_IMPORT #endif diff --git a/src/plugins/coreplugin/corepluginunittestfiles.pri b/src/plugins/coreplugin/corepluginunittestfiles.pri new file mode 100644 index 0000000000..9e30b81e76 --- /dev/null +++ b/src/plugins/coreplugin/corepluginunittestfiles.pri @@ -0,0 +1,7 @@ +DEFINES += CORE_STATIC_LIBRARY + +HEADERS += \ + $$PWD/id.h + +SOURCES += \ + $$PWD/id.cpp diff --git a/src/plugins/cppeditor/cppeditor.cpp b/src/plugins/cppeditor/cppeditor.cpp index b5e6f9657d..63d964af9e 100644 --- a/src/plugins/cppeditor/cppeditor.cpp +++ b/src/plugins/cppeditor/cppeditor.cpp @@ -38,6 +38,8 @@ #include "cppquickfixassistant.h" #include "cppuseselectionsupdater.h" +#include <clangbackendipc/sourcelocationscontainer.h> + #include <coreplugin/actionmanager/actioncontainer.h> #include <coreplugin/actionmanager/actionmanager.h> #include <coreplugin/editormanager/editormanager.h> @@ -55,6 +57,7 @@ #include <cpptools/cpptoolsreuse.h> #include <cpptools/cppworkingcopy.h> #include <cpptools/symbolfinder.h> +#include <cpptools/refactoringengineinterface.h> #include <texteditor/behaviorsettings.h> #include <texteditor/completionsettings.h> @@ -68,11 +71,14 @@ #include <texteditor/fontsettings.h> #include <texteditor/refactoroverlay.h> +#include <projectexplorer/projecttree.h> + #include <cplusplus/ASTPath.h> #include <cplusplus/FastPreprocessor.h> #include <cplusplus/MatchingText.h> #include <utils/qtcassert.h> +#include <QApplication> #include <QAction> #include <QElapsedTimer> #include <QFutureWatcher> @@ -378,7 +384,16 @@ bool CppEditorWidget::selectBlockDown() void CppEditorWidget::renameSymbolUnderCursor() { + if (refactoringEngine()) + renameSymbolUnderCursorClang(); + else + renameSymbolUnderCursorBuiltin(); +} + +void CppEditorWidget::renameSymbolUnderCursorBuiltin() +{ d->m_useSelectionsUpdater.abortSchedule(); + updateSemanticInfo(d->m_cppEditorDocument->recalculateSemanticInfo(), /*updateUseSelectionSynchronously=*/ true); @@ -386,6 +401,129 @@ void CppEditorWidget::renameSymbolUnderCursor() renameUsages(); // Rename non-local symbol or macro } +namespace { + +QList<ProjectPart::Ptr> fetchProjectParts(CppTools::CppModelManager *modelManager, + const Utils::FileName &filePath) +{ + QList<ProjectPart::Ptr> projectParts = modelManager->projectPart(filePath); + + if (projectParts.isEmpty()) + projectParts = modelManager->projectPartFromDependencies(filePath); + else if (projectParts.isEmpty()) + projectParts.append(modelManager->fallbackProjectPart()); + + return projectParts; +} + +ProjectPart *findProjectPartForCurrentProject(const QList<ProjectPart::Ptr> &projectParts, + ProjectExplorer::Project *currentProject) +{ + auto found = std::find_if(projectParts.cbegin(), + projectParts.cend(), + [&] (const CppTools::ProjectPart::Ptr &projectPart) { + return projectPart->project == currentProject; + }); + + if (found != projectParts.cend()) + return (*found).data(); + + return 0; +} + +} + +ProjectPart *CppEditorWidget::projectPart() const +{ + auto projectParts = fetchProjectParts(d->m_modelManager, textDocument()->filePath()); + + return findProjectPartForCurrentProject(projectParts, + ProjectExplorer::ProjectTree::currentProject()); +} + +namespace { + +using ClangBackEnd::V2::SourceLocationContainer; +using TextEditor::Convenience::selectAt; + +QTextCharFormat occurrencesTextCharFormat() +{ + using TextEditor::TextEditorSettings; + + return TextEditorSettings::fontSettings().toTextCharFormat(TextEditor::C_OCCURRENCES); +} + +QList<QTextEdit::ExtraSelection> +sourceLocationsToExtraSelections(const std::vector<SourceLocationContainer> &sourceLocations, + uint selectionLength, + CppEditorWidget *cppEditorWidget) +{ + const auto textCharFormat = occurrencesTextCharFormat(); + + QList<QTextEdit::ExtraSelection> selections; + selections.reserve(sourceLocations.size()); + + auto sourceLocationToExtraSelection = [&] (const SourceLocationContainer &sourceLocation) { + QTextEdit::ExtraSelection selection; + + selection.cursor = selectAt(cppEditorWidget->textCursor(), + sourceLocation.line(), + sourceLocation.column(), + selectionLength); + selection.format = textCharFormat; + + return selection; + }; + + + std::transform(sourceLocations.begin(), + sourceLocations.end(), + std::back_inserter(selections), + sourceLocationToExtraSelection); + + return selections; +}; + +} + +void CppEditorWidget::renameSymbolUnderCursorClang() +{ + using ClangBackEnd::SourceLocationsContainer; + + if (refactoringEngine()->isUsable()) { + d->m_useSelectionsUpdater.abortSchedule(); + + QPointer<CppEditorWidget> cppEditorWidget = this; + + auto renameSymbols = [=] (const QString &symbolName, + const SourceLocationsContainer &sourceLocations, + int revision) { + if (cppEditorWidget) { + viewport()->setCursor(Qt::IBeamCursor); + + if (revision == document()->revision()) { + auto selections = sourceLocationsToExtraSelections(sourceLocations.sourceLocationContainers(), + symbolName.size(), + cppEditorWidget); + setExtraSelections(TextEditor::TextEditorWidget::CodeSemanticsSelection, + selections); + d->m_localRenaming.updateSelectionsForVariableUnderCursor(selections); + if (!d->m_localRenaming.start()) + renameUsages(); + } + } + }; + + refactoringEngine()->startLocalRenaming(textCursor(), + textDocument()->filePath(), + document()->revision(), + projectPart(), + std::move(renameSymbols)); + + viewport()->setCursor(Qt::BusyCursor); + } +} + void CppEditorWidget::updatePreprocessorButtonTooltip() { QTC_ASSERT(d->m_preprocessorButton, return); @@ -500,6 +638,11 @@ RefactorMarkers CppEditorWidget::refactorMarkersWithoutClangMarkers() const return clearedRefactorMarkers; } +RefactoringEngineInterface *CppEditorWidget::refactoringEngine() const +{ + return CppTools::CppModelManager::refactoringEngine(); +} + bool CppEditorWidget::isSemanticInfoValidExceptLocalUses() const { return d->m_lastSemanticInfo.doc diff --git a/src/plugins/cppeditor/cppeditor.h b/src/plugins/cppeditor/cppeditor.h index 9f43890c79..626b16ab94 100644 --- a/src/plugins/cppeditor/cppeditor.h +++ b/src/plugins/cppeditor/cppeditor.h @@ -33,7 +33,9 @@ namespace CppTools { class CppEditorOutline; +class RefactoringEngineInterface; class SemanticInfo; +class ProjectPart; } namespace CppEditor { @@ -135,6 +137,13 @@ private: TextEditor::RefactorMarkers refactorMarkersWithoutClangMarkers() const; + CppTools::RefactoringEngineInterface *refactoringEngine() const; + + void renameSymbolUnderCursorClang(); + void renameSymbolUnderCursorBuiltin(); + + CppTools::ProjectPart *projectPart() const; + private: QScopedPointer<CppEditorWidgetPrivate> d; }; diff --git a/src/plugins/cpptools/cppmodelmanager.cpp b/src/plugins/cpptools/cppmodelmanager.cpp index 71703246bc..d20d1257b6 100644 --- a/src/plugins/cpptools/cppmodelmanager.cpp +++ b/src/plugins/cpptools/cppmodelmanager.cpp @@ -162,6 +162,9 @@ public: bool m_enableGC; QTimer m_delayedGcTimer; + + // Refactoring + RefactoringEngineInterface *m_refactoringEngine = nullptr; }; } // namespace Internal @@ -254,6 +257,16 @@ QString CppModelManager::editorConfigurationFileName() return QLatin1String("<per-editor-defines>"); } +void CppModelManager::setRefactoringEngine(RefactoringEngineInterface *refactoringEngine) +{ + instance()->d->m_refactoringEngine = refactoringEngine; +} + +RefactoringEngineInterface *CppModelManager::refactoringEngine() +{ + return instance()->d->m_refactoringEngine; +} + QString CppModelManager::configurationFileName() { return Preprocessor::configurationFileName(); diff --git a/src/plugins/cpptools/cppmodelmanager.h b/src/plugins/cpptools/cppmodelmanager.h index f3a5e6d100..8be30cd5ff 100644 --- a/src/plugins/cpptools/cppmodelmanager.h +++ b/src/plugins/cpptools/cppmodelmanager.h @@ -54,6 +54,7 @@ class BaseEditorDocumentProcessor; class CppCompletionAssistProvider; class CppEditorDocumentHandle; class CppIndexingSupport; +class RefactoringEngineInterface; class SymbolFinder; class WorkingCopy; @@ -171,6 +172,9 @@ public: static QString configurationFileName(); static QString editorConfigurationFileName(); + static void setRefactoringEngine(RefactoringEngineInterface *refactoringEngine); + static RefactoringEngineInterface *refactoringEngine(); + signals: /// Project data might be locked while this is emitted. void aboutToRemoveFiles(const QStringList &files); diff --git a/src/plugins/cpptools/cpptools.pro b/src/plugins/cpptools/cpptools.pro index dd0fc1d766..750c63f1de 100644 --- a/src/plugins/cpptools/cpptools.pro +++ b/src/plugins/cpptools/cpptools.pro @@ -76,8 +76,8 @@ HEADERS += \ projectpartheaderpath.h \ projectinfo.h \ projectpartbuilder.h \ - compileroptionsbuilder.h - + compileroptionsbuilder.h \ + refactoringengineinterface.h SOURCES += \ abstracteditorsupport.cpp \ baseeditordocumentparser.cpp \ diff --git a/src/plugins/cpptools/cpptoolsunittestfiles.pri b/src/plugins/cpptools/cpptoolsunittestfiles.pri index be0b6f7bde..318d74aaf5 100644 --- a/src/plugins/cpptools/cpptoolsunittestfiles.pri +++ b/src/plugins/cpptools/cpptoolsunittestfiles.pri @@ -7,7 +7,11 @@ contains(CONFIG, dll) { HEADERS += \ $$PWD/cppprojectfile.h \ $$PWD/senddocumenttracker.h \ + $$PWD/projectpart.h \ + $$PWD/compileroptionsbuilder.h SOURCES += \ $$PWD/cppprojectfile.cpp \ - $$PWD/senddocumenttracker.cpp + $$PWD/senddocumenttracker.cpp \ + $$PWD/projectpart.cpp \ + $$PWD/compileroptionsbuilder.cpp diff --git a/src/plugins/cpptools/refactoringengineinterface.h b/src/plugins/cpptools/refactoringengineinterface.h new file mode 100644 index 0000000000..2076a379d8 --- /dev/null +++ b/src/plugins/cpptools/refactoringengineinterface.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** 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 <utils/fileutils.h> + +#include <clangbackendipc/sourcelocationscontainer.h> +#include <clangbackendipc/refactoringclientinterface.h> + +QT_BEGIN_NAMESPACE +class QTextCursor; +QT_END_NAMESPACE + +namespace CppTools { + +class CppEditorWidget; +class ProjectPart; + +enum class CallType +{ + Synchronous, + Asynchronous +}; + +class RefactoringEngineInterface +{ +public: + using RenameCallback = ClangBackEnd::RefactoringClientInterface::RenameCallback; + + virtual void startLocalRenaming(const QTextCursor &textCursor, + const Utils::FileName &filePath, + int revision, + CppTools::ProjectPart *projectPart, + RenameCallback &&renameSymbolsCallback) = 0; + + virtual bool isUsable() const = 0; + +}; + +} // namespace CppTools diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro index 4f9753bb3f..4df7240982 100644 --- a/src/plugins/plugins.pro +++ b/src/plugins/plugins.pro @@ -76,6 +76,7 @@ exists(../shared/qbs/qbs.pro)|!isEmpty(QBS_INSTALL_DIR): \ isEmpty(LLVM_INSTALL_DIR):LLVM_INSTALL_DIR=$$(LLVM_INSTALL_DIR) exists($$LLVM_INSTALL_DIR) { SUBDIRS += clangcodemodel + SUBDIRS += clangrefactoring } else { warning("Set LLVM_INSTALL_DIR to build the Clang Code Model. " \ "For details, see doc/src/editors/creator-clang-codemodel.qdoc.") diff --git a/src/plugins/texteditor/convenience.cpp b/src/plugins/texteditor/convenience.cpp index 9d969d72ca..22dcb99e9b 100644 --- a/src/plugins/texteditor/convenience.cpp +++ b/src/plugins/texteditor/convenience.cpp @@ -61,6 +61,23 @@ QString textAt(QTextCursor tc, int pos, int length) return tc.selectedText().replace(QChar::ParagraphSeparator, QLatin1Char('\n')); } +QTextCursor selectAt(QTextCursor textCursor, uint line, uint column, uint length) +{ + if (line < 1) + line = 1; + + if (column < 1) + column = 1; + + textCursor.setPosition(0); + textCursor.movePosition(QTextCursor::NextBlock, QTextCursor::MoveAnchor, line - 1); + textCursor.movePosition(QTextCursor::NextCharacter,QTextCursor::MoveAnchor, column + length - 1 ); + + textCursor.movePosition(QTextCursor::PreviousCharacter,QTextCursor::KeepAnchor, length); + + return textCursor; +} + QTextCursor flippedCursor(const QTextCursor &cursor) { QTextCursor flipped = cursor; diff --git a/src/plugins/texteditor/convenience.h b/src/plugins/texteditor/convenience.h index 65dcd6be46..5cbff33bef 100644 --- a/src/plugins/texteditor/convenience.h +++ b/src/plugins/texteditor/convenience.h @@ -43,6 +43,8 @@ TEXTEDITOR_EXPORT bool convertPosition(const QTextDocument *document, TEXTEDITOR_EXPORT QString textAt(QTextCursor tc, int pos, int length); +TEXTEDITOR_EXPORT QTextCursor selectAt(QTextCursor textCursor, uint line, uint column, uint length); + TEXTEDITOR_EXPORT QTextCursor flippedCursor(const QTextCursor &cursor); } // Util diff --git a/src/shared/clang/clang_installation.pri b/src/shared/clang/clang_installation.pri index 0486d1c170..acd27644a7 100644 --- a/src/shared/clang/clang_installation.pri +++ b/src/shared/clang/clang_installation.pri @@ -40,13 +40,11 @@ defineReplace(findLLVMVersionFromLibDir) { defineReplace(findClangLibInLibDir) { libdir = $$1 - exists ($${libdir}/libclang.*) { - #message("LLVM was build with autotools") - return("clang") + exists ($${libdir}/libclang.so*) { + return("-lclang") } else { - exists ($${libdir}/liblibclang.*) { - #message("LLVM was build with CMake") - return("libclang") + exists ($${libdir}/libclang.lib) { + return("-llibclang") } } } @@ -65,45 +63,36 @@ defineReplace(findClangOnWindows) { } } -win32 { - LLVM_INCLUDEPATH = "$$LLVM_INSTALL_DIR/include" - LLVM_LIBDIR = $$findClangOnWindows() - isEmpty(LLVM_LIBDIR): error("Cannot find clang shared library at $${LLVM_INSTALL_DIR}") - LLVM_VERSION = $$findLLVMVersionFromLibDir($$LLVM_LIBDIR) +CLANGTOOLING_LIBS=-lclangTooling -lclangIndex -lclangFrontend -lclangParse -lclangSerialization \ + -lclangSema -lclangEdit -lclangAnalysis -lclangDriver -lclangASTMatchers \ + -lclangFormat -lclangToolingCore -lclangRewrite -lclangAST -lclangLex -lclangBasic - clang_lib = clang - !exists("$${LLVM_LIBDIR}/clang.*"): clang_lib = libclang +BIN_EXTENSION = +win32: BIN_EXTENSION = .exe - LLVM_LIBS = -L"$${LLVM_LIBDIR}" -l$${clang_lib} - LLVM_LIBS += -ladvapi32 -lshell32 -} +llvm_config = $$system_quote($$LLVM_INSTALL_DIR/bin/llvm-config) +requires(exists($$llvm_config$$BIN_EXTENSION)) +#message("llvm-config found, querying it for paths and version") +LLVM_LIBDIR = $$system($$llvm_config --libdir, lines) +LLVM_INCLUDEPATH = $$system($$llvm_config --includedir, lines) +output = $$system($$llvm_config --version, lines) +LLVM_VERSION = $$extractVersion($$output) +LLVM_STATIC_LIBS_STRING += $$system($$llvm_config --libs, lines) +LLVM_STATIC_LIBS_STRING += $$system($$llvm_config --system-libs, lines) -unix { - llvm_config = $$LLVM_INSTALL_DIR/bin/llvm-config - exists($$llvm_config) { - #message("llvm-config found, querying it for paths and version") - LLVM_LIBDIR = $$system($$llvm_config --libdir 2>/dev/null) - LLVM_INCLUDEPATH = $$system($$llvm_config --includedir 2>/dev/null) - output = $$system($$llvm_config --version 2>/dev/null) - LLVM_VERSION = $$extractVersion($$output) - } else { - #message("llvm-config not found, concluding paths and version from LLVM_INSTALL_DIR") - LLVM_INCLUDEPATH = $$LLVM_INSTALL_DIR/include - LLVM_LIBDIR = $$LLVM_INSTALL_DIR/lib - LLVM_VERSION = $$findLLVMVersionFromLibDir($$LLVM_LIBDIR) - } +LLVM_STATIC_LIBS = $$split(LLVM_STATIC_LIBS_STRING, " ") - LIBCLANG_MAIN_HEADER = $$LLVM_INCLUDEPATH/clang-c/Index.h - !exists($$LIBCLANG_MAIN_HEADER): error("Cannot find libclang's main header file, candidate: $$LIBCLANG_MAIN_HEADER") - !exists($$LLVM_LIBDIR): error("Cannot detect lib dir for clang, candidate: $$LLVM_LIBDIR") - clang_lib = $$findClangLibInLibDir($$LLVM_LIBDIR) - isEmpty(clang_lib): error("Cannot find Clang shared library in $$LLVM_LIBDIR") +LIBCLANG_MAIN_HEADER = $$LLVM_INCLUDEPATH/clang-c/Index.h +!exists($$LIBCLANG_MAIN_HEADER): error("Cannot find libclang's main header file, candidate: $$LIBCLANG_MAIN_HEADER") +!exists($$LLVM_LIBDIR): error("Cannot detect lib dir for clang, candidate: $$LLVM_LIBDIR") +CLANG_LIB = $$findClangLibInLibDir($$LLVM_LIBDIR) +isEmpty(CLANG_LIB): error("Cannot find Clang shared library in $$LLVM_LIBDIR") - !contains(QMAKE_DEFAULT_LIBDIRS, $$LLVM_LIBDIR): LLVM_LIBS = -L$${LLVM_LIBDIR} - LLVM_LIBS += -l$${clang_lib} - - contains(QMAKE_DEFAULT_INCDIRS, $$LLVM_INCLUDEPATH): LLVM_INCLUDEPATH = -} +!contains(QMAKE_DEFAULT_LIBDIRS, $$LLVM_LIBDIR): LIBCLANG_LIBS = -L$${LLVM_LIBDIR} +LIBCLANG_LIBS += $${CLANG_LIB} +!contains(QMAKE_DEFAULT_LIBDIRS, $$LLVM_LIBDIR): LIBTOOLING_LIBS = -L$${LLVM_LIBDIR} +LIBTOOLING_LIBS += $$CLANGTOOLING_LIBS $$LLVM_STATIC_LIBS +contains(QMAKE_DEFAULT_INCDIRS, $$LLVM_INCLUDEPATH): LLVM_INCLUDEPATH = isEmpty(LLVM_VERSION): error("Cannot determine clang version at $$LLVM_INSTALL_DIR") !versionIsAtLeast($$LLVM_VERSION, 3, 8, 0): { diff --git a/src/tools/clangbackend/clangbackend.pro b/src/tools/clangbackend/clangbackend.pro index c3210fedbf..5e03e24593 100644 --- a/src/tools/clangbackend/clangbackend.pro +++ b/src/tools/clangbackend/clangbackend.pro @@ -9,7 +9,7 @@ include(ipcsource/clangbackendclangipc-source.pri) QT += core network QT -= gui -LIBS += $$LLVM_LIBS +LIBS += $$LIBCLANG_LIBS INCLUDEPATH += $$LLVM_INCLUDEPATH SOURCES += clangbackendmain.cpp diff --git a/src/tools/clangbackend/clangbackendmain.cpp b/src/tools/clangbackend/clangbackendmain.cpp index 914df5c017..02014a3cf6 100644 --- a/src/tools/clangbackend/clangbackendmain.cpp +++ b/src/tools/clangbackend/clangbackendmain.cpp @@ -70,7 +70,7 @@ int main(int argc, char *argv[]) ClangCodeModelServer clangCodeModelServer; ConnectionServer<ClangCodeModelServer, ClangCodeModelClientProxy> connectionServer(connection); connectionServer.start(); - connectionServer.setClangCodeModelServer(&clangCodeModelServer); + connectionServer.setServer(&clangCodeModelServer); return application.exec(); } diff --git a/src/tools/clangrefactoringbackend/clangrefactoringbackend.pro b/src/tools/clangrefactoringbackend/clangrefactoringbackend.pro new file mode 100644 index 0000000000..64bdba68aa --- /dev/null +++ b/src/tools/clangrefactoringbackend/clangrefactoringbackend.pro @@ -0,0 +1,20 @@ +QTC_LIB_DEPENDS += \ + clangbackendipc + +include(../../qtcreatortool.pri) +include(../../shared/clang/clang_installation.pri) +include(source/clangrefactoringbackend-source.pri) + +QT += core network +QT -= gui + +LIBS += $$LIBTOOLING_LIBS +INCLUDEPATH += $$LLVM_INCLUDEPATH + +SOURCES += \ + clangrefactoringbackendmain.cpp + +unix { + !osx: QMAKE_LFLAGS += -Wl,-z,origin + !disable_external_rpath: QMAKE_LFLAGS += -Wl,-rpath,$$shell_quote($${LLVM_LIBDIR}) +} diff --git a/src/tools/clangrefactoringbackend/clangrefactoringbackendmain.cpp b/src/tools/clangrefactoringbackend/clangrefactoringbackendmain.cpp new file mode 100644 index 0000000000..fca9a0c9fc --- /dev/null +++ b/src/tools/clangrefactoringbackend/clangrefactoringbackendmain.cpp @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** 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 <QCommandLineParser> +#include <QCoreApplication> +#include <QLoggingCategory> + +#include <connectionserver.h> +#include <refactoringserver.h> +#include <refactoringclientproxy.h> + +using ClangBackEnd::RefactoringClientProxy; +using ClangBackEnd::RefactoringServer; +using ClangBackEnd::ConnectionServer; + +QString processArguments(QCoreApplication &application) +{ + QCommandLineParser parser; + parser.setApplicationDescription(QStringLiteral("Qt Creator Clang Refactoring Backend")); + parser.addHelpOption(); + parser.addVersionOption(); + parser.addPositionalArgument(QStringLiteral("connection"), QStringLiteral("Connection")); + + parser.process(application); + + if (parser.positionalArguments().isEmpty()) + parser.showHelp(1); + + return parser.positionalArguments().first(); +} + +int main(int argc, char *argv[]) +{ + //QLoggingCategory::setFilterRules(QStringLiteral("*.debug=false")); + + QCoreApplication::setOrganizationName(QStringLiteral("QtProject")); + QCoreApplication::setOrganizationDomain(QStringLiteral("qt-project.org")); + QCoreApplication::setApplicationName(QStringLiteral("ClangRefactoringBackend")); + QCoreApplication::setApplicationVersion(QStringLiteral("0.1.0")); + + QCoreApplication application(argc, argv); + + const QString connection = processArguments(application); + + RefactoringServer clangCodeModelServer; + ConnectionServer<RefactoringServer, RefactoringClientProxy> connectionServer(connection); + connectionServer.start(); + connectionServer.setServer(&clangCodeModelServer); + + + return application.exec(); +} + + diff --git a/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri b/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri new file mode 100644 index 0000000000..6bd6f7480f --- /dev/null +++ b/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri @@ -0,0 +1,23 @@ +INCLUDEPATH += $$PWD + +SOURCES += \ + $$PWD/refactoringcompilationdatabase.cpp \ + $$PWD/symbolfinder.cpp \ + $$PWD/symbollocationfinderaction.cpp \ + $$PWD/refactoringserver.cpp \ + $$PWD/sourcefilecallbacks.cpp \ + $$PWD/macropreprocessorcallbacks.cpp \ + $$PWD/findusrforcursoraction.cpp + +HEADERS += \ + $$PWD/refactoringcompilationdatabase.h \ + $$PWD/clangrefactoringbackend_global.h \ + $$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 diff --git a/src/tools/clangrefactoringbackend/source/clangrefactoringbackend_global.h b/src/tools/clangrefactoringbackend/source/clangrefactoringbackend_global.h new file mode 100644 index 0000000000..fc286b8780 --- /dev/null +++ b/src/tools/clangrefactoringbackend/source/clangrefactoringbackend_global.h @@ -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. +** +****************************************************************************/ + +#pragma once + +namespace llvm { +template <typename T, unsigned N> +class SmallVector; +} + +namespace ClangBackEnd { + +using USRName = llvm::SmallVector<char, 128>; + +// use std::filesystem::path if it is supported by all compilers +#ifdef WIN32 +const char nativeSeperator = '\\'; +#else +const char nativeSeperator = '/'; +#endif + +} diff --git a/src/tools/clangrefactoringbackend/source/findcursorusr.h b/src/tools/clangrefactoringbackend/source/findcursorusr.h new file mode 100644 index 0000000000..563f1d5816 --- /dev/null +++ b/src/tools/clangrefactoringbackend/source/findcursorusr.h @@ -0,0 +1,198 @@ +/**************************************************************************** +** +** 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/AST/AST.h> +#include <clang/AST/ASTContext.h> +#include <clang/AST/RecursiveASTVisitor.h> +#include <clang/Index/USRGeneration.h> +#include <llvm/ADT/SmallVector.h> + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +#include <vector> + +namespace ClangBackEnd { + +class FindNamedDeclarationASTVisitor : public clang::RecursiveASTVisitor<FindNamedDeclarationASTVisitor> +{ +public: + explicit FindNamedDeclarationASTVisitor(const clang::SourceManager &sourceManager, + const clang::SourceLocation cursorSourceLocation) + : sourceManager(sourceManager), + cursorSourceLocation(cursorSourceLocation) + { + } + + bool shouldVisitTemplateInstantiations() const + { + return true; + } + + bool shouldVisitImplicitCode() const + { + return true; + } + + bool VisitNamedDecl(const clang::NamedDecl *declaration) + { + auto name = declaration->getNameAsString(); + + return setResultIfCursorIsInBetween(declaration, declaration->getLocation(), + declaration->getNameAsString().length()); + } + + bool VisitDeclRefExpr(const clang::DeclRefExpr *expression) + { + if (!iterateNestedNameSpecifierLocation(expression->getQualifierLoc())) + return false; + + const auto *Decl = expression->getFoundDecl(); + return setResultIfCursorIsInBetween(Decl, expression->getLocation(), + Decl->getNameAsString().length()); + } + + bool VisitMemberExpr(const clang::MemberExpr *Expr) + { + const auto *Decl = Expr->getFoundDecl().getDecl(); + return setResultIfCursorIsInBetween(Decl, Expr->getMemberLoc(), + Decl->getNameAsString().length()); + } + + std::vector<const clang::NamedDecl*> takeNamedDecl() + { + return std::move(namedDeclarations); + } + +private: + bool canSetResult(const clang::NamedDecl *declaration, + clang::SourceLocation location) + { + return declaration + && !setResultIfCursorIsInBetween(declaration, + location, + declaration->getNameAsString().length()); + } + + bool iterateNestedNameSpecifierLocation(clang::NestedNameSpecifierLoc nameLocation) { + while (nameLocation) { + const auto *declaration = nameLocation.getNestedNameSpecifier()->getAsNamespace(); + if (canSetResult(declaration, nameLocation.getLocalBeginLoc())) + return false; + + nameLocation = nameLocation.getPrefix(); + } + + return true; + } + + bool isValidLocationWithCursorInside(clang::SourceLocation startLocation, + clang::SourceLocation endLocation) + { + return startLocation.isValid() + && startLocation.isFileID() + && endLocation.isValid() + && endLocation.isFileID() + && isCursorLocationBetween(startLocation, endLocation); + } + + bool setResultIfCursorIsInBetween(const clang::NamedDecl *declaration, + clang::SourceLocation startLocation, + clang::SourceLocation endLocation) + { + bool isValid = isValidLocationWithCursorInside(startLocation, endLocation); + + if (isValid) + namedDeclarations.push_back(declaration); + + return !isValid; + } + + bool setResultIfCursorIsInBetween(const clang::NamedDecl *declaration, + clang::SourceLocation location, + uint offset) { + return offset == 0 + || setResultIfCursorIsInBetween(declaration, location, location.getLocWithOffset(offset - 1)); + } + + bool isCursorLocationBetween(const clang::SourceLocation startLocation, + const clang::SourceLocation endLocation) + { + return cursorSourceLocation == startLocation + || cursorSourceLocation == endLocation + || (sourceManager.isBeforeInTranslationUnit(startLocation, cursorSourceLocation) + && sourceManager.isBeforeInTranslationUnit(cursorSourceLocation, endLocation)); + } + + std::vector<const clang::NamedDecl*> namedDeclarations; + const clang::SourceManager &sourceManager; + const clang::SourceLocation cursorSourceLocation; // The location to find the NamedDecl. +}; + +inline +std::vector<const clang::NamedDecl *> namedDeclarationsAt(const clang::ASTContext &Context, + const clang::SourceLocation cursorSourceLocation) +{ + const auto &sourceManager = Context.getSourceManager(); + const auto currentFile = sourceManager.getFilename(cursorSourceLocation); + + FindNamedDeclarationASTVisitor visitor(sourceManager, cursorSourceLocation); + + auto declarations = Context.getTranslationUnitDecl()->decls(); + for (auto ¤tDeclation : declarations) { + const auto &fileLocation = currentDeclation->getLocStart(); + const auto &fileName = sourceManager.getFilename(fileLocation); + if (fileName == currentFile) { + visitor.TraverseDecl(currentDeclation); + const auto &namedDeclarations = visitor.takeNamedDecl(); + + if (!namedDeclarations.empty()) + return namedDeclarations; + } + } + + return std::vector<const clang::NamedDecl *>(); +} + +inline +USRName USROfDeclaration(const clang::Decl *declaration) +{ + USRName buffer; + + if (declaration == nullptr || clang::index::generateUSRForDecl(declaration, buffer)) + return buffer; + + return buffer; +} + +} // namespace ClangBackend diff --git a/src/tools/clangrefactoringbackend/source/findlocationsofusrs.h b/src/tools/clangrefactoringbackend/source/findlocationsofusrs.h new file mode 100644 index 0000000000..64066ddf3d --- /dev/null +++ b/src/tools/clangrefactoringbackend/source/findlocationsofusrs.h @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** 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 "findcursorusr.h" + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +#include <clang/AST/ASTContext.h> +#include <clang/AST/RecursiveASTVisitor.h> +#include <clang/Basic/SourceLocation.h> +#include <clang/Index/USRGeneration.h> +#include <llvm/ADT/SmallVector.h> + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +#include <vector> + +namespace ClangBackEnd { + +class FindLocationsOfUSRsASTVisitor : public clang::RecursiveASTVisitor<FindLocationsOfUSRsASTVisitor> +{ +public: + explicit FindLocationsOfUSRsASTVisitor(std::vector<USRName> &unifiedSymbolResolutions) + : unifiedSymbolResolutions(unifiedSymbolResolutions) + { + std::sort(unifiedSymbolResolutions.begin(), unifiedSymbolResolutions.end()); + } + + bool VisitNamedDecl(const clang::NamedDecl *declaration) { + auto declarationUSR = USROfDeclaration(declaration); + + if (containsUSR(declarationUSR)) + LocationsFound.push_back(declaration->getLocation()); + + return true; + } + + bool VisitDeclRefExpr(const clang::DeclRefExpr *expression) { + const auto *declaration = expression->getFoundDecl(); + + iterateNestedNameSpecifierLocation(expression->getQualifierLoc()); + auto declarationUSR = USROfDeclaration(declaration); + + if (containsUSR(declarationUSR)) + LocationsFound.push_back(expression->getLocation()); + + return true; + } + + bool VisitMemberExpr(const clang::MemberExpr *expression) { + const auto *declaration = expression->getFoundDecl().getDecl(); + auto declarationUSR = USROfDeclaration(declaration); + + if (containsUSR(declarationUSR)) + LocationsFound.push_back(expression->getMemberLoc()); + + return true; + } + + bool shouldVisitTemplateInstantiations() const + { + return true; + } + + std::vector<clang::SourceLocation> takeFoundLocations() const { + return std::move(LocationsFound); + } + +private: + void iterateNestedNameSpecifierLocation(clang::NestedNameSpecifierLoc nameLocation) { + while (nameLocation) { + const auto *declaration = nameLocation.getNestedNameSpecifier()->getAsNamespace(); + if (declaration && containsUSR(USROfDeclaration(declaration))) + LocationsFound.push_back(nameLocation.getLocalBeginLoc()); + + nameLocation = nameLocation.getPrefix(); + } + } + + bool containsUSR(const USRName &unifiedSymbolResolution) + { + return std::binary_search(unifiedSymbolResolutions.cbegin(), + unifiedSymbolResolutions.cend(), + unifiedSymbolResolution); + } + +private: + + // All the locations of the USR were found. + std::vector<USRName> unifiedSymbolResolutions; + std::vector<clang::SourceLocation> LocationsFound; +}; + +inline +std::vector<clang::SourceLocation> takeLocationsOfUSRs(std::vector<USRName> &unifiedSymbolResolutions, + clang::Decl *declartation) +{ + FindLocationsOfUSRsASTVisitor visitor(unifiedSymbolResolutions); + + visitor.TraverseDecl(declartation); + + return visitor.takeFoundLocations(); +} + +} // namespace ClangBackend diff --git a/src/tools/clangrefactoringbackend/source/findusrforcursoraction.cpp b/src/tools/clangrefactoringbackend/source/findusrforcursoraction.cpp new file mode 100644 index 0000000000..2ea0d1353d --- /dev/null +++ b/src/tools/clangrefactoringbackend/source/findusrforcursoraction.cpp @@ -0,0 +1,140 @@ +/**************************************************************************** +** +** 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 "findusrforcursoraction.h" + +#include "findcursorusr.h" + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +#include <clang/AST/AST.h> +#include <clang/AST/ASTConsumer.h> +#include <clang/AST/ASTContext.h> + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +#include <algorithm> +#include <vector> + +namespace ClangBackEnd { + +namespace { + +std::vector<USRName> collectConstructorUnifiedSymbolResolutions(const clang::CXXRecordDecl *declarations) +{ + std::vector<USRName> unifiedSymbolResolutions; + + const auto constructorDeclarations = declarations->getDefinition()->ctors(); + + std::transform(constructorDeclarations.begin(), + constructorDeclarations.end(), + std::back_inserter(unifiedSymbolResolutions), + USROfDeclaration); + + return unifiedSymbolResolutions; +} + +void addUnifiedSymbolResolutionsForDeclaration(const std::vector<const clang::NamedDecl *> &declarations, + std::vector<USRName> &usrs) +{ + + std::transform(declarations.begin(), + declarations.end(), + std::back_inserter(usrs), + [&] (const clang::NamedDecl *declaration) { + return USROfDeclaration(declaration); + }); +} + +} + +class FindDeclarationsConsumer : public clang::ASTConsumer +{ +public: + FindDeclarationsConsumer(Utils::SmallString &symbolName, + std::vector<USRName> &unifiedSymbolResolutions, + uint line, + uint column) + : symbolName(symbolName), + unifiedSymbolResolutions(unifiedSymbolResolutions), + line(line), + column(column) + { + } + + void HandleTranslationUnit(clang::ASTContext &astContext) override { + const auto &sourceManager = astContext.getSourceManager(); + const auto cursorSourceLocation = sourceManager.translateLineCol(sourceManager.getMainFileID(), + line, + column); + + if (cursorSourceLocation.isValid()) + collectUnifiedSymbolResoltions(astContext, cursorSourceLocation); + } + + void collectUnifiedSymbolResoltions(clang::ASTContext &astContext, + const clang::SourceLocation &cursorSourceLocation) + { + const auto foundDeclarations = namedDeclarationsAt(astContext, cursorSourceLocation); + + if (!foundDeclarations.empty()) { + const auto firstFoundDeclaration = foundDeclarations.front(); + + if (const auto *constructorDecl = clang::dyn_cast<clang::CXXConstructorDecl>(firstFoundDeclaration)) { + const clang::CXXRecordDecl *foundDeclarationParent = constructorDecl->getParent(); + unifiedSymbolResolutions = collectConstructorUnifiedSymbolResolutions(foundDeclarationParent); + } else if (const auto *destructorDecl = clang::dyn_cast<clang::CXXDestructorDecl>(firstFoundDeclaration)) { + const clang::CXXRecordDecl *foundDeclarationParent = destructorDecl->getParent(); + unifiedSymbolResolutions = collectConstructorUnifiedSymbolResolutions(foundDeclarationParent); + } else if (const auto *recordDeclaration = clang::dyn_cast<clang::CXXRecordDecl>(firstFoundDeclaration)) { + unifiedSymbolResolutions = collectConstructorUnifiedSymbolResolutions(recordDeclaration); + } + + addUnifiedSymbolResolutionsForDeclaration(foundDeclarations, unifiedSymbolResolutions); + symbolName = firstFoundDeclaration->getNameAsString(); + } + } + +private: + Utils::SmallString &symbolName; + std::vector<USRName> &unifiedSymbolResolutions; + uint line; + uint column; +}; + +std::unique_ptr<clang::ASTConsumer> +USRFindingAction::newASTConsumer() { + std::unique_ptr<FindDeclarationsConsumer> Consumer( + new FindDeclarationsConsumer(symbolName, unifiedSymbolResolutions_, line, column)); + + return std::move(Consumer); +} + +} // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/findusrforcursoraction.h b/src/tools/clangrefactoringbackend/source/findusrforcursoraction.h new file mode 100644 index 0000000000..0bdd2bb4df --- /dev/null +++ b/src/tools/clangrefactoringbackend/source/findusrforcursoraction.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** 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 "clangrefactoringbackend_global.h" + +#include <utils/smallstring.h> + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +#include "clang/Frontend/FrontendAction.h" + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +namespace clang { +class ASTConsumer; +class CompilerInstance; +class NamedDecl; +} + +namespace ClangBackEnd { + +class USRFindingAction +{ +public: + USRFindingAction(uint line, uint column) + : line(line), + column(column) + { + } + + std::unique_ptr<clang::ASTConsumer> newASTConsumer(); + + std::string takeSymbolName() + { + return std::move(symbolName); + } + + std::vector<USRName> takeUnifiedSymbolResolutions() + { + return std::move(unifiedSymbolResolutions_); + } + +private: + Utils::SmallString symbolName; + std::vector<USRName> unifiedSymbolResolutions_; + uint line; + uint column; +}; + +} // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/macropreprocessorcallbacks.cpp b/src/tools/clangrefactoringbackend/source/macropreprocessorcallbacks.cpp new file mode 100644 index 0000000000..c0015f867d --- /dev/null +++ b/src/tools/clangrefactoringbackend/source/macropreprocessorcallbacks.cpp @@ -0,0 +1,43 @@ +/**************************************************************************** +** +** 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 "macropreprocessorcallbacks.h" + +namespace ClangBackEnd { + +MacroPreprocessorCallbacks::MacroPreprocessorCallbacks(SourceLocationsContainer &sourceLocationsContainer, + Utils::SmallString &symbolName, + clang::Preprocessor &preprocessor, + uint line, + uint column) + : sourceLocationsContainer(sourceLocationsContainer), + symbolName(symbolName), + preprocessor(preprocessor), + line(line), + column(column) +{ +} + +} // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/macropreprocessorcallbacks.h b/src/tools/clangrefactoringbackend/source/macropreprocessorcallbacks.h new file mode 100644 index 0000000000..cbc1edc9fd --- /dev/null +++ b/src/tools/clangrefactoringbackend/source/macropreprocessorcallbacks.h @@ -0,0 +1,192 @@ +/**************************************************************************** +** +** 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 "sourcelocationsutils.h" + +#include <sourcelocationscontainer.h> + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +#include <clang/Basic/SourceManager.h> +#include <clang/Lex/PPCallbacks.h> +#include <clang/Lex/Preprocessor.h> +#include <clang/Lex/MacroInfo.h> + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +#include <QDebug> + +namespace ClangBackEnd { + +struct MacroDirectiveToken +{ + MacroDirectiveToken(const clang::MacroDirective *macroDirective, + const clang::Token &token) + : macroDirective(macroDirective), + token(token) + {} + + const clang::MacroDirective *macroDirective; + const clang::Token token; +}; + +class MacroPreprocessorCallbacks : public clang::PPCallbacks +{ +public: + MacroPreprocessorCallbacks(SourceLocationsContainer &sourceLocationsContainer, + Utils::SmallString &symbolName, + clang::Preprocessor &preprocessor, + uint line, + uint column); + + void FileChanged(clang::SourceLocation location, + FileChangeReason reason, + clang::SrcMgr::CharacteristicKind /*fileType*/, + clang::FileID /*previousFileIdentifier*/) final + { + if (!isMainFileEntered) { + updateLocations(); + updateIsMainFileEntered(location, reason); + } + } + + void MacroDefined(const clang::Token &token, const clang::MacroDirective *macroDirective) final + { + if (isInMainFile(token)) { + if (includesCursorPosition(token)) { + sourceLocations.push_back(token.getLocation()); + cursorMacroDirective = macroDirective; + symbolName = Utils::SmallString(token.getIdentifierInfo()->getNameStart(), + token.getIdentifierInfo()->getLength()); + } + } + } + + void MacroExpands(const clang::Token &token, + const clang::MacroDefinition ¯oDefinition, + clang::SourceRange /*sourceRange*/, + const clang::MacroArgs * /*macroArguments*/) final + { + if (includesCursorPosition(token)) { + appendSourceLocations(token, macroDefinition); + cursorMacroDirective = macroDefinition.getLocalDirective(); + symbolName = Utils::SmallString(token.getIdentifierInfo()->getNameStart(), + token.getIdentifierInfo()->getLength()); + } else if (isCurrentTokenExpansion(macroDefinition)) { + sourceLocations.push_back(token.getLocation()); + } else if (isBeforeCursorSourceLocation()) { + preCursorMacroDirectiveTokens.emplace_back(macroDefinition.getLocalDirective(), token); + } + } + + void EndOfMainFile() final + { + appendSourceLocationsToSourceLocationsContainer(sourceLocationsContainer, + sourceLocations, + sourceManager()); + } + +private: + void appendSourceLocations(const clang::Token &token, + const clang::MacroDefinition ¯oDefinition) + { + sourceLocations.push_back(macroDefinition.getLocalDirective()->getLocation()); + for (const auto ¯oDirectiveToken : preCursorMacroDirectiveTokens) { + if (macroDirectiveToken.macroDirective == macroDefinition.getLocalDirective()) + sourceLocations.push_back(macroDirectiveToken.token.getLocation()); + } + sourceLocations.push_back(token.getLocation()); + } + + void updateLocations() + { + if (mainFileSourceLocation.isInvalid()) { + mainFileSourceLocation = sourceManager().getLocForStartOfFile(sourceManager().getMainFileID()); + cursorSourceLocation = sourceManager().translateLineCol(sourceManager().getMainFileID(), + line, + column); + } + } + + void updateIsMainFileEntered(clang::SourceLocation location, FileChangeReason reason) + { + if (location == mainFileSourceLocation && reason == PPCallbacks::EnterFile) + isMainFileEntered = true; + } + + const clang::SourceManager &sourceManager() const + { + return preprocessor.getSourceManager(); + } + + bool isInMainFile(const clang::Token &token) + { + return isMainFileEntered && sourceManager().isWrittenInMainFile(token.getLocation()); + } + + bool includesCursorPosition(const clang::Token &token) + { + auto start = token.getLocation(); + auto end = token.getEndLoc(); + + return cursorSourceLocation == start + || cursorSourceLocation == end + || (sourceManager().isBeforeInTranslationUnit(start, cursorSourceLocation) && + sourceManager().isBeforeInTranslationUnit(cursorSourceLocation, end)); + } + + bool isCurrentTokenExpansion(const clang::MacroDefinition ¯oDefinition) + { + return cursorMacroDirective + && cursorMacroDirective == macroDefinition.getLocalDirective(); + } + + bool isBeforeCursorSourceLocation() const + { + return !cursorMacroDirective; + } + +private: + std::vector<clang::SourceLocation> sourceLocations; + std::vector<MacroDirectiveToken> preCursorMacroDirectiveTokens; + SourceLocationsContainer &sourceLocationsContainer; + Utils::SmallString &symbolName; + clang::Preprocessor &preprocessor; + const clang::MacroDirective *cursorMacroDirective = nullptr; + clang::SourceLocation mainFileSourceLocation; + clang::SourceLocation cursorSourceLocation; + uint line; + uint column; + bool isMainFileEntered = false; +}; + +} // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/refactoringcompilationdatabase.cpp b/src/tools/clangrefactoringbackend/source/refactoringcompilationdatabase.cpp new file mode 100644 index 0000000000..555a50f96b --- /dev/null +++ b/src/tools/clangrefactoringbackend/source/refactoringcompilationdatabase.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. +** +****************************************************************************/ + +#include "refactoringcompilationdatabase.h" + +#include "clangrefactoringbackend_global.h" + +namespace ClangBackEnd { + +RefactoringCompilationDatabase::RefactoringCompilationDatabase() +{ +} + +namespace { + +std::string concatFilePath(const clang::tooling::CompileCommand &compileCommand) +{ + return compileCommand.Directory + nativeSeperator + compileCommand.Filename; +} +} + +std::vector<clang::tooling::CompileCommand> +RefactoringCompilationDatabase::getCompileCommands(llvm::StringRef filePath) const +{ + std::vector<clang::tooling::CompileCommand> foundCommands; + + std::copy_if(compileCommands.begin(), + compileCommands.end(), + std::back_inserter(foundCommands), + [&] (const clang::tooling::CompileCommand &compileCommand) { + return filePath == concatFilePath(compileCommand); + }); + + return foundCommands; +} + +std::vector<std::string> +RefactoringCompilationDatabase::getAllFiles() const +{ + std::vector<std::string> filePaths; + filePaths.reserve(compileCommands.size()); + + std::transform(compileCommands.begin(), + compileCommands.end(), + std::back_inserter(filePaths), + [&] (const clang::tooling::CompileCommand &compileCommand) { + return concatFilePath(compileCommand); + }); + + return filePaths; +} + +std::vector<clang::tooling::CompileCommand> +RefactoringCompilationDatabase::getAllCompileCommands() const +{ + return compileCommands; +} + +void RefactoringCompilationDatabase::addFile(const std::string &directory, + const std::string &fileName, + const std::vector<std::string> &commandLine) +{ + compileCommands.emplace_back(directory, fileName, commandLine); +} + +} // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/refactoringcompilationdatabase.h b/src/tools/clangrefactoringbackend/source/refactoringcompilationdatabase.h new file mode 100644 index 0000000000..8528c10b27 --- /dev/null +++ b/src/tools/clangrefactoringbackend/source/refactoringcompilationdatabase.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +#ifndef CLANGBACKEND_REFACTORINGCOMPILATIONDATABASE_H +#define CLANGBACKEND_REFACTORINGCOMPILATIONDATABASE_H + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +#include "clang/Tooling/CompilationDatabase.h" + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +namespace ClangBackEnd { + + +class RefactoringCompilationDatabase : public clang::tooling::CompilationDatabase +{ +public: + RefactoringCompilationDatabase(); + + std::vector<clang::tooling::CompileCommand> getCompileCommands(llvm::StringRef filePath) const override; + std::vector<std::string> getAllFiles() const override; + std::vector<clang::tooling::CompileCommand> getAllCompileCommands() const override; + + void addFile(const std::string &directory, + const std::string &fileName, + const std::vector<std::string> &commandLine); + +private: + std::vector<clang::tooling::CompileCommand> compileCommands; +}; + +} // namespace ClangBackEnd + +#endif // CLANGBACKEND_REFACTORINGCOMPILATIONDATABASE_H diff --git a/src/tools/clangrefactoringbackend/source/refactoringserver.cpp b/src/tools/clangrefactoringbackend/source/refactoringserver.cpp new file mode 100644 index 0000000000..d4725808b0 --- /dev/null +++ b/src/tools/clangrefactoringbackend/source/refactoringserver.cpp @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** 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 "refactoringserver.h" + +#include "symbolfinder.h" + +#include <refactoringclientinterface.h> +#include <requestsourcelocationforrenamingmessage.h> +#include <sourcelocationsforrenamingmessage.h> + +#include <QCoreApplication> + +namespace ClangBackEnd { + +RefactoringServer::RefactoringServer() +{ + +} + +void RefactoringServer::end() +{ + QCoreApplication::exit(); +} + +void RefactoringServer::requestSourceLocationsForRenamingMessage(RequestSourceLocationsForRenamingMessage &&message) +{ + SymbolFinder symbolFinder(message.line(), message.column()); + + symbolFinder.addFile(message.filePath().directory(), + message.filePath().name(), + message.unsavedContent(), + message.commandLine()); + + symbolFinder.findSymbol(); + + client()->sourceLocationsForRenamingMessage(SourceLocationsForRenamingMessage( + symbolFinder.takeSymbolName(), + symbolFinder.takeSourceLocations(), + message.textDocumentRevision())); +} + +} // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/refactoringserver.h b/src/tools/clangrefactoringbackend/source/refactoringserver.h new file mode 100644 index 0000000000..883a385a95 --- /dev/null +++ b/src/tools/clangrefactoringbackend/source/refactoringserver.h @@ -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. +** +****************************************************************************/ + +#ifndef CLANGBACKEND_REFACTORINGSERVER_H +#define CLANGBACKEND_REFACTORINGSERVER_H + +#include <refactoringserverinterface.h> + +namespace ClangBackEnd { + +class RefactoringServer : public RefactoringServerInterface +{ +public: + RefactoringServer(); + + void end() override; + void requestSourceLocationsForRenamingMessage(RequestSourceLocationsForRenamingMessage &&message) override; +}; + +} // namespace ClangBackEnd + +#endif // CLANGBACKEND_REFACTORINGSERVER_H diff --git a/src/tools/clangrefactoringbackend/source/sourcefilecallbacks.cpp b/src/tools/clangrefactoringbackend/source/sourcefilecallbacks.cpp new file mode 100644 index 0000000000..3963fbb6f5 --- /dev/null +++ b/src/tools/clangrefactoringbackend/source/sourcefilecallbacks.cpp @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** 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 "sourcefilecallbacks.h" + +#include "macropreprocessorcallbacks.h" + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +#include <clang/Frontend/CompilerInstance.h> +#include <clang/Lex/Preprocessor.h> + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +#include <memory> + +namespace ClangBackEnd { + +SourceFileCallbacks::SourceFileCallbacks(uint line, uint column) + : line(line), + column(column) +{ +} + +bool SourceFileCallbacks::handleBeginSource(clang::CompilerInstance &compilerInstance, llvm::StringRef /*fileName*/) +{ + auto &preprocessor = compilerInstance.getPreprocessor(); + + macroPreprocessorCallbacks = new MacroPreprocessorCallbacks(sourceLocationsContainer, + symbolName, + preprocessor, + line, + column); + + preprocessor.addPPCallbacks(std::unique_ptr<clang::PPCallbacks>(macroPreprocessorCallbacks)); + + return true; +} + +SourceLocationsContainer SourceFileCallbacks::takeSourceLocations() +{ + return std::move(sourceLocationsContainer); +} + +Utils::SmallString SourceFileCallbacks::takeSymbolName() +{ + return std::move(symbolName); +} + +bool SourceFileCallbacks::hasSourceLocations() const +{ + return sourceLocationsContainer.hasContent(); +} + + +} // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/sourcefilecallbacks.h b/src/tools/clangrefactoringbackend/source/sourcefilecallbacks.h new file mode 100644 index 0000000000..9a8b1cfe4b --- /dev/null +++ b/src/tools/clangrefactoringbackend/source/sourcefilecallbacks.h @@ -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. +** +****************************************************************************/ + +#pragma once + +#include <sourcelocationscontainer.h> + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +#include <clang/Tooling/Tooling.h> + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +namespace llvm { +class StringRef; +} + +namespace clang { +class CompilerInstance; +} + +namespace ClangBackEnd { + +class MacroPreprocessorCallbacks; +class SourceLocationsContainer; + +class SourceFileCallbacks : public clang::tooling::SourceFileCallbacks +{ +public: + SourceFileCallbacks(uint line, uint column); + + bool handleBeginSource(clang::CompilerInstance &compilerInstance, + llvm::StringRef fileName) override; + + SourceLocationsContainer takeSourceLocations(); + Utils::SmallString takeSymbolName(); + + bool hasSourceLocations() const; + +private: + SourceLocationsContainer sourceLocationsContainer; + Utils::SmallString symbolName; + MacroPreprocessorCallbacks *macroPreprocessorCallbacks; + uint line; + uint column; +}; + +} // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/sourcelocationsutils.h b/src/tools/clangrefactoringbackend/source/sourcelocationsutils.h new file mode 100644 index 0000000000..c2ae107f67 --- /dev/null +++ b/src/tools/clangrefactoringbackend/source/sourcelocationsutils.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** 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 <sourcelocationscontainer.h> + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +#include <clang/Basic/SourceManager.h> +#include <llvm/Support/FileSystem.h> +#include <llvm/Support/FileUtilities.h> + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +namespace ClangBackEnd { + +inline +Utils::SmallString absolutePath(const char *path) +{ + llvm::SmallString<256> absolutePath(path); + + if (!llvm::sys::path::is_absolute(absolutePath)) + llvm::sys::fs::make_absolute(absolutePath); + + return Utils::SmallString(absolutePath.begin(), absolutePath.end()); +} + +inline +void appendSourceLocationsToSourceLocationsContainer( + ClangBackEnd::SourceLocationsContainer &sourceLocationsContainer, + const std::vector<clang::SourceLocation> &sourceLocations, + const clang::SourceManager &sourceManager) +{ + sourceLocationsContainer.reserve(sourceLocations.size()); + + for (const auto &sourceLocation : sourceLocations) { + clang::FullSourceLoc fullSourceLocation(sourceLocation, sourceManager); + auto fileId = fullSourceLocation.getFileID(); + auto fileEntry = sourceManager.getFileEntryForID(fileId); + auto fileName = fileEntry->getName(); + auto fileDirectoryPath = absolutePath(fileEntry->getDir()->getName()); + + sourceLocationsContainer.insertFilePath(fileId.getHashValue(), + std::move(fileDirectoryPath), + fileName); + sourceLocationsContainer.insertSourceLocation(fileId.getHashValue(), + fullSourceLocation.getSpellingLineNumber(), + fullSourceLocation.getSpellingColumnNumber()); + } +} + +} // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/symbolfinder.cpp b/src/tools/clangrefactoringbackend/source/symbolfinder.cpp new file mode 100644 index 0000000000..47256b7549 --- /dev/null +++ b/src/tools/clangrefactoringbackend/source/symbolfinder.cpp @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** 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 "symbolfinder.h" + +#include "refactoringcompilationdatabase.h" +#include "sourcefilecallbacks.h" +#include "symbollocationfinderaction.h" + +namespace ClangBackEnd { + +SymbolFinder::SymbolFinder(uint line, uint column) + : usrFindingAction(line, column), + sourceFileCallbacks(line, column) +{ +} + +namespace { + +// use std::filesystem::path if it is supported by all compilers + +std::string toNativePath(std::string &&path) +{ +#ifdef WIN32 + std::transform(path.begin(), path.end(), path.begin(), [] (char sign) { + return sign == '/' ? '\\' : sign; + }); +#endif + + return std::move(path); +} +} + +void SymbolFinder::addFile(std::string &&directory, + std::string &&fileName, + std::string &&content, + std::vector<std::string> &&commandLine) +{ + fileContents.emplace_back(toNativePath(std::move(directory)), + std::move(fileName), + std::move(content), + std::move(commandLine)); +} + +void SymbolFinder::findSymbol() +{ + RefactoringCompilationDatabase compilationDatabase; + + for (auto &&fileContent : fileContents) + compilationDatabase.addFile(fileContent.directory, fileContent.fileName, fileContent.commandLine); + + std::vector<std::string> files; + + for (auto &&fileContent : fileContents) + files.push_back(fileContent.filePath); + + clang::tooling::ClangTool tool(compilationDatabase, files); + + for (auto &&fileContent : fileContents) { + if (!fileContent.content.empty()) + tool.mapVirtualFile(fileContent.filePath, fileContent.content); + } + + tool.run(clang::tooling::newFrontendActionFactory(&usrFindingAction, &sourceFileCallbacks).get()); + + if (sourceFileCallbacks.hasSourceLocations()) { + sourceLocations_ = sourceFileCallbacks.takeSourceLocations(); + symbolName = sourceFileCallbacks.takeSymbolName(); + } else { + symbolLocationFinderAction.setUnifiedSymbolResolutions(usrFindingAction.takeUnifiedSymbolResolutions()); + + tool.run(clang::tooling::newFrontendActionFactory(&symbolLocationFinderAction).get()); + + sourceLocations_ = symbolLocationFinderAction.takeSourceLocations(); + symbolName = usrFindingAction.takeSymbolName(); + } +} + +Utils::SmallString SymbolFinder::takeSymbolName() +{ + return std::move(symbolName); +} + +const std::vector<USRName> &SymbolFinder::unifiedSymbolResolutions() +{ + return symbolLocationFinderAction.unifiedSymbolResolutions(); +} + +const SourceLocationsContainer &SymbolFinder::sourceLocations() const +{ + return sourceLocations_; +} + +SourceLocationsContainer SymbolFinder::takeSourceLocations() +{ + return std::move(sourceLocations_); +} + +} // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/symbolfinder.h b/src/tools/clangrefactoringbackend/source/symbolfinder.h new file mode 100644 index 0000000000..94653409db --- /dev/null +++ b/src/tools/clangrefactoringbackend/source/symbolfinder.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** 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 "findusrforcursoraction.h" +#include "symbollocationfinderaction.h" +#include "sourcefilecallbacks.h" + +#include <sourcelocationscontainer.h> + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +#include "clang/Tooling/Refactoring.h" + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +#include <string> +#include <vector> + +namespace ClangBackEnd { + +struct FileContent +{ + FileContent(const std::string &directory, + const std::string &fileName, + const std::string &content, + const std::vector<std::string> &commandLine) + : directory(directory), + fileName(fileName), + filePath(directory + nativeSeperator + fileName), + content(content), + commandLine(commandLine) + {} + + std::string directory; + std::string fileName; + std::string filePath; + std::string content; + std::vector<std::string> commandLine; +}; + +class SymbolFinder +{ +public: + SymbolFinder(uint line, uint column); + + void addFile(std::string &&directory, + std::string &&fileName, + std::string &&content, + std::vector<std::string> &&commandLine); + + + void findSymbol(); + + Utils::SmallString takeSymbolName(); + const std::vector<USRName> &unifiedSymbolResolutions(); + const ClangBackEnd::SourceLocationsContainer &sourceLocations() const; + ClangBackEnd::SourceLocationsContainer takeSourceLocations(); + +private: + Utils::SmallString symbolName; + USRFindingAction usrFindingAction; + SymbolLocationFinderAction symbolLocationFinderAction; + SourceFileCallbacks sourceFileCallbacks; + std::vector<FileContent> fileContents; + ClangBackEnd::SourceLocationsContainer sourceLocations_; +}; + +} // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/symbollocationfinderaction.cpp b/src/tools/clangrefactoringbackend/source/symbollocationfinderaction.cpp new file mode 100644 index 0000000000..c5aba6ca90 --- /dev/null +++ b/src/tools/clangrefactoringbackend/source/symbollocationfinderaction.cpp @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** 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 "symbollocationfinderaction.h" + +#include "sourcelocationsutils.h" +#include "findlocationsofusrs.h" + +#include <clang/AST/ASTConsumer.h> +#include <clang/AST/ASTContext.h> + +#include <memory> + +namespace ClangBackEnd { + +class FindingSymbolsASTConsumer : public clang::ASTConsumer +{ +public: + FindingSymbolsASTConsumer(std::vector<USRName> &unifiedSymbolResolutions) + : unifiedSymbolResolutions(unifiedSymbolResolutions) + { + } + + void HandleTranslationUnit(clang::ASTContext &context) override + { + std::vector<clang::SourceLocation> sourceLocations; + + + auto &&sourceLocationsOfUsr = takeLocationsOfUSRs(unifiedSymbolResolutions, context.getTranslationUnitDecl()); + sourceLocations.insert(sourceLocations.end(), + sourceLocationsOfUsr.begin(), + sourceLocationsOfUsr.end()); + + + std::sort(sourceLocations.begin(), sourceLocations.end()); + auto newEnd = std::unique(sourceLocations.begin(), sourceLocations.end()); + sourceLocations.erase(newEnd, sourceLocations.end()); + + updateSourceLocations(sourceLocations, context.getSourceManager()); + + } + + void updateSourceLocations(const std::vector<clang::SourceLocation> &sourceLocations, + const clang::SourceManager &sourceManager) + { + appendSourceLocationsToSourceLocationsContainer(*sourceLocationsContainer, sourceLocations, sourceManager); + } + + void setSourceLocations(ClangBackEnd::SourceLocationsContainer *sourceLocations) + { + sourceLocationsContainer = sourceLocations; + } + +private: + ClangBackEnd::SourceLocationsContainer *sourceLocationsContainer = nullptr; + std::vector<USRName> &unifiedSymbolResolutions; +}; + +std::unique_ptr<clang::ASTConsumer> SymbolLocationFinderAction::newASTConsumer() +{ + auto consumer = std::unique_ptr<FindingSymbolsASTConsumer>(new FindingSymbolsASTConsumer(unifiedSymbolResolutions_)); + + consumer->setSourceLocations(&sourceLocations); + + return std::move(consumer); +} + +} // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/symbollocationfinderaction.h b/src/tools/clangrefactoringbackend/source/symbollocationfinderaction.h new file mode 100644 index 0000000000..237cd0150a --- /dev/null +++ b/src/tools/clangrefactoringbackend/source/symbollocationfinderaction.h @@ -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. +** +****************************************************************************/ + +#pragma once + +#include "clangrefactoringbackend_global.h" + +#include <sourcelocationscontainer.h> + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +#include <clang/Tooling/Refactoring.h> + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +namespace clang { +class ASTConsumer; +}; + +namespace ClangBackEnd { + +class SymbolLocationFinderAction +{ +public: + + std::unique_ptr<clang::ASTConsumer> newASTConsumer(); + + SourceLocationsContainer takeSourceLocations() + { + return std::move(sourceLocations); + } + + void setUnifiedSymbolResolutions(std::vector<USRName> &&unifiedSymbolResolutions) + { + unifiedSymbolResolutions_ = std::move(unifiedSymbolResolutions); + } + + const std::vector<USRName> &unifiedSymbolResolutions() const + { + return unifiedSymbolResolutions_; + } + +private: + ClangBackEnd::SourceLocationsContainer sourceLocations; + std::vector<USRName> unifiedSymbolResolutions_; +}; + +} // namespace ClangBackEnd diff --git a/src/tools/tools.pro b/src/tools/tools.pro index fe9f3a7397..5328bea036 100644 --- a/src/tools/tools.pro +++ b/src/tools/tools.pro @@ -21,6 +21,7 @@ mac { isEmpty(LLVM_INSTALL_DIR):LLVM_INSTALL_DIR=$$(LLVM_INSTALL_DIR) exists($$LLVM_INSTALL_DIR) { SUBDIRS += clangbackend + SUBDIRS += clangrefactoringbackend } isEmpty(BUILD_CPLUSPLUS_TOOLS):BUILD_CPLUSPLUS_TOOLS=$$(BUILD_CPLUSPLUS_TOOLS) |