Remove clangbackend

Change-Id: I5f4f9a2fc5469c4eeb112a46626791ffb9a57a85
Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
Christian Kandeler
2022-04-28 19:39:51 +02:00
parent 4b0b3e9e35
commit 5f9cbe7fe8
162 changed files with 0 additions and 27025 deletions

View File

@@ -1,10 +1,5 @@
add_subdirectory(3rdparty) add_subdirectory(3rdparty)
add_subdirectory(buildoutputparser) add_subdirectory(buildoutputparser)
if (NOT Clang_FOUND)
message(WARNING "Could not find Clang installation - disabling clangbackend.")
else ()
add_subdirectory(clangbackend)
endif ()
option(BUILD_CPLUSPLUS_TOOLS "Build CPlusPlus tools" OFF) option(BUILD_CPLUSPLUS_TOOLS "Build CPlusPlus tools" OFF)

View File

@@ -1,8 +0,0 @@
add_subdirectory(source)
add_qtc_executable(clangbackend
DEPENDS Qt5::Core Qt5::Network clangbackend_lib Sqlite ClangSupport libclang
SOURCES
../qtcreatorcrashhandler/crashhandlersetup.cpp ../qtcreatorcrashhandler/crashhandlersetup.h
clangbackendmain.cpp
)

View File

@@ -1,38 +0,0 @@
import qbs 1.0
QtcTool {
name: "clangbackend"
Depends { name: "ClangSupport" }
Depends { name: "libclang"; required: false }
Group {
prefix: "source/"
files: [
"*.h",
"*.cpp"
]
}
Group {
prefix: "../qtcreatorcrashhandler/"
files: [
"crashhandlersetup.cpp",
"crashhandlersetup.h",
]
}
files: [ "clangbackendmain.cpp" ]
condition: libclang.present
cpp.includePaths: base.concat(["source", libclang.llvmIncludeDir])
cpp.libraryPaths: base.concat(libclang.llvmLibDir)
cpp.dynamicLibraries: base.concat(libclang.llvmLibs)
cpp.rpaths: base.concat(libclang.llvmLibDir)
Properties {
condition: qbs.targetOS.contains("unix") && !qbs.targetOS.contains("macos")
cpp.linkerFlags: base.concat(["-z", "origin"])
}
}

View File

@@ -1,103 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "../qtcreatorcrashhandler/crashhandlersetup.h"
#include <QCommandLineParser>
#include <QCoreApplication>
#include <QLoggingCategory>
#include <connectionserver.h>
#include <clangcodemodelserver.h>
#include <clangcodemodelclientproxy.h>
#include <iostream>
#include <clocale>
using ClangBackEnd::ClangCodeModelClientProxy;
using ClangBackEnd::ClangCodeModelServer;
using ClangBackEnd::ConnectionServer;
QString processArguments(QCoreApplication &application)
{
QCommandLineParser parser;
parser.setApplicationDescription(QStringLiteral("Qt Creator Clang backend process."));
parser.addHelpOption();
parser.addVersionOption();
parser.addPositionalArgument(QStringLiteral("connection"), QStringLiteral("Connection"));
parser.process(application);
if (parser.positionalArguments().isEmpty())
parser.showHelp(1);
return parser.positionalArguments().constFirst();
}
#ifdef Q_OS_WIN
#include <windows.h>
static void messageOutput(QtMsgType type, const QMessageLogContext &/*context*/,
const QString &msg)
{
OutputDebugStringW(msg.toStdWString().c_str());
std::wcout << msg.toStdWString() << std::endl;
if (type == QtFatalMsg)
abort();
}
#endif
int main(int argc, char *argv[])
{
#ifdef Q_OS_WIN
qInstallMessageHandler(&messageOutput);
#endif
QCoreApplication::setOrganizationName(QStringLiteral("QtProject"));
QCoreApplication::setOrganizationDomain(QStringLiteral("qt-project.org"));
QCoreApplication::setApplicationName(QStringLiteral("ClangBackend"));
QCoreApplication::setApplicationVersion(QStringLiteral("1.0.0"));
QCoreApplication application(argc, argv);
// Some tidy checks use locale-dependent conversion functions and thus might throw exceptions.
std::setlocale(LC_NUMERIC, "C");
CrashHandlerSetup setupCrashHandler(QCoreApplication::applicationName(),
CrashHandlerSetup::DisableRestart);
const QString connection = processArguments(application);
// Printing the stack strace might dead lock as clang's stack printer allocates memory.
if (qEnvironmentVariableIntValue("QTC_CLANG_ENABLE_STACKTRACES"))
clang_enableStackTraces();
ClangCodeModelServer clangCodeModelServer;
ConnectionServer<ClangCodeModelServer, ClangCodeModelClientProxy> connectionServer;
connectionServer.setServer(&clangCodeModelServer);
connectionServer.start(connection);
return application.exec();
}

View File

@@ -1,74 +0,0 @@
add_qtc_library(clangbackend_lib STATIC
DEPENDS libclang
PUBLIC_DEPENDS
Qt5::Widgets # FIXME: change the way to get the gui pch to linkto
PUBLIC_DEFINES
$<TARGET_PROPERTY:ClangSupport,INTERFACE_COMPILE_DEFINITIONS>
$<TARGET_PROPERTY:Sqlite,INTERFACE_COMPILE_DEFINITIONS>
INCLUDES
$<TARGET_PROPERTY:ClangSupport,INTERFACE_INCLUDE_DIRECTORIES>
$<TARGET_PROPERTY:Sqlite,INTERFACE_INCLUDE_DIRECTORIES>
PUBLIC_INCLUDES
${CLANG_INCLUDE_DIRS}
"${CMAKE_CURRENT_LIST_DIR}"
SOURCES
clangasyncjob.h
clangbackend_global.h
clangclock.h
clangcodecompleteresults.cpp clangcodecompleteresults.h
clangcodemodelserver.cpp clangcodemodelserver.h
clangcompletecodejob.cpp clangcompletecodejob.h
clangdocument.cpp clangdocument.h
clangdocumentjob.h
clangdocumentprocessor.cpp clangdocumentprocessor.h
clangdocumentprocessors.cpp clangdocumentprocessors.h
clangdocuments.cpp clangdocuments.h
clangdocumentsuspenderresumer.cpp clangdocumentsuspenderresumer.h
clangexceptions.cpp clangexceptions.h
clangfilepath.cpp clangfilepath.h
clangfilesystemwatcher.cpp clangfilesystemwatcher.h
clangfollowsymbol.cpp clangfollowsymbol.h
clangfollowsymboljob.cpp clangfollowsymboljob.h
clangiasyncjob.cpp clangiasyncjob.h
clangjobcontext.cpp clangjobcontext.h
clangjobqueue.cpp clangjobqueue.h
clangjobrequest.cpp clangjobrequest.h
clangjobs.cpp clangjobs.h
clangparsesupportivetranslationunitjob.cpp clangparsesupportivetranslationunitjob.h
clangreferencescollector.cpp clangreferencescollector.h
clangrequestannotationsjob.cpp clangrequestannotationsjob.h
clangrequestreferencesjob.cpp clangrequestreferencesjob.h
clangrequesttooltipjob.cpp clangrequesttooltipjob.h
clangresumedocumentjob.cpp clangresumedocumentjob.h
clangstring.h
clangsupportivetranslationunitinitializer.cpp clangsupportivetranslationunitinitializer.h
clangsuspenddocumentjob.cpp clangsuspenddocumentjob.h
clangtooltipinfocollector.cpp clangtooltipinfocollector.h
clangtranslationunit.cpp clangtranslationunit.h
clangtranslationunits.cpp clangtranslationunits.h
clangtranslationunitupdater.cpp clangtranslationunitupdater.h
clangtype.cpp clangtype.h
clangunsavedfilesshallowarguments.cpp clangunsavedfilesshallowarguments.h
clangupdateannotationsjob.cpp clangupdateannotationsjob.h
clangupdateextraannotationsjob.cpp clangupdateextraannotationsjob.h
codecompleter.cpp codecompleter.h
codecompletionchunkconverter.cpp codecompletionchunkconverter.h
codecompletionsextractor.cpp codecompletionsextractor.h
commandlinearguments.cpp commandlinearguments.h
cursor.cpp cursor.h
diagnostic.cpp diagnostic.h
diagnosticset.cpp diagnosticset.h
diagnosticsetiterator.h
fixit.cpp fixit.h
fulltokeninfo.cpp fulltokeninfo.h
skippedsourceranges.cpp skippedsourceranges.h
sourcelocation.cpp sourcelocation.h
sourcerange.cpp sourcerange.h
token.cpp token.h
tokeninfo.cpp tokeninfo.h
tokenprocessor.h
tokenprocessoriterator.h
unsavedfile.cpp unsavedfile.h
unsavedfiles.cpp unsavedfiles.h
utf8positionfromlinecolumn.cpp utf8positionfromlinecolumn.h
)

View File

@@ -1,79 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "clangiasyncjob.h"
#include <utils/runextensions.h>
#include <QFutureWatcher>
#include <QObject>
namespace ClangBackEnd {
template<class Result>
class AsyncJob : public IAsyncJob
{
public:
AsyncJob() {}
~AsyncJob() {}
using Runner = std::function<Result()>;
Runner runner() const { return m_runner; }
void setRunner(const Runner &runner) { m_runner = runner; }
Result asyncResult() const { return m_futureWatcher.future().result(); }
QFuture<void> runAsync() final
{
const auto onFinished = [this]() {
finalizeAsyncRun();
setIsFinished(true);
finishedHandler()(this);
};
QObject::connect(&m_futureWatcher,
&QFutureWatcher<Result>::finished,
onFinished);
// Use 16MB stack size as clang_annotateTokens() would with an internal thread.
const Utils::StackSizeInBytes stackSize = 1024 * 1024 * 16;
const QFuture<Result> future = Utils::runAsync(stackSize, m_runner);
m_futureWatcher.setFuture(future);
return QFuture<void>(future);
}
void preventFinalization() final
{
m_futureWatcher.disconnect();
}
private:
Runner m_runner;
QFutureWatcher<Result> m_futureWatcher;
};
} // namespace ClangBackEnd

View File

@@ -1,39 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <clang-c/Index.h>
namespace ClangBackEnd {
enum class PreferredTranslationUnit
{
RecentlyParsed,
PreviouslyParsed,
LastUninitialized,
};
} // namespace ClangBackEnd

View File

@@ -1,36 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <chrono>
namespace ClangBackEnd {
using Clock = std::chrono::steady_clock;
using Duration = std::chrono::steady_clock::duration;
using TimePoint = std::chrono::steady_clock::time_point;
} // namespace ClangBackEnd

View File

@@ -1,83 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangcodecompleteresults.h"
#include <memory>
namespace ClangBackEnd {
using std::swap;
ClangCodeCompleteResults::ClangCodeCompleteResults(CXCodeCompleteResults *cxCodeCompleteResults)
: cxCodeCompleteResults(cxCodeCompleteResults)
{
}
ClangCodeCompleteResults::~ClangCodeCompleteResults()
{
clang_disposeCodeCompleteResults(cxCodeCompleteResults);
}
bool ClangCodeCompleteResults::isNull() const
{
return cxCodeCompleteResults == nullptr;
}
bool ClangCodeCompleteResults::isEmpty() const
{
return cxCodeCompleteResults->NumResults == 0;
}
bool ClangCodeCompleteResults::hasResults() const
{
return !isNull() && !isEmpty();
}
bool ClangCodeCompleteResults::hasUnknownContext() const
{
const unsigned long long contexts = clang_codeCompleteGetContexts(cxCodeCompleteResults);
return contexts == CXCompletionContext_Unknown;
}
CXCodeCompleteResults *ClangCodeCompleteResults::data() const
{
return cxCodeCompleteResults;
}
ClangCodeCompleteResults &ClangCodeCompleteResults::operator=(ClangCodeCompleteResults &&clangCodeCompleteResults)
{
swap(cxCodeCompleteResults, clangCodeCompleteResults.cxCodeCompleteResults);
return *this;
}
ClangCodeCompleteResults::ClangCodeCompleteResults(ClangCodeCompleteResults &&clangCodeCompleteResults)
{
swap(cxCodeCompleteResults, clangCodeCompleteResults.cxCodeCompleteResults);
}
} // namespace ClangBackEnd

View File

@@ -1,61 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <clang-c/Index.h>
#include <utf8string.h>
namespace ClangBackEnd {
class ClangCodeCompleteResults
{
public:
ClangCodeCompleteResults() = default;
ClangCodeCompleteResults(CXCodeCompleteResults *cxCodeCompleteResults);
~ClangCodeCompleteResults();
ClangCodeCompleteResults(const ClangCodeCompleteResults &ClangCodeCompleteResults) = delete;
const ClangCodeCompleteResults &operator=(const ClangCodeCompleteResults &ClangCodeCompleteResults) = delete;
ClangCodeCompleteResults(ClangCodeCompleteResults &&ClangCodeCompleteResults);
ClangCodeCompleteResults &operator=(ClangCodeCompleteResults &&ClangCodeCompleteResults);
bool isNull() const;
bool isEmpty() const;
bool hasResults() const;
bool hasUnknownContext() const;
CXCodeCompleteResults *data() const;
private:
CXCodeCompleteResults *cxCodeCompleteResults = nullptr;
};
} // namespace ClangBackEnd

View File

@@ -1,520 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangcodemodelserver.h"
#include "clangdocuments.h"
#include "clangdocumentsuspenderresumer.h"
#include "clangfilesystemwatcher.h"
#include "clangupdateannotationsjob.h"
#include "codecompleter.h"
#include "diagnosticset.h"
#include "tokenprocessor.h"
#include "clangexceptions.h"
#include "skippedsourceranges.h"
#include "unsavedfile.h"
#include <clangsupport/clangsupportdebugutils.h>
#include <clangsupport/clangcodemodelservermessages.h>
#include <utils/algorithm.h>
#include <utils/qtcassert.h>
#include <QCoreApplication>
#include <QDebug>
#include <QFileInfo>
#include <QLoggingCategory>
#include <QDir>
static Q_LOGGING_CATEGORY(serverLog, "qtc.clangbackend.server", QtWarningMsg);
static bool useSupportiveTranslationUnit()
{
static bool use = !qEnvironmentVariableIntValue("QTC_CLANG_NO_SUPPORTIVE_TRANSLATIONUNIT");
return use;
}
namespace ClangBackEnd {
ClangCodeModelServer::ClangCodeModelServer()
: documents(unsavedFiles)
{
updateAnnotationsTimer.setSingleShot(true);
QObject::connect(&updateAnnotationsTimer,
&QTimer::timeout,
[this]() {
processJobsForVisibleDocuments();
});
updateVisibleButNotCurrentDocumentsTimer.setSingleShot(true);
QObject::connect(&updateVisibleButNotCurrentDocumentsTimer,
&QTimer::timeout,
[this]() {
addAndRunUpdateJobs(documents.dirtyAndVisibleButNotCurrentDocuments());
});
QObject::connect(documents.clangFileSystemWatcher(),
&ClangFileSystemWatcher::fileChanged,
[this](const Utf8String &filePath) {
if (!documents.hasDocument(filePath))
updateAnnotationsTimer.start(0);
});
}
void ClangCodeModelServer::end()
{
QCoreApplication::exit();
}
void ClangCodeModelServer::documentsOpened(const ClangBackEnd::DocumentsOpenedMessage &message)
{
qCDebug(serverLog) << "########## documentsOpened";
TIME_SCOPE_DURATION("ClangCodeModelServer::documentsOpened");
try {
DocumentResetInfos toReset;
QVector<FileContainer> toCreate;
categorizeFileContainers(message.fileContainers, toCreate, toReset);
std::vector<Document> createdDocuments = documents.create(toCreate);
for (auto &document : createdDocuments) {
document.setDirtyIfDependencyIsMet(document.filePath());
DocumentProcessor processor = documentProcessors().create(document);
processor.jobs().setJobFinishedCallback([this](const Jobs::RunningJob &a, IAsyncJob *b) {
return onJobFinished(a, b);
});
}
const std::vector<Document> resetDocuments_ = resetDocuments(toReset);
unsavedFiles.createOrUpdate(message.fileContainers);
documents.setUsedByCurrentEditor(message.currentEditorFilePath);
documents.setVisibleInEditors(message.visibleEditorFilePaths);
processSuspendResumeJobs(documents.documents());
processJobsForVisibleDocuments();
} catch (const std::exception &exception) {
qWarning() << "Error in ClangCodeModelServer::documentsOpened:" << exception.what();
}
}
void ClangCodeModelServer::documentsChanged(const DocumentsChangedMessage &message)
{
qCDebug(serverLog) << "########## documentsChanged";
TIME_SCOPE_DURATION("ClangCodeModelServer::documentsChanged");
try {
const auto newerFileContainers = documents.newerFileContainers(message.fileContainers);
if (newerFileContainers.size() > 0) {
std::vector<Document> updateDocuments = documents.update(newerFileContainers);
unsavedFiles.createOrUpdate(newerFileContainers);
for (Document &document : updateDocuments) {
if (!document.isResponsivenessIncreased())
document.setResponsivenessIncreaseNeeded(true);
}
// Start the jobs on the next event loop iteration since otherwise
// we might block the translation unit for a completion request
// that comes right after this message.
updateAnnotationsTimer.start(0);
}
} catch (const std::exception &exception) {
qWarning() << "Error in ClangCodeModelServer::documentsChanged:" << exception.what();
}
}
void ClangCodeModelServer::documentsClosed(const ClangBackEnd::DocumentsClosedMessage &message)
{
qCDebug(serverLog) << "########## documentsClosed";
TIME_SCOPE_DURATION("ClangCodeModelServer::documentsClosed");
try {
for (const auto &fileContainer : message.fileContainers) {
const Document &document = documents.document(fileContainer);
documentProcessors().remove(document);
}
documents.remove(message.fileContainers);
unsavedFiles.remove(message.fileContainers);
} catch (const std::exception &exception) {
qWarning() << "Error in ClangCodeModelServer::documentsClosed:" << exception.what();
}
}
void ClangCodeModelServer::unsavedFilesUpdated(const UnsavedFilesUpdatedMessage &message)
{
qCDebug(serverLog) << "########## unsavedFilesUpdated";
TIME_SCOPE_DURATION("ClangCodeModelServer::unsavedFilesUpdated");
try {
unsavedFiles.createOrUpdate(message.fileContainers);
documents.updateDocumentsWithChangedDependencies(message.fileContainers);
resetDocumentsWithUnresolvedIncludes(documents.documents());
updateAnnotationsTimer.start(updateAnnotationsTimeOutInMs);
} catch (const std::exception &exception) {
qWarning() << "Error in ClangCodeModelServer::unsavedFilesUpdated:" << exception.what();
}
}
void ClangCodeModelServer::unsavedFilesRemoved(const UnsavedFilesRemovedMessage &message)
{
qCDebug(serverLog) << "########## unsavedFilesRemoved";
TIME_SCOPE_DURATION("ClangCodeModelServer::unsavedFilesRemoved");
try {
unsavedFiles.remove(message.fileContainers);
documents.updateDocumentsWithChangedDependencies(message.fileContainers);
} catch (const std::exception &exception) {
qWarning() << "Error in ClangCodeModelServer::unsavedFilesRemoved:" << exception.what();
}
}
void ClangCodeModelServer::requestCompletions(const ClangBackEnd::RequestCompletionsMessage &message)
{
qCDebug(serverLog) << "########## requestCompletions";
TIME_SCOPE_DURATION("ClangCodeModelServer::requestCompletions");
try {
Document document = documents.document(message.filePath);
DocumentProcessor processor = documentProcessors().processor(document);
JobRequest jobRequest = processor.createJobRequest(JobRequest::Type::RequestCompletions);
jobRequest.line = message.line;
jobRequest.column = message.column;
jobRequest.funcNameStartLine = message.funcNameStartLine;
jobRequest.funcNameStartColumn = message.funcNameStartColumn;
jobRequest.ticketNumber = message.ticketNumber;
processor.addJob(jobRequest);
processor.process();
} catch (const std::exception &exception) {
qWarning() << "Error in ClangCodeModelServer::requestCompletions:" << exception.what();
}
}
void ClangCodeModelServer::requestAnnotations(const RequestAnnotationsMessage &message)
{
qCDebug(serverLog) << "########## requestAnnotations";
TIME_SCOPE_DURATION("ClangCodeModelServer::requestAnnotations");
try {
auto document = documents.document(message.fileContainer.filePath);
DocumentProcessor processor = documentProcessors().processor(document);
processor.addJob(JobRequest::Type::RequestAnnotations);
processor.addJob(JobRequest::Type::UpdateExtraAnnotations);
processor.process();
} catch (const std::exception &exception) {
qWarning() << "Error in ClangCodeModelServer::requestAnnotations:" << exception.what();
}
}
template <class MessageType>
static void fillJobRequest(JobRequest &jobRequest, const MessageType &message)
{
jobRequest.line = message.line;
jobRequest.column = message.column;
jobRequest.ticketNumber = message.ticketNumber;
jobRequest.textCodecName = message.fileContainer.textCodecName;
// The unsaved files might get updater later, so take the current
// revision for the request.
jobRequest.documentRevision = message.fileContainer.documentRevision;
}
void ClangCodeModelServer::requestReferences(const RequestReferencesMessage &message)
{
qCDebug(serverLog) << "########## requestReferences";
TIME_SCOPE_DURATION("ClangCodeModelServer::requestReferences");
try {
const Document document = documents.document(message.fileContainer.filePath);
DocumentProcessor processor = documentProcessors().processor(document);
JobRequest jobRequest = processor.createJobRequest(JobRequest::Type::RequestReferences);
fillJobRequest(jobRequest, message);
jobRequest.localReferences = message.local;
processor.addJob(jobRequest);
processor.process();
} catch (const std::exception &exception) {
qWarning() << "Error in ClangCodeModelServer::requestReferences:" << exception.what();
}
}
void ClangCodeModelServer::requestFollowSymbol(const RequestFollowSymbolMessage &message)
{
qCDebug(serverLog) << "########## requestFollowSymbol";
TIME_SCOPE_DURATION("ClangCodeModelServer::requestFollowSymbol");
try {
Document document = documents.document(message.fileContainer.filePath);
DocumentProcessor processor = documentProcessors().processor(document);
JobRequest jobRequest = processor.createJobRequest(JobRequest::Type::RequestFollowSymbol);
fillJobRequest(jobRequest, message);
processor.addJob(jobRequest);
processor.process();
} catch (const std::exception &exception) {
qWarning() << "Error in ClangCodeModelServer::requestFollowSymbol:" << exception.what();
}
}
void ClangCodeModelServer::requestToolTip(const RequestToolTipMessage &message)
{
TIME_SCOPE_DURATION("ClangCodeModelServer::requestToolTip");
try {
const Document document = documents.document(message.fileContainer.filePath);
DocumentProcessor processor = documentProcessors().processor(document);
JobRequest jobRequest = processor.createJobRequest(JobRequest::Type::RequestToolTip);
fillJobRequest(jobRequest, message);
processor.addJob(jobRequest);
processor.process();
} catch (const std::exception &exception) {
qWarning() << "Error in ClangCodeModelServer::requestToolTip:" << exception.what();
}
}
void ClangCodeModelServer::documentVisibilityChanged(const DocumentVisibilityChangedMessage &message)
{
qCDebug(serverLog) << "########## documentVisibilityChanged";
TIME_SCOPE_DURATION("ClangCodeModelServer::documentVisibilityChanged");
try {
documents.setUsedByCurrentEditor(message.currentEditorFilePath);
documents.setVisibleInEditors(message.visibleEditorFilePaths);
processSuspendResumeJobs(documents.documents());
updateAnnotationsTimer.start(0);
} catch (const std::exception &exception) {
qWarning() << "Error in ClangCodeModelServer::documentVisibilityChanged:" << exception.what();
}
}
const Documents &ClangCodeModelServer::documentsForTestOnly() const
{
return documents;
}
QList<Jobs::RunningJob> ClangCodeModelServer::runningJobsForTestsOnly()
{
return documentProcessors().runningJobs();
}
int ClangCodeModelServer::queueSizeForTestsOnly()
{
return documentProcessors().queueSize();
}
bool ClangCodeModelServer::isTimerRunningForTestOnly() const
{
return updateAnnotationsTimer.isActive();
}
void ClangCodeModelServer::processJobsForVisibleDocuments()
{
processJobsForCurrentDocument();
processTimerForVisibleButNotCurrentDocuments();
}
void ClangCodeModelServer::processJobsForCurrentDocument()
{
auto currentDocuments = documents.filtered([](const Document &document) {
return document.isUsedByCurrentEditor() && document.isDirty();
});
QTC_CHECK(currentDocuments.size() <= 1);
addAndRunUpdateJobs(currentDocuments);
}
static void addUpdateAnnotationsJobsAndProcess(DocumentProcessor &processor)
{
processor.addJob(JobRequest::Type::UpdateAnnotations,
PreferredTranslationUnit::PreviouslyParsed);
processor.addJob(JobRequest::Type::UpdateExtraAnnotations,
PreferredTranslationUnit::RecentlyParsed);
processor.process();
}
void ClangCodeModelServer::addAndRunUpdateJobs(std::vector<Document> documents)
{
for (auto &document : documents) {
DocumentProcessor processor = documentProcessors().processor(document);
// Run the regular edit-reparse-job
addUpdateAnnotationsJobsAndProcess(processor);
// If requested, run jobs to increase the responsiveness of the document
if (useSupportiveTranslationUnit() && document.isResponsivenessIncreaseNeeded()) {
QTC_CHECK(!document.isResponsivenessIncreased());
QTC_CHECK(!processor.hasSupportiveTranslationUnit());
document.setResponsivenessIncreaseNeeded(false);
processor.startInitializingSupportiveTranslationUnit();
}
}
}
void ClangCodeModelServer::processTimerForVisibleButNotCurrentDocuments()
{
if (documents.dirtyAndVisibleButNotCurrentDocuments().empty()) {
updateVisibleButNotCurrentDocumentsTimer.stop();
} else {
updateVisibleButNotCurrentDocumentsTimer.start(
updateVisibleButNotCurrentDocumentsTimeOutInMs);
}
}
void ClangCodeModelServer::processSuspendResumeJobs(const std::vector<Document> &documents)
{
const SuspendResumeJobs suspendResumeJobs = createSuspendResumeJobs(documents);
for (const SuspendResumeJobsEntry &entry : suspendResumeJobs) {
DocumentProcessor processor = documentProcessors().processor(entry.document);
processor.addJob(entry.jobRequestType, entry.preferredTranslationUnit);
if (entry.jobRequestType == JobRequest::Type::ResumeDocument) {
processor.addJob(JobRequest::Type::UpdateExtraAnnotations,
PreferredTranslationUnit::RecentlyParsed);
}
processor.process();
}
}
bool ClangCodeModelServer::onJobFinished(const Jobs::RunningJob &jobRecord, IAsyncJob *job)
{
if (jobRecord.jobRequest.type == JobRequest::Type::UpdateAnnotations) {
const auto updateJob = static_cast<UpdateAnnotationsJob *>(job);
return resetDocumentsWithUnresolvedIncludes({updateJob->pinnedDocument()});
}
return false;
}
void ClangCodeModelServer::categorizeFileContainers(const QVector<FileContainer> &fileContainers,
QVector<FileContainer> &toCreate,
DocumentResetInfos &toReset) const
{
for (const FileContainer &fileContainer : fileContainers) {
const std::vector<Document> matching = documents.filtered([&](const Document &document) {
return document.filePath() == fileContainer.filePath;
});
if (matching.empty())
toCreate.push_back(fileContainer);
else
toReset.push_back(DocumentResetInfo{*matching.begin(), fileContainer});
}
}
std::vector<Document> ClangCodeModelServer::resetDocuments(const DocumentResetInfos &infos)
{
std::vector<Document> newDocuments;
for (const DocumentResetInfo &info : infos) {
const Document &document = info.documentToRemove;
QTC_CHECK(document.filePath() == info.fileContainer.filePath);
documents.remove({document.fileContainer()});
Document newDocument = *documents.create({info.fileContainer}).begin();
newDocument.setDirtyIfDependencyIsMet(document.filePath());
newDocument.setIsUsedByCurrentEditor(document.isUsedByCurrentEditor());
newDocument.setIsVisibleInEditor(document.isVisibleInEditor(), document.visibleTimePoint());
newDocument.setResponsivenessIncreaseNeeded(document.isResponsivenessIncreased());
documentProcessors().reset(document, newDocument);
newDocuments.push_back(newDocument);
}
return newDocuments;
}
static bool isDocumentWithUnresolvedIncludesFixable(const Document &document,
const UnsavedFiles &unsavedFiles)
{
for (uint i = 0; i < unsavedFiles.count(); ++i) {
const UnsavedFile &unsavedFile = unsavedFiles.at(i);
const Utf8String unsavedFilePath = QDir::cleanPath(unsavedFile.filePath());
for (const Utf8String &unresolvedPath : document.unresolvedFilePaths()) {
const QString documentDir = QFileInfo(document.filePath()).absolutePath();
const QString candidate = QDir::cleanPath(documentDir + "/" + unresolvedPath.toString());
if (Utf8String(candidate) == unsavedFilePath)
return true;
for (const Utf8String &headerPath : document.headerPaths()) {
Utf8String candidate = headerPath;
candidate.append(QStringLiteral("/"));
candidate.append(unresolvedPath);
candidate = QDir::cleanPath(candidate);
if (candidate == unsavedFilePath)
return true;
}
}
}
return false;
}
int ClangCodeModelServer::resetDocumentsWithUnresolvedIncludes(
const std::vector<Document> &documents)
{
DocumentResetInfos toReset;
for (const Document &document : documents) {
if (document.unresolvedFilePaths().isEmpty())
continue;
if (isDocumentWithUnresolvedIncludesFixable(document, unsavedFiles))
toReset << DocumentResetInfo{document, document.fileContainer()};
}
resetDocuments(toReset);
return toReset.size();
}
void ClangCodeModelServer::setUpdateAnnotationsTimeOutInMsForTestsOnly(int value)
{
updateAnnotationsTimeOutInMs = value;
}
void ClangCodeModelServer::setUpdateVisibleButNotCurrentDocumentsTimeOutInMsForTestsOnly(int value)
{
updateVisibleButNotCurrentDocumentsTimeOutInMs = value;
}
DocumentProcessors &ClangCodeModelServer::documentProcessors()
{
if (!documentProcessors_) {
// DocumentProcessors needs a reference to the client, but the client
// is not known at construction time of ClangCodeModelServer, so
// construct DocumentProcessors in a lazy manner.
documentProcessors_.reset(new DocumentProcessors(documents, unsavedFiles, *client()));
}
return *documentProcessors_.data();
}
} // namespace ClangBackEnd

View File

@@ -1,109 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "clangdocument.h"
#include "clangdocuments.h"
#include "clangdocumentprocessors.h"
#include "clangjobrequest.h"
#include "unsavedfiles.h"
#include <clangcodemodelserverinterface.h>
#include <ipcclientprovider.h>
#include <utf8string.h>
#include <QScopedPointer>
#include <QTimer>
namespace ClangBackEnd {
struct DocumentResetInfo {
Document documentToRemove;
FileContainer fileContainer;
};
using DocumentResetInfos = QVector<DocumentResetInfo>;
class ClangCodeModelServer : public ClangCodeModelServerInterface,
public IpcClientProvider<ClangCodeModelClientInterface>
{
public:
ClangCodeModelServer();
void end() override;
void documentsOpened(const DocumentsOpenedMessage &message) override;
void documentsChanged(const DocumentsChangedMessage &message) override;
void documentsClosed(const DocumentsClosedMessage &message) override;
void documentVisibilityChanged(const DocumentVisibilityChangedMessage &message) override;
void unsavedFilesUpdated(const UnsavedFilesUpdatedMessage &message) override;
void unsavedFilesRemoved(const UnsavedFilesRemovedMessage &message) override;
void requestCompletions(const RequestCompletionsMessage &message) override;
void requestAnnotations(const RequestAnnotationsMessage &message) override;
void requestReferences(const RequestReferencesMessage &message) override;
void requestFollowSymbol(const RequestFollowSymbolMessage &message) override;
void requestToolTip(const RequestToolTipMessage &message) override;
public: // for tests
const Documents &documentsForTestOnly() const;
QList<Jobs::RunningJob> runningJobsForTestsOnly();
int queueSizeForTestsOnly();
bool isTimerRunningForTestOnly() const;
void setUpdateAnnotationsTimeOutInMsForTestsOnly(int value);
void setUpdateVisibleButNotCurrentDocumentsTimeOutInMsForTestsOnly(int value);
DocumentProcessors &documentProcessors();
private:
void processJobsForVisibleDocuments();
void processJobsForCurrentDocument();
void processTimerForVisibleButNotCurrentDocuments();
void processSuspendResumeJobs(const std::vector<Document> &documents);
bool onJobFinished(const Jobs::RunningJob &jobRecord, IAsyncJob *job);
void categorizeFileContainers(const QVector<FileContainer> &fileContainers,
QVector<FileContainer> &toCreate,
DocumentResetInfos &toReset) const;
std::vector<Document> resetDocuments(const DocumentResetInfos &infos);
int resetDocumentsWithUnresolvedIncludes(const std::vector<Document> &documents);
void addAndRunUpdateJobs(std::vector<Document> documents);
private:
UnsavedFiles unsavedFiles;
Documents documents;
QScopedPointer<DocumentProcessors> documentProcessors_; // Delayed initialization
QTimer updateAnnotationsTimer;
int updateAnnotationsTimeOutInMs = 1500;
QTimer updateVisibleButNotCurrentDocumentsTimer;
int updateVisibleButNotCurrentDocumentsTimeOutInMs = 2000;
};
} // namespace ClangBackEnd

View File

@@ -1,73 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangcompletecodejob.h"
#include <clangsupport/clangsupportdebugutils.h>
#include <clangsupport/clangcodemodelclientinterface.h>
#include <clangsupport/completionsmessage.h>
#include <utils/qtcassert.h>
namespace ClangBackEnd {
IAsyncJob::AsyncPrepareResult CompleteCodeJob::prepareAsyncRun()
{
const JobRequest jobRequest = context().jobRequest;
QTC_ASSERT(jobRequest.type == JobRequest::Type::RequestCompletions, return AsyncPrepareResult());
QTC_ASSERT(acquireDocument(), return AsyncPrepareResult());
const TranslationUnit translationUnit = *m_translationUnit;
const UnsavedFiles unsavedFiles = *context().unsavedFiles;
const quint32 line = jobRequest.line;
const quint32 column = jobRequest.column;
const qint32 funcNameStartLine = jobRequest.funcNameStartLine;
const qint32 funcNameStartColumn = jobRequest.funcNameStartColumn;
setRunner([translationUnit, unsavedFiles, line, column,
funcNameStartLine, funcNameStartColumn]() {
TIME_SCOPE_DURATION("CompleteCodeJobRunner");
UnsavedFiles theUnsavedFiles = unsavedFiles;
CompleteCodeJob::AsyncResult asyncResult;
asyncResult = translationUnit.complete(theUnsavedFiles, line, column,
funcNameStartLine, funcNameStartColumn);
return asyncResult;
});
return AsyncPrepareResult{translationUnit.id()};
}
void CompleteCodeJob::finalizeAsyncRun()
{
if (context().isDocumentOpen()) {
const AsyncResult result = asyncResult();
const CompletionsMessage message(result, context().jobRequest.ticketNumber);
context().client->completions(message);
}
}
} // namespace ClangBackEnd

