forked from qt-creator/qt-creator
Remove clangbackend
Change-Id: I5f4f9a2fc5469c4eeb112a46626791ffb9a57a85 Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
@@ -1,10 +1,5 @@
|
||||
add_subdirectory(3rdparty)
|
||||
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)
|
||||
|
||||
|
@@ -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
|
||||
)
|
@@ -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"])
|
||||
}
|
||||
}
|
@@ -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();
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
)
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
||||
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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 ¤tToken = *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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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 ¬AddableReason)
|
||||
{
|
||||
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
|
@@ -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 ¬AddableReason);
|
||||
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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
||||
|
@@ -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
|
@@ -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
|
@@ -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
|
||||
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
||||
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
||||
|
@@ -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
|
@@ -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
|
||||
|
@@ -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
|
@@ -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
|
||||
|
@@ -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
|
@@ -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
|
||||
|
@@ -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
|
@@ -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 ¤tCompletion : 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(¤tCompletion);
|
||||
} 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(¤tCompletion);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 ¤tCompletion : 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 << ¤tCompletion;
|
||||
}
|
||||
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
|
||||
|
@@ -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 ¤tCodeCompletion() 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
|
@@ -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
|
@@ -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
|
@@ -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
|
||||
|
@@ -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
|
@@ -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
|
||||
|
@@ -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
|
@@ -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
|
||||
|
@@ -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
|
@@ -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;
|
||||
};
|
||||
|
||||
}
|
@@ -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
|
||||
|
@@ -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
|
@@ -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> ¤tOutputArgumentRanges)
|
||||
: 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
|
@@ -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
|
@@ -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
|
||||
|
@@ -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
|
@@ -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
Reference in New Issue
Block a user