View File

@@ -1,43 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "clangdocumentjob.h"
#include <clangsupport/codecompletion.h>
namespace ClangBackEnd {
class CompleteCodeJob : public DocumentJob<CodeCompletions>
{
public:
using AsyncResult = CodeCompletions;
AsyncPrepareResult prepareAsyncRun() override;
void finalizeAsyncRun() override;
};
} // namespace ClangBackEnd

View File

@@ -1,453 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangdocument.h"
#include "clangdocuments.h"
#include "clangstring.h"
#include "clangunsavedfilesshallowarguments.h"
#include "codecompleter.h"
#include "clangexceptions.h"
#include "clangtranslationunit.h"
#include "clangtranslationunits.h"
#include "clangtranslationunitupdater.h"
#include "unsavedfiles.h"
#include "unsavedfile.h"
#include <utf8string.h>
#include <QDebug>
#include <QFileInfo>
#include <QLoggingCategory>
#include <ostream>
namespace ClangBackEnd {
class DocumentData
{
public:
DocumentData(const Utf8String &filePath,
const Utf8StringVector &compilationArguments,
const Utf8StringVector &headerPaths,
Documents &documents);
~DocumentData();
public:
Documents &documents;
const Utf8String filePath;
const Utf8StringVector compilationArguments;
const Utf8StringVector headerPaths;
TranslationUnits translationUnits;
QSet<Utf8String> dependedFilePaths;
QSet<Utf8String> unresolvedFilePaths;
uint documentRevision = 0;
TimePoint visibleTimePoint;
TimePoint isDirtyChangeTimePoint;
bool isDirty = false;
bool hasParseOrReparseFailed = false;
bool isUsedByCurrentEditor = false;
bool isVisibleInEditor = false;
bool increaseResponsiveness = false;
bool isSuspended = false;
};
DocumentData::DocumentData(const Utf8String &filePath,
const Utf8StringVector &compilationArguments,
const Utf8StringVector &headerPaths,
Documents &documents)
: documents(documents),
filePath(filePath),
compilationArguments(compilationArguments),
headerPaths(headerPaths),
translationUnits(filePath),
isDirtyChangeTimePoint(Clock::now())
{
dependedFilePaths.insert(filePath);
translationUnits.createAndAppend();
}
DocumentData::~DocumentData()
{
}
Document::Document(const Utf8String &filePath,
const Utf8StringVector &compilationArguments,
const Utf8StringVector &headerPaths,
Documents &documents,
FileExistsCheck fileExistsCheck)
: d(std::make_shared<DocumentData>(filePath,
compilationArguments,
headerPaths,
documents))
{
if (fileExistsCheck == FileExistsCheck::Check)
checkIfFileExists();
}
Document::~Document() = default;
Document::Document(const Document &) = default;
Document &Document::operator=(const Document &) = default;
Document::Document(Document &&other)
: d(std::move(other.d))
{
}
Document &Document::operator=(Document &&other)
{
d = std::move(other.d);
return *this;
}
void Document::reset()
{
d.reset();
}
bool Document::isNull() const
{
return !d;
}
bool Document::isIntact() const
{
return !isNull()
&& fileExists()
&& !d->hasParseOrReparseFailed;
}
bool Document::isParsed() const
{
return d->translationUnits.areAllTranslationUnitsParsed();
}
long Document::useCount() const
{
return d.use_count();
}
Utf8String Document::filePath() const
{
checkIfNull();
return d->filePath;
}
Utf8StringVector Document::compilationArguments() const
{
checkIfNull();
return d->compilationArguments;
}
Utf8StringVector Document::headerPaths() const
{
checkIfNull();
return d->headerPaths;
}
FileContainer Document::fileContainer() const
{
checkIfNull();
return FileContainer(d->filePath,
d->compilationArguments,
d->headerPaths,
Utf8String(),
false,
d->documentRevision);
}
uint Document::documentRevision() const
{
checkIfNull();
return d->documentRevision;
}
void Document::setDocumentRevision(uint revision)
{
checkIfNull();
d->documentRevision = revision;
}
bool Document::isResponsivenessIncreased() const
{
return d->translationUnits.size() > 1;
}
bool Document::isResponsivenessIncreaseNeeded() const
{
checkIfNull();
return d->increaseResponsiveness;
}
void Document::setResponsivenessIncreaseNeeded(bool responsivenessIncreaseNeeded)
{
d->increaseResponsiveness = responsivenessIncreaseNeeded;
}
bool Document::isSuspended() const
{
checkIfNull();
return d->isSuspended;
}
void Document::setIsSuspended(bool isSuspended)
{
checkIfNull();
d->isSuspended = isSuspended;
}
bool Document::isUsedByCurrentEditor() const
{
checkIfNull();
return d->isUsedByCurrentEditor;
}
void Document::setIsUsedByCurrentEditor(bool isUsedByCurrentEditor)
{
checkIfNull();
d->isUsedByCurrentEditor = isUsedByCurrentEditor;
}
bool Document::isVisibleInEditor() const
{
checkIfNull();
return d->isVisibleInEditor;
}
void Document::setIsVisibleInEditor(bool isVisibleInEditor, const TimePoint &timePoint)
{
checkIfNull();
if (isVisibleInEditor)
d->visibleTimePoint = timePoint;
d->isVisibleInEditor = isVisibleInEditor;
}
TimePoint Document::visibleTimePoint() const
{
checkIfNull();
return d->visibleTimePoint;;
}
bool Document::isDirty() const
{
checkIfNull();
return d->isDirty;
}
TimePoint Document::isDirtyTimeChangePoint() const
{
checkIfNull();
return d->isDirtyChangeTimePoint;
}
void Document::setDirtyIfDependencyIsMet(const Utf8String &filePath)
{
if (d->dependedFilePaths.contains(filePath) && isMainFileAndExistsOrIsOtherFile(filePath))
setDirty();
}
TranslationUnitUpdateInput Document::createUpdateInput() const
{
TranslationUnitUpdateInput updateInput;
updateInput.reparseNeeded = d->isDirty;
updateInput.needsToBeReparsedChangeTimePoint = d->isDirtyChangeTimePoint;
updateInput.filePath = d->filePath;
updateInput.compilationArguments = d->compilationArguments;
updateInput.unsavedFiles = d->documents.unsavedFiles();
return updateInput;
}
TranslationUnitUpdater Document::createUpdater() const
{
TranslationUnit unit = translationUnit();
const TranslationUnitUpdateInput updateInput = createUpdateInput();
TranslationUnitUpdater updater(unit.id(),
unit.cxIndex(),
unit.cxTranslationUnit(),
updateInput);
return updater;
}
void Document::setHasParseOrReparseFailed(bool hasFailed)
{
d->hasParseOrReparseFailed = hasFailed;
}
void Document::incorporateUpdaterResult(const TranslationUnitUpdateResult &result) const
{
d->hasParseOrReparseFailed = result.hasParseOrReparseFailed;
if (d->hasParseOrReparseFailed) {
d->isDirty = false;
return;
}
if (result.hasParsed() || result.hasReparsed()) {
d->dependedFilePaths = result.dependedOnFilePaths;
const TimePoint timePoint = qMax(result.parseTimePoint, result.reparseTimePoint);
d->translationUnits.updateParseTimePoint(result.translationUnitId, timePoint);
}
d->documents.addWatchedFiles(d->dependedFilePaths);
if (result.hasReparsed()
&& result.needsToBeReparsedChangeTimePoint == d->isDirtyChangeTimePoint) {
d->isDirty = false;
}
}
const QSet<Utf8String> Document::unresolvedFilePaths() const
{
checkIfNull();
return d->unresolvedFilePaths;
}
void Document::setUnresolvedFilePaths(const QSet<Utf8String> &unresolved)
{
checkIfNull();
d->unresolvedFilePaths = unresolved;
}
TranslationUnit Document::translationUnit(PreferredTranslationUnit preferredTranslationUnit) const
{
checkIfNull();
return d->translationUnits.get(preferredTranslationUnit);
}
TranslationUnits &Document::translationUnits() const
{
return d->translationUnits;
}
void Document::parse() const
{
checkIfNull();
const TranslationUnitUpdateInput updateInput = createUpdateInput();
TranslationUnitUpdateResult result = translationUnit().parse(updateInput);
incorporateUpdaterResult(result);
}
void Document::reparse() const
{
checkIfNull();
const TranslationUnitUpdateInput updateInput = createUpdateInput();
TranslationUnitUpdateResult result = translationUnit().reparse(updateInput);
incorporateUpdaterResult(result);
}
const QSet<Utf8String> Document::dependedFilePaths() const
{
checkIfNull();
checkIfFileExists();
return d->dependedFilePaths;
}
void Document::setDependedFilePaths(const QSet<Utf8String> &filePaths)
{
d->dependedFilePaths = filePaths;
}
void Document::setDirty()
{
d->isDirtyChangeTimePoint = Clock::now();
d->isDirty = true;
}
void Document::checkIfNull() const
{
if (isNull())
throw DocumentIsNullException();
}
void Document::checkIfFileExists() const
{
if (!fileExists())
throw DocumentFileDoesNotExistException(d->filePath);
}
bool Document::fileExists() const
{
return QFileInfo::exists(d->filePath.toString());
}
bool Document::isMainFileAndExistsOrIsOtherFile(const Utf8String &filePath) const
{
if (filePath == d->filePath)
return QFileInfo::exists(d->filePath);
return true;
}
bool operator==(const Document &first, const Document &second)
{
return first.filePath() == second.filePath();
}
std::ostream &operator<<(std::ostream &os, const Document &document)
{
os << "("
<< document.filePath() << ", "
<< document.documentRevision()
<< ")";
return os;
}
} // namespace ClangBackEnd

View File

@@ -1,142 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "clangtranslationunitupdater.h"
#include "clangbackend_global.h"
#include "clangtranslationunit.h"
#include <utf8stringvector.h>
#include <clang-c/Index.h>
#include <QSet>
#include <QtGlobal>
#include <memory>
class Utf8String;
namespace ClangBackEnd {
class TranslationUnit;
class TranslationUnits;
class DocumentData;
class TranslationUnitUpdateResult;
class FileContainer;
class Documents;
class Document
{
public:
enum class FileExistsCheck {
Check,
DoNotCheck
};
Document() = default;
Document(const Utf8String &filePath,
const Utf8StringVector &compilationArguments,
const Utf8StringVector &headerPaths,
Documents &documents,
FileExistsCheck fileExistsCheck = FileExistsCheck::Check);
~Document();
Document(const Document &document);
Document &operator=(const Document &document);
Document(Document &&document);
Document &operator=(Document &&document);
void reset();
bool isNull() const;
bool isIntact() const;
bool isParsed() const;
long useCount() const;
Utf8String filePath() const;
Utf8StringVector compilationArguments() const;
Utf8StringVector headerPaths() const;
FileContainer fileContainer() const;
uint documentRevision() const;
void setDocumentRevision(uint revision);
bool isResponsivenessIncreased() const;
bool isResponsivenessIncreaseNeeded() const;
void setResponsivenessIncreaseNeeded(bool responsivenessIncreaseNeeded);
bool isSuspended() const;
void setIsSuspended(bool isSuspended);
bool isUsedByCurrentEditor() const;
void setIsUsedByCurrentEditor(bool isUsedByCurrentEditor);
bool isVisibleInEditor() const;
void setIsVisibleInEditor(bool isVisibleInEditor, const TimePoint &timePoint);
TimePoint visibleTimePoint() const;
bool isDirty() const;
TimePoint isDirtyTimeChangePoint() const;
void setDirtyIfDependencyIsMet(const Utf8String &filePath);
TranslationUnitUpdateInput createUpdateInput() const;
void incorporateUpdaterResult(const TranslationUnitUpdateResult &result) const;
const QSet<Utf8String> unresolvedFilePaths() const;
void setUnresolvedFilePaths(const QSet<Utf8String> &unresolved);
TranslationUnit translationUnit(PreferredTranslationUnit preferredTranslationUnit
= PreferredTranslationUnit::RecentlyParsed) const;
TranslationUnits &translationUnits() const;
friend bool operator==(const Document &first, const Document &second);
friend std::ostream &operator<<(std::ostream &os, const Document &document);
public: // for tests
void parse() const;
void reparse() const;
const QSet<Utf8String> dependedFilePaths() const;
void setDependedFilePaths(const QSet<Utf8String> &filePaths);
TranslationUnitUpdater createUpdater() const;
void setHasParseOrReparseFailed(bool hasFailed);
private:
void setDirty();
void checkIfNull() const;
void checkIfFileExists() const;
bool fileExists() const;
bool isMainFileAndExistsOrIsOtherFile(const Utf8String &filePath) const;
private:
mutable std::shared_ptr<DocumentData> d;
};
} // namespace ClangBackEnd

View File

@@ -1,67 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "clangasyncjob.h"
#include "clangdocument.h"
#include <clangsupport/filecontainer.h>
#include <memory>
namespace ClangBackEnd {
template<class Result>
class DocumentJob : public AsyncJob<Result>
{
public:
Document pinnedDocument() const { return m_pinnedDocument; }
protected:
bool acquireDocument()
{
try {
m_pinnedDocument = IAsyncJob::context().documentForJobRequest();
m_pinnedFileContainer = m_pinnedDocument.fileContainer();
const PreferredTranslationUnit preferredTranslationUnit
= IAsyncJob::context().jobRequest.preferredTranslationUnit;
m_translationUnit.reset(
new TranslationUnit(m_pinnedDocument.translationUnit(preferredTranslationUnit)));
return true;
} catch (const std::exception &) {
return false;
}
}
protected:
Document m_pinnedDocument;
FileContainer m_pinnedFileContainer;
std::unique_ptr<TranslationUnit> m_translationUnit;
};
} // namespace ClangBackEnd

View File

@@ -1,149 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangdocumentprocessor.h"
#include "clangdocuments.h"
#include "clangjobs.h"
#include "clangsupportivetranslationunitinitializer.h"
#include "clangdocument.h"
#include "clangtranslationunits.h"
#include <utils/algorithm.h>
#include <utils/qtcassert.h>
#include <QFileInfo>
namespace ClangBackEnd {
class DocumentProcessorData
{
public:
DocumentProcessorData(const Document &document,
Documents &documents,
UnsavedFiles &unsavedFiles,
ClangCodeModelClientInterface &client)
: document(document)
, documents(documents)
, jobs(documents, unsavedFiles, client, QFileInfo(document.filePath()).fileName())
, supportiveTranslationUnitInitializer(document, jobs)
{
const auto isDocumentClosedChecker = [this](const Utf8String &filePath) {
return !this->documents.hasDocument(filePath);
};
supportiveTranslationUnitInitializer.setIsDocumentClosedChecker(isDocumentClosedChecker);
}
public:
Document document;
Documents &documents;
Jobs jobs;
SupportiveTranslationUnitInitializer supportiveTranslationUnitInitializer;
};
DocumentProcessor::DocumentProcessor(const Document &document,
Documents &documents,
UnsavedFiles &unsavedFiles,
ClangCodeModelClientInterface &client)
: d(std::make_shared<DocumentProcessorData>(document,
documents,
unsavedFiles,
client))
{
}
Jobs &DocumentProcessor::jobs() const
{
return d->jobs;
}
JobRequest DocumentProcessor::createJobRequest(
JobRequest::Type type,
PreferredTranslationUnit preferredTranslationUnit) const
{
return d->jobs.createJobRequest(d->document, type, preferredTranslationUnit);
}
void DocumentProcessor::addJob(const JobRequest &jobRequest)
{
d->jobs.add(jobRequest);
}
void DocumentProcessor::addJob(JobRequest::Type type, PreferredTranslationUnit preferredTranslationUnit)
{
d->jobs.add(d->document, type, preferredTranslationUnit);
}
JobRequests DocumentProcessor::process()
{
return d->jobs.process();
}
JobRequests DocumentProcessor::stop()
{
d->supportiveTranslationUnitInitializer.abort();
return d->jobs.stop();
}
Document DocumentProcessor::document() const
{
return d->document;
}
bool DocumentProcessor::hasSupportiveTranslationUnit() const
{
return d->supportiveTranslationUnitInitializer.state()
!= SupportiveTranslationUnitInitializer::State::NotInitialized;
}
void DocumentProcessor::startInitializingSupportiveTranslationUnit()
{
d->supportiveTranslationUnitInitializer.startInitializing();
}
bool DocumentProcessor::isSupportiveTranslationUnitInitialized() const
{
return d->supportiveTranslationUnitInitializer.state()
== SupportiveTranslationUnitInitializer::State::Initialized;
}
JobRequests &DocumentProcessor::queue()
{
return d->jobs.queue();
}
QList<Jobs::RunningJob> DocumentProcessor::runningJobs() const
{
return d->jobs.runningJobs();
}
int DocumentProcessor::queueSize() const
{
return d->jobs.queue().size();
}
} // namespace ClangBackEnd

View File

@@ -1,79 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "clangjobrequest.h"
#include "clangjobs.h"
#include <memory>
namespace ClangBackEnd {
class ClangCodeModelClientInterface;
class Document;
class Documents;
class DocumentProcessorData;
class JobRequest;
class UnsavedFiles;
class DocumentProcessor
{
public:
DocumentProcessor(const Document &document,
Documents &documents,
UnsavedFiles &unsavedFiles,
ClangCodeModelClientInterface &client);
Jobs &jobs() const;
JobRequest createJobRequest(JobRequest::Type type,
PreferredTranslationUnit preferredTranslationUnit
= PreferredTranslationUnit::RecentlyParsed) const;
void addJob(const JobRequest &jobRequest);
void addJob(JobRequest::Type type,
PreferredTranslationUnit preferredTranslationUnit
= PreferredTranslationUnit::RecentlyParsed);
JobRequests process();
JobRequests stop();
Document document() const;
bool hasSupportiveTranslationUnit() const;
void startInitializingSupportiveTranslationUnit();
public: // for tests
bool isSupportiveTranslationUnitInitialized() const;
JobRequests &queue();
QList<Jobs::RunningJob> runningJobs() const;
int queueSize() const;
private:
std::shared_ptr<DocumentProcessorData> d;
};
} // namespace ClangBackEnd

View File

@@ -1,127 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangdocumentprocessors.h"
#include "clangdocument.h"
#include "clangexceptions.h"
#include <utils/algorithm.h>
namespace ClangBackEnd {
DocumentProcessors::DocumentProcessors(Documents &documents,
UnsavedFiles &unsavedFiles,
ClangCodeModelClientInterface &client)
: m_documents(documents)
, m_unsavedFiles(unsavedFiles)
, m_client(client)
{
}
DocumentProcessor DocumentProcessors::create(const Document &document)
{
const Utf8String filePath{document.filePath()};
if (m_processors.contains(filePath))
throw DocumentProcessorAlreadyExists(document.filePath());
const DocumentProcessor element(document, m_documents, m_unsavedFiles, m_client);
m_processors.insert(filePath, element);
return element;
}
DocumentProcessor DocumentProcessors::processor(const Document &document)
{
const Utf8String filePath = document.filePath();
const auto it = m_processors.find(filePath);
if (it == m_processors.end())
throw DocumentProcessorDoesNotExist(filePath);
return *it;
}
QList<DocumentProcessor> DocumentProcessors::processors() const
{
return m_processors.values();
}
void DocumentProcessors::remove(const Document &document)
{
const int itemsRemoved = m_processors.remove(document.filePath());
if (itemsRemoved != 1)
throw DocumentProcessorDoesNotExist(document.filePath());
}
void DocumentProcessors::reset(const Document &oldDocument, const Document &newDocument)
{
// Wait until the currently running jobs finish and remember the not yet
// processed job requests for the new processor...
const JobRequests jobsStillInQueue = processor(oldDocument).stop();
// ...but do not take over irrelevant ones.
const JobRequests jobsForNewProcessor = Utils::filtered(jobsStillInQueue,
[](const JobRequest &job) {
return job.isTakeOverable();
});
const Jobs::JobFinishedCallback jobFinishedCallback
= processor(oldDocument).jobs().jobFinishedCallback();
// Remove current processor
remove(oldDocument);
// Create new processor and take over not yet processed jobs.
DocumentProcessor newProcessor = create(newDocument);
for (const JobRequest &job : jobsForNewProcessor)
newProcessor.addJob(job);
newProcessor.jobs().setJobFinishedCallback(jobFinishedCallback);
}
JobRequests DocumentProcessors::process()
{
JobRequests jobsStarted;
for (auto &processor : m_processors)
jobsStarted += processor.process();
return jobsStarted;
}
QList<Jobs::RunningJob> DocumentProcessors::runningJobs() const
{
QList<Jobs::RunningJob> jobs;
for (auto &processor : m_processors)
jobs += processor.runningJobs();
return jobs;
}
int DocumentProcessors::queueSize() const
{
int total = 0;
for (auto &processor : m_processors)
total += processor.queueSize();
return total;
}
} // namespace ClangBackEnd

View File

@@ -1,67 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "clangdocumentprocessor.h"
#include "clangjobs.h"
#include <utf8string.h>
#include <QMap>
namespace ClangBackEnd {
class Document;
class DocumentProcessor;
class DocumentProcessors
{
public:
DocumentProcessors(Documents &documents,
UnsavedFiles &unsavedFiles,
ClangCodeModelClientInterface &client);
DocumentProcessor create(const Document &document);
DocumentProcessor processor(const Document &document);
void remove(const Document &document);
void reset(const Document &oldDocument, const Document &newDocument);
JobRequests process();
public: // for tests
QList<DocumentProcessor> processors() const;
QList<Jobs::RunningJob> runningJobs() const;
int queueSize() const;
private:
Documents &m_documents;
UnsavedFiles &m_unsavedFiles;
ClangCodeModelClientInterface &m_client;
QMap<Utf8String, DocumentProcessor> m_processors;
};
} // namespace ClangBackEnd

View File

@@ -1,291 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangdocuments.h"
#include <diagnosticset.h>
#include <tokenprocessor.h>
#include <clangexceptions.h>
#include <skippedsourceranges.h>
#include <unsavedfiles.h>
#include <utils/algorithm.h>
#include <QDebug>
#include <algorithm>
namespace ClangBackEnd {
bool operator==(const FileContainer &fileContainer, const Document &document)
{
return fileContainer.filePath == document.filePath();
}
bool operator==(const Document &document, const FileContainer &fileContainer)
{
return fileContainer == document;
}
Documents::Documents(UnsavedFiles &unsavedFiles)
: fileSystemWatcher(*this),
unsavedFiles_(unsavedFiles)
{
}
std::vector<Document> Documents::create(const QVector<FileContainer> &fileContainers)
{
checkIfDocumentsDoNotExist(fileContainers);
std::vector<Document> createdDocuments;
for (const FileContainer &fileContainer : fileContainers) {
if (fileContainer.hasUnsavedFileContent)
updateDocumentsWithChangedDependency(fileContainer.filePath);
createdDocuments.push_back(createDocument(fileContainer));
}
return createdDocuments;
}
std::vector<Document> Documents::update(const QVector<FileContainer> &fileContainers)
{
checkIfDocumentsForFilePathsExist(fileContainers);
std::vector<Document> createdDocuments;
for (const FileContainer &fileContainer : fileContainers) {
const std::vector<Document> documents = updateDocument(fileContainer);
createdDocuments.insert(createdDocuments.end(), documents.begin(), documents.end());
updateDocumentsWithChangedDependency(fileContainer.filePath);
}
return createdDocuments;
}
static bool removeFromFileContainer(QVector<FileContainer> &fileContainers, const Document &document)
{
auto position = std::remove(fileContainers.begin(), fileContainers.end(), document);
bool entryIsRemoved = position != fileContainers.end();
fileContainers.erase(position, fileContainers.end());
return entryIsRemoved;
}
void Documents::remove(const QVector<FileContainer> &fileContainers)
{
removeDocuments(fileContainers);
updateDocumentsWithChangedDependencies(fileContainers);
}
void Documents::setUsedByCurrentEditor(const Utf8String &filePath)
{
for (Document &document : documents_)
document.setIsUsedByCurrentEditor(document.filePath() == filePath);
}
void Documents::setVisibleInEditors(const Utf8StringVector &filePaths)
{
const TimePoint timePoint = Clock::now();
for (Document &document : documents_)
document.setIsVisibleInEditor(filePaths.contains(document.filePath()), timePoint);
}
const Document &Documents::document(const Utf8String &filePath) const
{
auto findIterator = findDocument(filePath);
if (findIterator == documents_.end())
throw DocumentDoesNotExistException(filePath);
return *findIterator;
}
const Document &Documents::document(const FileContainer &fileContainer) const
{
return document(fileContainer.filePath);
}
const std::vector<Document> &Documents::documents() const
{
return documents_;
}
const std::vector<Document> Documents::filtered(const IsMatchingDocument &isMatchingDocument) const
{
return Utils::filtered(documents_, isMatchingDocument);
}
std::vector<Document> Documents::dirtyAndVisibleButNotCurrentDocuments() const
{
return filtered([](const Document &document) {
return document.isDirty()
&& document.isVisibleInEditor()
&& !document.isUsedByCurrentEditor();
});
}
UnsavedFiles Documents::unsavedFiles() const
{
return unsavedFiles_;
}
void Documents::addWatchedFiles(QSet<Utf8String> &filePaths)
{
fileSystemWatcher.addFiles(filePaths);
}
void Documents::updateDocumentsWithChangedDependency(const Utf8String &filePath)
{
for (auto &document : documents_)
document.setDirtyIfDependencyIsMet(filePath);
}
void Documents::updateDocumentsWithChangedDependencies(const QVector<FileContainer> &fileContainers)
{
for (const FileContainer &fileContainer : fileContainers)
updateDocumentsWithChangedDependency(fileContainer.filePath);
}
QVector<FileContainer> Documents::newerFileContainers(const QVector<FileContainer> &fileContainers) const
{
QVector<FileContainer> newerContainers;
auto documentIsNewer = [this] (const FileContainer &fileContainer) {
try {
return document(fileContainer).documentRevision() != fileContainer.documentRevision;
} catch (const DocumentDoesNotExistException &) {
return true;
}
};
std::copy_if(fileContainers.cbegin(),
fileContainers.cend(),
std::back_inserter(newerContainers),
documentIsNewer);
return newerContainers;
}
const ClangFileSystemWatcher *Documents::clangFileSystemWatcher() const
{
return &fileSystemWatcher;
}
Document Documents::createDocument(const FileContainer &fileContainer)
{
const Document::FileExistsCheck checkIfFileExists = fileContainer.hasUnsavedFileContent
? Document::FileExistsCheck::DoNotCheck
: Document::FileExistsCheck::Check;
documents_.emplace_back(fileContainer.filePath,
fileContainer.compilationArguments,
fileContainer.headerPaths,
*this,
checkIfFileExists);
documents_.back().setDocumentRevision(fileContainer.documentRevision);
return documents_.back();
}
std::vector<Document> Documents::updateDocument(const FileContainer &fileContainer)
{
const auto documents = findAllDocumentsWithFilePath(fileContainer.filePath);
for (auto document : documents)
document.setDocumentRevision(fileContainer.documentRevision);
return documents;
}
std::vector<Document>::const_iterator Documents::findDocument(const FileContainer &fileContainer) const
{
return std::find(documents_.begin(), documents_.end(), fileContainer);
}
std::vector<Document> Documents::findAllDocumentsWithFilePath(const Utf8String &filePath)
{
const auto filePathCompare = [&filePath] (const Document &document) {
return document.filePath() == filePath;
};
std::vector<Document> documents;
std::copy_if(documents_.begin(),
documents_.end(),
std::back_inserter(documents),
filePathCompare);
return documents;
}
bool Documents::hasDocument(const Utf8String &filePath) const
{
auto filePathCompare = [&filePath] (const Document &document) {
return document.filePath() == filePath;
};
auto findIterator = std::find_if(documents_.begin(), documents_.end(), filePathCompare);
return findIterator != documents_.end();
}
void Documents::checkIfDocumentsDoNotExist(const QVector<FileContainer> &fileContainers) const
{
for (const FileContainer &fileContainer : fileContainers) {
if (hasDocument(fileContainer.filePath))
throw DocumentAlreadyExistsException(fileContainer.filePath);
}
}
void Documents::checkIfDocumentsForFilePathsExist(const QVector<FileContainer> &fileContainers) const
{
for (const FileContainer &fileContainer : fileContainers) {
if (!hasDocument(fileContainer.filePath))
throw DocumentDoesNotExistException(fileContainer.filePath);
}
}
void Documents::removeDocuments(const QVector<FileContainer> &fileContainers)
{
QVector<FileContainer> processedFileContainers = fileContainers;
auto removeBeginIterator = std::remove_if(documents_.begin(), documents_.end(), [&processedFileContainers] (const Document &document) {
return removeFromFileContainer(processedFileContainers, document);
});
documents_.erase(removeBeginIterator, documents_.end());
if (!processedFileContainers.isEmpty()) {
const FileContainer fileContainer = processedFileContainers.first();
throw DocumentDoesNotExistException(fileContainer.filePath);
}
}
} // namespace ClangBackEnd

View File

@@ -1,90 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "clangdocument.h"
#include "clangfilesystemwatcher.h"
#include <filecontainer.h>
#include <QVector>
#include <functional>
#include <vector>
namespace ClangBackEnd {
class UnsavedFiles;
class Documents
{
public:
Documents(UnsavedFiles &unsavedFiles);
std::vector<Document> create(const QVector<FileContainer> &fileContainers);
std::vector<Document> update(const QVector<FileContainer> &fileContainers);
void remove(const QVector<FileContainer> &fileContainers);
void setUsedByCurrentEditor(const Utf8String &filePath);
void setVisibleInEditors(const Utf8StringVector &filePaths);
const Document &document(const Utf8String &filePath) const;
const Document &document(const FileContainer &fileContainer) const;
bool hasDocument(const Utf8String &filePath) const;
const std::vector<Document> &documents() const;
using IsMatchingDocument = std::function<bool(const Document &document)>;
const std::vector<Document> filtered(const IsMatchingDocument &isMatchingDocument) const;
std::vector<Document> dirtyAndVisibleButNotCurrentDocuments() const;
UnsavedFiles unsavedFiles() const;
void addWatchedFiles(QSet<Utf8String> &filePaths);
void updateDocumentsWithChangedDependency(const Utf8String &filePath);
void updateDocumentsWithChangedDependencies(const QVector<FileContainer> &fileContainers);
QVector<FileContainer> newerFileContainers(const QVector<FileContainer> &fileContainers) const;
const ClangFileSystemWatcher *clangFileSystemWatcher() const;
private:
Document createDocument(const FileContainer &fileContainer);
std::vector<Document> updateDocument(const FileContainer &fileContainer);
std::vector<Document>::const_iterator findDocument(const FileContainer &fileContainer) const;
std::vector<Document> findAllDocumentsWithFilePath(const Utf8String &filePath);
void checkIfDocumentsDoNotExist(const QVector<FileContainer> &fileContainers) const;
void checkIfDocumentsForFilePathsExist(const QVector<FileContainer> &fileContainers) const;
void removeDocuments(const QVector<FileContainer> &fileContainers);
private:
ClangFileSystemWatcher fileSystemWatcher;
std::vector<Document> documents_;
UnsavedFiles &unsavedFiles_;
};
} // namespace ClangBackEnd

View File

@@ -1,134 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangdocumentsuspenderresumer.h"
#include "clangsupport_global.h"
#include "clangdocumentprocessors.h"
#include "clangdocuments.h"
#include <utils/algorithm.h>
#include <algorithm>
namespace ClangBackEnd {
constexpr int DefaultHotDocumentsSize = 7;
void categorizeHotColdDocuments(int hotDocumentsSize,
const std::vector<Document> &inDocuments,
std::vector<Document> &hotDocuments,
std::vector<Document> &coldDocuments)
{
// Sort documents, most recently used/visible at top
std::vector<Document> documents = inDocuments;
std::stable_sort(documents.begin(), documents.end(), [](const Document &a, const Document &b) {
return a.visibleTimePoint() > b.visibleTimePoint();
});
// Ensure that visible documents are always hot, otherwise not all visible
// documents will be resumed.
const auto isVisible = [](const Document &document) { return document.isVisibleInEditor(); };
const int visibleDocumentsSize = Utils::count(documents, isVisible);
hotDocumentsSize = std::max(hotDocumentsSize, visibleDocumentsSize);
if (documents.size() <= uint(hotDocumentsSize)) {
hotDocuments = documents;
coldDocuments.clear();
} else {
const auto firstColdIterator = documents.begin() + hotDocumentsSize;
hotDocuments = std::vector<Document>(documents.begin(), firstColdIterator);
coldDocuments = std::vector<Document>(firstColdIterator, documents.end());
}
}
static int hotDocumentsSize()
{
static int hotDocuments = -1;
if (hotDocuments == -1) {
bool ok = false;
const int fromEnvironment = qEnvironmentVariableIntValue("QTC_CLANG_HOT_DOCUMENTS", &ok);
hotDocuments = ok && fromEnvironment >= 1 ? fromEnvironment : DefaultHotDocumentsSize;
}
return hotDocuments;
}
static SuspendResumeJobs createJobs(const Document &document, JobRequest::Type type)
{
SuspendResumeJobs jobs;
jobs.append({document, type, PreferredTranslationUnit::RecentlyParsed});
if (document.isResponsivenessIncreased())
jobs.append({document, type, PreferredTranslationUnit::PreviouslyParsed});
return jobs;
}
static bool isFineDocument(const Document &document)
{
return !document.isNull() && document.isIntact();
}
static bool isSuspendable(const Document &document)
{
return isFineDocument(document)
&& !document.isSuspended()
&& !document.isVisibleInEditor()
&& document.isParsed();
}
static bool isResumable(const Document &document)
{
return isFineDocument(document)
&& document.isSuspended()
&& document.isVisibleInEditor();
}
SuspendResumeJobs createSuspendResumeJobs(const std::vector<Document> &documents,
int customHotDocumentSize)
{
SuspendResumeJobs jobs;
std::vector<Document> hotDocuments;
std::vector<Document> coldDocuments;
const int size = (customHotDocumentSize == -1) ? hotDocumentsSize() : customHotDocumentSize;
categorizeHotColdDocuments(size, documents, hotDocuments, coldDocuments);
// Cold documents should be suspended...
const std::vector<Document> toSuspend = Utils::filtered(coldDocuments, &isSuspendable);
for (const Document &document : toSuspend)
jobs += createJobs(document, JobRequest::Type::SuspendDocument);
// ...and hot documents that were suspended should be resumed
const std::vector<Document> toResume = Utils::filtered(hotDocuments, &isResumable);
for (const Document &document : toResume)
jobs += createJobs(document, JobRequest::Type::ResumeDocument);
return jobs;
}
} // namespace ClangBackEnd

View File

@@ -1,62 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "clangdocument.h"
#include "clangjobrequest.h"
#include <vector>
namespace ClangBackEnd {
class SuspendResumeJobsEntry {
public:
SuspendResumeJobsEntry() = default;
SuspendResumeJobsEntry(const Document &document,
JobRequest::Type jobRequestType,
PreferredTranslationUnit preferredTranslationUnit)
: document(document)
, jobRequestType(jobRequestType)
, preferredTranslationUnit(preferredTranslationUnit)
{
}
Document document;
JobRequest::Type jobRequestType = JobRequest::Type::SuspendDocument;
PreferredTranslationUnit preferredTranslationUnit = PreferredTranslationUnit::RecentlyParsed;
};
using SuspendResumeJobs = QVector<SuspendResumeJobsEntry>;
SuspendResumeJobs createSuspendResumeJobs(const std::vector<Document> &documents,
int customHotDocumentCounts = -1);
// for tests
void categorizeHotColdDocuments(int hotDocumentsSize,
const std::vector<Document> &inDocuments,
std::vector<Document> &hotDocuments,
std::vector<Document> &coldDocuments);
} // namespace ClangBackEnd

View File

@@ -1,83 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangexceptions.h"
namespace ClangBackEnd {
const char *ClangBaseException::what() const noexcept
{
return m_info.constData();
}
DocumentAlreadyExistsException::DocumentAlreadyExistsException(const Utf8String &filePath)
{
m_info += Utf8StringLiteral("Document '")
+ filePath
+ Utf8StringLiteral("' already exists!");
}
DocumentDoesNotExistException::DocumentDoesNotExistException(const Utf8String &filePath)
{
m_info += Utf8StringLiteral("Document '")
+ filePath
+ Utf8StringLiteral("' does not exist!");
}
DocumentFileDoesNotExistException::DocumentFileDoesNotExistException(
const Utf8String &filePath)
{
m_info += Utf8StringLiteral("File ")
+ filePath
+ Utf8StringLiteral(" does not exist in file system!");
}
DocumentIsNullException::DocumentIsNullException()
{
m_info = Utf8String::fromUtf8("Tried to access a null Document!");
}
DocumentProcessorAlreadyExists::DocumentProcessorAlreadyExists(const Utf8String &filePath)
{
m_info = Utf8StringLiteral("Document processor for file '")
+ filePath
+ Utf8StringLiteral("' already exists!");
}
DocumentProcessorDoesNotExist::DocumentProcessorDoesNotExist(const Utf8String &filePath)
{
m_info = Utf8StringLiteral("Document processor for file '")
+ filePath
+ Utf8StringLiteral("' does not exist!");
}
TranslationUnitDoesNotExist::TranslationUnitDoesNotExist(const Utf8String &filePath)
{
m_info += Utf8StringLiteral("TranslationUnit for file '")
+ filePath
+ Utf8StringLiteral("' does not exist.");
}
} // namespace ClangBackEnd

View File

@@ -1,87 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <utf8stringvector.h>
#include <clang-c/Index.h>
#include <exception>
namespace ClangBackEnd {
class ClangBaseException : public std::exception
{
public:
const char *what() const noexcept override;
protected:
Utf8String m_info;
};
class DocumentAlreadyExistsException : public ClangBaseException
{
public:
DocumentAlreadyExistsException(const Utf8String &filePath);
};
class DocumentDoesNotExistException : public ClangBaseException
{
public:
DocumentDoesNotExistException(const Utf8String &filePath);
};
class DocumentFileDoesNotExistException : public ClangBaseException
{
public:
DocumentFileDoesNotExistException(const Utf8String &filePath);
};
class DocumentIsNullException : public ClangBaseException
{
public:
DocumentIsNullException();
};
class DocumentProcessorAlreadyExists : public ClangBaseException
{
public:
DocumentProcessorAlreadyExists(const Utf8String &filePath);
};
class DocumentProcessorDoesNotExist : public ClangBaseException
{
public:
DocumentProcessorDoesNotExist(const Utf8String &filePath);
};
class TranslationUnitDoesNotExist : public ClangBaseException
{
public:
TranslationUnitDoesNotExist(const Utf8String &filePath);
};
} // namespace ClangBackEnd

View File

@@ -1,89 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangfilepath.h"
#include <utf8string.h>
#include <QByteArray>
#if defined(Q_OS_WIN)
// Parameterized QDir::toNativeSeparators/-fromNativeSeparators for QByteArray
static inline QByteArray replace(const QByteArray &pathName, char toReplace, char replacement)
{
int i = pathName.indexOf(toReplace);
if (i != -1) {
QByteArray n(pathName);
char * const data = n.data();
data[i++] = replacement;
for (; i < n.length(); ++i) {
if (data[i] == toReplace)
data[i] = replacement;
}
return n;
}
return pathName;
}
#endif
static QByteArray fromNativeSeparatorsForQByteArray(const QByteArray &pathName)
{
#if defined(Q_OS_WIN)
return replace(pathName, '\\', '/');
#else
return pathName;
#endif
}
static QByteArray toNativeSeparatorsForQByteArray(const QByteArray &pathName)
{
#if defined(Q_OS_WIN)
return replace(pathName, '/', '\\');
#else
return pathName;
#endif
}
namespace ClangBackEnd {
Utf8String FilePath::fromNativeSeparators(const Utf8String &pathName)
{
const QByteArray pathNameAsByteArray = pathName.toByteArray();
return Utf8String::fromUtf8(fromNativeSeparatorsForQByteArray(pathNameAsByteArray));
}
Utf8String FilePath::toNativeSeparators(const Utf8String &pathName)
{
const QByteArray pathNameAsByteArray = pathName.toByteArray();
return Utf8String::fromUtf8(toNativeSeparatorsForQByteArray(pathNameAsByteArray));
}
} // namespace ClangBackEnd

View File

@@ -1,38 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
class Utf8String;
namespace ClangBackEnd {
class FilePath {
public:
static Utf8String fromNativeSeparators(const Utf8String &pathName);
static Utf8String toNativeSeparators(const Utf8String &pathName);
};
} // namespace ClangBackEnd

View File

@@ -1,91 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangfilesystemwatcher.h"
#include "clangdocuments.h"
#include <utf8stringvector.h>
#include <QFileInfo>
#include <QStringList>
#include <algorithm>
#include <iterator>
namespace ClangBackEnd {
namespace {
QStringList toStringList(const QSet<Utf8String> &files)
{
QStringList resultList;
resultList.reserve(files.size());
std::copy(files.cbegin(), files.cend(), std::back_inserter(resultList));
return resultList;
}
QStringList filterExistingFiles(QStringList &&filePaths)
{
auto fileExists = [] (const QString &filePath) {
return QFileInfo::exists(filePath);
};
auto startOfNonExistingFilePaths = std::partition(filePaths.begin(),
filePaths.end(),
fileExists);
filePaths.erase(startOfNonExistingFilePaths, filePaths.end());
return std::move(filePaths);
}
}
ClangFileSystemWatcher::ClangFileSystemWatcher(Documents &documents)
: documents(documents)
{
connect(&watcher,
&QFileSystemWatcher::fileChanged,
this,
&ClangFileSystemWatcher::updateDocumentsWithChangedDependencies);
}
void ClangFileSystemWatcher::addFiles(const QSet<Utf8String> &filePaths)
{
const auto existingFiles = filterExistingFiles(toStringList(filePaths));
if (!existingFiles.isEmpty())
watcher.addPaths(existingFiles);
}
void ClangFileSystemWatcher::updateDocumentsWithChangedDependencies(const QString &filePath)
{
documents.updateDocumentsWithChangedDependency(filePath);
emit fileChanged(filePath);
}
} // namespace ClangBackEnd

View File

@@ -1,57 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <QFileSystemWatcher>
#include <QSet>
class Utf8String;
namespace ClangBackEnd {
class Documents;
class ClangFileSystemWatcher : public QObject
{
Q_OBJECT
public:
ClangFileSystemWatcher(Documents &documents);
void addFiles(const QSet<Utf8String> &filePaths);
signals:
void fileChanged(const Utf8String &filePath);
private:
void updateDocumentsWithChangedDependencies(const QString &filePath);
private:
QFileSystemWatcher watcher;
Documents &documents;
};
} // namespace ClangBackEnd

View File

@@ -1,163 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangfollowsymbol.h"
#include "clangfollowsymboljob.h"
#include "commandlinearguments.h"
#include "cursor.h"
#include "clangstring.h"
#include "sourcerange.h"
#include "token.h"
#include "clangsupportdebugutils.h"
#include <utils/qtcassert.h>
#include <future>
namespace ClangBackEnd {
static SourceRange getOperatorRange(const Tokens &tokens,
std::vector<Token>::const_iterator currentToken)
{
const SourceLocation start = currentToken->location();
currentToken += 2;
while (currentToken != tokens.cend() && !(currentToken->spelling() == "("))
++currentToken;
return SourceRange(start, currentToken->location());
}
static SourceRangeContainer extractMatchingTokenRange(const Cursor &cursor,
const Utf8String &tokenStr)
{
Tokens tokens(cursor.sourceRange());
for (auto it = tokens.cbegin(); it != tokens.cend(); ++it) {
const Token &currentToken = *it;
if (!(tokenStr == currentToken.spelling()))
continue;
if (cursor.isFunctionLike() || cursor.isConstructorOrDestructor()) {
if (tokenStr == "operator")
return getOperatorRange(tokens, it);
auto nextIt = it + 1;
if (nextIt == tokens.cend() || !(nextIt->spelling() == "("))
continue;
}
return currentToken.extent();
}
return SourceRangeContainer();
}
FollowSymbolResult FollowSymbol::followSymbol(CXTranslationUnit tu,
const Cursor &fullCursor,
uint line,
uint column)
{
Tokens tokens(fullCursor.sourceRange());
if (!tokens.size()) {
const Cursor tuCursor(clang_getTranslationUnitCursor(tu));
tokens = Tokens(tuCursor.sourceRange());
}
if (!tokens.size())
return SourceRangeContainer();
std::vector<Cursor> cursors = tokens.annotate();
const int tokenIndex = tokens.getTokenIndex(tu, line, column);
QTC_ASSERT(tokenIndex >= 0, return SourceRangeContainer());
const Utf8String tokenSpelling = tokens[tokenIndex].spelling();
if (tokenSpelling.isEmpty())
return SourceRangeContainer();
Cursor cursor{cursors[tokenIndex]};
if (cursor.kind() == CXCursor_CXXThisExpr && tokenSpelling != "this") { // QTCREATORBUG-25342
cursor.semanticParent().visit([&cursor](CXCursor current, CXCursor parent) {
if (current == cursor && parent.kind == CXCursor_MemberRefExpr
&& cursor.sourceLocation() == Cursor(parent).sourceLocation()) {
cursor = parent;
return CXChildVisit_Break;
}
return CXChildVisit_Recurse;
});
}
if (cursor.kind() == CXCursor_InclusionDirective) {
CXFile file = clang_getIncludedFile(cursors[tokenIndex].cx());
const ClangString filename(clang_getFileName(file));
const SourceLocation loc(tu, clang_getLocation(tu, file, 1, 1));
FollowSymbolResult result;
result.range = SourceRangeContainer(SourceRange(loc, loc));
// CLANG-UPGRADE-CHECK: Remove if we don't use empty generated ui_* headers anymore.
if (Utf8String(filename).contains("ui_"))
result.isResultOnlyForFallBack = true;
return result;
}
// For definitions we can always find a declaration in current TU
if (cursor.isDefinition()) {
if (tokenSpelling == "auto") {
Type type = cursor.type().pointeeType();
if (!type.isValid())
type = cursor.type();
const Cursor declCursor = type.declaration();
return extractMatchingTokenRange(declCursor, declCursor.spelling());
}
const Cursor declCursor = cursor.canonical();
FollowSymbolResult result;
result.range = extractMatchingTokenRange(declCursor, tokenSpelling);
result.isResultOnlyForFallBack = cursor.isFunctionLike() && declCursor == cursor;
return result;
}
if (!cursor.isDeclaration()) {
// This is the symbol usage
// We want to return definition
cursor = cursor.referenced();
if (cursor.isNull())
return SourceRangeContainer();
FollowSymbolResult result;
// We can't find definition in this TU or it's a virtual method call
if (!cursor.isDefinition() || cursor.isVirtualMethod())
result.isResultOnlyForFallBack = true;
result.range = extractMatchingTokenRange(cursor, tokenSpelling);
return result;
}
const bool isFunction = cursor.isFunctionLike();
cursor = cursor.definition();
// If we are able to find a definition in current TU
if (!cursor.isNull())
return extractMatchingTokenRange(cursor, tokenSpelling);
return FollowSymbolResult({}, isFunction);
}
} // namespace ClangBackEnd

View File

@@ -1,50 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <QVector>
#include <clang-c/Index.h>
class Utf8String;
namespace ClangBackEnd {
class CommandLineArguments;
class Cursor;
class FollowSymbolResult;
class SourceRangeContainer;
class FollowSymbol
{
public:
static FollowSymbolResult followSymbol(CXTranslationUnit tu,
const Cursor &fullCursor,
uint line,
uint column);
};
} // namespace ClangBackEnd

View File

@@ -1,68 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangfollowsymboljob.h"
#include <clangsupport/clangsupportdebugutils.h>
#include <clangsupport/followsymbolmessage.h>
#include <clangsupport/clangcodemodelclientinterface.h>
#include <utils/qtcassert.h>
namespace ClangBackEnd {
IAsyncJob::AsyncPrepareResult FollowSymbolJob::prepareAsyncRun()
{
const JobRequest jobRequest = context().jobRequest;
QTC_ASSERT(jobRequest.type == JobRequest::Type::RequestFollowSymbol,
return AsyncPrepareResult());
QTC_ASSERT(acquireDocument(), return AsyncPrepareResult());
const TranslationUnit translationUnit = *m_translationUnit;
const TranslationUnitUpdateInput updateInput = m_pinnedDocument.createUpdateInput();
const quint32 line = jobRequest.line;
const quint32 column = jobRequest.column;
setRunner([translationUnit, line, column]() {
TIME_SCOPE_DURATION("FollowSymbolJobRunner");
return translationUnit.followSymbol(line, column);
});
return AsyncPrepareResult{translationUnit.id()};
}
void FollowSymbolJob::finalizeAsyncRun()
{
if (!context().isOutdated()) {
const AsyncResult result = asyncResult();
const FollowSymbolMessage message(m_pinnedFileContainer,
result,
context().jobRequest.ticketNumber);
context().client->followSymbol(message);
}
}
} // namespace ClangBackEnd

View File

@@ -1,43 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "clangdocumentjob.h"
#include <clangsupport/followsymbolmessage.h>
#include <clangsupport/sourcerangecontainer.h>
namespace ClangBackEnd {
class FollowSymbolJob : public DocumentJob<FollowSymbolResult>
{
public:
using AsyncResult = FollowSymbolResult;
AsyncPrepareResult prepareAsyncRun() override;
void finalizeAsyncRun() override;
};
} // namespace ClangBackEnd

View File

@@ -1,71 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangiasyncjob.h"
Q_LOGGING_CATEGORY(jobsLog, "qtc.clangbackend.jobs", QtWarningMsg);
namespace ClangBackEnd {
IAsyncJob::IAsyncJob()
: m_context(JobContext())
{
}
IAsyncJob::~IAsyncJob()
{
}
JobContext IAsyncJob::context() const
{
return m_context;
}
void IAsyncJob::setContext(const JobContext &context)
{
m_context = context;
}
IAsyncJob::FinishedHandler IAsyncJob::finishedHandler() const
{
return m_finishedHandler;
}
void IAsyncJob::setFinishedHandler(const IAsyncJob::FinishedHandler &finishedHandler)
{
m_finishedHandler = finishedHandler;
}
bool IAsyncJob::isFinished() const
{
return m_isFinished;
}
void IAsyncJob::setIsFinished(bool isFinished)
{
m_isFinished = isFinished;
}
} // namespace ClangBackEnd

View File

@@ -1,75 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "clangjobcontext.h"
#include <QFuture>
#include <QLoggingCategory>
#include <functional>
Q_DECLARE_LOGGING_CATEGORY(jobsLog);
#define qCDebugJobs() qCDebug(jobsLog) << "[" << m_logTag << "]"
namespace ClangBackEnd {
class IAsyncJob
{
public:
struct AsyncPrepareResult {
operator bool() const { return !translationUnitId.isEmpty(); }
Utf8String translationUnitId;
};
public:
IAsyncJob();
virtual ~IAsyncJob();
JobContext context() const;
void setContext(const JobContext &context);
using FinishedHandler = std::function<void(IAsyncJob *job)>;
FinishedHandler finishedHandler() const;
void setFinishedHandler(const FinishedHandler &finishedHandler);
virtual AsyncPrepareResult prepareAsyncRun() = 0;
virtual QFuture<void> runAsync() = 0;
virtual void finalizeAsyncRun() = 0;
virtual void preventFinalization() = 0;
public: // for tests
bool isFinished() const;
void setIsFinished(bool isFinished);
private:
bool m_isFinished = false;
FinishedHandler m_finishedHandler;
JobContext m_context;
};
} // namespace ClangBackEnd

View File

@@ -1,73 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangiasyncjob.h"
#include "clangdocuments.h"
namespace ClangBackEnd {
JobContext::JobContext(const JobRequest &jobRequest,
Documents *documents,
UnsavedFiles *unsavedFiles,
ClangCodeModelClientInterface *clientInterface)
: jobRequest(jobRequest)
, documents(documents)
, unsavedFiles(unsavedFiles)
, client(clientInterface)
{
}
Document JobContext::documentForJobRequest() const
{
return documents->document(jobRequest.filePath);
}
bool JobContext::isOutdated() const
{
return !isDocumentOpen() || documentRevisionChanged();
}
bool JobContext::isDocumentOpen() const
{
const bool hasDocument = documents->hasDocument(jobRequest.filePath);
if (!hasDocument)
qCDebug(jobsLog) << "Document already closed for results of" << jobRequest;
return hasDocument;
}
bool JobContext::documentRevisionChanged() const
{
const Document &document = documents->document(jobRequest.filePath);
const bool revisionChanged = document.documentRevision() != jobRequest.documentRevision;
if (revisionChanged)
qCDebug(jobsLog) << "Document revision changed for results of" << jobRequest;
return revisionChanged;
}
} // ClangBackEnd

View File

@@ -1,59 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "clangjobrequest.h"
namespace ClangBackEnd {
class ClangCodeModelClientInterface;
class Document;
class Documents;
class UnsavedFiles;
class JobContext
{
public:
JobContext() = default;
JobContext(const JobRequest &jobRequest,
Documents *documents,
UnsavedFiles *unsavedFiles,
ClangCodeModelClientInterface *client);
Document documentForJobRequest() const;
bool isOutdated() const;
bool isDocumentOpen() const;
bool documentRevisionChanged() const;
public:
JobRequest jobRequest;
Documents *documents = nullptr;
UnsavedFiles *unsavedFiles = nullptr;
ClangCodeModelClientInterface *client = nullptr;
};
} // namespace ClangBackEnd

View File

@@ -1,313 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangiasyncjob.h"
#include "clangjobqueue.h"
#include "clangdocument.h"
#include "clangdocuments.h"
#include "clangtranslationunits.h"
#include "unsavedfiles.h"
#include <utils/algorithm.h>
namespace ClangBackEnd {
JobQueue::JobQueue(Documents &documents, const Utf8String &logTag)
: m_documents(documents)
, m_logTag(logTag)
{
}
bool JobQueue::add(const JobRequest &job)
{
QString notAddableReason;
if (isJobRequestAddable(job, notAddableReason)) {
qCDebugJobs() << "Adding" << job;
m_queue.append(job);
return true;
} else {
qCDebugJobs() << "Not adding" << job << notAddableReason;
cancelJobRequest(job);
return false;
}
}
int JobQueue::size() const
{
return m_queue.size();
}
JobRequests JobQueue::processQueue()
{
removeExpiredRequests();
prioritizeRequests();
const JobRequests jobsToRun = takeJobRequestsToRunNow();
return jobsToRun;
}
void JobQueue::removeExpiredRequests()
{
JobRequests cleanedRequests;
foreach (const JobRequest &jobRequest, m_queue) {
try {
QString expirationReason;
if (isJobRequestExpired(jobRequest, expirationReason)) {
qCDebugJobs() << "Expired:" << jobRequest << expirationReason;
cancelJobRequest(jobRequest);
} else {
cleanedRequests.append(jobRequest);
}
} catch (const std::exception &exception) {
qWarning() << "Error in Jobs::removeOutDatedRequests for"
<< jobRequest << ":" << exception.what();
}
}
m_queue = cleanedRequests;
}
bool JobQueue::isJobRequestAddable(const JobRequest &jobRequest, QString &notAddableReason)
{
if (m_queue.contains(jobRequest)) {
notAddableReason = "duplicate request in queue";
return false;
}
if (isJobRunningForJobRequest(jobRequest)) {
notAddableReason = "duplicate request for already running job";
return false;
}
if (!m_documents.hasDocument(jobRequest.filePath)) {
notAddableReason = "document already closed";
return false;
}
const Document document = m_documents.document(jobRequest.filePath);
if (!document.isIntact()) {
notAddableReason = "document not intact";
return false;
}
return true;
}
bool JobQueue::isJobRequestExpired(const JobRequest &jobRequest, QString &expirationReason)
{
const JobRequest::ExpirationConditions conditions = jobRequest.expirationConditions;
const UnsavedFiles unsavedFiles = m_documents.unsavedFiles();
using Condition = JobRequest::ExpirationCondition;
if (conditions.testFlag(Condition::UnsavedFilesChanged)) {
if (jobRequest.unsavedFilesChangeTimePoint != unsavedFiles.lastChangeTimePoint()) {
expirationReason = "outdated unsaved files";
return true;
}
}
if (conditions.testFlag(Condition::DocumentClosed)) {
if (!m_documents.hasDocument(jobRequest.filePath)) {
expirationReason = "document already closed";
return true;
}
const Document document
= m_documents.document(jobRequest.filePath);
if (!document.isIntact()) {
expirationReason = "document not intact";
return true;
}
if (conditions.testFlag(Condition::DocumentRevisionChanged)) {
if (document.documentRevision() > jobRequest.documentRevision) {
expirationReason = "changed document revision";
return true;
}
}
}
return false;
}
static int priority(const Document &document)
{
int thePriority = 0;
if (document.isUsedByCurrentEditor())
thePriority += 1000;
if (document.isVisibleInEditor())
thePriority += 100;
return thePriority;
}
void JobQueue::prioritizeRequests()
{
const auto lessThan = [this] (const JobRequest &r1, const JobRequest &r2) {
// TODO: Getting the TU is O(n) currently, so this might become expensive for large n.
const Document &t1 = m_documents.document(r1.filePath);
const Document &t2 = m_documents.document(r2.filePath);
return priority(t1) > priority(t2);
};
std::stable_sort(m_queue.begin(), m_queue.end(), lessThan);
}
void JobQueue::cancelJobRequest(const JobRequest &jobRequest)
{
if (m_cancelJobRequest)
m_cancelJobRequest(jobRequest);
}
bool JobQueue::areRunConditionsMet(const JobRequest &request, const Document &document) const
{
using Condition = JobRequest::RunCondition;
const JobRequest::RunConditions conditions = request.runConditions;
if (conditions.testFlag(Condition::DocumentSuspended) && !document.isSuspended()) {
qCDebugJobs() << "Not choosing due to unsuspended document:" << request;
return false;
}
if (conditions.testFlag(Condition::DocumentUnsuspended) && document.isSuspended()) {
qCDebugJobs() << "Not choosing due to suspended document:" << request;
return false;
}
if (conditions.testFlag(Condition::DocumentVisible) && !document.isVisibleInEditor()) {
qCDebugJobs() << "Not choosing due to invisible document:" << request;
return false;
}
if (conditions.testFlag(Condition::DocumentNotVisible) && document.isVisibleInEditor()) {
qCDebugJobs() << "Not choosing due to visible document:" << request;
return false;
}
if (conditions.testFlag(Condition::CurrentDocumentRevision)) {
if (document.isDirty()) {
// TODO: If the document is dirty due to a project update,
// references are processes later than ideal.
qCDebugJobs() << "Not choosing due to dirty document:" << request;
return false;
}
if (request.documentRevision != document.documentRevision()) {
qCDebugJobs() << "Not choosing due to revision mismatch:" << request;
return false;
}
}
if (conditions.testFlag(Condition::DocumentParsed)
&& !document.translationUnits().hasParsedTranslationUnit()) {
qCDebugJobs() << "Not choosing due to not yet parsed translation unit:" << request;
return false;
}
return true;
}
JobRequests JobQueue::takeJobRequestsToRunNow()
{
JobRequests jobsToRun;
using TranslationUnitIds = QSet<Utf8String>;
TranslationUnitIds translationUnitsScheduledForThisRun;
for (int pos = 0; pos < m_queue.size(); ++pos) {
const JobRequest &request = m_queue.at(pos);
try {
const Document &document = m_documents.document(request.filePath);
if (!areRunConditionsMet(request, document))
continue;
const Utf8String id = document.translationUnit(request.preferredTranslationUnit).id();
if (translationUnitsScheduledForThisRun.contains(id))
continue;
if (isJobRunningForTranslationUnit(id))
continue;
translationUnitsScheduledForThisRun.insert(id);
jobsToRun += request;
m_queue.removeAt(pos--);
} catch (const std::exception &exception) {
qWarning() << "Error in Jobs::takeJobRequestsToRunNow for"
<< request << ":" << exception.what();
}
}
return jobsToRun;
}
bool JobQueue::isJobRunningForTranslationUnit(const Utf8String &translationUnitId)
{
if (m_isJobRunningForTranslationUnitHandler)
return m_isJobRunningForTranslationUnitHandler(translationUnitId);
return false;
}
bool JobQueue::isJobRunningForJobRequest(const JobRequest &jobRequest)
{
if (m_isJobRunningForJobRequestHandler)
return m_isJobRunningForJobRequestHandler(jobRequest);
return false;
}
void JobQueue::setIsJobRunningForTranslationUnitHandler(
const IsJobRunningForTranslationUnitHandler &isJobRunningHandler)
{
m_isJobRunningForTranslationUnitHandler = isJobRunningHandler;
}
void JobQueue::setIsJobRunningForJobRequestHandler(
const JobQueue::IsJobRunningForJobRequestHandler &isJobRunningHandler)
{
m_isJobRunningForJobRequestHandler = isJobRunningHandler;
}
void JobQueue::setCancelJobRequest(const JobQueue::CancelJobRequest &cancelJobRequest)
{
m_cancelJobRequest = cancelJobRequest;
}
JobRequests &JobQueue::queue()
{
return m_queue;
}
const JobRequests &JobQueue::queue() const
{
return m_queue;
}
} // namespace ClangBackEnd

View File

@@ -1,83 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "clangjobrequest.h"
#include <functional>
namespace ClangBackEnd {
class Documents;
class JobQueue
{
public:
JobQueue(Documents &documents, const Utf8String &logTag = Utf8String());
bool add(const JobRequest &job);
JobRequests processQueue();
using IsJobRunningForTranslationUnitHandler = std::function<bool(const Utf8String &)>;
void setIsJobRunningForTranslationUnitHandler(
const IsJobRunningForTranslationUnitHandler &isJobRunningHandler);
using IsJobRunningForJobRequestHandler = std::function<bool(const JobRequest &)>;
void setIsJobRunningForJobRequestHandler(
const IsJobRunningForJobRequestHandler &isJobRunningHandler);
using CancelJobRequest = std::function<void(const JobRequest &)>;
void setCancelJobRequest(const CancelJobRequest &cancelJobRequest);
public: // for tests
JobRequests &queue();
const JobRequests &queue() const;
int size() const;
void prioritizeRequests();
private:
bool areRunConditionsMet(const JobRequest &request, const Document &document) const;
void cancelJobRequest(const JobRequest &jobRequest);
bool isJobRunningForTranslationUnit(const Utf8String &translationUnitId);
bool isJobRunningForJobRequest(const JobRequest &jobRequest);
JobRequests takeJobRequestsToRunNow();
void removeExpiredRequests();
bool isJobRequestAddable(const JobRequest &jobRequest, QString &notAddableReason);
bool isJobRequestExpired(const JobRequest &jobRequest, QString &expirationReason);
private:
Documents &m_documents;
Utf8String m_logTag;
IsJobRunningForTranslationUnitHandler m_isJobRunningForTranslationUnitHandler;
IsJobRunningForJobRequestHandler m_isJobRunningForJobRequestHandler;
CancelJobRequest m_cancelJobRequest;
JobRequests m_queue;
};
} // namespace ClangBackEnd

View File

@@ -1,299 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangjobrequest.h"
#include "clangcompletecodejob.h"
#include "clangfollowsymboljob.h"
#include "clangparsesupportivetranslationunitjob.h"
#include "clangrequestannotationsjob.h"
#include "clangrequestreferencesjob.h"
#include "clangrequesttooltipjob.h"
#include "clangresumedocumentjob.h"
#include "clangsuspenddocumentjob.h"
#include "clangupdateannotationsjob.h"
#include "clangupdateextraannotationsjob.h"
#include <clangsupport/clangcodemodelclientinterface.h>
#include <clangsupport/completionsmessage.h>
#include <clangsupport/followsymbolmessage.h>
#include <clangsupport/referencesmessage.h>
#include <clangsupport/tooltipmessage.h>
#include <utils/qtcassert.h>
#include <QFileInfo>
#include <ostream>
namespace ClangBackEnd {
#define RETURN_TEXT_FOR_CASE(enumValue) case JobRequest::Type::enumValue: return #enumValue
static const char *JobRequestTypeToText(JobRequest::Type type)
{
switch (type) {
RETURN_TEXT_FOR_CASE(Invalid);
RETURN_TEXT_FOR_CASE(UpdateAnnotations);
RETURN_TEXT_FOR_CASE(UpdateExtraAnnotations);
RETURN_TEXT_FOR_CASE(ParseSupportiveTranslationUnit);
RETURN_TEXT_FOR_CASE(RequestCompletions);
RETURN_TEXT_FOR_CASE(RequestAnnotations);
RETURN_TEXT_FOR_CASE(RequestReferences);
RETURN_TEXT_FOR_CASE(RequestFollowSymbol);
RETURN_TEXT_FOR_CASE(RequestToolTip);
RETURN_TEXT_FOR_CASE(SuspendDocument);
RETURN_TEXT_FOR_CASE(ResumeDocument);
}
return "UnhandledJobRequestType";
}
#undef RETURN_TEXT_FOR_CASE
#define RETURN_TEXT_FOR_CASE(enumValue) case PreferredTranslationUnit::enumValue: return #enumValue
const char *preferredTranslationUnitToText(PreferredTranslationUnit type)
{
switch (type) {
RETURN_TEXT_FOR_CASE(RecentlyParsed);
RETURN_TEXT_FOR_CASE(PreviouslyParsed);
RETURN_TEXT_FOR_CASE(LastUninitialized);
}
return "UnhandledPreferredTranslationUnitType";
}
#undef RETURN_TEXT_FOR_CASE
QDebug operator<<(QDebug debug, JobRequest::Type type)
{
debug << JobRequestTypeToText(type);
return debug;
}
std::ostream &operator<<(std::ostream &os, JobRequest::Type type)
{
return os << JobRequestTypeToText(type);
}
std::ostream &operator<<(std::ostream &os, PreferredTranslationUnit preferredTranslationUnit)
{
return os << preferredTranslationUnitToText(preferredTranslationUnit);
}
QDebug operator<<(QDebug debug, const JobRequest &jobRequest)
{
debug.nospace() << "Job<"
<< jobRequest.id
<< ","
<< QFileInfo(jobRequest.filePath).fileName()
<< ","
<< JobRequestTypeToText(jobRequest.type)
<< ","
<< preferredTranslationUnitToText(jobRequest.preferredTranslationUnit)
<< ">";
return debug.space();
}
static JobRequest::ExpirationConditions expirationConditionsForType(JobRequest::Type type)
{
using Type = JobRequest::Type;
using Condition = JobRequest::ExpirationCondition;
using Conditions = JobRequest::ExpirationConditions;
switch (type) {
case Type::UpdateAnnotations:
case Type::UpdateExtraAnnotations:
return Conditions(Condition::AnythingChanged);
case Type::RequestReferences:
case Type::RequestAnnotations:
case Type::RequestToolTip:
case Type::RequestFollowSymbol:
return Conditions(Condition::DocumentClosed)
| Conditions(Condition::DocumentRevisionChanged);
default:
return Condition::DocumentClosed;
}
}
static JobRequest::RunConditions conditionsForType(JobRequest::Type type)
{
using Type = JobRequest::Type;
using Condition = JobRequest::RunCondition;
using Conditions = JobRequest::RunConditions;
if (type == Type::SuspendDocument) {
return Conditions(Condition::DocumentUnsuspended)
| Conditions(Condition::DocumentNotVisible);
}
if (type == Type::ResumeDocument) {
return Conditions(Condition::DocumentSuspended)
| Conditions(Condition::DocumentVisible);
}
Conditions conditions = Conditions(Condition::DocumentUnsuspended)
| Conditions(Condition::DocumentVisible);
if (type == Type::RequestReferences || type == Type::RequestFollowSymbol
|| type == Type::RequestToolTip || type == Type::UpdateExtraAnnotations) {
conditions |= Condition::CurrentDocumentRevision;
}
if (type != Type::UpdateAnnotations && type != Type::ParseSupportiveTranslationUnit)
conditions |= Condition::DocumentParsed;
return conditions;
}
bool JobRequest::isTakeOverable() const
{
// When new project information comes in and there are unprocessed jobs
// in the queue, we need to decide what to do with them.
switch (type) {
// Never discard these as the client side might wait for a response.
case Type::RequestCompletions:
case Type::RequestReferences:
case Type::RequestFollowSymbol:
case Type::RequestToolTip:
return true;
// Discard this one as UpdateAnnotations will have the same effect.
case Type::RequestAnnotations:
// Discard Suspend because the document will be cleared anyway.
// Discard Resume because a (re)parse will happen on demand.
case Type::SuspendDocument:
case Type::ResumeDocument:
// Discard these as they are initial jobs that will be recreated on demand
// anyway.
case Type::UpdateAnnotations:
case Type::UpdateExtraAnnotations:
// Discard these as they only make sense in a row. Avoid splitting them up.
case Type::ParseSupportiveTranslationUnit:
case Type::Invalid:
return false;
}
return false;
}
JobRequest::JobRequest(Type type)
{
static quint64 idCounter = 0;
id = ++idCounter;
this->type = type;
runConditions = conditionsForType(type);
expirationConditions = expirationConditionsForType(type);
}
IAsyncJob *JobRequest::createJob() const
{
switch (type) {
case JobRequest::Type::Invalid:
QTC_CHECK(false && "Cannot create job for invalid job request.");
break;
case JobRequest::Type::UpdateAnnotations:
return new UpdateAnnotationsJob();
case JobRequest::Type::UpdateExtraAnnotations:
return new UpdateExtraAnnotationsJob();
case JobRequest::Type::ParseSupportiveTranslationUnit:
return new ParseSupportiveTranslationUnitJob();
case JobRequest::Type::RequestCompletions:
return new CompleteCodeJob();
case JobRequest::Type::RequestAnnotations:
return new RequestAnnotationsJob();
case JobRequest::Type::RequestReferences:
return new RequestReferencesJob();
case JobRequest::Type::RequestToolTip:
return new RequestToolTipJob();
case JobRequest::Type::RequestFollowSymbol:
return new FollowSymbolJob();
case JobRequest::Type::SuspendDocument:
return new SuspendDocumentJob();
case JobRequest::Type::ResumeDocument:
return new ResumeDocumentJob();
}
return nullptr;
}
void JobRequest::cancelJob(ClangCodeModelClientInterface &client) const
{
// If a job request with a ticket number is cancelled, the plugin side
// must get back some results in order to clean up the state there.
switch (type) {
case JobRequest::Type::Invalid:
case JobRequest::Type::UpdateAnnotations:
case JobRequest::Type::UpdateExtraAnnotations:
case JobRequest::Type::ParseSupportiveTranslationUnit:
case JobRequest::Type::RequestAnnotations:
case JobRequest::Type::SuspendDocument:
case JobRequest::Type::ResumeDocument:
break;
case JobRequest::Type::RequestReferences:
client.references(ReferencesMessage(FileContainer(),
QVector<SourceRangeContainer>(),
false,
ticketNumber));
break;
case JobRequest::Type::RequestToolTip:
client.tooltip(ToolTipMessage(FileContainer(), ToolTipInfo(), ticketNumber));
break;
case JobRequest::Type::RequestCompletions:
client.completions(CompletionsMessage(CodeCompletions(), ticketNumber));
break;
case JobRequest::Type::RequestFollowSymbol:
client.followSymbol(
FollowSymbolMessage(FileContainer(), SourceRangeContainer(), ticketNumber));
break;
}
}
bool JobRequest::operator==(const JobRequest &other) const
{
return type == other.type
&& expirationConditions == other.expirationConditions
&& runConditions == other.runConditions
&& filePath == other.filePath
&& unsavedFilesChangeTimePoint == other.unsavedFilesChangeTimePoint
&& documentRevision == other.documentRevision
&& preferredTranslationUnit == other.preferredTranslationUnit
&& line == other.line
&& column == other.column
&& ticketNumber == other.ticketNumber;
// Additional members that are not compared here explicitly are
// supposed to depend on the already compared ones.
}
} // namespace ClangBackEnd

View File

@@ -1,128 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "clangbackend_global.h"
#include "clangclock.h"
#include <utf8string.h>
#include <utf8stringvector.h>
#include <QFlags>
#include <QDebug>
#include <QVector>
#include <functional>
namespace ClangBackEnd {
class ClangCodeModelClientInterface;
class Document;
class IAsyncJob;
class JobRequest
{
public:
enum class Type {
Invalid,
UpdateAnnotations,
UpdateExtraAnnotations,
ParseSupportiveTranslationUnit,
RequestCompletions,
RequestAnnotations,
RequestReferences,
RequestFollowSymbol,
RequestToolTip,
SuspendDocument,
ResumeDocument,
};
enum class RunCondition {
NoCondition = 1 << 0,
DocumentVisible = 1 << 1,
DocumentNotVisible = 1 << 2,
DocumentSuspended = 1 << 3,
DocumentUnsuspended = 1 << 4,
DocumentParsed = 1 << 5,
CurrentDocumentRevision = 1 << 6,
};
Q_DECLARE_FLAGS(RunConditions, RunCondition)
enum class ExpirationCondition {
Never = 1 << 0,
DocumentClosed = 1 << 1,
DocumentRevisionChanged = 1 << 2, // Only effective if DocumentIsClosed is also set
UnsavedFilesChanged = 1 << 3,
AnythingChanged = DocumentClosed
| DocumentRevisionChanged
| UnsavedFilesChanged,
};
Q_DECLARE_FLAGS(ExpirationConditions, ExpirationCondition)
public:
JobRequest(Type type = Type::Invalid);
IAsyncJob *createJob() const;
void cancelJob(ClangCodeModelClientInterface &client) const;
bool isTakeOverable() const;
bool operator==(const JobRequest &other) const;
friend QDebug operator<<(QDebug debug, const JobRequest &jobRequest);
public:
quint64 id = 0;
Type type;
ExpirationConditions expirationConditions;
RunConditions runConditions;
// General
Utf8String filePath;
TimePoint unsavedFilesChangeTimePoint;
uint documentRevision = 0;
PreferredTranslationUnit preferredTranslationUnit = PreferredTranslationUnit::RecentlyParsed;
// Specific to some jobs
quint32 line = 0;
quint32 column = 0;
qint32 funcNameStartLine = -1;
qint32 funcNameStartColumn = -1;
quint64 ticketNumber = 0;
Utf8String textCodecName;
bool localReferences = false;
};
using JobRequests = QVector<JobRequest>;
std::ostream &operator<<(std::ostream &os, JobRequest::Type type);
std::ostream &operator<<(std::ostream &os, PreferredTranslationUnit preferredTranslationUnit);
} // namespace ClangBackEnd

View File

@@ -1,226 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangjobs.h"
#include "clangdocument.h"
#include "clangiasyncjob.h"
#include <QDebug>
#include <QLoggingCategory>
#include <utils/algorithm.h>
#include <utils/futuresynchronizer.h>
#include <utils/qtcassert.h>
namespace ClangBackEnd {
Jobs::Jobs(Documents &documents,
UnsavedFiles &unsavedFiles,
ClangCodeModelClientInterface &client,
const Utf8String &logTag)
: m_documents(documents)
, m_unsavedFiles(unsavedFiles)
, m_client(client)
, m_logTag(logTag)
, m_queue(documents, logTag)
{
m_queue.setIsJobRunningForTranslationUnitHandler([this](const Utf8String &translationUnitId) {
return isJobRunningForTranslationUnit(translationUnitId);
});
m_queue.setIsJobRunningForJobRequestHandler([this](const JobRequest &jobRequest) {
return isJobRunningForJobRequest(jobRequest);
});
m_queue.setCancelJobRequest([this](const JobRequest &jobRequest) {
jobRequest.cancelJob(m_client);
});
}
Jobs::~Jobs()
{
foreach (IAsyncJob *asyncJob, m_running.keys())
asyncJob->preventFinalization();
Utils::FutureSynchronizer waitForFinishedJobs;
foreach (const RunningJob &runningJob, m_running.values())
waitForFinishedJobs.addFuture(runningJob.future);
foreach (IAsyncJob *asyncJob, m_running.keys())
delete asyncJob;
}
JobRequest Jobs::createJobRequest(const Document &document,
JobRequest::Type type,
PreferredTranslationUnit preferredTranslationUnit) const
{
JobRequest jobRequest(type);
jobRequest.filePath = document.filePath();
jobRequest.unsavedFilesChangeTimePoint = m_unsavedFiles.lastChangeTimePoint();
jobRequest.documentRevision = document.documentRevision();
jobRequest.preferredTranslationUnit = preferredTranslationUnit;
return jobRequest;
}
void Jobs::add(const JobRequest &job)
{
m_queue.add(job);
}
void Jobs::add(const Document &document,
JobRequest::Type type,
PreferredTranslationUnit preferredTranslationUnit)
{
const JobRequest jobRequest = createJobRequest(document, type, preferredTranslationUnit);
m_queue.add(jobRequest);
}
JobRequests Jobs::process()
{
const JobRequests jobsToRun = m_queue.processQueue();
const JobRequests jobsStarted = runJobs(jobsToRun);
QTC_CHECK(jobsToRun.size() == jobsStarted.size());
return jobsStarted;
}
JobRequests Jobs::stop()
{
// Take the queued jobs to prevent processing them.
const JobRequests queuedJobs = queue();
queue().clear();
// Wait until currently running jobs finish.
Utils::FutureSynchronizer waitForFinishedJobs;
foreach (const RunningJob &runningJob, m_running.values())
waitForFinishedJobs.addFuture(runningJob.future);
return queuedJobs;
}
Jobs::JobFinishedCallback Jobs::finishedCallback() const
{
return m_jobFinishedCallback;
}
JobRequests Jobs::runJobs(const JobRequests &jobsRequests)
{
JobRequests jobsStarted;
foreach (const JobRequest &jobRequest, jobsRequests) {
if (runJob(jobRequest))
jobsStarted += jobRequest;
}
return jobsStarted;
}
bool Jobs::runJob(const JobRequest &jobRequest)
{
IAsyncJob *asyncJob = jobRequest.createJob();
QTC_ASSERT(asyncJob, return false);
JobContext context(jobRequest, &m_documents, &m_unsavedFiles, &m_client);
asyncJob->setContext(context);
if (const IAsyncJob::AsyncPrepareResult prepareResult = asyncJob->prepareAsyncRun()) {
qCDebugJobs() << "Running" << jobRequest
<< "with TranslationUnit" << prepareResult.translationUnitId;
asyncJob->setFinishedHandler([this](IAsyncJob *asyncJob){ onJobFinished(asyncJob); });
const QFuture<void> future = asyncJob->runAsync();
const RunningJob runningJob{jobRequest, prepareResult.translationUnitId, future};
m_running.insert(asyncJob, runningJob);
return true;
} else {
qCDebugJobs() << "Preparation failed for " << jobRequest;
delete asyncJob;
}
return false;
}
void Jobs::onJobFinished(IAsyncJob *asyncJob)
{
qCDebugJobs() << "Finishing" << asyncJob->context().jobRequest;
if (m_jobFinishedCallback) {
const RunningJob runningJob = m_running.value(asyncJob);
if (m_jobFinishedCallback(runningJob, asyncJob))
return;
}
m_running.remove(asyncJob);
delete asyncJob;
process();
}
Jobs::JobFinishedCallback Jobs::jobFinishedCallback() const
{
return m_jobFinishedCallback;
}
void Jobs::setJobFinishedCallback(const JobFinishedCallback &jobFinishedCallback)
{
m_jobFinishedCallback = jobFinishedCallback;
}
QList<Jobs::RunningJob> Jobs::runningJobs() const
{
return m_running.values();
}
JobRequests &Jobs::queue()
{
return m_queue.queue();
}
const JobRequests &Jobs::queue() const
{
return m_queue.queue();
}
bool Jobs::isJobRunningForTranslationUnit(const Utf8String &translationUnitId) const
{
const auto hasTranslationUnitId = [translationUnitId](const RunningJob &runningJob) {
return runningJob.translationUnitId == translationUnitId;
};
return Utils::anyOf(m_running.values(), hasTranslationUnitId);
}
bool Jobs::isJobRunningForJobRequest(const JobRequest &jobRequest) const
{
const auto hasJobRequest = [jobRequest](const RunningJob &runningJob) {
return runningJob.jobRequest == jobRequest;
};
return Utils::anyOf(m_running.values(), hasJobRequest);
}
} // namespace ClangBackEnd

View File

@@ -1,102 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "clangjobqueue.h"
#include <clangsupport/clangcodemodelclientinterface.h>
#include <QFuture>
#include <functional>
namespace ClangBackEnd {
class ClangCodeModelClientInterface;
class Documents;
class IAsyncJob;
class UnsavedFiles;
class Jobs
{
public:
struct RunningJob {
JobRequest jobRequest;
Utf8String translationUnitId;
QFuture<void> future;
};
using RunningJobs = QHash<IAsyncJob *, RunningJob>;
using JobFinishedCallback = std::function<bool(RunningJob, IAsyncJob *)>;
public:
Jobs(Documents &documents,
UnsavedFiles &unsavedFiles,
ClangCodeModelClientInterface &client,
const Utf8String &logTag = Utf8String());
~Jobs();
JobRequest createJobRequest(const Document &document, JobRequest::Type type,
PreferredTranslationUnit preferredTranslationUnit
= PreferredTranslationUnit::RecentlyParsed) const;
void add(const JobRequest &job);
void add(const Document &document,
JobRequest::Type type,
PreferredTranslationUnit preferredTranslationUnit
= PreferredTranslationUnit::RecentlyParsed);
JobRequests process();
JobRequests stop();
JobFinishedCallback finishedCallback() const;
void setJobFinishedCallback(const JobFinishedCallback &jobFinishedCallback);
public /*for tests*/:
QList<RunningJob> runningJobs() const;
JobRequests &queue();
const JobRequests &queue() const;
bool isJobRunningForTranslationUnit(const Utf8String &translationUnitId) const;
bool isJobRunningForJobRequest(const JobRequest &jobRequest) const;
JobFinishedCallback jobFinishedCallback() const;
private:
JobRequests runJobs(const JobRequests &jobRequest);
bool runJob(const JobRequest &jobRequest);
void onJobFinished(IAsyncJob *asyncJob);
private:
Documents &m_documents;
UnsavedFiles &m_unsavedFiles;
ClangCodeModelClientInterface &m_client;
Utf8String m_logTag;
JobQueue m_queue;
RunningJobs m_running;
JobFinishedCallback m_jobFinishedCallback;
};
} // namespace ClangBackEnd

View File

@@ -1,63 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangparsesupportivetranslationunitjob.h"
#include <clangsupport/clangsupportdebugutils.h>
#include <utils/qtcassert.h>
namespace ClangBackEnd {
IAsyncJob::AsyncPrepareResult ParseSupportiveTranslationUnitJob::prepareAsyncRun()
{
const JobRequest jobRequest = context().jobRequest;
QTC_ASSERT(jobRequest.type == JobRequest::Type::ParseSupportiveTranslationUnit, return AsyncPrepareResult());
QTC_ASSERT(acquireDocument(), return AsyncPrepareResult());
const TranslationUnit translationUnit = *m_translationUnit;
const TranslationUnitUpdateInput updateInput = m_pinnedDocument.createUpdateInput();
setRunner([translationUnit, updateInput]() {
TIME_SCOPE_DURATION("ParseSupportiveTranslationUnitJob");
TranslationUnitUpdateInput theUpdateInput = updateInput;
theUpdateInput.parseNeeded = true;
return translationUnit.update(updateInput);
});
return AsyncPrepareResult{translationUnit.id()};
}
void ParseSupportiveTranslationUnitJob::finalizeAsyncRun()
{
if (!context().isOutdated()) {
const AsyncResult result = asyncResult();
m_pinnedDocument.incorporateUpdaterResult(result);
}
}
} // namespace ClangBackEnd

View File

@@ -1,42 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "clangdocumentjob.h"
#include "clangtranslationunitupdater.h"
namespace ClangBackEnd {
class ParseSupportiveTranslationUnitJob : public DocumentJob<TranslationUnitUpdateResult>
{
public:
using AsyncResult = TranslationUnitUpdateResult;
AsyncPrepareResult prepareAsyncRun() override;
void finalizeAsyncRun() override;
};
} // namespace ClangBackEnd

View File

@@ -1,226 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangreferencescollector.h"
#include "clangstring.h"
#include "cursor.h"
#include "sourcerange.h"
#include "token.h"
#include <clangsupport/sourcerangecontainer.h>
#include <utils/qtcassert.h>
#include <utf8string.h>
#include <QDebug>
namespace ClangBackEnd {
namespace {
class ReferencedCursor
{
public:
static ReferencedCursor find(const Cursor &cursor)
{
// Query the referenced cursor directly instead of first testing with cursor.isReference().
// cursor.isReference() reports false for e.g. CXCursor_DeclRefExpr or CXCursor_CallExpr
// although it returns a valid cursor.
const Cursor referenced = cursor.referenced();
if (referenced.isValid())
return handleReferenced(referenced);
const Cursor definition = cursor.definition();
if (definition.isValid())
return definition;
return cursor;
}
Utf8String usr() const
{
return cursor.unifiedSymbolResolution() + usrSuffix;
}
bool isLocalVariable() const
{
return cursor.isLocalVariable();
}
private:
ReferencedCursor(const Cursor &cursor, const Utf8String &usrSuffix = Utf8String())
: cursor(cursor)
, usrSuffix(usrSuffix)
{}
static ReferencedCursor handleReferenced(const Cursor &cursor)
{
if (cursor.kind() == CXCursor_OverloadedDeclRef) {
// e.g. Text cursor is on "App" of "using N::App;".
if (cursor.overloadedDeclarationsCount() >= 1)
return cursor.overloadedDeclaration(0);
}
if (cursor.isConstructorOrDestructor()) {
const Type type = cursor.type();
if (type.isValid()) {
const Cursor typeDeclaration = type.declaration();
if (typeDeclaration.isValid()) {
// A CXCursor_CallExpr like "new Foo" has a type of CXType_Record and its
// declaration is e.g. CXCursor_ClassDecl.
return typeDeclaration;
} else {
// A CXCursor_Constructor like "Foo();" has a type of CXType_FunctionProto
// and its type declaration is invalid, so use the semantic parent.
const Cursor parent = cursor.semanticParent();
if (parent.isValid())
return parent;
}
}
}
if (cursor.isFunctionLike() || cursor.isTemplateLike()) {
const Cursor parent = cursor.semanticParent();
const ClangString spelling = cursor.spelling();
return {parent, Utf8StringLiteral("_qtc_") + Utf8String(spelling)};
}
return cursor;
}
private:
Cursor cursor;
Utf8String usrSuffix;
};
class ReferencesCollector
{
public:
ReferencesCollector(CXTranslationUnit cxTranslationUnit);
ReferencesResult collect(uint line, uint column, bool localReferences = false) const;
private:
bool pointsToIdentifier(int line, int column, unsigned *tokenIndex) const;
bool matchesIdentifier(const Token &token, const Utf8String &identifier) const;
bool checkToken(unsigned index, const Utf8String &identifier, const Utf8String &usr) const;
private:
CXTranslationUnit m_cxTranslationUnit = nullptr;
Tokens m_tokens;
std::vector<Cursor> m_cursors;
};
ReferencesCollector::ReferencesCollector(CXTranslationUnit cxTranslationUnit)
: m_cxTranslationUnit(cxTranslationUnit)
, m_tokens(Cursor(clang_getTranslationUnitCursor(m_cxTranslationUnit)).sourceRange())
, m_cursors(m_tokens.annotate())
{
}
bool ReferencesCollector::pointsToIdentifier(int line, int column, unsigned *tokenIndex) const
{
for (int i = 0; i < m_tokens.size(); ++i) {
const Token &token = m_tokens[i];
if (token.kind() == CXToken_Identifier && token.extent().contains(line, column)) {
*tokenIndex = i;
return true;
}
}
return false;
}
bool ReferencesCollector::matchesIdentifier(const Token &token,
const Utf8String &identifier) const
{
const CXTokenKind tokenKind = token.kind();
if (tokenKind == CXToken_Identifier)
return token.spelling() == identifier;
return false;
}
bool ReferencesCollector::checkToken(unsigned index, const Utf8String &identifier,
const Utf8String &usr) const
{
const Token &token = m_tokens[index];
if (!matchesIdentifier(token, identifier))
return false;
{ // For debugging only
// const SourceRange range{m_cxTranslationUnit, clang_getTokenExtent(m_cxTranslationUnit, token)};
// const uint line = range.start().line();
// const ClangString spellingCs = clang_getTokenSpelling(m_cxTranslationUnit, token);
// const Utf8String spelling = spellingCs;
// qWarning() << "ReferencesCollector::checkToken:" << line << spelling;
}
const ReferencedCursor candidate = ReferencedCursor::find(m_cursors[index]);
return candidate.usr() == usr;
}
ReferencesResult ReferencesCollector::collect(uint line, uint column, bool localReferences) const
{
ReferencesResult result;
unsigned index = 0;
if (!pointsToIdentifier(line, column, &index))
return result;
const ReferencedCursor refCursor = ReferencedCursor::find(m_cursors[index]);
const Utf8String usr = refCursor.usr();
if (usr.isEmpty())
return result;
if (localReferences && !refCursor.isLocalVariable())
return result;
const Token &token = m_tokens[index];
const Utf8String identifier = token.spelling();
for (int i = 0; i < m_tokens.size(); ++i) {
if (checkToken(i, identifier, usr))
result.references.append(m_tokens[i].extent());
}
result.isLocalVariable = refCursor.isLocalVariable();
return result;
}
} // anonymous namespace
ReferencesResult collectReferences(CXTranslationUnit cxTranslationUnit,
uint line,
uint column,
bool localReferences)
{
ReferencesCollector collector(cxTranslationUnit);
return collector.collect(line, column, localReferences);
}
} // namespace ClangBackEnd

View File

@@ -1,61 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <clangsupport/sourcerangecontainer.h>
#include <QVector>
#include <clang-c/Index.h>
namespace ClangBackEnd {
class ReferencesResult
{
public:
ReferencesResult() = default;
ReferencesResult(bool isLocalVariable, const QVector<SourceRangeContainer> &references)
: isLocalVariable(isLocalVariable)
, references(references)
{}
bool operator==(const ReferencesResult &other) const
{
return isLocalVariable == other.isLocalVariable
&& references == other.references;
}
bool isLocalVariable = false;
QVector<SourceRangeContainer> references;
};
ReferencesResult collectReferences(CXTranslationUnit cxTranslationUnit,
uint line,
uint column,
bool localReferences = false);
} // namespace ClangBackEnd

View File

@@ -1,70 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangrequestannotationsjob.h"
#include <clangsupport/annotationsmessage.h>
#include <clangsupport/clangsupportdebugutils.h>
#include <clangsupport/clangcodemodelclientinterface.h>
#include <utils/qtcassert.h>
namespace ClangBackEnd {
IAsyncJob::AsyncPrepareResult RequestAnnotationsJob::prepareAsyncRun()
{
const JobRequest jobRequest = context().jobRequest;
QTC_ASSERT(jobRequest.type == JobRequest::Type::RequestAnnotations,
return AsyncPrepareResult());
QTC_ASSERT(acquireDocument(), return AsyncPrepareResult());
const TranslationUnit translationUnit = *m_translationUnit;
setRunner([translationUnit]() {
TIME_SCOPE_DURATION("RequestAnnotationsJobRunner");
RequestAnnotationsJob::AsyncResult asyncResult;
translationUnit.extractAnnotations(asyncResult.firstHeaderErrorDiagnostic,
asyncResult.diagnostics,
asyncResult.tokenInfos,
asyncResult.skippedSourceRanges);
return asyncResult;
});
return AsyncPrepareResult{translationUnit.id()};
}
void RequestAnnotationsJob::finalizeAsyncRun()
{
if (context().isDocumentOpen()) {
const AsyncResult result = asyncResult();
context().client->annotations(AnnotationsMessage(m_pinnedFileContainer,
result.diagnostics,
result.firstHeaderErrorDiagnostic,
result.tokenInfos,
result.skippedSourceRanges));
}
}
} // namespace ClangBackEnd

View File

@@ -1,53 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "clangdocumentjob.h"
#include <clangsupport/diagnosticcontainer.h>
#include <clangsupport/tokeninfocontainer.h>
#include <clangsupport/sourcerangecontainer.h>
namespace ClangBackEnd {
struct RequestAnnotationsJobResult
{
ClangBackEnd::DiagnosticContainer firstHeaderErrorDiagnostic;
QVector<ClangBackEnd::DiagnosticContainer> diagnostics;
QVector<TokenInfoContainer> tokenInfos;
QVector<SourceRangeContainer> skippedSourceRanges;
};
class RequestAnnotationsJob : public DocumentJob<RequestAnnotationsJobResult>
{
public:
using AsyncResult = RequestAnnotationsJobResult;
AsyncPrepareResult prepareAsyncRun() override;
void finalizeAsyncRun() override;
};
} // namespace ClangBackEnd

View File

@@ -1,68 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangrequestreferencesjob.h"
#include <clangsupport/clangsupportdebugutils.h>
#include <clangsupport/referencesmessage.h>
#include <clangsupport/clangcodemodelclientinterface.h>
#include <utils/qtcassert.h>
namespace ClangBackEnd {
IAsyncJob::AsyncPrepareResult RequestReferencesJob::prepareAsyncRun()
{
const JobRequest jobRequest = context().jobRequest;
QTC_ASSERT(jobRequest.type == JobRequest::Type::RequestReferences,
return AsyncPrepareResult());
QTC_ASSERT(acquireDocument(), return AsyncPrepareResult());
const TranslationUnit translationUnit = *m_translationUnit;
const quint32 line = jobRequest.line;
const quint32 column = jobRequest.column;
const bool localReferences = jobRequest.localReferences;
setRunner([translationUnit, line, column, localReferences]() {
TIME_SCOPE_DURATION("RequestReferencesJobRunner");
return translationUnit.references(line, column, localReferences);
});
return AsyncPrepareResult{translationUnit.id()};
}
void RequestReferencesJob::finalizeAsyncRun()
{
if (!context().isOutdated()) {
const AsyncResult result = asyncResult();
const ReferencesMessage message(m_pinnedFileContainer,
result.references,
result.isLocalVariable,
context().jobRequest.ticketNumber);
context().client->references(message);
}
}
} // namespace ClangBackEnd

View File

@@ -1,42 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "clangdocumentjob.h"
#include "clangreferencescollector.h"
namespace ClangBackEnd {
class RequestReferencesJob : public DocumentJob<ReferencesResult>
{
public:
using AsyncResult = ReferencesResult;
AsyncPrepareResult prepareAsyncRun() override;
void finalizeAsyncRun() override;
};
} // namespace ClangBackEnd

View File

@@ -1,67 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2018 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 "clangrequesttooltipjob.h"
#include <clangsupport/clangsupportdebugutils.h>
#include <clangsupport/clangcodemodelclientinterface.h>
#include <clangsupport/tooltipmessage.h>
#include <utils/qtcassert.h>
namespace ClangBackEnd {
IAsyncJob::AsyncPrepareResult RequestToolTipJob::prepareAsyncRun()
{
const JobRequest jobRequest = context().jobRequest;
QTC_ASSERT(jobRequest.type == JobRequest::Type::RequestToolTip, return AsyncPrepareResult());
QTC_ASSERT(acquireDocument(), return AsyncPrepareResult());
const TranslationUnit translationUnit = *m_translationUnit;
const UnsavedFiles unsavedFiles = *context().unsavedFiles;
const quint32 line = jobRequest.line;
const quint32 column = jobRequest.column;
const Utf8String textCodecName = jobRequest.textCodecName;
setRunner([translationUnit, unsavedFiles, line, column, textCodecName]() {
TIME_SCOPE_DURATION("RequestToolTipJobRunner");
UnsavedFiles theUnsavedFiles = unsavedFiles;
return translationUnit.tooltip(theUnsavedFiles, textCodecName, line, column);
});
return AsyncPrepareResult{translationUnit.id()};
}
void RequestToolTipJob::finalizeAsyncRun()
{
if (!context().isOutdated()) {
const AsyncResult result = asyncResult();
context().client->tooltip(ToolTipMessage(m_pinnedFileContainer,
result,
context().jobRequest.ticketNumber));
}
}
} // namespace ClangBackEnd

View File

@@ -1,43 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2018 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 <clangsupport/tooltipinfo.h>
#include "clangdocumentjob.h"
namespace ClangBackEnd {
class RequestToolTipJob : public DocumentJob<ToolTipInfo>
{
public:
using AsyncResult = ToolTipInfo;
AsyncPrepareResult prepareAsyncRun() override;
void finalizeAsyncRun() override;
};
} // namespace ClangBackEnd

View File

@@ -1,54 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangresumedocumentjob.h"
#include <utils/qtcassert.h>
namespace ClangBackEnd {
void ResumeDocumentJob::finalizeAsyncRun()
{
if (context().isDocumentOpen()) {
if (QTC_GUARD(asyncResult().updateResult.hasReparsed()))
m_pinnedDocument.setIsSuspended(false);
}
UpdateAnnotationsJob::finalizeAsyncRun();
}
bool ResumeDocumentJob::isExpectedJobRequestType(const JobRequest &jobRequest) const
{
return jobRequest.type == JobRequest::Type::ResumeDocument;
}
TranslationUnitUpdateInput ResumeDocumentJob::createUpdateInput(const Document &document) const
{
TranslationUnitUpdateInput input = UpdateAnnotationsJob::createUpdateInput(document);
input.reparseNeeded = true;
return input;
}
} // namespace ClangBackEnd

View File

@@ -1,44 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "clangasyncjob.h"
#include "clangdocument.h"
#include "clangupdateannotationsjob.h"
namespace ClangBackEnd {
class ResumeDocumentJob : public UpdateAnnotationsJob
{
public:
void finalizeAsyncRun() override;
private:
bool isExpectedJobRequestType(const JobRequest &jobRequest) const override;
TranslationUnitUpdateInput createUpdateInput(const Document &document) const override;
};
} // namespace ClangBackEnd

View File

@@ -1,174 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <clang-c/CXString.h>
#include <utf8string.h>
#include <cstring>
#include <ostream>
namespace ClangBackEnd {
class ClangString
{
public:
ClangString(CXString cxString)
: m_cxString(cxString)
{
}
~ClangString()
{
clang_disposeString(m_cxString);
}
ClangString(const ClangString &) = delete;
const ClangString &operator=(const ClangString &) = delete;
ClangString(ClangString &&other)
: m_cxString(std::move(other.m_cxString))
{
other.m_cxString.data = nullptr;
other.m_cxString.private_flags = 0;
}
ClangString &operator=(ClangString &&other)
{
if (this != &other) {
clang_disposeString(m_cxString);
m_cxString = std::move(other.m_cxString);
other.m_cxString.data = nullptr;
other.m_cxString.private_flags = 0;
}
return *this;
}
const char *cString() const
{
return clang_getCString(m_cxString);
}
operator Utf8String() const
{
return Utf8String(cString(), -1);
}
bool isNull() const
{
return m_cxString.data == nullptr;
}
bool hasContent() const
{
return !isNull() && std::strlen(cString()) > 0;
}
bool startsWith(const char* str) const
{
return std::strncmp(cString(), str, strlen(str)) == 0;
}
friend bool operator==(const ClangString &first, const ClangString &second)
{
return std::strcmp(first.cString(), second.cString()) == 0;
}
template<std::size_t Size>
friend bool operator==(const ClangString &first, const char(&second)[Size])
{
return std::strncmp(first.cString(), second, Size) == 0; // Size includes \0
}
template<std::size_t Size>
friend bool operator==(const char(&first)[Size], const ClangString &second)
{
return second == first;
}
template<typename Type,
typename = typename std::enable_if<std::is_pointer<Type>::value>::type
>
friend bool operator==(const ClangString &first, Type second)
{
return std::strcmp(first.cString(), second) == 0;
}
template<typename Type,
typename = typename std::enable_if<std::is_pointer<Type>::value>::type
>
friend bool operator==(Type first, const ClangString &second)
{
return second == first;
}
friend bool operator!=(const ClangString &first, const ClangString &second)
{
return !(first == second);
}
template<std::size_t Size>
friend bool operator!=(const ClangString &first, const char(&second)[Size])
{
return !(first == second);
}
template<std::size_t Size>
friend bool operator!=(const char(&first)[Size], const ClangString &second)
{
return second != first;
}
template<typename Type,
typename = typename std::enable_if<std::is_pointer<Type>::value>::type
>
friend bool operator!=(const ClangString &first, Type second)
{
return !(first == second);
}
template<typename Type,
typename = typename std::enable_if<std::is_pointer<Type>::value>::type
>
friend bool operator!=(Type first, const ClangString &second)
{
return !(first == second);
}
friend std::ostream &operator<<(std::ostream &os, const ClangString &string)
{
return os << string.cString();
}
private:
CXString m_cxString;
};
} // namespace ClangBackEnd

View File

@@ -1,124 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangsupportivetranslationunitinitializer.h"
#include "clangjobs.h"
#include "clangtranslationunits.h"
#include <utils/qtcassert.h>
namespace ClangBackEnd {
SupportiveTranslationUnitInitializer::SupportiveTranslationUnitInitializer(
const Document &document,
Jobs &jobs)
: m_document(document)
, m_jobs(jobs)
{
}
void SupportiveTranslationUnitInitializer::setIsDocumentClosedChecker(
const IsDocumentClosedChecker &isDocumentClosedChecker)
{
m_isDocumentClosedChecker = isDocumentClosedChecker;
}
SupportiveTranslationUnitInitializer::State SupportiveTranslationUnitInitializer::state() const
{
return m_state;
}
void SupportiveTranslationUnitInitializer::startInitializing()
{
if (!checkStateAndDocument(State::NotInitialized))
return;
m_document.translationUnits().createAndAppend();
m_jobs.setJobFinishedCallback([this](const Jobs::RunningJob &runningJob, IAsyncJob *) {
checkIfParseJobFinished(runningJob);
return false;
});
addJob(JobRequest::Type::ParseSupportiveTranslationUnit);
m_jobs.process();
m_state = State::WaitingForParseJob;
}
void SupportiveTranslationUnitInitializer::abort()
{
if (m_document.translationUnits().size() > 1)
m_jobs.setJobFinishedCallback(Jobs::JobFinishedCallback());
m_state = State::Aborted;
}
void SupportiveTranslationUnitInitializer::checkIfParseJobFinished(const Jobs::RunningJob &job)
{
if (!checkStateAndDocument(State::WaitingForParseJob))
return;
if (job.jobRequest.type == JobRequest::Type::ParseSupportiveTranslationUnit) {
if (m_document.translationUnits().areAllTranslationUnitsParsed()) {
m_jobs.setJobFinishedCallback(nullptr);
m_state = State::Initialized;
} else {
// The supportive translation unit was parsed, but the document
// revision changed in the meanwhile, so try again.
addJob(JobRequest::Type::ParseSupportiveTranslationUnit);
}
}
}
bool SupportiveTranslationUnitInitializer::checkStateAndDocument(State currentExpectedState)
{
if (m_state != currentExpectedState) {
m_state = State::Aborted;
return false;
}
QTC_CHECK(m_isDocumentClosedChecker);
if (m_isDocumentClosedChecker(m_document.filePath())) {
m_state = State::Aborted;
return false;
}
return true;
}
void SupportiveTranslationUnitInitializer::addJob(JobRequest::Type jobRequestType)
{
const JobRequest jobRequest = m_jobs.createJobRequest(
m_document, jobRequestType, PreferredTranslationUnit::LastUninitialized);
m_jobs.add(jobRequest);
}
void SupportiveTranslationUnitInitializer::setState(const State &state)
{
m_state = state;
}
} // namespace ClangBackEnd

View File

@@ -1,72 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangdocument.h"
#include "clangjobs.h"
#include <functional>
#pragma once
namespace ClangBackEnd {
class SupportiveTranslationUnitInitializer
{
public:
using IsDocumentClosedChecker = std::function<bool(const Utf8String &)>;
enum class State {
NotInitialized,
WaitingForParseJob,
Initialized,
Aborted
};
public:
SupportiveTranslationUnitInitializer(const Document &document, Jobs &jobs);
void setIsDocumentClosedChecker(const IsDocumentClosedChecker &isDocumentClosedChecker);
State state() const;
void startInitializing();
void abort();
public: // for tests
void setState(const State &state);
void checkIfParseJobFinished(const Jobs::RunningJob &job);
private:
bool checkStateAndDocument(State currentExpectedState);
void addJob(JobRequest::Type jobRequestType);
private:
Document m_document;
Jobs &m_jobs;
State m_state = State::NotInitialized;
IsDocumentClosedChecker m_isDocumentClosedChecker;
};
} // namespace ClangBackEnd

View File

@@ -1,59 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangsuspenddocumentjob.h"
#include <clangsupport/clangsupportdebugutils.h>
#include <utils/qtcassert.h>
namespace ClangBackEnd {
IAsyncJob::AsyncPrepareResult SuspendDocumentJob::prepareAsyncRun()
{
const JobRequest jobRequest = context().jobRequest;
QTC_ASSERT(jobRequest.type == JobRequest::Type::SuspendDocument, return AsyncPrepareResult());
QTC_ASSERT(acquireDocument(), return AsyncPrepareResult());
TranslationUnit translationUnit = *m_translationUnit;
setRunner([translationUnit]() {
TIME_SCOPE_DURATION("SuspendDocumentJobRunner");
return translationUnit.suspend();
});
return AsyncPrepareResult{translationUnit.id()};
}
void SuspendDocumentJob::finalizeAsyncRun()
{
if (context().isDocumentOpen()) {
const bool suspendSucceeded = asyncResult();
if (QTC_GUARD(suspendSucceeded)) {
m_pinnedDocument.setIsSuspended(true);
}
}
}
} // namespace ClangBackEnd

View File

@@ -1,39 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "clangdocumentjob.h"
namespace ClangBackEnd {
class SuspendDocumentJob : public DocumentJob<bool>
{
public:
AsyncPrepareResult prepareAsyncRun() override;
void finalizeAsyncRun() override;
};
} // namespace ClangBackEnd

View File

@@ -1,574 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2018 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 "clangtooltipinfocollector.h"
#include "clangbackend_global.h"
#include "clangstring.h"
#include "cursor.h"
#include "sourcerange.h"
#include "token.h"
#include "unsavedfiles.h"
#include "unsavedfile.h"
#include <clangsupport/sourcerangecontainer.h>
#include <utils/fileutils.h>
#include <utils/qtcassert.h>
#include <utils/qtcassert.h>
#include <utils/textfileformat.h>
#include <utf8string.h>
#include <QDebug>
#include <QDir>
#include <QTextCodec>
namespace ClangBackEnd {
Utf8String qualificationPrefix(const Cursor &cursor)
{
// TODO: Implement with qualificationPrefixAsVector()
Utf8String qualifiedName;
for (Cursor parent = cursor.semanticParent();
parent.isValid() && (parent.kind() == CXCursor_Namespace);
parent = parent.semanticParent()) {
qualifiedName = parent.spelling() + Utf8StringLiteral("::") + qualifiedName;
}
return qualifiedName;
}
namespace {
Utf8StringVector qualificationPrefixAsVector(const Cursor &cursor)
{
Utf8StringVector result;
for (Cursor parent = cursor.semanticParent();
parent.isValid() && (parent.kind() == CXCursor_Namespace || parent.isCompoundType());
parent = parent.semanticParent()) {
result.prepend(parent.spelling());
}
return result;
}
Utf8String displayName(const Cursor &cursor)
{
if (cursor.kind() == CXCursor_ClassTemplate) {
// TODO: The qualification should be part of the display name. Fix this in libclang.
return qualificationPrefix(cursor) + cursor.displayName();
}
return cursor.displayName();
}
Utf8String textForFunctionLike(const Cursor &cursor)
{
CXPrintingPolicy policy = clang_getCursorPrintingPolicy(cursor.cx());
clang_PrintingPolicy_setProperty(policy, CXPrintingPolicy_FullyQualifiedName, 1);
clang_PrintingPolicy_setProperty(policy, CXPrintingPolicy_TerseOutput, 1);
// Avoid printing attributes/pragmas
clang_PrintingPolicy_setProperty(policy, CXPrintingPolicy_PolishForDeclaration, 1);
clang_PrintingPolicy_setProperty(policy, CXPrintingPolicy_SuppressInitializers, 1);
const Utf8String prettyPrinted = ClangString(
clang_getCursorPrettyPrinted(cursor.cx(), policy));
clang_PrintingPolicy_dispose(policy);
return prettyPrinted;
}
Utf8String textForEnumConstantDecl(const Cursor &cursor)
{
const Cursor semanticParent = cursor.semanticParent();
QTC_ASSERT(semanticParent.kind() == CXCursor_EnumDecl, return Utf8String());
const Type enumType = semanticParent.enumType();
if (enumType.isUnsigned())
return Utf8String::number(cursor.enumConstantUnsignedValue());
return Utf8String::number(cursor.enumConstantValue());
}
Utf8String textForInclusionDirective(const Cursor &cursor)
{
const CXFile includedFile = cursor.includedFile();
const Utf8String fileName = ClangString(clang_getFileName(includedFile));
return QDir::toNativeSeparators(fileName.toString());
}
Utf8String textForAnyTypeAlias(const Cursor &cursor)
{
// For a CXCursor_TypeAliasTemplateDecl the type of cursor/referenced
// is invalid, so we do not get the underlying type. This here solely
// reports the unresolved name instead of the empty string.
if (cursor.kind() == CXCursor_TypeAliasTemplateDecl)
return cursor.displayName();
return cursor.type().alias().utf8Spelling();
}
bool includeSizeForCursor(const Cursor &cursor)
{
return cursor.isCompoundType()
|| cursor.kind() == CXCursor_EnumDecl
|| cursor.kind() == CXCursor_UnionDecl
|| cursor.kind() == CXCursor_FieldDecl;
}
Utf8String sizeInBytes(const Cursor &cursor)
{
if (includeSizeForCursor(cursor)) {
bool ok = false;
const long long size = cursor.type().sizeOf(&ok);
if (ok)
return Utf8String::number(size);
}
return Utf8String();
}
QVariant value(const Cursor &cursor)
{
if (!clang_isDeclaration(cursor.cx().kind) && !clang_isExpression(cursor.cx().kind))
return {};
const CXEvalResult evalResult = clang_Cursor_Evaluate(cursor.cx());
QVariant v;
switch (clang_EvalResult_getKind(evalResult)) {
case CXEval_Int:
v = clang_EvalResult_isUnsignedInt(evalResult)
? QVariant::fromValue(clang_EvalResult_getAsUnsigned(evalResult))
: QVariant::fromValue(clang_EvalResult_getAsLongLong(evalResult));
break;
case CXEval_Float:
v = QVariant::fromValue(clang_EvalResult_getAsDouble(evalResult));
break;
default:
break;
}
clang_EvalResult_dispose(evalResult);
return v;
}
Cursor referencedCursor(const Cursor &cursor)
{
// Query the referenced cursor directly instead of first testing with cursor.isReference().
// cursor.isReference() reports false for e.g. CXCursor_DeclRefExpr or CXCursor_CallExpr
// although it returns a valid cursor.
const Cursor referenced = cursor.referenced();
if (referenced.isValid())
return referenced;
const Cursor definition = cursor.definition();
if (definition.isValid())
return definition;
return cursor;
}
class ToolTipInfoCollector
{
public:
ToolTipInfoCollector(UnsavedFiles &unsavedFiles,
const Utf8String &textCodecName,
const Utf8String &mainFilePath,
CXTranslationUnit cxTranslationUnit);
ToolTipInfo collect(uint line, uint column) const;
private:
Utf8String text(const Cursor &cursor, const Cursor &referenced) const;
Utf8String textForMacroExpansion(const Cursor &cursor) const;
Utf8String textForNamespaceAlias(const Cursor &cursor) const;
ToolTipInfo qDocInfo(const Cursor &cursor) const;
CXSourceLocation toCXSourceLocation(uint line, uint column) const;
UnsavedFile unsavedFile(const Utf8String &filePath) const;
Utf8String lineRange(const Utf8String &filePath, unsigned fromLine, unsigned toLine) const;
private:
UnsavedFiles &m_unsavedFiles;
const Utf8String m_textCodecName;
const Utf8String m_mainFilePath;
CXTranslationUnit m_cxTranslationUnit = nullptr;
};
ToolTipInfoCollector::ToolTipInfoCollector(UnsavedFiles &unsavedFiles,
const Utf8String &textCodecName,
const Utf8String &mainFilePath,
CXTranslationUnit cxTranslationUnit)
: m_unsavedFiles(unsavedFiles)
, m_textCodecName(textCodecName)
, m_mainFilePath(mainFilePath)
, m_cxTranslationUnit(cxTranslationUnit)
{
}
Utf8String ToolTipInfoCollector::text(const Cursor &cursor, const Cursor &referenced) const
{
if (cursor.kind() == CXCursor_MacroExpansion)
return textForMacroExpansion(referenced);
if (referenced.kind() == CXCursor_EnumConstantDecl)
return textForEnumConstantDecl(referenced);
if (referenced.kind() == CXCursor_InclusionDirective)
return textForInclusionDirective(referenced);
if (referenced.kind() == CXCursor_Namespace)
return qualificationPrefix(referenced) + referenced.spelling();
if (referenced.kind() == CXCursor_NamespaceAlias)
return textForNamespaceAlias(referenced);
if (referenced.isAnyTypeAlias())
return textForAnyTypeAlias(referenced);
if (referenced.isFunctionLike() || referenced.kind() == CXCursor_Constructor)
return textForFunctionLike(referenced);
if (referenced.kind() == CXCursor_VarDecl)
return referenced.type().spelling(); // e.g. "Zii<int>"
const Type referencedType = referenced.type();
if (referencedType.isValid()) {
// Generally, the type includes the qualification but has this limitations:
// * namespace aliases are not resolved
// * outer class of a inner template class is not included
// The type includes the qualification, but not resolved namespace aliases.
// For a CXType_Record, this also includes e.g. "const " as prefix.
return referencedType.canonical().utf8Spelling();
}
return displayName(referenced);
}
Utf8String ToolTipInfoCollector::textForMacroExpansion(const Cursor &cursor) const
{
QTC_ASSERT(cursor.kind() == CXCursor_MacroDefinition, return Utf8String());
const SourceRange sourceRange = cursor.sourceRange();
const SourceLocation start = sourceRange.start();
const SourceLocation end = sourceRange.end();
return lineRange(start.filePath(), start.line(), end.line());
}
Utf8String ToolTipInfoCollector::textForNamespaceAlias(const Cursor &cursor) const
{
// TODO: Add some libclang API to get the aliased name straight away.
const Tokens tokens(cursor.sourceRange());
Utf8String aliasedName;
// Start at 3 in order to skip these tokens: namespace X =
for (int i = 3; i < tokens.size(); ++i)
aliasedName += tokens[i].spelling();
return aliasedName;
}
static Utf8String typeName(const Type &type)
{
return type.declaration().spelling();
}
static Utf8String qdocMark(const Cursor &cursor)
{
if (cursor.kind() == CXCursor_ClassTemplate)
return cursor.spelling();
if (cursor.type().kind() == CXType_Enum
|| cursor.type().kind() == CXType_Typedef
|| cursor.type().kind() == CXType_Record)
return typeName(cursor.type());
Utf8String text = cursor.displayName();
if (cursor.kind() == CXCursor_FunctionDecl) {
// TODO: Remove this workaround by fixing this in
// libclang with the help of CXPrintingPolicy.
text.replace(Utf8StringLiteral("<>"), Utf8String());
}
return text;
}
static ToolTipInfo::QdocCategory qdocCategory(const Cursor &cursor)
{
if (cursor.isFunctionLike())
return ToolTipInfo::Function;
if (cursor.kind() == CXCursor_MacroDefinition)
return ToolTipInfo::Macro;
if (cursor.kind() == CXCursor_EnumConstantDecl)
return ToolTipInfo::Enum;
if (cursor.type().kind() == CXType_Enum)
return ToolTipInfo::Enum;
if (cursor.kind() == CXCursor_InclusionDirective)
return ToolTipInfo::Brief;
// TODO: Handle CXCursor_NamespaceAlias, too?!
if (cursor.kind() == CXCursor_Namespace)
return ToolTipInfo::ClassOrNamespace;
if (cursor.isCompoundType())
return ToolTipInfo::ClassOrNamespace;
if (cursor.kind() == CXCursor_NamespaceAlias)
return ToolTipInfo::ClassOrNamespace;
if (cursor.type().kind() == CXType_Typedef)
return ToolTipInfo::Typedef;
if (cursor.type().kind() == CXType_Record)
return ToolTipInfo::ClassOrNamespace;
if (cursor.kind() == CXCursor_TypeAliasTemplateDecl)
return ToolTipInfo::Typedef;
if (cursor.kind() == CXCursor_ClassTemplate)
return ToolTipInfo::ClassOrNamespace;
return ToolTipInfo::Unknown;
}
static Utf8String name(const Cursor &cursor)
{
if (cursor.type().kind() == CXType_Record || cursor.kind() == CXCursor_EnumDecl)
return typeName(cursor.type());
return cursor.spelling();
}
static Utf8StringVector qDocIdCandidates(const Cursor &cursor)
{
Utf8StringVector components = qualificationPrefixAsVector(cursor);
if (components.isEmpty())
return { name(cursor) };
components << name(cursor);
Utf8StringVector result;
Utf8String name;
for (auto it = components.rbegin(); it != components.rend(); ++it) {
if (name.isEmpty())
name = *it;
else
name = *it + (Utf8StringLiteral("::") + name);
result.prepend(name);
}
return result;
}
// TODO: Add libclang API for this?!
static bool isBuiltinOrPointerToBuiltin(const Type &type)
{
Type theType = type;
if (theType.isBuiltinType())
return true;
// TODO: Simplify
// TODO: Test with **
while (theType.pointeeType().isValid() && theType != theType.pointeeType()) {
theType = theType.pointeeType();
if (theType.isBuiltinType())
return true;
}
return false;
}
ToolTipInfo ToolTipInfoCollector::qDocInfo(const Cursor &cursor) const
{
ToolTipInfo result;
if (isBuiltinOrPointerToBuiltin(cursor.type()))
return result;
if (cursor.kind() == CXCursor_Constructor) {
const ToolTipInfo parentInfo = qDocInfo(cursor.semanticParent());
result.qdocIdCandidates = parentInfo.qdocIdCandidates;
result.qdocMark = parentInfo.qdocMark;
result.qdocCategory = ToolTipInfo::Unknown;
return result;
}
result.qdocIdCandidates = qDocIdCandidates(cursor);
result.qdocMark = qdocMark(cursor);
result.qdocCategory = qdocCategory(cursor);
if (cursor.type().kind() == CXType_Record) {
result.qdocIdCandidates = qDocIdCandidates(cursor.type().declaration());
return result;
}
if (cursor.kind() == CXCursor_VarDecl || cursor.kind() == CXCursor_ParmDecl
|| cursor.kind() == CXCursor_FieldDecl) {
// maybe template instantiation
if (cursor.type().kind() == CXType_Unexposed && cursor.type().canonical().kind() == CXType_Record) {
result.qdocIdCandidates = qDocIdCandidates(cursor.type().canonical().declaration());
result.qdocMark = typeName(cursor.type());
result.qdocCategory = ToolTipInfo::ClassOrNamespace;
return result;
}
Type type = cursor.type();
while (type.pointeeType().isValid() && type != type.pointeeType())
type = type.pointeeType();
const Cursor typeCursor = type.declaration();
result.qdocIdCandidates = qDocIdCandidates(typeCursor);
result.qdocCategory = qdocCategory(typeCursor);
result.qdocMark = typeName(type);
}
// TODO: Handle also RValueReference()
if (cursor.type().isLValueReference()) {
const Cursor pointeeTypeDeclaration = cursor.type().pointeeType().declaration();
result.qdocIdCandidates = qDocIdCandidates(pointeeTypeDeclaration);
result.qdocMark = pointeeTypeDeclaration.spelling();
result.qdocCategory = qdocCategory(pointeeTypeDeclaration);
return result;
}
return result;
}
CXSourceLocation ToolTipInfoCollector::toCXSourceLocation(uint line, uint column) const
{
return clang_getLocation(m_cxTranslationUnit,
clang_getFile(m_cxTranslationUnit,
m_mainFilePath.constData()),
line,
column);
}
UnsavedFile ToolTipInfoCollector::unsavedFile(const Utf8String &filePath) const
{
const UnsavedFile &unsavedFile = m_unsavedFiles.unsavedFile(filePath);
if (!unsavedFile.filePath().isEmpty())
return unsavedFile;
// Create an unsaved file with the file content from disk.
// TODO: Make use of clang_getFileContents() instead of reading from disk.
QTextCodec *codec = QTextCodec::codecForName(m_textCodecName);
QByteArray fileContent;
QString errorString;
using namespace Utils;
const TextFileFormat::ReadResult readResult
= TextFileFormat::readFileUTF8(Utils::FilePath::fromString(filePath),
codec,
&fileContent,
&errorString);
if (readResult != TextFileFormat::ReadSuccess) {
qWarning() << "Failed to read file" << filePath << ":" << errorString;
return UnsavedFile();
}
return UnsavedFile(filePath, Utf8String::fromByteArray(fileContent));
}
Utf8String ToolTipInfoCollector::lineRange(const Utf8String &filePath,
unsigned fromLine,
unsigned toLine) const
{
if (toLine < fromLine)
return Utf8String();
const UnsavedFile file = unsavedFile(filePath);
if (file.fileContent().isEmpty())
return Utf8String();
return file.lineRange(fromLine, toLine);
}
ToolTipInfo ToolTipInfoCollector::collect(uint line, uint column) const
{
Cursor cursor = clang_getCursor(m_cxTranslationUnit, toCXSourceLocation(line, column));
if (!cursor.isValid()) { // QTCREATORBUG-21194
Tokens tokens(Cursor(clang_getTranslationUnitCursor(m_cxTranslationUnit)).sourceRange());
if (!tokens.size())
return {};
// TODO: Only annotate the tokens up until the location we are interested in?
// Same goes for FollowSymbol.
const std::vector<Cursor> cursors = tokens.annotate();
const int tokenIndex = tokens.getTokenIndex(m_cxTranslationUnit, line, column);
QTC_ASSERT(tokenIndex >= 0, return {});
const Utf8String tokenSpelling = tokens[tokenIndex].spelling();
if (tokenSpelling.isEmpty())
return {};
cursor = cursors[tokenIndex];
}
if (!cursor.isValid())
return {};
const Cursor referenced = referencedCursor(cursor);
QTC_CHECK(referenced.isValid());
ToolTipInfo info;
info.text = text(cursor, referenced);
info.briefComment = referenced.briefComment();
info.value = value(cursor);
{
ToolTipInfo qDocToolTipInfo = qDocInfo(referenced);
info.qdocIdCandidates = qDocToolTipInfo.qdocIdCandidates;
info.qdocMark = qDocToolTipInfo.qdocMark;
info.qdocCategory = qDocToolTipInfo.qdocCategory;
}
info.sizeInBytes = sizeInBytes(cursor);
return info;
}
} // anonymous namespace
ToolTipInfo collectToolTipInfo(UnsavedFiles &unsavedFiles,
const Utf8String &textCodecName,
const Utf8String &mainFilePath,
CXTranslationUnit cxTranslationUnit,
uint line,
uint column)
{
ToolTipInfoCollector collector(unsavedFiles, textCodecName, mainFilePath, cxTranslationUnit);
const ToolTipInfo info = collector.collect(line, column);
return info;
}
} // namespace ClangBackEnd

View File

@@ -1,48 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2018 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 <utf8string.h>
#include <clangsupport/tooltipinfo.h>
#include <clang-c/Index.h>
namespace ClangBackEnd {
class Cursor;
class UnsavedFiles;
ToolTipInfo collectToolTipInfo(UnsavedFiles &unsavedFiles,
const Utf8String &textCodecName,
const Utf8String &mainFilePath,
CXTranslationUnit cxTranslationUnit,
uint line,
uint column);
Utf8String qualificationPrefix(const Cursor &cursor);
} // namespace ClangBackEnd

View File

@@ -1,262 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangtranslationunit.h"
#include "clangbackend_global.h"
#include "clangreferencescollector.h"
#include "clangtooltipinfocollector.h"
#include "clangtranslationunitupdater.h"
#include "clangfollowsymbol.h"
#include "clangfollowsymboljob.h"
#include "tokenprocessor.h"
#include <codecompleter.h>
#include <cursor.h>
#include <diagnosticcontainer.h>
#include <diagnosticset.h>
#include <skippedsourceranges.h>
#include <sourcelocation.h>
#include <sourcerange.h>
#include <commandlinearguments.h>
#include <utils/qtcassert.h>
namespace ClangBackEnd {
TranslationUnit::TranslationUnit(const Utf8String &id,
const Utf8String &filepath,
CXIndex &cxIndex,
CXTranslationUnit &cxTranslationUnit)
: m_id(id)
, m_filePath(filepath)
, m_cxIndex(cxIndex)
, m_cxTranslationUnit(cxTranslationUnit)
{
}
bool TranslationUnit::isNull() const
{
return !m_cxTranslationUnit || !m_cxIndex || m_filePath.isEmpty() || m_id.isEmpty();
}
Utf8String TranslationUnit::id() const
{
return m_id;
}
Utf8String TranslationUnit::filePath() const
{
return m_filePath;
}
CXIndex &TranslationUnit::cxIndex() const
{
return m_cxIndex;
}
CXTranslationUnit &TranslationUnit::cxTranslationUnit() const
{
return m_cxTranslationUnit;
}
TranslationUnitUpdateResult TranslationUnit::update(
const TranslationUnitUpdateInput &parseInput) const
{
TranslationUnitUpdater updater(id(), cxIndex(), cxTranslationUnit(), parseInput);
return updater.update(TranslationUnitUpdater::UpdateMode::AsNeeded);
}
TranslationUnitUpdateResult TranslationUnit::parse(
const TranslationUnitUpdateInput &parseInput) const
{
TranslationUnitUpdater updater(id(), cxIndex(), cxTranslationUnit(), parseInput);
return updater.update(TranslationUnitUpdater::UpdateMode::ParseIfNeeded);
}
TranslationUnitUpdateResult TranslationUnit::reparse(
const TranslationUnitUpdateInput &parseInput) const
{
TranslationUnitUpdater updater(id(), cxIndex(), cxTranslationUnit(), parseInput);
return updater.update(TranslationUnitUpdater::UpdateMode::ForceReparse);
}
bool TranslationUnit::suspend() const
{
return clang_suspendTranslationUnit(cxTranslationUnit());
}
CodeCompletions TranslationUnit::complete(UnsavedFiles &unsavedFiles, uint line, uint column,
int funcNameStartLine, int funcNameStartColumn) const
{
return CodeCompleter(*this, unsavedFiles).complete(line, column, funcNameStartLine,
funcNameStartColumn);
}
void TranslationUnit::extractAnnotations(
DiagnosticContainer &firstHeaderErrorDiagnostic,
QVector<DiagnosticContainer> &mainFileDiagnostics,
QVector<TokenInfoContainer> &tokenInfos,
QVector<SourceRangeContainer> &skippedSourceRanges) const
{
extractDiagnostics(firstHeaderErrorDiagnostic, mainFileDiagnostics);
tokenInfos = this->tokenInfos().toTokenInfoContainers();
skippedSourceRanges = this->skippedSourceRanges().toSourceRangeContainers();
}
ToolTipInfo TranslationUnit::tooltip(UnsavedFiles &unsavedFiles,
const Utf8String &textCodecName,
uint line,
uint column) const
{
return collectToolTipInfo(unsavedFiles,
textCodecName,
filePath(),
m_cxTranslationUnit,
line,
column);
}
ReferencesResult TranslationUnit::references(uint line, uint column, bool localReferences) const
{
return collectReferences(m_cxTranslationUnit, line, column, localReferences);
}
DiagnosticSet TranslationUnit::diagnostics() const
{
return DiagnosticSet(m_cxTranslationUnit, clang_getDiagnosticSetFromTU(m_cxTranslationUnit));
}
SourceLocation TranslationUnit::sourceLocationAt(uint line,uint column) const
{
return SourceLocation(m_cxTranslationUnit,
clang_getLocation(m_cxTranslationUnit,
clang_getFile(m_cxTranslationUnit,
m_filePath.constData()),
line, column));
}
SourceLocation TranslationUnit::sourceLocationAt(const Utf8String &filePath,
uint line,
uint column) const
{
return SourceLocation(m_cxTranslationUnit,
clang_getLocation(m_cxTranslationUnit,
clang_getFile(m_cxTranslationUnit,
filePath.constData()),
line, column));
}
SourceRange TranslationUnit::sourceRange(uint fromLine,
uint fromColumn,
uint toLine,
uint toColumn) const
{
return SourceRange(sourceLocationAt(fromLine, fromColumn),
sourceLocationAt(toLine, toColumn));
}
Cursor TranslationUnit::cursorAt(uint line, uint column) const
{
return clang_getCursor(m_cxTranslationUnit, sourceLocationAt(line, column));
}
Cursor TranslationUnit::cursorAt(const Utf8String &filePath,
uint line,
uint column) const
{
return clang_getCursor(m_cxTranslationUnit, sourceLocationAt(filePath, line, column));
}
Cursor TranslationUnit::cursor() const
{
return clang_getTranslationUnitCursor(m_cxTranslationUnit);
}
TokenProcessor<TokenInfo> TranslationUnit::tokenInfos() const
{
return tokenInfosInRange(cursor().sourceRange());
}
TokenProcessor<TokenInfo> TranslationUnit::tokenInfosInRange(const SourceRange &range) const
{
return TokenProcessor<TokenInfo>(range);
}
TokenProcessor<FullTokenInfo> TranslationUnit::fullTokenInfos() const
{
return fullTokenInfosInRange(cursor().sourceRange());
}
TokenProcessor<FullTokenInfo> TranslationUnit::fullTokenInfosInRange(const SourceRange &range) const
{
return TokenProcessor<FullTokenInfo>(range);
}
SkippedSourceRanges TranslationUnit::skippedSourceRanges() const
{
return SkippedSourceRanges(m_cxTranslationUnit, m_filePath.constData());
}
static bool isMainFileDiagnostic(const Utf8String &mainFilePath, const Diagnostic &diagnostic)
{
return diagnostic.location().filePath() == mainFilePath;
}
static bool isHeaderErrorDiagnostic(const Utf8String &mainFilePath, const Diagnostic &diagnostic)
{
const bool isCritical = diagnostic.severity() == DiagnosticSeverity::Error
|| diagnostic.severity() == DiagnosticSeverity::Fatal;
return isCritical && diagnostic.location().filePath() != mainFilePath;
}
void TranslationUnit::extractDiagnostics(DiagnosticContainer &firstHeaderErrorDiagnostic,
QVector<DiagnosticContainer> &mainFileDiagnostics) const
{
mainFileDiagnostics.clear();
mainFileDiagnostics.reserve(int(diagnostics().size()));
bool hasFirstHeaderErrorDiagnostic = false;
for (const Diagnostic &diagnostic : diagnostics()) {
if (!hasFirstHeaderErrorDiagnostic && isHeaderErrorDiagnostic(m_filePath, diagnostic)) {
hasFirstHeaderErrorDiagnostic = true;
firstHeaderErrorDiagnostic = diagnostic.toDiagnosticContainer();
}
if (isMainFileDiagnostic(m_filePath, diagnostic))
mainFileDiagnostics.push_back(diagnostic.toDiagnosticContainer());
}
}
FollowSymbolResult TranslationUnit::followSymbol(uint line, uint column) const
{
return FollowSymbol::followSymbol(m_cxTranslationUnit, cursorAt(line, column), line, column);
}
} // namespace ClangBackEnd

View File

@@ -1,115 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "fulltokeninfo.h"
#include "tokenprocessor.h"
#include <clangsupport/codecompletion.h>
#include <clang-c/Index.h>
namespace ClangBackEnd {
class Cursor;
class DiagnosticContainer;
class DiagnosticSet;
class FollowSymbolResult;
class ReferencesResult;
class SkippedSourceRanges;
class SourceLocation;
class SourceRange;
class SourceRangeContainer;
class ToolTipInfo;
class TranslationUnitUpdateInput;
class TranslationUnitUpdateResult;
class UnsavedFiles;
class CommandLineArguments;
class TranslationUnit
{
public:
TranslationUnit(const Utf8String &id,
const Utf8String &filePath,
CXIndex &cxIndex,
CXTranslationUnit &cxTranslationUnit);
bool isNull() const;
Utf8String id() const;
Utf8String filePath() const;
CXIndex &cxIndex() const;
CXTranslationUnit &cxTranslationUnit() const;
bool suspend() const;
TranslationUnitUpdateResult update(const TranslationUnitUpdateInput &parseInput) const;
TranslationUnitUpdateResult parse(const TranslationUnitUpdateInput &parseInput) const;
TranslationUnitUpdateResult reparse(const TranslationUnitUpdateInput &parseInput) const;
CodeCompletions complete(UnsavedFiles &unsavedFiles, uint line, uint column,
int funcNameStartLine, int funcNameStartColumn) const;
void extractDiagnostics(DiagnosticContainer &firstHeaderErrorDiagnostic,
QVector<DiagnosticContainer> &mainFileDiagnostics) const;
void extractAnnotations(DiagnosticContainer &firstHeaderErrorDiagnostic,
QVector<DiagnosticContainer> &mainFileDiagnostics,
QVector<TokenInfoContainer> &tokenInfos,
QVector<SourceRangeContainer> &skippedSourceRanges) const;
ReferencesResult references(uint line, uint column, bool localReferences = false) const;
ToolTipInfo tooltip(UnsavedFiles &unsavedFiles,
const Utf8String &textCodecName,
uint line,
uint column) const;
DiagnosticSet diagnostics() const;
SourceLocation sourceLocationAt(uint line, uint column) const;
SourceLocation sourceLocationAt(const Utf8String &filePath, uint line, uint column) const;
SourceRange sourceRange(uint fromLine, uint fromColumn, uint toLine, uint toColumn) const;
Cursor cursorAt(uint line, uint column) const;
Cursor cursorAt(const Utf8String &filePath, uint line, uint column) const;
Cursor cursor() const;
TokenProcessor<TokenInfo> tokenInfos() const;
TokenProcessor<TokenInfo> tokenInfosInRange(const SourceRange &range) const;
TokenProcessor<FullTokenInfo> fullTokenInfos() const;
TokenProcessor<FullTokenInfo> fullTokenInfosInRange(const SourceRange &range) const;
SkippedSourceRanges skippedSourceRanges() const;
FollowSymbolResult followSymbol(uint line, uint column) const;
private:
const Utf8String m_id;
const Utf8String m_filePath;
CXIndex &m_cxIndex;
CXTranslationUnit &m_cxTranslationUnit;
};
} // namespace ClangBackEnd

View File

@@ -1,162 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangtranslationunits.h"
#include "clangexceptions.h"
#include "clangtranslationunit.h"
#include <utils/algorithm.h>
#include <utils/qtcassert.h>
#include <QFileInfo>
#include <QLoggingCategory>
#include <QUuid>
static Q_LOGGING_CATEGORY(tuLog, "qtc.clangbackend.translationunits", QtWarningMsg);
namespace ClangBackEnd {
TranslationUnits::TranslationUnitData::TranslationUnitData(const Utf8String &id)
: id(id)
{}
TranslationUnits::TranslationUnitData::~TranslationUnitData()
{
qCDebug(tuLog) << "Destroying TranslationUnit" << id;
clang_disposeTranslationUnit(cxTranslationUnit);
clang_disposeIndex(cxIndex);
}
TranslationUnits::TranslationUnits(const Utf8String &filePath)
: m_filePath(filePath)
{
}
TranslationUnit TranslationUnits::createAndAppend()
{
const Utf8String id = Utf8String::fromByteArray(QUuid::createUuid().toByteArray());
qCDebug(tuLog) << "Creating TranslationUnit" << id << "for" << QFileInfo(m_filePath).fileName();
m_units.append(TranslationUnitDataPtr(new TranslationUnitData(id)));
return toTranslationUnit(m_units.last());
}
void TranslationUnits::removeAll()
{
m_units.clear();
}
TranslationUnit TranslationUnits::get(PreferredTranslationUnit type)
{
if (m_units.isEmpty())
throw TranslationUnitDoesNotExist(m_filePath);
if (m_units.size() == 1)
return toTranslationUnit(m_units.first());
if (areAllTranslationUnitsParsed())
return getPreferredTranslationUnit(type);
if (type == PreferredTranslationUnit::LastUninitialized)
return toTranslationUnit(m_units.last());
return toTranslationUnit(m_units.first());
}
void TranslationUnits::updateParseTimePoint(const Utf8String &translationUnitId,
TimePoint timePoint)
{
QTC_CHECK(timePoint != TimePoint());
findUnit(translationUnitId).parseTimePoint = timePoint;
qCDebug(tuLog) << "Updated" << translationUnitId << "for" << QFileInfo(m_filePath).fileName()
<< "RecentlyParsed:" << get(PreferredTranslationUnit::RecentlyParsed).id()
<< "PreviouslyParsed:" << get(PreferredTranslationUnit::PreviouslyParsed).id();
}
TimePoint TranslationUnits::parseTimePoint(const Utf8String &translationUnitId)
{
return findUnit(translationUnitId).parseTimePoint;
}
bool TranslationUnits::areAllTranslationUnitsParsed() const
{
return Utils::allOf(m_units, [](const TranslationUnitDataPtr &unit) {
return unit->parseTimePoint != TimePoint();
});
}
bool TranslationUnits::hasParsedTranslationUnit() const
{
return Utils::anyOf(m_units, [](const TranslationUnitDataPtr &unit) {
return unit->parseTimePoint != TimePoint();
});
}
int TranslationUnits::size() const
{
return m_units.size();
}
TranslationUnit TranslationUnits::getPreferredTranslationUnit(PreferredTranslationUnit type)
{
using TuDataPtr = TranslationUnitDataPtr;
const auto lessThan = [](const TuDataPtr &a, const TuDataPtr &b) {
return a->parseTimePoint < b->parseTimePoint;
};
auto it = type == PreferredTranslationUnit::RecentlyParsed
? std::max_element(m_units.begin(), m_units.end(), lessThan)
: std::min_element(m_units.begin(), m_units.end(), lessThan);
if (it == m_units.end())
throw TranslationUnitDoesNotExist(m_filePath);
return toTranslationUnit(*it);
}
TranslationUnits::TranslationUnitData &TranslationUnits::findUnit(
const Utf8String &translationUnitId)
{
for (TranslationUnitDataPtr &unit : m_units) {
if (translationUnitId == unit->id)
return *unit;
}
throw TranslationUnitDoesNotExist(m_filePath);
}
TranslationUnit TranslationUnits::toTranslationUnit(const TranslationUnitDataPtr &unit)
{
return TranslationUnit(unit->id,
m_filePath,
unit->cxIndex,
unit->cxTranslationUnit);
}
} // namespace ClangBackEnd

View File

@@ -1,84 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "clangbackend_global.h"
#include "clangclock.h"
#include <utf8string.h>
#include <clang-c/Index.h>
#include <QList>
#include <QSharedPointer>
namespace ClangBackEnd {
class TranslationUnit;
class TranslationUnits
{
public:
class TranslationUnitData {
public:
TranslationUnitData(const Utf8String &id);
~TranslationUnitData();
Utf8String id;
CXTranslationUnit cxTranslationUnit = nullptr;
CXIndex cxIndex = nullptr;
TimePoint parseTimePoint;
};
using TranslationUnitDataPtr = QSharedPointer<TranslationUnitData>;
public:
TranslationUnits(const Utf8String &filePath);
TranslationUnit createAndAppend();
void removeAll();
TranslationUnit get(PreferredTranslationUnit type = PreferredTranslationUnit::RecentlyParsed);
void updateParseTimePoint(const Utf8String &translationUnitId, TimePoint timePoint);
bool areAllTranslationUnitsParsed() const;
bool hasParsedTranslationUnit() const;
public: // for tests
int size() const;
TimePoint parseTimePoint(const Utf8String &translationUnitId);
private:
TranslationUnit getPreferredTranslationUnit(PreferredTranslationUnit type);
TranslationUnitData &findUnit(const Utf8String &translationUnitId);
TranslationUnit toTranslationUnit(const TranslationUnitDataPtr &unit);
private:
Utf8String m_filePath;
QList<TranslationUnitDataPtr> m_units;
};
} // namespace ClangBackEnd

View File

@@ -1,227 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangtranslationunitupdater.h"
#include "clangbackend_global.h"
#include "clangfilepath.h"
#include "clangstring.h"
#include "clangunsavedfilesshallowarguments.h"
#include <QLoggingCategory>
static Q_LOGGING_CATEGORY(verboseLibLog, "qtc.clangbackend.verboselib", QtWarningMsg);
static bool isVerboseModeEnabled()
{
return verboseLibLog().isDebugEnabled();
}
namespace ClangBackEnd {
TranslationUnitUpdater::TranslationUnitUpdater(const Utf8String translationUnitId,
CXIndex &index,
CXTranslationUnit &cxTranslationUnit,
const TranslationUnitUpdateInput &updateData)
: m_cxIndex(index)
, m_cxTranslationUnit(cxTranslationUnit)
, m_in(updateData)
{
m_out.translationUnitId = translationUnitId;
}
TranslationUnitUpdateResult TranslationUnitUpdater::update(UpdateMode mode)
{
createIndexIfNeeded();
switch (mode) {
case UpdateMode::AsNeeded:
recreateAndParseIfNeeded();
reparseIfNeeded();
break;
case UpdateMode::ParseIfNeeded:
recreateAndParseIfNeeded();
break;
case UpdateMode::ForceReparse:
reparse();
break;
}
return m_out;
}
void TranslationUnitUpdater::recreateAndParseIfNeeded()
{
removeTranslationUnitIfProjectPartWasChanged();
createTranslationUnitIfNeeded();
}
void TranslationUnitUpdater::removeTranslationUnitIfProjectPartWasChanged()
{
if (m_in.parseNeeded) {
clang_disposeTranslationUnit(m_cxTranslationUnit);
m_cxTranslationUnit = nullptr;
}
}
#define RETURN_TEXT_FOR_CASE(enumValue) case enumValue: return #enumValue
static const char *errorCodeToText(CXErrorCode errorCode)
{
switch (errorCode) {
RETURN_TEXT_FOR_CASE(CXError_Success);
RETURN_TEXT_FOR_CASE(CXError_Failure);
RETURN_TEXT_FOR_CASE(CXError_Crashed);
RETURN_TEXT_FOR_CASE(CXError_InvalidArguments);
RETURN_TEXT_FOR_CASE(CXError_ASTReadError);
}
return "UnknownCXErrorCode";
}
#undef RETURN_TEXT_FOR_CASE
void TranslationUnitUpdater::createTranslationUnitIfNeeded()
{
if (!m_cxTranslationUnit) {
m_cxTranslationUnit = CXTranslationUnit();
const auto args = commandLineArguments();
if (isVerboseModeEnabled())
args.print();
UnsavedFilesShallowArguments unsaved = m_in.unsavedFiles.shallowArguments();
m_parseErrorCode = clang_parseTranslationUnit2(m_cxIndex,
nullptr,
args.data(),
args.count(),
unsaved.data(),
unsaved.count(),
defaultParseOptions(),
&m_cxTranslationUnit);
if (parseWasSuccessful()) {
updateIncludeFilePaths();
m_out.parseTimePoint = Clock::now();
} else {
qWarning() << "Parsing" << m_in.filePath << "failed:"
<< errorCodeToText(m_parseErrorCode);
m_out.hasParseOrReparseFailed = true;
}
}
}
void TranslationUnitUpdater::reparseIfNeeded()
{
if (m_in.reparseNeeded)
reparse();
}
void TranslationUnitUpdater::reparse()
{
UnsavedFilesShallowArguments unsaved = m_in.unsavedFiles.shallowArguments();
m_reparseErrorCode = clang_reparseTranslationUnit(
m_cxTranslationUnit,
unsaved.count(),
unsaved.data(),
clang_defaultReparseOptions(m_cxTranslationUnit));
if (reparseWasSuccessful()) {
updateIncludeFilePaths();
m_out.reparseTimePoint = Clock::now();
m_out.needsToBeReparsedChangeTimePoint = m_in.needsToBeReparsedChangeTimePoint;
} else {
qWarning() << "Reparsing" << m_in.filePath << "failed:" << m_reparseErrorCode;
m_out.hasParseOrReparseFailed = true;
}
}
void TranslationUnitUpdater::updateIncludeFilePaths()
{
m_out.dependedOnFilePaths.clear();
m_out.dependedOnFilePaths.insert(m_in.filePath);
clang_getInclusions(m_cxTranslationUnit,
includeCallback,
const_cast<TranslationUnitUpdater *>(this));
}
uint TranslationUnitUpdater::defaultParseOptions()
{
return CXTranslationUnit_CacheCompletionResults
| CXTranslationUnit_PrecompiledPreamble
| CXTranslationUnit_CreatePreambleOnFirstParse
| CXTranslationUnit_SkipFunctionBodies
| CXTranslationUnit_LimitSkipFunctionBodiesToPreamble
// CLANG-UPGRADE-CHECK: Remove when required version is 9
#if (LLVM_VERSION_MAJOR >= 9) || defined(CINDEX_VERSION_HAS_SKIPWARNINGSFROMINCLUDEDFILES_BACKPORTED)
| CXTranslationUnit_IgnoreNonErrorsFromIncludedFiles
#endif
| CXTranslationUnit_IncludeBriefCommentsInCodeCompletion
| CXTranslationUnit_DetailedPreprocessingRecord
| CXTranslationUnit_KeepGoing;
}
void TranslationUnitUpdater::createIndexIfNeeded()
{
if (!m_cxIndex) {
const bool displayDiagnostics = isVerboseModeEnabled();
m_cxIndex = clang_createIndex(1, displayDiagnostics);
}
}
void TranslationUnitUpdater::includeCallback(CXFile included_file,
CXSourceLocation *,
unsigned, CXClientData clientData)
{
ClangString includeFilePath(clang_getFileName(included_file));
TranslationUnitUpdater *updater = static_cast<TranslationUnitUpdater *>(clientData);
updater->m_out.dependedOnFilePaths.insert(FilePath::fromNativeSeparators(includeFilePath));
}
bool TranslationUnitUpdater::parseWasSuccessful() const
{
return m_parseErrorCode == CXError_Success;
}
bool TranslationUnitUpdater::reparseWasSuccessful() const
{
return m_reparseErrorCode == 0;
}
CommandLineArguments TranslationUnitUpdater::commandLineArguments() const
{
return CommandLineArguments(m_in.filePath.constData(),
m_in.compilationArguments,
isVerboseModeEnabled());
}
} // namespace ClangBackEnd

View File

@@ -1,119 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "clangclock.h"
#include "commandlinearguments.h"
#include "unsavedfiles.h"
#include "utf8stringvector.h"
#include <clang-c/Index.h>
#include <QSet>
namespace ClangBackEnd {
class TranslationUnitUpdateInput {
public:
bool parseNeeded = false;
bool reparseNeeded = false;
TimePoint needsToBeReparsedChangeTimePoint;
Utf8String filePath;
Utf8StringVector compilationArguments;
UnsavedFiles unsavedFiles;
};
class TranslationUnitUpdateResult {
public:
bool hasParsed() const
{ return parseTimePoint != TimePoint(); }
bool hasReparsed() const
{ return reparseTimePoint != TimePoint(); }
public:
Utf8String translationUnitId;
bool hasParseOrReparseFailed = false;
TimePoint parseTimePoint;
TimePoint reparseTimePoint;
TimePoint needsToBeReparsedChangeTimePoint;
QSet<Utf8String> dependedOnFilePaths;
};
class TranslationUnitUpdater {
public:
enum class UpdateMode {
AsNeeded,
ParseIfNeeded,
ForceReparse,
};
public:
TranslationUnitUpdater(const Utf8String translationUnitId,
CXIndex &index,
CXTranslationUnit &cxTranslationUnit,
const TranslationUnitUpdateInput &in);
TranslationUnitUpdateResult update(UpdateMode mode);
CommandLineArguments commandLineArguments() const;
static uint defaultParseOptions();
private:
void createIndexIfNeeded();
void createTranslationUnitIfNeeded();
void removeTranslationUnitIfProjectPartWasChanged();
void reparseIfNeeded();
void recreateAndParseIfNeeded();
void reparse();
void updateIncludeFilePaths();
static void includeCallback(CXFile included_file,
CXSourceLocation *,
unsigned,
CXClientData clientData);
bool parseWasSuccessful() const;
bool reparseWasSuccessful() const;
private:
CXIndex &m_cxIndex;
CXTranslationUnit &m_cxTranslationUnit;
CXErrorCode m_parseErrorCode = CXError_Success;
int m_reparseErrorCode = 0;
const TranslationUnitUpdateInput m_in;
TranslationUnitUpdateResult m_out;
};
} // namespace ClangBackEnd

View File

@@ -1,282 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangtype.h"
#include "clangstring.h"
#include "cursor.h"
#include <utf8string.h>
#include <ostream>
namespace ClangBackEnd {
bool Type::isValid() const
{
return m_cxType.kind != CXType_Invalid;
}
bool Type::isConstant() const
{
return clang_isConstQualifiedType(m_cxType);
}
bool Type::isConstantReference()
{
return isLValueReference() && pointeeType().isConstant();
}
bool Type::isPointer() const
{
return m_cxType.kind == CXType_Pointer;
}
bool Type::isPointerToConstant() const
{
return isPointer() && pointeeType().isConstant();
}
bool Type::isConstantPointer() const
{
return isPointer() && isConstant();
}
bool Type::isLValueReference() const
{
return m_cxType.kind == CXType_LValueReference;
}
bool Type::isReferencingConstant() const
{
return (isPointer() || isLValueReference()) && pointeeType().isConstant();
}
bool Type::isOutputArgument() const
{
if (isLValueReference() && !pointeeType().isConstant())
return true;
// We consider a pointer an output argument if it is non-const at any level.
// This is consistent with how we categorize references in CppEditor.
Type t = *this;
while (t.isPointer()) {
t = t.pointeeType();
if (!t.isConstant())
return true;
}
return false;
}
bool Type::isBuiltinType() const
{
return m_cxType.kind >= CXType_FirstBuiltin && m_cxType.kind <= CXType_LastBuiltin;
}
bool Type::isUnsigned() const
{
return m_cxType.kind == CXType_UChar
|| m_cxType.kind == CXType_UShort
|| m_cxType.kind == CXType_UInt
|| m_cxType.kind == CXType_ULong
|| m_cxType.kind == CXType_ULongLong
|| m_cxType.kind == CXType_UInt128;
}
Utf8String Type::utf8Spelling() const
{
return ClangString(clang_getTypeSpelling(m_cxType));
}
ClangString Type::spelling() const
{
return ClangString(clang_getTypeSpelling(m_cxType));
}
static const char *builtinTypeToText(CXTypeKind kind)
{
// CLANG-UPGRADE-CHECK: Check for added built-in types.
switch (kind) {
case CXType_Void:
return "void";
case CXType_Bool:
return "bool";
// See also ${CLANG_REPOSITORY}/lib/Sema/SemaChecking.cpp - IsSameCharType().
case CXType_Char_U:
case CXType_UChar:
return "unsigned char";
case CXType_Char_S:
case CXType_SChar:
return "signed char";
case CXType_Char16:
return "char16_t";
case CXType_Char32:
return "char32_t";
case CXType_WChar:
return "wchar_t";
case CXType_UShort:
return "unsigned short";
case CXType_UInt:
return "unsigned int";
case CXType_ULong:
return "unsigned long";
case CXType_ULongLong:
return "unsigned long long";
case CXType_Short:
return "short";
case CXType_Int:
return "int";
case CXType_Long:
return "long";
case CXType_LongLong:
return "long long";
case CXType_Float:
return "float";
case CXType_Double:
return "double";
case CXType_LongDouble:
return "long double";
case CXType_NullPtr:
return "nullptr_t";
// https://gcc.gnu.org/onlinedocs/gcc/_005f_005fint128.html
case CXType_Int128: return "__int128";
case CXType_UInt128: return "unsigned __int128";
// https://gcc.gnu.org/onlinedocs/gcc/Floating-Types.html
case CXType_Float128: return "__float128";
case CXType_Float16: return "_Float16";
// https://www.khronos.org/registry/OpenCL/sdk/2.1/docs/man/xhtml/scalarDataTypes.html
case CXType_Half:
return "half";
default:
return "";
}
}
Utf8String Type::builtinTypeToString() const
{
const char *text = builtinTypeToText(m_cxType.kind);
return Utf8String::fromByteArray(QByteArray::fromRawData(text, int(strlen(text))));
}
int Type::argumentCount() const
{
return clang_getNumArgTypes(m_cxType);
}
Type Type::alias() const
{
return clang_getTypedefDeclUnderlyingType(clang_getTypeDeclaration(m_cxType));
}
Type Type::canonical() const
{
return clang_getCanonicalType(m_cxType);
}
Type Type::classType() const
{
return clang_Type_getClassType(m_cxType);
}
Type Type::pointeeType() const
{
return clang_getPointeeType(m_cxType);
}
Type Type::resultType() const
{
return clang_getResultType(m_cxType);
}
Type Type::argument(int index) const
{
return clang_getArgType(m_cxType, index);
}
Cursor Type::declaration() const
{
return clang_getTypeDeclaration(m_cxType);
}
long long Type::sizeOf(bool *isValid) const
{
const long long size = clang_Type_getSizeOf(m_cxType);
*isValid = size != CXTypeLayoutError_Invalid
&& size != CXTypeLayoutError_Incomplete
&& size != CXTypeLayoutError_Dependent;
return size;
}
CXTypeKind Type::kind() const
{
return m_cxType.kind;
}
Type::Type(CXType cxType)
: m_cxType(cxType)
{
}
bool operator==(Type first, Type second)
{
return clang_equalTypes(first.m_cxType, second.m_cxType);
}
bool operator!=(Type first, Type second)
{
return !operator==(first, second);
}
std::ostream &operator<<(std::ostream &os, CXTypeKind typeKind)
{
ClangString typeKindSpelling(clang_getTypeKindSpelling(typeKind));
return os << typeKindSpelling.cString();
}
std::ostream &operator<<(std::ostream &os, const Type &type)
{
ClangString typeKindSpelling(clang_getTypeKindSpelling(type.kind()));
os << typeKindSpelling
<< ": \"" << type.spelling() << "\"";
return os;
}
} // namespace ClangBackEnd

View File

@@ -1,86 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <clang-c/Index.h>
#include <iosfwd>
class Utf8String;
namespace ClangBackEnd {
class Cursor;
class ClangString;
class Type
{
friend class Cursor;
friend bool operator==(Type first, Type second);
friend bool operator!=(Type first, Type second);
public:
bool isValid() const;
bool isConstant() const;
bool isConstantReference();
bool isPointer() const;
bool isPointerToConstant() const;
bool isConstantPointer() const;
bool isLValueReference() const;
bool isReferencingConstant() const;
bool isOutputArgument() const;
bool isBuiltinType() const;
bool isUnsigned() const;
Utf8String utf8Spelling() const;
ClangString spelling() const;
Utf8String builtinTypeToString() const;
int argumentCount() const;
Type alias() const;
Type canonical() const;
Type classType() const;
Type pointeeType() const;
Type resultType() const;
Type argument(int index) const;
Cursor declaration() const;
long long sizeOf(bool *isValid) const;
CXTypeKind kind() const;
private:
Type(CXType cxType);
private:
CXType m_cxType;
};
std::ostream &operator<<(std::ostream &os, CXTypeKind typeKind);
std::ostream &operator<<(std::ostream &os, const Type &type);
} // namespace ClangBackEnd

View File

@@ -1,57 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangunsavedfilesshallowarguments.h"
#include "clangfilepath.h"
#include "unsavedfile.h"
#include "unsavedfiles.h"
namespace ClangBackEnd {
UnsavedFilesShallowArguments::UnsavedFilesShallowArguments(const UnsavedFiles &unsavedFiles)
{
const int unsavedFilesCount = int(unsavedFiles.count());
m_cxUnsavedFiles.resize(unsavedFilesCount);
for (int i = 0, total = unsavedFilesCount; i < total; ++i) {
const UnsavedFile &unsavedFile = unsavedFiles.at(i);
m_cxUnsavedFiles[i].Filename = unsavedFile.nativeFilePath().constData();
m_cxUnsavedFiles[i].Contents = unsavedFile.fileContent().constData();
m_cxUnsavedFiles[i].Length = uint(unsavedFile.fileContent().byteSize());
}
}
uint UnsavedFilesShallowArguments::count() const
{
return uint(m_cxUnsavedFiles.count());
}
CXUnsavedFile *UnsavedFilesShallowArguments::data()
{
return m_cxUnsavedFiles.data();
}
} // namespace ClangBackEnd

View File

@@ -1,49 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <QVector>
#include <clang-c/Index.h>
namespace ClangBackEnd {
class UnsavedFile;
class UnsavedFiles;
class UnsavedFilesShallowArguments {
public:
UnsavedFilesShallowArguments() = default;
UnsavedFilesShallowArguments(const UnsavedFiles &unsavedFiles);
uint count() const;
CXUnsavedFile *data();
private:
QVector<CXUnsavedFile> m_cxUnsavedFiles;
};
} // namespace ClangBackEnd

View File

@@ -1,116 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangupdateannotationsjob.h"
#include <clangsupport/annotationsmessage.h>
#include <clangsupport/clangsupportdebugutils.h>
#include <clangsupport/clangcodemodelclientinterface.h>
#include <utils/qtcassert.h>
#include <QRegularExpression>
namespace ClangBackEnd {
// TODO: Add libclang API for this.
static QSet<Utf8String> unresolvedFilePaths(const QVector<DiagnosticContainer> &diagnostics)
{
// We expect something like:
// fatal error: 'ops.h' file not found
QRegularExpression re("'(.*)' file not found");
QSet<Utf8String> unresolved;
for (const DiagnosticContainer &diagnostic : diagnostics) {
if (diagnostic.severity == DiagnosticSeverity::Error
&& diagnostic.category == Utf8StringLiteral("Lexical or Preprocessor Issue")) {
const QString path = re.match(diagnostic.text).captured(1);
if (!path.isEmpty())
unresolved << path;
}
}
return unresolved;
}
IAsyncJob::AsyncPrepareResult UpdateAnnotationsJob::prepareAsyncRun()
{
const JobRequest jobRequest = context().jobRequest;
QTC_ASSERT(isExpectedJobRequestType(jobRequest), return AsyncPrepareResult());
QTC_ASSERT(acquireDocument(), return AsyncPrepareResult());
const TranslationUnit translationUnit = *m_translationUnit;
const TranslationUnitUpdateInput updateInput = createUpdateInput(m_pinnedDocument);
setRunner([translationUnit, updateInput]() {
TIME_SCOPE_DURATION("UpdateAnnotationsJobRunner");
// Update
UpdateAnnotationsJob::AsyncResult asyncResult;
asyncResult.updateResult = translationUnit.update(updateInput);
// Collect
translationUnit.extractAnnotations(asyncResult.firstHeaderErrorDiagnostic,
asyncResult.diagnostics,
asyncResult.tokenInfos,
asyncResult.skippedSourceRanges);
asyncResult.unresolvedFilePaths.unite(
unresolvedFilePaths({asyncResult.firstHeaderErrorDiagnostic}));
asyncResult.unresolvedFilePaths.unite(unresolvedFilePaths(asyncResult.diagnostics));
return asyncResult;
});
return AsyncPrepareResult{translationUnit.id()};
}
void UpdateAnnotationsJob::finalizeAsyncRun()
{
if (!context().isOutdated()) {
const AsyncResult result = asyncResult();
m_pinnedDocument.incorporateUpdaterResult(result.updateResult);
m_pinnedDocument.setUnresolvedFilePaths(result.unresolvedFilePaths);
context().client->annotations(AnnotationsMessage(m_pinnedFileContainer,
result.diagnostics,
result.firstHeaderErrorDiagnostic,
result.tokenInfos,
result.skippedSourceRanges));
}
}
bool UpdateAnnotationsJob::isExpectedJobRequestType(const JobRequest &jobRequest) const
{
return jobRequest.type == JobRequest::Type::UpdateAnnotations;
}
TranslationUnitUpdateInput
UpdateAnnotationsJob::createUpdateInput(const Document &document) const
{
return document.createUpdateInput();
}
} // namespace ClangBackEnd

View File

@@ -1,63 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "clangdocumentjob.h"
#include <clangsupport/diagnosticcontainer.h>
#include <clangsupport/tokeninfocontainer.h>
#include <clangsupport/sourcerangecontainer.h>
#include <QSet>
#include <QVector>
namespace ClangBackEnd {
struct UpdateAnnotationsJobResult
{
TranslationUnitUpdateResult updateResult;
QSet<Utf8String> unresolvedFilePaths;
ClangBackEnd::DiagnosticContainer firstHeaderErrorDiagnostic;
QVector<ClangBackEnd::DiagnosticContainer> diagnostics;
QVector<TokenInfoContainer> tokenInfos;
QVector<SourceRangeContainer> skippedSourceRanges;
};
class UpdateAnnotationsJob : public DocumentJob<UpdateAnnotationsJobResult>
{
public:
using AsyncResult = UpdateAnnotationsJobResult;
AsyncPrepareResult prepareAsyncRun() override;
void finalizeAsyncRun() override;
protected:
virtual bool isExpectedJobRequestType(const JobRequest &jobRequest) const;
virtual TranslationUnitUpdateInput createUpdateInput(const Document &document) const;
};
} // namespace ClangBackEnd

View File

@@ -1,59 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2018 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 "clangupdateextraannotationsjob.h"
#include <clangsupport/annotationsmessage.h>
#include <clangsupport/clangsupportdebugutils.h>
#include <clangsupport/clangcodemodelclientinterface.h>
#include <utils/qtcassert.h>
namespace ClangBackEnd {
IAsyncJob::AsyncPrepareResult UpdateExtraAnnotationsJob::prepareAsyncRun()
{
const JobRequest jobRequest = context().jobRequest;
QTC_ASSERT(acquireDocument(), return AsyncPrepareResult());
const TranslationUnit translationUnit = *m_translationUnit;
setRunner([translationUnit]() {
TIME_SCOPE_DURATION("UpdateExtraAnnotationsJobRunner");
return translationUnit.fullTokenInfos().toTokenInfoContainers();
});
return AsyncPrepareResult{translationUnit.id()};
}
void UpdateExtraAnnotationsJob::finalizeAsyncRun()
{
if (context().isOutdated())
return;
context().client->annotations(AnnotationsMessage(m_pinnedFileContainer, asyncResult()));
}
} // namespace ClangBackEnd

View File

@@ -1,43 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2018 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 "clangdocumentjob.h"
#include <clangsupport/tokeninfocontainer.h>
namespace ClangBackEnd {
using UpdateExtraAnnotationsJobResult = QVector<TokenInfoContainer>;
class UpdateExtraAnnotationsJob : public DocumentJob<UpdateExtraAnnotationsJobResult>
{
public:
AsyncPrepareResult prepareAsyncRun() override;
void finalizeAsyncRun() override;
};
} // namespace ClangBackEnd

View File

@@ -1,219 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "codecompleter.h"
#include "clangbackend_global.h"
#include "clangcodecompleteresults.h"
#include "clangdocument.h"
#include "clangexceptions.h"
#include "clangfilepath.h"
#include "clangstring.h"
#include "clangtranslationunitupdater.h"
#include "clangunsavedfilesshallowarguments.h"
#include "codecompletionsextractor.h"
#include "cursor.h"
#include "sourcelocation.h"
#include "sourcerange.h"
#include "unsavedfile.h"
#include "unsavedfiles.h"
#include <utils/qtcassert.h>
#include <clang-c/Index.h>
namespace ClangBackEnd {
namespace {
CodeCompletions toCodeCompletions(const UnsavedFile &unsavedFile,
const ClangCodeCompleteResults &results,
bool onlyFunctionOverloads)
{
if (results.isNull())
return CodeCompletions();
CodeCompletionsExtractor extractor(unsavedFile, results.data());
CodeCompletions codeCompletions = extractor.extractAll(onlyFunctionOverloads);
return codeCompletions;
}
// CLANG-UPGRADE-CHECK: Remove this workaround once we require LLVM/Clang 11 as that version makes
// the workaround pointless.
void filterUnknownContextResults(ClangCodeCompleteResults &results,
const UnsavedFile &theUnsavedFile,
uint line,
uint column)
{
if (results.hasUnknownContext()) {
bool positionIsOk = false;
const uint position = theUnsavedFile.toUtf8Position(line, column - 1, &positionIsOk);
if (positionIsOk && (theUnsavedFile.hasCharacterAt(position, '.')
|| (theUnsavedFile.hasCharacterAt(position - 1, '-')
&& theUnsavedFile.hasCharacterAt(position, '>')))) {
results = {};
}
}
}
} // anonymous namespace
CodeCompleter::CodeCompleter(const TranslationUnit &translationUnit,
const UnsavedFiles &unsavedFiles)
: translationUnit(translationUnit)
, unsavedFiles(unsavedFiles)
{
}
static void replaceWithOpeningParen(UnsavedFile &file, uint line, uint column)
{
bool ok;
const uint pos = file.toUtf8Position(line, column, &ok);
QTC_ASSERT(ok, return;);
file.replaceAt(pos, 1, Utf8String("(", 1));
}
CodeCompletions CodeCompleter::complete(int line, int column,
int funcNameStartLine,
int funcNameStartColumn)
{
if (funcNameStartLine >= 0) {
UnsavedFile &file = unsavedFiles.unsavedFile(translationUnit.filePath());
// Replace '{' by '(' to get proper FunctionOverloadCompletionKind for constructor.
if (file.hasCharacterAt(line, column - 1, '{'))
replaceWithOpeningParen(file, line, column - 1);
}
// Check if we have a smart pointer completion and get proper constructor signatures in results.
// Results are empty when it's not a smart pointer or this completion failed.
ClangCodeCompleteResults clangCompletions = completeSmartPointerCreation(line,
column,
funcNameStartLine,
funcNameStartColumn);
// Default completion.
if (clangCompletions.isNull() || clangCompletions.isEmpty())
clangCompletions = completeHelper(line, column);
filterUnknownContextResults(clangCompletions, unsavedFile(), line, column);
return toCodeCompletions(unsavedFiles.unsavedFile(translationUnit.filePath()),
clangCompletions,
funcNameStartLine >= 0);
}
// For given "make_unique<T>" / "make_shared<T>" / "QSharedPointer<T>::create" return "new T("
// Otherwize return empty QString
static QString tweakName(const Utf8String &oldName)
{
if (!oldName.contains('>'))
return QString();
QString fullName = oldName.toString().trimmed();
if (!fullName.endsWith('>')) {
// This is the class<type>::method case - remove ::method part
if (!fullName.endsWith("create") || !fullName.contains("QSharedPointer"))
return QString();
fullName = fullName.mid(0, fullName.lastIndexOf(':') - 1);
} else if (!fullName.contains("make_unique") && !fullName.contains("make_shared")) {
return QString();
}
int templateStart = fullName.indexOf('<');
QString templatePart = fullName.mid(templateStart + 1,
fullName.length() - templateStart - 2);
return "new " + templatePart + "(";
}
ClangCodeCompleteResults CodeCompleter::completeSmartPointerCreation(uint line,
uint column,
int funcNameStartLine,
int funcNameStartColumn)
{
if (column <= 1 || funcNameStartLine == -1)
return ClangCodeCompleteResults();
UnsavedFile &file = unsavedFiles.unsavedFile(translationUnit.filePath());
if (!file.hasCharacterAt(line, column - 1, '('))
return ClangCodeCompleteResults();
bool ok;
const uint startPos = file.toUtf8Position(funcNameStartLine, funcNameStartColumn, &ok);
QTC_ASSERT(ok, return ClangCodeCompleteResults(););
const uint endPos = file.toUtf8Position(line, column - 1, &ok);
QTC_ASSERT(ok, return ClangCodeCompleteResults(););
const Utf8String content = file.fileContent();
const Utf8String oldName = content.mid(startPos, endPos - startPos);
const QString updatedName = tweakName(oldName);
if (updatedName.isEmpty())
return ClangCodeCompleteResults();
column += updatedName.length();
file.replaceAt(endPos + 1, 0, updatedName);
ClangCodeCompleteResults results = completeHelper(line, column);
if (results.isEmpty()) {
column -= updatedName.length();
file.replaceAt(endPos + 1, updatedName.length(), QString());
}
return results;
}
ClangCodeCompleteResults CodeCompleter::completeHelper(uint line, uint column)
{
const Utf8String nativeFilePath = FilePath::toNativeSeparators(translationUnit.filePath());
UnsavedFilesShallowArguments unsaved = unsavedFiles.shallowArguments();
return clang_codeCompleteAt(translationUnit.cxTranslationUnit(),
nativeFilePath.constData(),
line,
column,
unsaved.data(),
unsaved.count(),
defaultOptions());
}
uint CodeCompleter::defaultOptions() const
{
uint options = CXCodeComplete_IncludeMacros
| CXCodeComplete_IncludeCompletionsWithFixIts
| CXCodeComplete_IncludeCodePatterns;
if (TranslationUnitUpdater::defaultParseOptions()
& CXTranslationUnit_IncludeBriefCommentsInCodeCompletion) {
options |= CXCodeComplete_IncludeBriefComments;
}
return options;
}
UnsavedFile &CodeCompleter::unsavedFile()
{
return unsavedFiles.unsavedFile(translationUnit.filePath());
}
} // namespace ClangBackEnd

View File

@@ -1,64 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "clangtranslationunit.h"
#include "unsavedfiles.h"
#include <codecompletion.h>
#include <utf8stringvector.h>
namespace ClangBackEnd {
class ClangCodeCompleteResults;
class CodeCompleter
{
public:
CodeCompleter(const TranslationUnit &translationUnit,
const UnsavedFiles &unsavedFiles);
CodeCompletions complete(int line, int column,
int funcNameStartLine = -1,
int funcNameStartColumn = -1);
private:
uint defaultOptions() const;
UnsavedFile &unsavedFile();
ClangCodeCompleteResults completeHelper(uint line, uint column);
ClangCodeCompleteResults completeSmartPointerCreation(uint line,
uint column,
int funcNameStartLine,
int funcNameStartColumn);
private:
TranslationUnit translationUnit;
UnsavedFiles unsavedFiles;
};
} // namespace ClangBackEnd

View File

@@ -1,83 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "codecompletionchunkconverter.h"
#include "clangstring.h"
namespace ClangBackEnd {
void CodeCompletionChunkConverter::extractCompletionChunks(CXCompletionString completionString)
{
const uint completionChunkCount = clang_getNumCompletionChunks(completionString);
chunks.reserve(completionChunkCount);
for (uint chunkIndex = 0; chunkIndex < completionChunkCount; ++chunkIndex) {
const CodeCompletionChunk::Kind kind = chunkKind(completionString, chunkIndex);
if (kind == CodeCompletionChunk::Optional) {
extractOptionalCompletionChunks(clang_getCompletionChunkCompletionString(completionString, chunkIndex));
} else {
chunks.append(CodeCompletionChunk(kind,
chunkText(completionString, chunkIndex)));
}
}
}
void CodeCompletionChunkConverter::extractOptionalCompletionChunks(CXCompletionString completionString)
{
const uint completionChunkCount = clang_getNumCompletionChunks(completionString);
for (uint chunkIndex = 0; chunkIndex < completionChunkCount; ++chunkIndex) {
const CodeCompletionChunk::Kind kind = chunkKind(completionString, chunkIndex);
if (kind == CodeCompletionChunk::Optional)
extractOptionalCompletionChunks(clang_getCompletionChunkCompletionString(completionString, chunkIndex));
else
chunks.append(CodeCompletionChunk(kind, chunkText(completionString, chunkIndex), true));
}
}
CodeCompletionChunk::Kind CodeCompletionChunkConverter::chunkKind(CXCompletionString completionString, uint chunkIndex)
{
return CodeCompletionChunk::Kind(clang_getCompletionChunkKind(completionString, chunkIndex));
}
CodeCompletionChunks CodeCompletionChunkConverter::extract(CXCompletionString completionString)
{
CodeCompletionChunkConverter converter;
converter.extractCompletionChunks(completionString);
return converter.chunks;
}
Utf8String CodeCompletionChunkConverter::chunkText(CXCompletionString completionString, uint chunkIndex)
{
return ClangString(clang_getCompletionChunkText(completionString, chunkIndex));
}
} // namespace ClangBackEnd

View File

@@ -1,52 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <codecompletionchunk.h>
#include <QVector>
#include <clang-c/Index.h>
namespace ClangBackEnd {
class CodeCompletionChunkConverter
{
public:
static CodeCompletionChunks extract(CXCompletionString completionString);
static Utf8String chunkText(CXCompletionString completionString, uint chunkIndex);
private:
static CodeCompletionChunk::Kind chunkKind(CXCompletionString completionString, uint chunkIndex);
void extractCompletionChunks(CXCompletionString completionString);
void extractOptionalCompletionChunks(CXCompletionString completionString);
private:
CodeCompletionChunks chunks;
};
} // namespace ClangBackEnd

View File

@@ -1,530 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "codecompletionsextractor.h"
#include "clangbackend_global.h"
#include "clangstring.h"
#include "clangtranslationunit.h"
#include "codecompletionchunkconverter.h"
#include "sourcelocation.h"
#include "sourcerange.h"
#include "unsavedfile.h"
#include <utils/algorithm.h>
#include <utils/qtcassert.h>
#include <QPair>
#include <QDebug>
#include <cmath>
#include <limits>
namespace ClangBackEnd {
CodeCompletionsExtractor::CodeCompletionsExtractor(const UnsavedFile &unsavedFile,
CXCodeCompleteResults *cxCodeCompleteResults)
: unsavedFile(unsavedFile)
, cxCodeCompleteResults(cxCodeCompleteResults)
{
}
bool CodeCompletionsExtractor::next()
{
const uint cxCodeCompleteResultCount = cxCodeCompleteResults->NumResults;
if (cxCodeCompleteResultIndex < cxCodeCompleteResultCount) {
currentCxCodeCompleteResult = cxCodeCompleteResults->Results[cxCodeCompleteResultIndex];
currentCodeCompletion_ = CodeCompletion();
extractCompletionKind();
extractText();
extractPriority();
extractAvailability();
extractHasParameters();
extractBriefComment();
extractCompletionChunks();
adaptPriority();
extractRequiredFixIts();
++cxCodeCompleteResultIndex;
return true;
}
return false;
}
bool CodeCompletionsExtractor::peek(const Utf8String &name)
{
const uint cxCodeCompleteResultCount = cxCodeCompleteResults->NumResults;
uint peekCxCodeCompleteResultIndex = cxCodeCompleteResultIndex;
while (peekCxCodeCompleteResultIndex < cxCodeCompleteResultCount) {
if (hasText(name, cxCodeCompleteResults->Results[peekCxCodeCompleteResultIndex].CompletionString))
return true;
++peekCxCodeCompleteResultIndex;
}
return false;
}
CodeCompletions CodeCompletionsExtractor::extractAll(bool onlyFunctionOverloads)
{
CodeCompletions codeCompletions;
codeCompletions.reserve(int(cxCodeCompleteResults->NumResults));
while (next())
codeCompletions.append(currentCodeCompletion_);
handleCompletions(codeCompletions, onlyFunctionOverloads);
return codeCompletions;
}
static CodeCompletions filterFunctionOverloads(const CodeCompletions &completions)
{
return ::Utils::filtered(completions, [](const CodeCompletion &completion) {
return completion.completionKind == CodeCompletion::FunctionOverloadCompletionKind;
});
}
static void adaptOverloadsPriorities(CodeCompletions &codeCompletions)
{
std::map<Utf8String, std::vector<CodeCompletion *>> cachedOverloads;
for (CodeCompletion &currentCompletion : codeCompletions) {
if (currentCompletion.completionKind != CodeCompletion::ConstructorCompletionKind
&& currentCompletion.completionKind != CodeCompletion::FunctionCompletionKind
&& currentCompletion.completionKind
!= CodeCompletion::FunctionDefinitionCompletionKind) {
continue;
}
auto found = cachedOverloads.find(currentCompletion.text);
if (found == cachedOverloads.end()) {
cachedOverloads[currentCompletion.text].push_back(&currentCompletion);
} else {
const quint32 oldPriority = found->second.front()->priority;
if (currentCompletion.priority >= oldPriority) {
currentCompletion.priority = oldPriority;
} else {
const quint32 newPriority = currentCompletion.priority;
for (CodeCompletion *completion : found->second)
completion->priority = newPriority;
}
found->second.push_back(&currentCompletion);
}
}
}
static int comparePriorities(quint32 p1, quint32 p2)
{
static const int fuzziness = 2; // Each of const and volatile can introduce a diff of 1.
const int diff = p1 - p2;
if (std::abs(diff) > fuzziness)
return diff;
return 0;
}
// The list is already ordered, but since we pass the priorities up to higher layers,
// we should make sure that adjacent values become identical.
static void mergeAdjacentPriorities(CodeCompletions &completions)
{
static const int maxValue = std::numeric_limits<quint32>::max();
QPair<QVector<CodeCompletion *>, quint32> priorityGroup;
priorityGroup.second = maxValue;
const auto assignGroupPriority = [&priorityGroup] {
for (CodeCompletion * const c : qAsConst(priorityGroup.first))
c->priority = priorityGroup.second;
};
for (CodeCompletion &currentCompletion : completions) {
const int prioCmp = comparePriorities(priorityGroup.second, currentCompletion.priority);
if (prioCmp < 0) {
assignGroupPriority();
priorityGroup.first.clear();
priorityGroup.second = currentCompletion.priority;
} else if (currentCompletion.priority > priorityGroup.second)
priorityGroup.second = currentCompletion.priority;
priorityGroup.first << &currentCompletion;
}
assignGroupPriority();
}
static void sortCodeCompletions(CodeCompletions &codeCompletions)
{
auto currentItemsCompare = [](const CodeCompletion &first,
const CodeCompletion &second) {
// Items without fix-its come first.
if (first.requiredFixIts.empty() != second.requiredFixIts.empty())
return first.requiredFixIts.empty() > second.requiredFixIts.empty();
const int prioCmpResult = comparePriorities(first.priority, second.priority);
if (prioCmpResult != 0)
return prioCmpResult < 0;
const int textCmp = first.text.toString().compare(second.text);
if (textCmp != 0)
return textCmp < 0;
return first.completionKind < second.completionKind;
};
// Keep the order for the items with the same priority and name.
std::stable_sort(codeCompletions.begin(), codeCompletions.end(), currentItemsCompare);
}
void CodeCompletionsExtractor::handleCompletions(CodeCompletions &codeCompletions,
bool onlyFunctionOverloads)
{
if (onlyFunctionOverloads) {
const CodeCompletions overloadCompletions = filterFunctionOverloads(codeCompletions);
// If filtered completions are empty the assumption we need function overloads is wrong
// therefore we do not use filtered results in that case.
if (!overloadCompletions.isEmpty())
codeCompletions = overloadCompletions;
}
adaptOverloadsPriorities(codeCompletions);
sortCodeCompletions(codeCompletions);
mergeAdjacentPriorities(codeCompletions);
}
void CodeCompletionsExtractor::extractCompletionKind()
{
switch (currentCxCodeCompleteResult.CursorKind) {
case CXCursor_FunctionTemplate:
currentCodeCompletion_.completionKind = CodeCompletion::TemplateFunctionCompletionKind;
break;
case CXCursor_CXXMethod:
extractMethodCompletionKind();
break;
case CXCursor_FunctionDecl:
case CXCursor_ConversionFunction:
currentCodeCompletion_.completionKind = CodeCompletion::FunctionCompletionKind;
break;
case CXCursor_VariableRef:
case CXCursor_MemberRef:
case CXCursor_VarDecl:
case CXCursor_FieldDecl:
case CXCursor_ParmDecl:
case CXCursor_NonTypeTemplateParameter:
currentCodeCompletion_.completionKind = CodeCompletion::VariableCompletionKind;
break;
case CXCursor_StructDecl:
case CXCursor_UnionDecl:
case CXCursor_ClassDecl:
case CXCursor_TemplateTypeParameter:
currentCodeCompletion_.completionKind = CodeCompletion::ClassCompletionKind;
break;
case CXCursor_TypedefDecl:
case CXCursor_TypeAliasDecl:
currentCodeCompletion_.completionKind = CodeCompletion::TypeAliasCompletionKind;
break;
case CXCursor_ClassTemplatePartialSpecialization:
case CXCursor_ClassTemplate:
case CXCursor_TemplateTemplateParameter:
currentCodeCompletion_.completionKind = CodeCompletion::TemplateClassCompletionKind;
break;
case CXCursor_Namespace:
case CXCursor_NamespaceAlias:
currentCodeCompletion_.completionKind = CodeCompletion::NamespaceCompletionKind;
break;
case CXCursor_EnumDecl:
currentCodeCompletion_.completionKind = CodeCompletion::EnumerationCompletionKind;
break;
case CXCursor_EnumConstantDecl:
currentCodeCompletion_.completionKind = CodeCompletion::EnumeratorCompletionKind;
break;
case CXCursor_Constructor:
currentCodeCompletion_.completionKind = CodeCompletion::ConstructorCompletionKind;
break;
case CXCursor_Destructor:
currentCodeCompletion_.completionKind = CodeCompletion::DestructorCompletionKind;
break;
case CXCursor_MacroDefinition:
extractMacroCompletionKind();
break;
case CXCursor_NotImplemented:
currentCodeCompletion_.completionKind = CodeCompletion::KeywordCompletionKind;
break;
case CXCursor_OverloadCandidate:
currentCodeCompletion_.completionKind = CodeCompletion::FunctionOverloadCompletionKind;
break;
default:
currentCodeCompletion_.completionKind = CodeCompletion::Other;
}
}
void CodeCompletionsExtractor::extractText()
{
const uint completionChunkCount = clang_getNumCompletionChunks(currentCxCodeCompleteResult.CompletionString);
for (uint chunkIndex = 0; chunkIndex < completionChunkCount; ++chunkIndex) {
const CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(currentCxCodeCompleteResult.CompletionString, chunkIndex);
if (chunkKind == CXCompletionChunk_TypedText) {
currentCodeCompletion_.text = CodeCompletionChunkConverter::chunkText(currentCxCodeCompleteResult.CompletionString, chunkIndex);
break;
}
}
}
void CodeCompletionsExtractor::extractMethodCompletionKind()
{
CXCompletionString cxCompletionString = cxCodeCompleteResults->Results[cxCodeCompleteResultIndex].CompletionString;
const unsigned long long contexts = clang_codeCompleteGetContexts(cxCodeCompleteResults);
const uint annotationCount = clang_getCompletionNumAnnotations(cxCompletionString);
for (uint annotationIndex = 0; annotationIndex < annotationCount; ++annotationIndex) {
ClangString annotation = clang_getCompletionAnnotation(cxCompletionString, annotationIndex);
if (annotation == Utf8StringLiteral("qt_signal")) {
currentCodeCompletion_.completionKind = CodeCompletion::SignalCompletionKind;
return;
}
if (annotation == Utf8StringLiteral("qt_slot")) {
currentCodeCompletion_.completionKind = CodeCompletion::SlotCompletionKind;
return;
}
}
currentCodeCompletion_.completionKind = CodeCompletion::FunctionDefinitionCompletionKind;
if ((contexts & CXCompletionContext_DotMemberAccess)
|| (contexts & CXCompletionContext_ArrowMemberAccess)) {
currentCodeCompletion_.completionKind = CodeCompletion::FunctionCompletionKind;
}
}
void CodeCompletionsExtractor::extractMacroCompletionKind()
{
CXCompletionString cxCompletionString = cxCodeCompleteResults->Results[cxCodeCompleteResultIndex].CompletionString;
const uint completionChunkCount = clang_getNumCompletionChunks(cxCompletionString);
for (uint chunkIndex = 0; chunkIndex < completionChunkCount; ++chunkIndex) {
CXCompletionChunkKind kind = clang_getCompletionChunkKind(cxCompletionString, chunkIndex);
if (kind == CXCompletionChunk_Placeholder) {
currentCodeCompletion_.completionKind = CodeCompletion::FunctionCompletionKind;
return;
}
}
currentCodeCompletion_.completionKind = CodeCompletion::PreProcessorCompletionKind;
}
void CodeCompletionsExtractor::extractPriority()
{
CXCompletionString cxCompletionString = cxCodeCompleteResults->Results[cxCodeCompleteResultIndex].CompletionString;
quint32 priority = clang_getCompletionPriority(cxCompletionString);
currentCodeCompletion_.priority = priority;
}
void CodeCompletionsExtractor::extractAvailability()
{
CXCompletionString cxCompletionString = cxCodeCompleteResults->Results[cxCodeCompleteResultIndex].CompletionString;
CXAvailabilityKind cxAvailabilityKind = clang_getCompletionAvailability(cxCompletionString);
switch (cxAvailabilityKind) {
case CXAvailability_Available:
currentCodeCompletion_.availability = CodeCompletion::Available;
break;
case CXAvailability_Deprecated:
currentCodeCompletion_.availability = CodeCompletion::Deprecated;
break;
case CXAvailability_NotAvailable:
currentCodeCompletion_.availability = CodeCompletion::NotAvailable;
break;
case CXAvailability_NotAccessible:
// QTCREATORBUG-25244
if (currentCodeCompletion_.completionKind == CodeCompletion::FunctionDefinitionCompletionKind)
currentCodeCompletion_.availability = CodeCompletion::Available;
else
currentCodeCompletion_.availability = CodeCompletion::NotAccessible;
break;
}
}
void CodeCompletionsExtractor::extractHasParameters()
{
const uint completionChunkCount = clang_getNumCompletionChunks(currentCxCodeCompleteResult.CompletionString);
for (uint chunkIndex = 0; chunkIndex < completionChunkCount; ++chunkIndex) {
const CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(currentCxCodeCompleteResult.CompletionString, chunkIndex);
if (chunkKind == CXCompletionChunk_LeftParen) {
const CXCompletionChunkKind nextChunkKind = clang_getCompletionChunkKind(currentCxCodeCompleteResult.CompletionString, chunkIndex + 1);
currentCodeCompletion_.hasParameters = nextChunkKind != CXCompletionChunk_RightParen;
return;
}
}
}
void CodeCompletionsExtractor::extractBriefComment()
{
ClangString briefComment = clang_getCompletionBriefComment(currentCxCodeCompleteResult.CompletionString);
currentCodeCompletion_.briefComment = briefComment;
}
void CodeCompletionsExtractor::extractCompletionChunks()
{
currentCodeCompletion_.chunks = CodeCompletionChunkConverter::extract(currentCxCodeCompleteResult.CompletionString);
}
SourceRangeContainer toRangeContainer(const UnsavedFile &file, CXSourceRange cxSourceRange)
{
const CXSourceLocation start = clang_getRangeStart(cxSourceRange);
const CXSourceLocation end = clang_getRangeEnd(cxSourceRange);
uint startLine = 0;
uint startColumn = 0;
uint endLine = 0;
uint endColumn = 0;
clang_getFileLocation(start, nullptr, &startLine, &startColumn, nullptr);
clang_getFileLocation(end, nullptr, &endLine, &endColumn, nullptr);
QTC_ASSERT(startLine == endLine, return SourceRangeContainer(););
const Utf8String lineText = file.lineRange(startLine, endLine);
startColumn = lineText.mid(0, startColumn - 1).toString().size() + 1;
endColumn = lineText.mid(0, endColumn - 1).toString().size() + 1;
return SourceRangeContainer(SourceLocationContainer(file.filePath(), startLine, startColumn),
SourceLocationContainer(file.filePath(), endLine, endColumn));
}
void CodeCompletionsExtractor::extractRequiredFixIts()
{
unsigned fixItsNumber = clang_getCompletionNumFixIts(cxCodeCompleteResults,
cxCodeCompleteResultIndex);
if (!fixItsNumber)
return;
CXSourceRange range;
for (unsigned i = 0; i < fixItsNumber; ++i) {
ClangString fixIt = clang_getCompletionFixIt(cxCodeCompleteResults,
cxCodeCompleteResultIndex,
i,
&range);
currentCodeCompletion_.requiredFixIts.push_back(
FixItContainer(Utf8String(fixIt), toRangeContainer(unsavedFile, range)));
}
}
void CodeCompletionsExtractor::adaptPriority()
{
decreasePriorityForDestructors();
decreasePriorityForNonAvailableCompletions();
decreasePriorityForQObjectInternals();
decreasePriorityForSignals();
decreasePriorityForOperators();
}
void CodeCompletionsExtractor::decreasePriorityForNonAvailableCompletions()
{
if (currentCodeCompletion_.availability != CodeCompletion::Available)
currentCodeCompletion_.priority = currentCodeCompletion_.priority * 100;
}
void CodeCompletionsExtractor::decreasePriorityForDestructors()
{
if (currentCodeCompletion_.completionKind == CodeCompletion::DestructorCompletionKind)
currentCodeCompletion_.priority = currentCodeCompletion_.priority * 100;
}
void CodeCompletionsExtractor::decreasePriorityForSignals()
{
if (currentCodeCompletion_.completionKind == CodeCompletion::SignalCompletionKind)
currentCodeCompletion_.priority = currentCodeCompletion_.priority * 100;
}
void CodeCompletionsExtractor::decreasePriorityForQObjectInternals()
{
quint32 priority = currentCodeCompletion_.priority;
if (currentCodeCompletion_.text.startsWith("qt_"))
priority *= 100;
if (currentCodeCompletion_.text == Utf8StringLiteral("metaObject"))
priority *= 10;
if (currentCodeCompletion_.text == Utf8StringLiteral("staticMetaObject"))
priority *= 100;
currentCodeCompletion_.priority = priority;
}
bool isOperator(CXCursorKind cxCursorKind, const Utf8String &name)
{
return cxCursorKind == CXCursor_ConversionFunction
|| (cxCursorKind == CXCursor_CXXMethod
&& name.startsWith(Utf8StringLiteral("operator")));
}
void CodeCompletionsExtractor::decreasePriorityForOperators()
{
quint32 priority = currentCodeCompletion_.priority;
if (isOperator(currentCxCodeCompleteResult.CursorKind, currentCodeCompletion().text))
priority *= 100;
currentCodeCompletion_.priority = priority;
}
bool CodeCompletionsExtractor::hasText(const Utf8String &text, CXCompletionString cxCompletionString) const
{
const uint completionChunkCount = clang_getNumCompletionChunks(cxCompletionString);
for (uint chunkIndex = 0; chunkIndex < completionChunkCount; ++chunkIndex) {
const CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(cxCompletionString, chunkIndex);
if (chunkKind == CXCompletionChunk_TypedText) {
const ClangString currentText(clang_getCompletionChunkText(cxCompletionString, chunkIndex));
return text == currentText;
}
}
return false;
}
const CodeCompletion &CodeCompletionsExtractor::currentCodeCompletion() const
{
return currentCodeCompletion_;
}
std::ostream &operator<<(std::ostream &os, const CodeCompletionsExtractor &extractor)
{
os << "name: " << extractor.currentCodeCompletion().text
<< ", kind: " << extractor.currentCodeCompletion().completionKind
<< ", priority: " << extractor.currentCodeCompletion().priority
<< ", kind: " << extractor.currentCodeCompletion().availability;
return os;
}
} // namespace ClangBackEnd

View File

@@ -1,91 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <codecompletion.h>
#include <clang-c/Index.h>
#include <QVector>
#include <iosfwd>
namespace ClangBackEnd {
class UnsavedFile;
class CodeCompletionsExtractor
{
public:
CodeCompletionsExtractor(const UnsavedFile &unsavedFile,
CXCodeCompleteResults *cxCodeCompleteResults);
CodeCompletionsExtractor(CodeCompletionsExtractor&) = delete;
CodeCompletionsExtractor &operator=(CodeCompletionsExtractor&) = delete;
CodeCompletionsExtractor(CodeCompletionsExtractor&&) = delete;
CodeCompletionsExtractor &operator=(CodeCompletionsExtractor&&) = delete;
bool next();
bool peek(const Utf8String &name);
CodeCompletions extractAll(bool onlyFunctionOverloads);
const CodeCompletion &currentCodeCompletion() const;
private:
void extractCompletionKind();
void extractText();
void extractMethodCompletionKind();
void extractMacroCompletionKind();
void extractPriority();
void extractAvailability();
void extractHasParameters();
void extractBriefComment();
void extractCompletionChunks();
void extractRequiredFixIts();
void adaptPriority();
void decreasePriorityForNonAvailableCompletions();
void decreasePriorityForDestructors();
void decreasePriorityForSignals();
void decreasePriorityForQObjectInternals();
void decreasePriorityForOperators();
void handleCompletions(CodeCompletions &codeCompletions, bool onlyFunctionOverloads);
bool hasText(const Utf8String &text, CXCompletionString cxCompletionString) const;
private:
CodeCompletion currentCodeCompletion_;
const UnsavedFile &unsavedFile;
CXCompletionResult currentCxCodeCompleteResult{CXCursor_UnexposedDecl, nullptr};
CXCodeCompleteResults *cxCodeCompleteResults = nullptr;
uint cxCodeCompleteResultIndex = 0;
};
std::ostream &operator<<(std::ostream &os, const CodeCompletionsExtractor &extractor);
} // namespace ClangBackEnd

View File

@@ -1,128 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "commandlinearguments.h"
#include "clangfilepath.h"
#include <utf8string.h>
#include <utils/algorithm.h>
#include <utils/qtcprocess.h>
#include <QByteArray>
#include <QDebug>
static QList<QByteArray> splitArgs(QString &argsString)
{
QList<QByteArray> result;
Utils::ProcessArgs::ArgIterator it(&argsString);
while (it.next())
result.append(it.value().toUtf8());
return result;
}
template<size_t Size>
static QList<QByteArray> extraOptions(const char(&environment)[Size])
{
if (!qEnvironmentVariableIsSet(environment))
return QList<QByteArray>();
QString arguments = QString::fromLocal8Bit(qgetenv(environment));
return splitArgs(arguments);
}
static QList<QByteArray> extraClangCodeModelPrependOptions() {
constexpr char ccmPrependOptions[] = "QTC_CLANG_CCM_CMD_PREPEND";
static const QList<QByteArray> options = extraOptions(ccmPrependOptions);
if (!options.isEmpty())
qWarning() << "ClangCodeModel options are prepended with " << options;
return options;
}
static QList<QByteArray> extraClangCodeModelAppendOptions() {
constexpr char ccmAppendOptions[] = "QTC_CLANG_CCM_CMD_APPEND";
static const QList<QByteArray> options = extraOptions(ccmAppendOptions);
if (!options.isEmpty())
qWarning() << "ClangCodeModel options are appended with " << options;
return options;
}
namespace ClangBackEnd {
CommandLineArguments::CommandLineArguments(const char *filePath,
const Utf8StringVector &compilationArguments,
bool addVerboseOption)
: m_prependArgs(extraClangCodeModelPrependOptions()),
m_appendArgs(extraClangCodeModelAppendOptions())
{
const int elementsToReserve = m_prependArgs.size()
+ compilationArguments.size()
+ (addVerboseOption ? 1 : 0)
+ m_appendArgs.size();
m_arguments.reserve(static_cast<size_t>(elementsToReserve));
for (const auto &argument : m_prependArgs)
m_arguments.push_back(argument.constData());
for (const auto &argument : compilationArguments)
m_arguments.push_back(argument.constData());
if (addVerboseOption)
m_arguments.push_back("-v");
for (const auto &argument : m_appendArgs)
m_arguments.push_back(argument.constData());
m_nativeFilePath = FilePath::toNativeSeparators(Utf8String::fromUtf8(filePath));
m_arguments.push_back(m_nativeFilePath.constData());
}
const char * const *CommandLineArguments::data() const
{
return m_arguments.data();
}
int CommandLineArguments::count() const
{
return int(m_arguments.size());
}
const char *CommandLineArguments::at(int position) const
{
return m_arguments.at(uint(position));
}
static Utf8String maybeQuoted(const char *argumentAsCString)
{
const QString argumentAsQString = QString::fromUtf8(argumentAsCString);
const QString quotedArgument = Utils::ProcessArgs::quoteArg(argumentAsQString);
return Utf8String::fromString(quotedArgument);
}
void CommandLineArguments::print() const
{
auto cerr = qCritical();
cerr << "Arguments to libclang:";
for (const auto &argument : m_arguments)
cerr.noquote() << maybeQuoted(argument).constData();
}
} // namespace ClangBackEnd

View File

@@ -1,54 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <utf8stringvector.h>
#include <vector>
namespace ClangBackEnd {
class CommandLineArguments
{
public:
CommandLineArguments(const char *filePath,
const Utf8StringVector &compilationArguments,
bool addVerboseOption);
const char * const *data() const;
int count() const;
const char * at(int position) const;
void print() const;
private:
Utf8String m_nativeFilePath;
const QList<QByteArray> m_prependArgs;
const QList<QByteArray> m_appendArgs;
std::vector<const char *> m_arguments;
};
} // namespace ClangBackEnd

View File

@@ -1,544 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "cursor.h"
#include "clangstring.h"
#include "sourcelocation.h"
#include "sourcerange.h"
#include "clangbackend_global.h"
#include <ostream>
namespace ClangBackEnd {
Cursor::Cursor()
: m_cxCursor(clang_getNullCursor())
{
}
Cursor::Cursor(CXCursor cxCursor)
: m_cxCursor(cxCursor)
{
}
bool Cursor::isNull() const
{
return clang_Cursor_isNull(m_cxCursor);
}
bool Cursor::isValid() const
{
return !clang_isInvalid(kind());
}
bool Cursor::isTranslationUnit() const
{
return clang_isTranslationUnit(kind());
}
bool Cursor::isDefinition() const
{
return clang_isCursorDefinition(m_cxCursor);
}
bool Cursor::isDynamicCall() const
{
return clang_Cursor_isDynamicCall(m_cxCursor);
}
bool Cursor::isVirtualMethod() const
{
return clang_CXXMethod_isVirtual(m_cxCursor);
}
bool Cursor::isPureVirtualMethod() const
{
return clang_CXXMethod_isPureVirtual(m_cxCursor);
}
bool Cursor::isConstantMethod() const
{
return clang_CXXMethod_isConst(m_cxCursor);
}
bool Cursor::isStaticMethod() const
{
return clang_CXXMethod_isStatic(m_cxCursor);
}
bool Cursor::isCompoundType() const
{
switch (kind()) {
case CXCursor_ClassDecl:
case CXCursor_StructDecl:
case CXCursor_UnionDecl: return true;
default: return false;
}
}
bool Cursor::isDeclaration() const
{
return clang_isDeclaration(kind());
}
bool Cursor::isInvalidDeclaration() const
{
return clang_isInvalidDeclaration(m_cxCursor);
}
bool Cursor::isParameter() const
{
return kind() == CXCursor_ParmDecl;
}
bool Cursor::isLocalVariable() const
{
switch (semanticParent().kind()) {
case CXCursor_FunctionDecl:
case CXCursor_CXXMethod:
case CXCursor_Constructor:
case CXCursor_Destructor:
case CXCursor_ConversionFunction:
case CXCursor_FunctionTemplate:
case CXCursor_ObjCInstanceMethodDecl: return true;
default:
return false;
}
}
bool Cursor::isReference() const
{
return clang_isReference(kind());
}
bool Cursor::isExpression() const
{
return clang_isExpression(kind());
}
bool Cursor::isFunctionLike() const
{
const CXCursorKind k = kind();
return k == CXCursor_FunctionDecl
|| k == CXCursor_CXXMethod
|| k == CXCursor_FunctionTemplate;
}
bool Cursor::isConstructorOrDestructor() const
{
const CXCursorKind k = kind();
return k == CXCursor_Constructor
|| k == CXCursor_Destructor;
}
bool Cursor::isTemplateLike() const
{
switch (kind()) {
case CXCursor_ClassTemplate:
case CXCursor_ClassTemplatePartialSpecialization:
return true;
case CXCursor_ClassDecl:
return specializedCursorTemplate().isValid();
default:
return false;
}
Q_UNREACHABLE();
}
bool Cursor::isAnyTypeAlias() const
{
const CXCursorKind k = kind();
return k == CXCursor_TypeAliasDecl
|| k == CXCursor_TypedefDecl
|| k == CXCursor_TypeAliasTemplateDecl;
}
bool Cursor::hasFinalFunctionAttribute() const
{
bool hasFinal = false;
visit([&] (Cursor cursor, Cursor /*parent*/) {
if (cursor.kind() == CXCursor_CXXFinalAttr) {
hasFinal = true;
return CXChildVisit_Break;
} else {
return CXChildVisit_Recurse;
}
});
return hasFinal;
}
bool Cursor::hasFinalClassAttribute() const
{
bool hasFinal = false;
visit([&] (Cursor cursor, Cursor /*parent*/) {
switch (cursor.kind()) {
case CXCursor_CXXFinalAttr:
hasFinal = true;
return CXChildVisit_Break;
case CXCursor_CXXMethod:
return CXChildVisit_Break;
default:
return CXChildVisit_Recurse;
}
});
return hasFinal;
}
bool Cursor::isUnexposed() const
{
return clang_isUnexposed(kind());
}
bool Cursor::isAnonymous() const
{
return clang_Cursor_isAnonymous(m_cxCursor);
}
ClangString Cursor::unifiedSymbolResolution() const
{
return ClangString(clang_getCursorUSR(m_cxCursor));
}
ClangString Cursor::mangling() const
{
return ClangString(clang_Cursor_getMangling(m_cxCursor));
}
ClangString Cursor::spelling() const
{
return ClangString(clang_getCursorSpelling(m_cxCursor));
}
Utf8String Cursor::displayName() const
{
Utf8String result = ClangString(clang_getCursorDisplayName(m_cxCursor));
if (!result.hasContent() && isAnonymous())
result = Utf8String("(anonymous)");
return result;
}
ClangString Cursor::briefComment() const
{
return ClangString(clang_Cursor_getBriefCommentText(m_cxCursor));
}
Utf8String Cursor::rawComment() const
{
Utf8String comment = ClangString(clang_Cursor_getRawCommentText(m_cxCursor));
comment.replace(Utf8String("\r\n"), Utf8String("\n"));
return comment;
}
int Cursor::argumentCount() const
{
return clang_Cursor_getNumArguments(m_cxCursor);
}
Type Cursor::type() const
{
return clang_getCursorType(m_cxCursor);
}
Type Cursor::nonPointerTupe() const
{
auto typeResult = type();
if (typeResult.isPointer())
typeResult = typeResult.pointeeType();
return typeResult;
}
Type Cursor::enumType() const
{
return clang_getEnumDeclIntegerType(m_cxCursor);
}
long long Cursor::enumConstantValue() const
{
return clang_getEnumConstantDeclValue(m_cxCursor);
}
unsigned long long Cursor::enumConstantUnsignedValue() const
{
return clang_getEnumConstantDeclUnsignedValue(m_cxCursor);
}
Cursor Cursor::specializedCursorTemplate() const
{
return clang_getSpecializedCursorTemplate(m_cxCursor);
}
CXFile Cursor::includedFile() const
{
return clang_getIncludedFile(m_cxCursor);
}
SourceLocation Cursor::sourceLocation() const
{
return {cxTranslationUnit(), clang_getCursorLocation(m_cxCursor)};
}
CXSourceLocation Cursor::cxSourceLocation() const
{
return clang_getCursorLocation(m_cxCursor);
}
SourceRange Cursor::sourceRange() const
{
return {cxTranslationUnit(), clang_getCursorExtent(m_cxCursor)};
}
CXSourceRange Cursor::cxSourceRange() const
{
return clang_getCursorExtent(m_cxCursor);
}
CXTranslationUnit Cursor::cxTranslationUnit() const
{
return clang_Cursor_getTranslationUnit(m_cxCursor);
}
SourceRange Cursor::commentRange() const
{
return {cxTranslationUnit(), clang_Cursor_getCommentRange(m_cxCursor)};
}
bool Cursor::hasSameSourceLocationAs(const Cursor &other) const
{
return clang_equalLocations(clang_getCursorLocation(m_cxCursor),
clang_getCursorLocation(other.m_cxCursor));
}
Cursor Cursor::definition() const
{
return clang_getCursorDefinition(m_cxCursor);
}
Cursor Cursor::canonical() const
{
return clang_getCanonicalCursor(m_cxCursor);
}
Cursor Cursor::referenced() const
{
return clang_getCursorReferenced(m_cxCursor);
}
Cursor Cursor::semanticParent() const
{
return clang_getCursorSemanticParent(m_cxCursor);
}
Cursor Cursor::lexicalParent() const
{
return clang_getCursorLexicalParent(m_cxCursor);
}
Cursor Cursor::functionBaseDeclaration() const
{
auto functionBaseCursor = functionBase();
if (functionBaseCursor.isValid())
return functionBaseCursor.nonPointerTupe().canonical().declaration();
else
return semanticParent().semanticParent();
}
Cursor Cursor::functionBase() const
{
Cursor functionBaseCursor;
visit([&] (Cursor cursor, Cursor /*parentCursor*/) {
switch (cursor.kind()) {
case CXCursor_DeclRefExpr:
functionBaseCursor = cursor; ;
return CXChildVisit_Break;
default:
return CXChildVisit_Recurse;
}
});
return functionBaseCursor;
}
Type Cursor::resultType() const
{
return clang_getResultType(type().m_cxType);
}
Cursor Cursor::argument(int index) const
{
return clang_Cursor_getArgument(m_cxCursor, index);
}
unsigned Cursor::overloadedDeclarationsCount() const
{
return clang_getNumOverloadedDecls(m_cxCursor);
}
Cursor Cursor::overloadedDeclaration(unsigned index) const
{
return clang_getOverloadedDecl(m_cxCursor, index);
}
namespace {
bool isNotUnexposedLValueReference(const Cursor &argument, const Type &argumentType)
{
return !(argument.isUnexposed() && argumentType.isLValueReference());
}
}
void Cursor::collectOutputArgumentRangesTo(std::vector<CXSourceRange> &outputArgumentRanges) const
{
const Type callExpressionType = referenced().type();
const int argumentCount = this->argumentCount();
const std::size_t maxSize = std::size_t(std::max(0, argumentCount))
+ outputArgumentRanges.size();
outputArgumentRanges.reserve(maxSize);
for (int argumentIndex = 0; argumentIndex < argumentCount; ++argumentIndex) {
const Cursor argument = this->argument(argumentIndex);
const Type argumentType = callExpressionType.argument(argumentIndex);
if (isNotUnexposedLValueReference(argument, argumentType)
&& argumentType.isOutputArgument()) {
outputArgumentRanges.push_back(argument.cxSourceRange());
}
}
}
std::vector<CXSourceRange> Cursor::outputArgumentRanges() const
{
std::vector<CXSourceRange> outputArgumentRanges;
collectOutputArgumentRangesTo(outputArgumentRanges);
return outputArgumentRanges;
}
CXCursorKind Cursor::kind() const
{
return clang_getCursorKind(m_cxCursor);
}
CXCursor Cursor::cx() const
{
return m_cxCursor;
}
StorageClass Cursor::storageClass() const
{
CXCursor cursor = m_cxCursor;
if (!isDeclaration())
cursor = referenced().m_cxCursor;
const CX_StorageClass cxStorageClass = clang_Cursor_getStorageClass(cursor);
switch (cxStorageClass) {
case CX_SC_Invalid:
case CX_SC_OpenCLWorkGroupLocal:
break;
case CX_SC_None:
return StorageClass::None;
case CX_SC_Extern:
return StorageClass::Extern;
case CX_SC_Static:
return StorageClass::Static;
case CX_SC_PrivateExtern:
return StorageClass::PrivateExtern;
case CX_SC_Auto:
return StorageClass::Auto;
case CX_SC_Register:
return StorageClass::Register;
}
return StorageClass::Invalid;
}
AccessSpecifier Cursor::accessSpecifier() const
{
CXCursor cursor = m_cxCursor;
if (!isDeclaration())
cursor = referenced().m_cxCursor;
const CX_CXXAccessSpecifier cxAccessSpecifier = clang_getCXXAccessSpecifier(cursor);
switch (cxAccessSpecifier) {
case CX_CXXInvalidAccessSpecifier:
break;
case CX_CXXPublic:
return AccessSpecifier::Public;
case CX_CXXProtected:
return AccessSpecifier::Protected;
case CX_CXXPrivate:
return AccessSpecifier::Private;
}
return AccessSpecifier::Invalid;
}
bool operator==(const Cursor &first, const Cursor &second)
{
return clang_equalCursors(first.m_cxCursor, second.m_cxCursor);
}
bool operator!=(const Cursor &first, const Cursor &second)
{
return !(first == second);
}
std::ostream &operator<<(std::ostream &os, CXCursorKind cursorKind)
{
ClangString cursorKindSpelling(clang_getCursorKindSpelling(cursorKind));
return os << cursorKindSpelling.cString();
}
std::ostream &operator<<(std::ostream &os, const Cursor &cursor)
{
if (cursor.isValid()) {
ClangString cursorKindSpelling(clang_getCursorKindSpelling(cursor.kind()));
os << cursorKindSpelling << " ";
auto identifier = cursor.displayName();
if (identifier.hasContent()) {
os << "\""
<< identifier
<< "\": ";
}
os << cursor.sourceLocation();
} else {
os << "Invalid cursor!";
}
return os;
}
} // namespace ClangBackEnd

View File

@@ -1,151 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "clangtype.h"
#include <clangsupport/clangsupport_global.h>
#include <clang-c/Index.h>
#include <iosfwd>
#include <vector>
namespace ClangBackEnd {
class SourceLocation;
class SourceRange;
class ClangString;
class Cursor
{
friend class Type;
friend bool operator==(const Cursor &first, const Cursor &second);
public:
Cursor();
Cursor(CXCursor cxCursor);
bool isNull() const;
bool isValid() const;
bool isTranslationUnit() const;
bool isDefinition() const;
bool isDynamicCall() const;
bool isVirtualMethod() const;
bool isPureVirtualMethod() const;
bool isConstantMethod() const;
bool isStaticMethod() const;
bool isCompoundType() const;
bool isDeclaration() const;
bool isInvalidDeclaration() const;
bool isParameter() const;
bool isLocalVariable() const;
bool isReference() const;
bool isExpression() const;
bool isFunctionLike() const;
bool isConstructorOrDestructor() const;
bool isTemplateLike() const;
bool isAnyTypeAlias() const;
bool hasFinalFunctionAttribute() const;
bool hasFinalClassAttribute() const;
bool isUnexposed() const;
bool isAnonymous() const;
Utf8String displayName() const;
ClangString unifiedSymbolResolution() const;
ClangString mangling() const;
ClangString spelling() const;
ClangString briefComment() const;
Utf8String rawComment() const;
int argumentCount() const;
Type type() const;
Type nonPointerTupe() const;
Type enumType() const;
long long enumConstantValue() const;
unsigned long long enumConstantUnsignedValue() const;
SourceLocation sourceLocation() const;
CXSourceLocation cxSourceLocation() const;
SourceRange sourceRange() const;
CXSourceRange cxSourceRange() const;
CXTranslationUnit cxTranslationUnit() const;
SourceRange commentRange() const;
bool hasSameSourceLocationAs(const Cursor &other) const;
Cursor definition() const;
Cursor canonical() const;
Cursor referenced() const;
Cursor semanticParent() const;
Cursor lexicalParent() const;
Cursor functionBaseDeclaration() const;
Cursor functionBase() const;
Type resultType() const;
Cursor argument(int index) const;
unsigned overloadedDeclarationsCount() const;
Cursor overloadedDeclaration(unsigned index) const;
Cursor specializedCursorTemplate() const;
AccessSpecifier accessSpecifier() const;
StorageClass storageClass() const;
CXFile includedFile() const;
void collectOutputArgumentRangesTo(
std::vector<CXSourceRange> &outputArgumentRanges) const;
std::vector<CXSourceRange> outputArgumentRanges() const;
CXCursorKind kind() const;
template <class VisitorCallback>
void visit(VisitorCallback visitorCallback) const;
CXCursor cx() const;
private:
CXCursor m_cxCursor;
};
template <class VisitorCallback>
void Cursor::visit(VisitorCallback visitorCallback) const
{
auto visitor = [] (CXCursor cursor, CXCursor parent, CXClientData lambda) -> CXChildVisitResult {
auto &visitorCallback = *static_cast<VisitorCallback*>(lambda);
return visitorCallback(cursor, parent);
};
clang_visitChildren(m_cxCursor, visitor, &visitorCallback);
}
bool operator==(const Cursor &first, const Cursor &second);
bool operator!=(const Cursor &first, const Cursor &second);
std::ostream &operator<<(std::ostream &os, CXCursorKind cursorKind);
std::ostream &operator<<(std::ostream &os, const Cursor &cursor);
} // namespace ClangBackEnd

View File

@@ -1,181 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "diagnostic.h"
#include "clangstring.h"
#include "diagnosticset.h"
#include "fixit.h"
#include "sourcelocation.h"
#include "sourcerange.h"
#include <diagnosticcontainer.h>
#include <memory>
namespace ClangBackEnd {
Diagnostic::Diagnostic(CXTranslationUnit translationUnit, CXDiagnostic cxDiagnostic)
: cxDiagnostic(cxDiagnostic),
cxTranslationUnit(translationUnit)
{
}
Diagnostic::~Diagnostic()
{
clang_disposeDiagnostic(cxDiagnostic);
}
Diagnostic::Diagnostic(Diagnostic &&other)
: cxDiagnostic(std::move(other.cxDiagnostic)),
cxTranslationUnit(std::move(other.cxTranslationUnit))
{
other.cxDiagnostic = nullptr;
other.cxTranslationUnit = nullptr;
}
Diagnostic &Diagnostic::operator=(Diagnostic &&other)
{
if (this != &other) {
clang_disposeDiagnostic(cxDiagnostic);
cxDiagnostic = std::move(other.cxDiagnostic);
cxTranslationUnit = std::move(other.cxTranslationUnit);
other.cxDiagnostic = nullptr;
other.cxTranslationUnit = nullptr;
}
return *this;
}
bool Diagnostic::isNull() const
{
return cxDiagnostic == nullptr;
}
Utf8String Diagnostic::text() const
{
return ClangString(clang_formatDiagnostic(cxDiagnostic, 0));
}
Utf8String Diagnostic::category() const
{
return ClangString(clang_getDiagnosticCategoryText(cxDiagnostic));
}
std::pair<Utf8String, Utf8String> Diagnostic::options() const
{
CXString disableString;
const Utf8String enableOption = ClangString(clang_getDiagnosticOption(cxDiagnostic, &disableString));
const Utf8String disableOption = ClangString(disableString);
return {enableOption, disableOption};
}
SourceLocation Diagnostic::location() const
{
return {cxTranslationUnit, clang_getDiagnosticLocation(cxDiagnostic)};
}
DiagnosticSeverity Diagnostic::severity() const
{
return static_cast<DiagnosticSeverity>(clang_getDiagnosticSeverity(cxDiagnostic));
}
std::vector<SourceRange> Diagnostic::ranges() const
{
std::vector<SourceRange> ranges;
const uint rangesCount = clang_getDiagnosticNumRanges(cxDiagnostic);
ranges.reserve(rangesCount);
for (uint index = 0; index < rangesCount; ++index) {
const SourceRange sourceRange {cxTranslationUnit,
clang_getDiagnosticRange(cxDiagnostic, index)};
if (sourceRange.isValid())
ranges.push_back(std::move(sourceRange));
}
return ranges;
}
std::vector<FixIt> Diagnostic::fixIts() const
{
std::vector<FixIt> fixIts;
const uint fixItsCount = clang_getDiagnosticNumFixIts(cxDiagnostic);
fixIts.reserve(fixItsCount);
for (uint index = 0; index < fixItsCount; ++index)
fixIts.push_back(FixIt(cxTranslationUnit, cxDiagnostic, index));
return fixIts;
}
DiagnosticSet Diagnostic::childDiagnostics() const
{
return DiagnosticSet(cxTranslationUnit, clang_getChildDiagnostics(cxDiagnostic));
}
DiagnosticContainer Diagnostic::toDiagnosticContainer() const
{
return DiagnosticContainer(text(),
category(),
options(),
severity(),
location().toSourceLocationContainer(),
getSourceRangeContainers(),
getFixItContainers(),
childDiagnostics().toDiagnosticContainers());
}
QVector<SourceRangeContainer> Diagnostic::getSourceRangeContainers() const
{
auto rangeVector = ranges();
QVector<SourceRangeContainer> sourceRangeContainers;
sourceRangeContainers.reserve(int(rangeVector.size()));
for (auto &&sourceRange : rangeVector)
sourceRangeContainers.push_back(sourceRange.toSourceRangeContainer());
return sourceRangeContainers;
}
QVector<FixItContainer> Diagnostic::getFixItContainers() const
{
auto fixItVector = fixIts();
QVector<FixItContainer> fixItContainers;
fixItContainers.reserve(int(fixItVector.size()));
for (auto &&fixIt : fixItVector)
fixItContainers.push_back(fixIt.toFixItContainer());
return fixItContainers;
}
} // namespace ClangBackEnd

View File

@@ -1,92 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <clangsupport_global.h>
#include <QVector>
#include <clang-c/Index.h>
#include <functional>
#include <vector>
class Utf8String;
namespace ClangBackEnd {
class SourceLocation;
class SourceRange;
class FixIt;
class DiagnosticSet;
class DiagnosticContainer;
class SourceRangeContainer;
class FixItContainer;
class Diagnostic
{
friend class DiagnosticSet;
friend class DiagnosticSetIterator;
friend bool operator==(Diagnostic first, Diagnostic second);
public:
~Diagnostic();
Diagnostic(const Diagnostic &) = delete;
const Diagnostic &operator=(const Diagnostic &) = delete;
Diagnostic(Diagnostic &&other);
Diagnostic &operator=(Diagnostic &&other);
bool isNull() const;
Utf8String text() const;
Utf8String category() const;
std::pair<Utf8String, Utf8String> options() const;
SourceLocation location() const;
DiagnosticSeverity severity() const;
std::vector<SourceRange> ranges() const;
std::vector<FixIt> fixIts() const;
DiagnosticSet childDiagnostics() const;
DiagnosticContainer toDiagnosticContainer() const;
private:
Diagnostic(CXTranslationUnit translationUnit, CXDiagnostic cxDiagnostic);
QVector<SourceRangeContainer> getSourceRangeContainers() const;
QVector<FixItContainer> getFixItContainers() const;
private:
CXDiagnostic cxDiagnostic;
CXTranslationUnit cxTranslationUnit;
};
inline bool operator==(Diagnostic first, Diagnostic second)
{
return first.cxDiagnostic == second.cxDiagnostic;
}
} // namespace ClangBackEnd

View File

@@ -1,124 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "diagnosticset.h"
#include "diagnostic.h"
#include <diagnosticcontainer.h>
#include <memory>
namespace ClangBackEnd {
DiagnosticSet::DiagnosticSet(CXTranslationUnit translationUnit, CXDiagnosticSet cxDiagnosticSet)
: cxDiagnosticSet(cxDiagnosticSet),
cxTranslationUnit(translationUnit)
{
}
DiagnosticSet::~DiagnosticSet()
{
clang_disposeDiagnosticSet(cxDiagnosticSet);
}
DiagnosticSet::DiagnosticSet(DiagnosticSet &&other)
: cxDiagnosticSet(std::move(other.cxDiagnosticSet)),
cxTranslationUnit(std::move(other.cxTranslationUnit))
{
other.cxDiagnosticSet = nullptr;
}
DiagnosticSet &DiagnosticSet::operator=(DiagnosticSet &&other)
{
if (this != &other) {
clang_disposeDiagnosticSet(cxDiagnosticSet);
cxDiagnosticSet = std::move(other.cxDiagnosticSet);
cxTranslationUnit = std::move(other.cxTranslationUnit);
other.cxDiagnosticSet = nullptr;
other.cxTranslationUnit = nullptr;
}
return *this;
}
Diagnostic DiagnosticSet::front() const
{
return Diagnostic(cxTranslationUnit, clang_getDiagnosticInSet(cxDiagnosticSet, 0));
}
Diagnostic DiagnosticSet::back() const
{
return Diagnostic(cxTranslationUnit, clang_getDiagnosticInSet(cxDiagnosticSet, size() - 1));
}
DiagnosticSet::ConstIterator DiagnosticSet::begin() const
{
return DiagnosticSetIterator(cxTranslationUnit, cxDiagnosticSet, 0);
}
DiagnosticSet::ConstIterator DiagnosticSet::end() const
{
return DiagnosticSetIterator(cxTranslationUnit, cxDiagnosticSet, size());
}
QVector<DiagnosticContainer> DiagnosticSet::toDiagnosticContainers() const
{
const auto isAcceptedDiagnostic = [](const Diagnostic &) { return true; };
return toDiagnosticContainers(isAcceptedDiagnostic);
}
QVector<DiagnosticContainer> DiagnosticSet::toDiagnosticContainers(
const IsAcceptedDiagnostic &isAcceptedDiagnostic) const
{
QVector<DiagnosticContainer> diagnosticContainers;
diagnosticContainers.reserve(size());
for (const Diagnostic &diagnostic : *this) {
if (isAcceptedDiagnostic(diagnostic))
diagnosticContainers.push_back(diagnostic.toDiagnosticContainer());
}
return diagnosticContainers;
}
uint DiagnosticSet::size() const
{
return clang_getNumDiagnosticsInSet(cxDiagnosticSet);
}
bool DiagnosticSet::isNull() const
{
return cxDiagnosticSet == nullptr;
}
Diagnostic DiagnosticSet::at(uint index) const
{
return Diagnostic(cxTranslationUnit, clang_getDiagnosticInSet(cxDiagnosticSet, index));
}
} // namespace ClangBackEnd

View File

@@ -1,82 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "diagnostic.h"
#include "diagnosticsetiterator.h"
#include <clang-c/Index.h>
#include <QVector>
#include <functional>
namespace ClangBackEnd {
class DiagnosticSetIterator;
class DiagnosticSet
{
friend class TranslationUnit;
friend class Diagnostic;
public:
using ConstIterator = DiagnosticSetIterator;
public:
~DiagnosticSet();
DiagnosticSet(const DiagnosticSet &) = delete;
const DiagnosticSet &operator=(const DiagnosticSet &) = delete;
DiagnosticSet(DiagnosticSet &&other);
DiagnosticSet &operator=(DiagnosticSet &&other);
uint size() const;
bool isNull() const;
Diagnostic at(uint index) const;
Diagnostic front() const;
Diagnostic back() const;
ConstIterator begin() const;
ConstIterator end() const;
using IsAcceptedDiagnostic = std::function<bool (const Diagnostic &)>;
QVector<DiagnosticContainer> toDiagnosticContainers() const;
QVector<DiagnosticContainer> toDiagnosticContainers(
const IsAcceptedDiagnostic &isAcceptedDiagnostic) const;
private:
DiagnosticSet(CXTranslationUnit translationUnit, CXDiagnosticSet cxDiagnosticSet);
private:
CXDiagnosticSet cxDiagnosticSet;
CXTranslationUnit cxTranslationUnit;
};
} // namespace ClangBackEnd

View File

@@ -1,95 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "diagnostic.h"
#include <iterator>
#include <clang-c/Index.h>
namespace ClangBackEnd {
using uint = unsigned int;
class DiagnosticSet;
class DiagnosticSetIterator
{
public:
using iterator_category = std::random_access_iterator_tag;
using value_type = Diagnostic;
using difference_type = uint;
using pointer = Diagnostic *;
using reference = Diagnostic &;
DiagnosticSetIterator(CXTranslationUnit translationUnit,
CXDiagnosticSet cxDiagnosticSet,
uint index)
: cxDiagnosticSet(cxDiagnosticSet),
cxTranslationUnit(translationUnit),
index(index)
{}
DiagnosticSetIterator(const DiagnosticSetIterator &other)
: cxDiagnosticSet(other.cxDiagnosticSet),
index(other.index)
{}
DiagnosticSetIterator& operator++()
{
++index;
return *this;
}
DiagnosticSetIterator operator++(int)
{
uint oldIndex = index++;
return DiagnosticSetIterator(cxTranslationUnit, cxDiagnosticSet, oldIndex);
}
bool operator==(const DiagnosticSetIterator &other) const
{
return index == other.index && cxDiagnosticSet == other.cxDiagnosticSet;
}
bool operator!=(const DiagnosticSetIterator &other) const
{
return index != other.index || cxDiagnosticSet != other.cxDiagnosticSet;
}
Diagnostic operator*()
{
return Diagnostic(cxTranslationUnit, clang_getDiagnosticInSet(cxDiagnosticSet, index));
}
private:
CXDiagnosticSet cxDiagnosticSet;
CXTranslationUnit cxTranslationUnit;
uint index;
};
}

View File

@@ -1,58 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "fixit.h"
#include "clangstring.h"
#include <fixitcontainer.h>
namespace ClangBackEnd {
const Utf8String &FixIt::text() const
{
return text_;
}
const SourceRange &FixIt::range() const
{
return sourceRange;
}
FixItContainer FixIt::toFixItContainer() const
{
return FixItContainer(text_, sourceRange.toSourceRangeContainer());
}
FixIt::FixIt(CXTranslationUnit translationUnit, CXDiagnostic cxDiagnostic, uint index)
{
CXSourceRange cxSourceRange;
text_ = ClangString(clang_getDiagnosticFixIt(cxDiagnostic, index, &cxSourceRange));
sourceRange = SourceRange(translationUnit, cxSourceRange);
}
} // namespace ClangBackEnd

View File

@@ -1,57 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "sourcerange.h"
#include <utf8string.h>
#include <clang-c/Index.h>
namespace ClangBackEnd {
class FixItContainer;
using uint = unsigned int;
class FixIt
{
friend class Diagnostic;
public:
const Utf8String &text() const;
const SourceRange &range() const;
FixItContainer toFixItContainer() const;
private:
FixIt(CXTranslationUnit translationUnit, CXDiagnostic cxDiagnostic, uint index);
private:
SourceRange sourceRange;
Utf8String text_;
};
} // namespace ClangBackEnd

View File

@@ -1,264 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2018 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 "clangstring.h"
#include "clangtooltipinfocollector.h"
#include "cursor.h"
#include "fulltokeninfo.h"
#include "sourcerange.h"
#include "token.h"
#include "tokenprocessor.h"
#include <utils/predicates.h>
namespace ClangBackEnd {
FullTokenInfo::FullTokenInfo(const Cursor &cursor,
const Token *token,
std::vector<CXSourceRange> &currentOutputArgumentRanges)
: TokenInfo(cursor, token, currentOutputArgumentRanges)
{
}
FullTokenInfo::operator TokenInfoContainer() const
{
return TokenInfoContainer(line(), column(), length(), m_types, m_extraInfo);
}
static Utf8String fullyQualifiedType(const Cursor &cursor) {
Utf8String prefix;
if (cursor.kind() == CXCursor_ClassTemplate || cursor.kind() == CXCursor_Namespace)
return qualificationPrefix(cursor) + cursor.displayName();
return cursor.type().canonical().spelling();
}
void FullTokenInfo::updateTypeSpelling(const Cursor &cursor, bool functionLike)
{
m_extraInfo.semanticParentTypeSpelling = fullyQualifiedType(cursor.semanticParent());
if (!functionLike) {
m_extraInfo.typeSpelling = fullyQualifiedType(cursor);
return;
}
m_extraInfo.token = cursor.displayName();
// On the client side full type is typeSpelling + token.
m_extraInfo.typeSpelling = cursor.type().resultType().utf8Spelling();
}
static Utf8String propertyParentSpelling(CXTranslationUnit cxTranslationUnit,
const Utf8String &filePath,
uint line, uint column)
{
// Q_PROPERTY expands into QPropertyMagicFunction which can be found as a child of
// the containing class.
Cursor tuCursor = clang_getTranslationUnitCursor(cxTranslationUnit);
Utf8String parentSpelling;
tuCursor.visit([&filePath, line, column, &parentSpelling](CXCursor cxCursor, CXCursor parent) {
const CXCursorKind kind = clang_getCursorKind(cxCursor);
if (kind == CXCursor_Namespace || kind == CXCursor_StructDecl
|| kind == CXCursor_ClassDecl || kind == CXCursor_StaticAssert) {
Cursor cursor(cxCursor);
const SourceRange range = cursor.sourceRange();
if (range.start().filePath() != filePath)
return CXChildVisit_Continue;
if (range.contains(line, column)) {
if (kind == CXCursor_Namespace || kind == CXCursor_StructDecl
|| kind == CXCursor_ClassDecl) {
return CXChildVisit_Recurse;
}
// CXCursor_StaticAssert case. This is Q_PROPERTY static_assert
parentSpelling = Cursor(parent).type().spelling();
return CXChildVisit_Break;
}
}
return CXChildVisit_Continue;
});
return parentSpelling;
}
static Utf8String getPropertyType(const SourceLocation &location, uint propertyPosition)
{
// Extract property type from the source code
CXFile cxFile;
uint offset;
clang_getFileLocation(location.cx(), &cxFile, nullptr, nullptr, &offset);
const char *const contents = clang_getFileContents(location.tu(), cxFile, nullptr);
const int keywordOffset = QByteArray::fromRawData(contents, propertyPosition)
.lastIndexOf("Q_PROPERTY");
if (keywordOffset == -1)
return {};
const char * const keywordStart = contents + keywordOffset;
const char *typeStart = keywordStart + 10;
typeStart += std::strspn(typeStart, "( \t\n\r");
if (typeStart - keywordStart >= propertyPosition)
return Utf8String();
auto typeEnd = std::find_if(std::reverse_iterator<const char*>(keywordStart + propertyPosition),
std::reverse_iterator<const char*>(typeStart),
Utils::unequalTo(' '));
return Utf8String(typeStart, static_cast<int>(&(*typeEnd) + 1 - typeStart));
}
void FullTokenInfo::updatePropertyData()
{
const SourceRange range = m_token->extent();
m_extraInfo.semanticParentTypeSpelling = propertyParentSpelling(m_token->tu(),
range.start().filePath(),
line(),
column());
m_extraInfo.cursorRange = range;
m_extraInfo.declaration = true;
m_extraInfo.definition = true;
m_extraInfo.typeSpelling = getPropertyType(range.start(), column() - 1);
}
void FullTokenInfo::identifierKind(const Cursor &cursor, Recursion recursion)
{
updateTypeSpelling(cursor);
TokenInfo::identifierKind(cursor, recursion);
m_extraInfo.identifier = (cursor.kind() != CXCursor_PreprocessingDirective);
if (m_types.mainHighlightingType == HighlightingType::QtProperty)
updatePropertyData();
else
m_extraInfo.cursorRange = cursor.sourceRange();
}
void FullTokenInfo::referencedTypeKind(const Cursor &cursor)
{
updateTypeSpelling(cursor.referenced());
TokenInfo::referencedTypeKind(cursor);
}
void FullTokenInfo::functionKind(const Cursor &cursor, Recursion recursion)
{
updateTypeSpelling(cursor, true);
TokenInfo::functionKind(cursor, recursion);
m_extraInfo.accessSpecifier = cursor.accessSpecifier();
m_extraInfo.storageClass = cursor.storageClass();
bool isSignal = false;
bool isSlot = false;
m_originalCursor.visit([&isSignal, &isSlot](CXCursor cursor, CXCursor) {
Cursor cur(cursor);
ClangString spelling = cur.spelling();
if (spelling == "qt_signal")
isSignal = true;
else if (spelling == "qt_slot")
isSlot = true;
return CXChildVisit_Break;
});
m_extraInfo.signal = isSignal;
m_extraInfo.slot = isSlot;
}
void FullTokenInfo::variableKind(const Cursor &cursor)
{
TokenInfo::variableKind(cursor);
m_extraInfo.accessSpecifier = cursor.accessSpecifier();
m_extraInfo.storageClass = cursor.storageClass();
}
void FullTokenInfo::fieldKind(const Cursor &cursor)
{
TokenInfo::fieldKind(cursor);
m_extraInfo.accessSpecifier = cursor.accessSpecifier();
m_extraInfo.storageClass = cursor.storageClass();
}
void FullTokenInfo::memberReferenceKind(const Cursor &cursor)
{
TokenInfo::memberReferenceKind(cursor);
if (cursor.isDynamicCall()) {
m_extraInfo.storageClass = cursor.storageClass();
m_extraInfo.accessSpecifier = cursor.accessSpecifier();
}
}
void FullTokenInfo::keywordKind()
{
TokenInfo::keywordKind();
if (m_originalCursor.isAnonymous()) {
CXCursorKind cursorKind = m_originalCursor.kind();
if (cursorKind == CXCursor_EnumDecl)
m_types.mixinHighlightingTypes.push_back(HighlightingType::Enum);
else if (cursorKind == CXCursor_ClassDecl)
m_types.mixinHighlightingTypes.push_back(HighlightingType::Class);
else if (cursorKind == CXCursor_StructDecl)
m_types.mixinHighlightingTypes.push_back(HighlightingType::Struct);
else if (cursorKind == CXCursor_Namespace)
m_types.mixinHighlightingTypes.push_back(HighlightingType::Namespace);
m_extraInfo.declaration = m_extraInfo.definition = true;
m_extraInfo.token = m_originalCursor.displayName();
updateTypeSpelling(m_originalCursor);
m_extraInfo.cursorRange = m_originalCursor.sourceRange();
}
}
void FullTokenInfo::overloadedOperatorKind()
{
TokenInfo::overloadedOperatorKind();
if (!m_types.mixinHighlightingTypes.contains(HighlightingType::OverloadedOperator))
return;
// Overloaded operator
m_extraInfo.identifier = true;
if (!m_originalCursor.isDeclaration())
return;
// Overloaded operator declaration
m_extraInfo.declaration = true;
m_extraInfo.definition = m_originalCursor.isDefinition();
updateTypeSpelling(m_originalCursor, true);
m_extraInfo.cursorRange = m_originalCursor.sourceRange();
m_extraInfo.accessSpecifier = m_originalCursor.accessSpecifier();
m_extraInfo.storageClass = m_originalCursor.storageClass();
}
void FullTokenInfo::evaluate()
{
m_extraInfo.token = m_token->spelling();
CXTokenKind cxTokenKind = m_token->kind();
if (cxTokenKind == CXToken_Identifier) {
m_extraInfo.declaration = m_originalCursor.isDeclaration();
m_extraInfo.definition = m_originalCursor.isDefinition();
}
m_extraInfo.includeDirectivePath = (m_originalCursor.kind() == CXCursor_InclusionDirective);
TokenInfo::evaluate();
}
} // namespace ClangBackEnd

View File

@@ -1,59 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2018 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 "tokeninfo.h"
namespace ClangBackEnd {
class FullTokenInfo : public TokenInfo
{
template<class T> friend class TokenProcessor;
public:
FullTokenInfo() = default;
FullTokenInfo(const Cursor &cursor,
const Token *token,
std::vector<CXSourceRange> &m_currentOutputArgumentRanges);
void evaluate() override;
operator TokenInfoContainer() const override;
protected:
void identifierKind(const Cursor &cursor, Recursion recursion) override;
void referencedTypeKind(const Cursor &cursor) override;
void functionKind(const Cursor &cursor, Recursion recursion) override;
void variableKind(const Cursor &cursor) override;
void fieldKind(const Cursor &cursor) override;
void memberReferenceKind(const Cursor &cursor) override;
void keywordKind() override;
void overloadedOperatorKind() override;
private:
void updateTypeSpelling(const Cursor &cursor, bool functionLike = false);
void updatePropertyData();
ExtraInfo m_extraInfo;
};
} // namespace ClangBackEnd

View File

@@ -1,134 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "skippedsourceranges.h"
#include "sourcerangecontainer.h"
#include <QVector>
#include <algorithm>
namespace ClangBackEnd {
SkippedSourceRanges::SkippedSourceRanges(CXTranslationUnit cxTranslationUnit, const char *filePath)
: cxTranslationUnit(cxTranslationUnit)
, cxSkippedSourceRanges(clang_getSkippedRanges(cxTranslationUnit,
clang_getFile(cxTranslationUnit, filePath)))
{
}
SkippedSourceRanges::~SkippedSourceRanges()
{
clang_disposeSourceRangeList(cxSkippedSourceRanges);
}
SkippedSourceRanges &SkippedSourceRanges::operator=(SkippedSourceRanges &&other)
{
if (this != &other) {
this->~SkippedSourceRanges();
cxTranslationUnit = other.cxTranslationUnit;
cxSkippedSourceRanges = other.cxSkippedSourceRanges;
other.cxTranslationUnit = nullptr;
other.cxSkippedSourceRanges = nullptr;
}
return *this;
}
// For some reason, libclang starts the skipped range on the line containing the
// preprocessor directive preceding the ifdef'ed out code (i.e. #if or #else)
// and ends it on the line following the ifdef'ed out code (#else or #endif, respectively).
// We don't want the preprocessor directives grayed out, so adapt the locations.
static SourceRange adaptedSourceRange(CXTranslationUnit cxTranslationUnit, const SourceRange &range)
{
const SourceLocation end = range.end();
return SourceRange {
SourceLocation(cxTranslationUnit,
clang_getLocation(cxTranslationUnit,
clang_getFile(cxTranslationUnit,
end.filePath().constData()),
range.start().line() + 1, 1)),
SourceLocation(cxTranslationUnit,
clang_getLocation(cxTranslationUnit,
clang_getFile(cxTranslationUnit,
end.filePath().constData()),
end.line(), 1))
};
}
// TODO: This should report a line range.
std::vector<SourceRange> SkippedSourceRanges::sourceRanges() const
{
std::vector<SourceRange> sourceRanges;
auto sourceRangeCount = cxSkippedSourceRanges->count;
sourceRanges.reserve(sourceRangeCount);
for (uint i = 0; i < cxSkippedSourceRanges->count; ++i) {
const SourceRange range {cxTranslationUnit, cxSkippedSourceRanges->ranges[i]};
const SourceRange adaptedRange = adaptedSourceRange(cxTranslationUnit, range);
sourceRanges.push_back(adaptedRange);
}
return sourceRanges;
}
QVector<SourceRangeContainer> SkippedSourceRanges::toSourceRangeContainers() const
{
QVector<SourceRangeContainer> sourceRangeContainers;
auto sourceRanges = this->sourceRanges();
std::copy(sourceRanges.cbegin(),
sourceRanges.cend(),
std::back_inserter(sourceRangeContainers));
return sourceRangeContainers;
}
bool SkippedSourceRanges::isNull() const
{
return cxTranslationUnit == nullptr || cxSkippedSourceRanges == nullptr;
}
ClangBackEnd::SkippedSourceRanges::operator QVector<SourceRangeContainer>() const
{
return toSourceRangeContainers();
}
SkippedSourceRanges::SkippedSourceRanges(SkippedSourceRanges &&other)
: cxTranslationUnit(other.cxTranslationUnit)
, cxSkippedSourceRanges(other.cxSkippedSourceRanges)
{
other.cxTranslationUnit = nullptr;
other.cxSkippedSourceRanges = nullptr;
}
} // namespace ClangBackEnd

View File

@@ -1,59 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "sourcerange.h"
namespace ClangBackEnd {
class SourceRangeContainer;
class SkippedSourceRanges
{
public:
SkippedSourceRanges(CXTranslationUnit Document, const char *filePath);
~SkippedSourceRanges();
SkippedSourceRanges(const SkippedSourceRanges &) = delete;
const SkippedSourceRanges &operator=(const SkippedSourceRanges &) = delete;
SkippedSourceRanges(SkippedSourceRanges &&);
SkippedSourceRanges &operator=(SkippedSourceRanges &&);
std::vector<SourceRange> sourceRanges() const;
QVector<SourceRangeContainer> toSourceRangeContainers() const;
bool isNull() const;
operator QVector<SourceRangeContainer>() const;
private:
CXTranslationUnit cxTranslationUnit = nullptr;
CXSourceRangeList *cxSkippedSourceRanges = nullptr;
};
} // namespace ClangBackEnd

View File

@@ -1,148 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "sourcelocation.h"
#include "clangdocument.h"
#include "clangfilepath.h"
#include "clangstring.h"
#include <clangsupport/sourcelocationcontainer.h>
#include <clangsupport/utf8string.h>
#include <utils/textutils.h>
#include <ostream>
namespace ClangBackEnd {
SourceLocation::SourceLocation()
: m_cxSourceLocation(clang_getNullLocation())
{
}
const Utf8String &SourceLocation::filePath() const
{
if (!m_isEvaluated)
evaluate();
if (m_isFilePathNormalized)
return m_filePath;
m_isFilePathNormalized = true;
m_filePath = FilePath::fromNativeSeparators(m_filePath);
return m_filePath;
}
int SourceLocation::line() const
{
if (!m_isEvaluated)
evaluate();
return m_line;
}
int SourceLocation::column() const
{
if (!m_isEvaluated)
evaluate();
return m_column;
}
int SourceLocation::offset() const
{
if (!m_isEvaluated)
evaluate();
return m_offset;
}
SourceLocationContainer SourceLocation::toSourceLocationContainer() const
{
if (!m_isEvaluated)
evaluate();
return SourceLocationContainer(filePath(), m_line, m_column);
}
void SourceLocation::evaluate() const
{
m_isEvaluated = true;
CXFile cxFile;
unsigned line, column, offset;
clang_getFileLocation(m_cxSourceLocation,
&cxFile,
&line,
&column,
&offset);
m_line = line;
m_column = column;
m_offset = offset;
m_isFilePathNormalized = false;
if (!cxFile)
return;
m_filePath = ClangString(clang_getFileName(cxFile));
if (m_column > 1) {
const int lineStart = m_offset + 1 - m_column;
const char *contents = clang_getFileContents(m_cxTranslationUnit, cxFile, nullptr);
if (!contents)
return;
// (1) column in SourceLocation is the actual column shown by CppEditor.
// (2) column in Clang is the utf8 byte offset from the beginning of the line.
// Here we convert column from (2) to (1).
m_column = QString::fromUtf8(&contents[lineStart], m_column - 1).size() + 1;
}
}
SourceLocation::SourceLocation(CXTranslationUnit cxTranslationUnit,
CXSourceLocation cxSourceLocation)
: m_cxSourceLocation(cxSourceLocation)
, m_cxTranslationUnit(cxTranslationUnit)
{
}
SourceLocation::operator CXSourceLocation() const
{
return m_cxSourceLocation;
}
std::ostream &operator<<(std::ostream &os, const SourceLocation &sourceLocation)
{
auto filePath = sourceLocation.filePath();
if (filePath.hasContent())
os << filePath << ", ";
os << "line: " << sourceLocation.line()
<< ", column: "<< sourceLocation.column()
<< ", offset: "<< sourceLocation.offset();
return os;
}
} // namespace ClangBackEnd

Some files were not shown because too many files have changed in this diff Show More